From d8398594b7bc43da5eb865321c5a50cec4b3923d Mon Sep 17 00:00:00 2001 From: damithc Date: Mon, 25 May 2020 00:58:18 +0800 Subject: [PATCH 01/50] Add Gradle support --- build.gradle | 46 ++++++ gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 58695 bytes gradle/wrapper/gradle-wrapper.properties | 5 + gradlew | 183 +++++++++++++++++++++++ gradlew.bat | 103 +++++++++++++ text-ui-test/runtest.sh | 0 6 files changed, 337 insertions(+) create mode 100644 build.gradle create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 gradlew.bat mode change 100644 => 100755 text-ui-test/runtest.sh diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000000..20c0521cc7 --- /dev/null +++ b/build.gradle @@ -0,0 +1,46 @@ +plugins { + id 'java' + id 'application' + id 'checkstyle' + id 'com.github.johnrengelman.shadow' version '5.1.0' +} + +repositories { + mavenCentral() +} + +dependencies { + testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.5.0' + testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.5.0' +} + +test { + useJUnitPlatform() + + testLogging { + events "passed", "skipped", "failed" + + showExceptions true + exceptionFormat "full" + showCauses true + showStackTraces true + showStandardStreams = false + } +} + +application { + mainClassName = "seedu.duke.Duke" +} + +shadowJar { + archiveBaseName = "duke" + archiveClassifier = null +} + +checkstyle { + toolVersion = '8.29' +} + +run{ + standardInput = System.in +} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..f3d88b1c2faf2fc91d853cd5d4242b5547257070 GIT binary patch literal 58695 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 literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000..b7c8c5dbf5 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.2-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 0000000000..2fe81a7d95 --- /dev/null +++ b/gradlew @@ -0,0 +1,183 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000000..62bd9b9cce --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,103 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/text-ui-test/runtest.sh b/text-ui-test/runtest.sh old mode 100644 new mode 100755 From 6a815ae23382ae5d643366f56a7d47984a9158f8 Mon Sep 17 00:00:00 2001 From: Decaxical Date: Tue, 25 Jan 2022 20:30:34 +0800 Subject: [PATCH 02/50] implement echoes Echoes the commands inputted by the user --- README.md | 2 +- src/main/java/Duke.java | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8715d4d915..48ba0c52c4 100644 --- a/README.md +++ b/README.md @@ -21,4 +21,4 @@ Prerequisites: JDK 11, update Intellij to the most recent version. | | | | | | | |/ / _ \ | |_| | |_| | < __/ |____/ \__,_|_|\_\___| - ``` + ``` \ No newline at end of file diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index 5d313334cc..27b3732132 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -1,4 +1,16 @@ +import java.util.Scanner; + public class Duke { + public static void echo() { + Scanner getUserInput = new Scanner(System.in); + String userInput = ""; + while (!userInput.equals("bye")) { + System.out.println(userInput); + userInput = getUserInput.nextLine(); + } + System.out.println("Till we meet again"); + } + public static void main(String[] args) { String logo = " ____ _ \n" + "| _ \\ _ _| | _____ \n" @@ -6,5 +18,7 @@ public static void main(String[] args) { + "| |_| | |_| | < __/\n" + "|____/ \\__,_|_|\\_\\___|\n"; System.out.println("Hello from\n" + logo); + System.out.println("How may I assist you?"); + echo(); } } From a716a9b73d5d6ec212f86f66a45580ac5b9d00be Mon Sep 17 00:00:00 2001 From: Decaxical Date: Tue, 25 Jan 2022 21:29:50 +0800 Subject: [PATCH 03/50] List ability implemented the ability to add tasks to a list and to display it --- src/main/java/Duke.java | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index 27b3732132..b50b2b8455 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -1,11 +1,27 @@ import java.util.Scanner; +import java.util.ArrayList; public class Duke { - public static void echo() { + + public static void displayList(ArrayList taskList) { + int taskCounter = 1; + for(String task:taskList) { + System.out.println(String.format("%d. %s", taskCounter, task)); + taskCounter++; + } + } + + public static void listOperations() { + ArrayList taskList = new ArrayList<>(); Scanner getUserInput = new Scanner(System.in); - String userInput = ""; + String userInput = getUserInput.nextLine(); while (!userInput.equals("bye")) { - System.out.println(userInput); + if (userInput.equals("list")) { + displayList(taskList); + } else { + taskList.add(userInput); + System.out.println("added: " + userInput); + } userInput = getUserInput.nextLine(); } System.out.println("Till we meet again"); @@ -19,6 +35,6 @@ public static void main(String[] args) { + "|____/ \\__,_|_|\\_\\___|\n"; System.out.println("Hello from\n" + logo); System.out.println("How may I assist you?"); - echo(); + listOperations(); } } From bb75b50a17c3483fd161736ca3211404a3b2a36b Mon Sep 17 00:00:00 2001 From: Decaxical Date: Wed, 26 Jan 2022 10:29:40 +0800 Subject: [PATCH 04/50] Added mark and unmark task functionality Added a new class task to help with marking and unmarking --- src/main/java/Duke.java | 78 ++++++++++++++++++++++++++++++++++------- src/main/java/Task.java | 22 ++++++++++++ 2 files changed, 88 insertions(+), 12 deletions(-) create mode 100644 src/main/java/Task.java diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index b50b2b8455..202afbf49e 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -1,30 +1,83 @@ +//package DukeTaskBot; +import java.util.Locale; import java.util.Scanner; import java.util.ArrayList; public class Duke { - public static void displayList(ArrayList taskList) { + private static ArrayList taskList; + private static Scanner getUserInput; + + private static void initialize(){ + taskList = new ArrayList<>(); + getUserInput = new Scanner(System.in); + } + + public static void displayList(ArrayList taskList) { int taskCounter = 1; - for(String task:taskList) { - System.out.println(String.format("%d. %s", taskCounter, task)); + for(Task task:taskList) { + System.out.printf("%d. %s \n", taskCounter, task.toString()); taskCounter++; } } public static void listOperations() { - ArrayList taskList = new ArrayList<>(); - Scanner getUserInput = new Scanner(System.in); String userInput = getUserInput.nextLine(); - while (!userInput.equals("bye")) { - if (userInput.equals("list")) { + String[] parsedUserInput = userInput.split(" "); + switch (parsedUserInput[0].toLowerCase()) { + case "" : + listOperations(); + break; + case "bye": + System.out.println("Till we meet again"); + break; + case "list": displayList(taskList); - } else { - taskList.add(userInput); + listOperations(); + break; + case "mark": + int taskToMarkNumber = Integer.parseInt(parsedUserInput[1]); + if (taskToMarkNumber > taskList.size()) { + System.out.println("I am afraid that's an invalid task! Please check your task number"); + listOperations(); + break; + } + Task taskToMark = taskList.get(taskToMarkNumber - 1); + taskToMark.markAsDone(); + System.out.println("Duly noted. The following task is marked as done"); + System.out.println(taskToMark.toString()); + listOperations(); + break; + case "unmark": + int taskToUnmarkNumber = Integer.parseInt(parsedUserInput[1]); + if (taskToUnmarkNumber > taskList.size()) { + System.out.println("I am afraid that's an invalid task! Please check your task number"); + listOperations(); + break; + } + Task taskToUnmark = taskList.get(taskToUnmarkNumber - 1); + taskToUnmark.markAsNotDone(); + System.out.println("Very well. The following task has been marked as undone"); + System.out.println(taskToUnmark.toString()); + listOperations(); + break; + default: + Task taskToAdd = new Task(userInput); + taskList.add(taskToAdd); System.out.println("added: " + userInput); - } - userInput = getUserInput.nextLine(); + listOperations(); } - System.out.println("Till we meet again"); +// while (!userInput.equals("bye")) { +// if (userInput.equals("list")) { +// displayList(taskList); +// } else { +// Task taskToAdd = new Task(userInput); +// taskList.add(taskToAdd); +// System.out.println("added: " + userInput); +// } +// userInput = getUserInput.nextLine(); +// } +// System.out.println("Till we meet again"); } public static void main(String[] args) { @@ -35,6 +88,7 @@ public static void main(String[] args) { + "|____/ \\__,_|_|\\_\\___|\n"; System.out.println("Hello from\n" + logo); System.out.println("How may I assist you?"); + initialize(); listOperations(); } } diff --git a/src/main/java/Task.java b/src/main/java/Task.java new file mode 100644 index 0000000000..7f6aae79da --- /dev/null +++ b/src/main/java/Task.java @@ -0,0 +1,22 @@ +public class Task { + String content; + boolean markedDone = false; + + public Task(String content) { + this.content = content; + } + + public void markAsDone() { + this.markedDone = true; + } + + public void markAsNotDone() { + this.markedDone = false; + } + + @Override + public String toString() { + return "[" + (this.markedDone ? "X" : " ") + "] " + this.content; + } + +} From 8e1949471b3fd4d3dd192e4962c35efe6d8ac96f Mon Sep 17 00:00:00 2001 From: Decaxical Date: Sun, 30 Jan 2022 16:31:50 +0800 Subject: [PATCH 05/50] Implement Todo, Event, Deadline functionality made Todo, Event and Deadline extend from task --- src/main/java/Deadline.java | 14 ++++ src/main/java/Duke.java | 126 ++++++++++++++++++++---------------- src/main/java/Event.java | 14 ++++ src/main/java/Todo.java | 10 +++ 4 files changed, 110 insertions(+), 54 deletions(-) create mode 100644 src/main/java/Deadline.java create mode 100644 src/main/java/Event.java create mode 100644 src/main/java/Todo.java diff --git a/src/main/java/Deadline.java b/src/main/java/Deadline.java new file mode 100644 index 0000000000..f71479f7d8 --- /dev/null +++ b/src/main/java/Deadline.java @@ -0,0 +1,14 @@ +public class Deadline extends Task{ + + private String date; + + public Deadline(String content, String date) { + super(content); + this.date = date; + } + + @Override + public String toString() { + return String.format("[D]%s (by: %s)", super.toString(), this.date); + } +} diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index 202afbf49e..a95afdbbac 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -13,71 +13,89 @@ private static void initialize(){ getUserInput = new Scanner(System.in); } - public static void displayList(ArrayList taskList) { + public static void displayTaskList() { + if (taskList.isEmpty()) { + System.out.println("Your current task list is empty"); + return; + } int taskCounter = 1; + System.out.println("These are the current tasks in your list:"); for(Task task:taskList) { System.out.printf("%d. %s \n", taskCounter, task.toString()); taskCounter++; } } - public static void listOperations() { + public static void displayTaskAdd(Task addedTask){ + System.out.println("This task has been added as requested:"); + System.out.println(addedTask.toString()); + System.out.printf("You now have %d item(s) in your list\n", taskList.size()); + } + + public static void commandProcessor() { String userInput = getUserInput.nextLine(); - String[] parsedUserInput = userInput.split(" "); + String[] parsedUserInput = userInput.split(" ", 2); switch (parsedUserInput[0].toLowerCase()) { - case "" : - listOperations(); - break; - case "bye": - System.out.println("Till we meet again"); - break; - case "list": - displayList(taskList); - listOperations(); - break; - case "mark": - int taskToMarkNumber = Integer.parseInt(parsedUserInput[1]); - if (taskToMarkNumber > taskList.size()) { - System.out.println("I am afraid that's an invalid task! Please check your task number"); - listOperations(); - break; - } - Task taskToMark = taskList.get(taskToMarkNumber - 1); - taskToMark.markAsDone(); - System.out.println("Duly noted. The following task is marked as done"); - System.out.println(taskToMark.toString()); - listOperations(); + case "" : + commandProcessor(); + break; + case "bye": + System.out.println("Till we meet again"); + break; + case "list": + displayTaskList(); + commandProcessor(); + break; + case "mark": + int taskToMarkNumber = Integer.parseInt(parsedUserInput[1]); + if (taskToMarkNumber > taskList.size()) { + System.out.println("I am afraid that's an invalid task! Please check your task number"); + commandProcessor(); break; - case "unmark": - int taskToUnmarkNumber = Integer.parseInt(parsedUserInput[1]); - if (taskToUnmarkNumber > taskList.size()) { - System.out.println("I am afraid that's an invalid task! Please check your task number"); - listOperations(); - break; - } - Task taskToUnmark = taskList.get(taskToUnmarkNumber - 1); - taskToUnmark.markAsNotDone(); - System.out.println("Very well. The following task has been marked as undone"); - System.out.println(taskToUnmark.toString()); - listOperations(); + } + Task taskToMark = taskList.get(taskToMarkNumber - 1); + taskToMark.markAsDone(); + System.out.println("Duly noted. The following task has been marked as done"); + System.out.println(taskToMark.toString()); + commandProcessor(); + break; + case "unmark": + int taskToUnmarkNumber = Integer.parseInt(parsedUserInput[1]); + if (taskToUnmarkNumber > taskList.size()) { + System.out.println("I am afraid that's an invalid task! Please check your task number"); + commandProcessor(); break; - default: - Task taskToAdd = new Task(userInput); - taskList.add(taskToAdd); - System.out.println("added: " + userInput); - listOperations(); + } + Task taskToUnmark = taskList.get(taskToUnmarkNumber - 1); + taskToUnmark.markAsNotDone(); + System.out.println("Very well. The following task has been marked as undone"); + System.out.println(taskToUnmark.toString()); + commandProcessor(); + break; + case "todo": + Todo newTodo = new Todo(parsedUserInput[1]); + taskList.add(newTodo); + displayTaskAdd(newTodo); + commandProcessor(); + break; + case "deadline": + String[] deadlineParse = parsedUserInput[1].split(" /[Bb][Yy] ", 2); + Deadline newDeadline = new Deadline(deadlineParse[0], deadlineParse[1]); + taskList.add(newDeadline); + displayTaskAdd(newDeadline); + commandProcessor(); + break; + case "event": + String[] eventParse = parsedUserInput[1].split(" /[Aa][Tt] ", 2); + Event newEvent = new Event(eventParse[0], eventParse[1]); + taskList.add(newEvent); + displayTaskAdd(newEvent); + commandProcessor(); + break; + default: + System.out.println("I am unable to process your request. Please try again"); + commandProcessor(); } -// while (!userInput.equals("bye")) { -// if (userInput.equals("list")) { -// displayList(taskList); -// } else { -// Task taskToAdd = new Task(userInput); -// taskList.add(taskToAdd); -// System.out.println("added: " + userInput); -// } -// userInput = getUserInput.nextLine(); -// } -// System.out.println("Till we meet again"); } public static void main(String[] args) { @@ -89,6 +107,6 @@ public static void main(String[] args) { System.out.println("Hello from\n" + logo); System.out.println("How may I assist you?"); initialize(); - listOperations(); + commandProcessor(); } } diff --git a/src/main/java/Event.java b/src/main/java/Event.java new file mode 100644 index 0000000000..da32e29a58 --- /dev/null +++ b/src/main/java/Event.java @@ -0,0 +1,14 @@ +public class Event extends Task{ + + private String date; + + public Event(String content, String date) { + super(content); + this.date = date; + } + + @Override + public String toString() { + return String.format("[E]%s (at: %s)", super.toString(), this.date); + } +} diff --git a/src/main/java/Todo.java b/src/main/java/Todo.java new file mode 100644 index 0000000000..f9900ac31a --- /dev/null +++ b/src/main/java/Todo.java @@ -0,0 +1,10 @@ +public class Todo extends Task{ + public Todo(String content) { + super(content); + } + + @Override + public String toString() { + return String.format("[T]%s", super.toString()); + } +} From b38e28d9ff9d227d6f47c0fff443b4c34d0a92ac Mon Sep 17 00:00:00 2001 From: Decaxical Date: Sun, 30 Jan 2022 17:56:29 +0800 Subject: [PATCH 06/50] Text-UI-Testing update added input.txt and expected.txt and ensure test passed --- text-ui-test/EXPECTED.TXT | 12 ++++++++++++ text-ui-test/input.txt | 5 +++++ 2 files changed, 17 insertions(+) diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 657e74f6e7..a0d1d5f171 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -5,3 +5,15 @@ Hello from | |_| | |_| | < __/ |____/ \__,_|_|\_\___| +How may I assist you? +Your current task list is empty +This task has been added as requested: +[T][ ] borrow book +You now have 1 item(s) in your list +This task has been added as requested: +[D][ ] return book (by: sunday) +You now have 2 item(s) in your list +This task has been added as requested: +[E][ ] project meeting (at: Mon 2-4pm) +You now have 3 item(s) in your list +Till we meet again diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index e69de29bb2..f6953e22d8 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -0,0 +1,5 @@ +list +todo borrow book +deadline return book /by sunday +event project meeting /at Mon 2-4pm +bye From fafdd6298959f019b4fe8e65959f86fe9840f095 Mon Sep 17 00:00:00 2001 From: Decaxical Date: Tue, 1 Feb 2022 10:31:53 +0800 Subject: [PATCH 07/50] Implemented DukeExceptions Implemented DukeInvalidArgumentException and DukeException. handles when todo has no description and invalid command --- src/main/java/{ => duke}/Duke.java | 53 +++++++++++++------ .../java/duke/exceptions/DukeException.java | 7 +++ .../DukeInvalidArgumentException.java | 7 +++ src/main/java/{ => duke/tasks}/Deadline.java | 2 + src/main/java/{ => duke/tasks}/Event.java | 2 + src/main/java/{ => duke/tasks}/Task.java | 2 + src/main/java/{ => duke/tasks}/Todo.java | 2 + 7 files changed, 60 insertions(+), 15 deletions(-) rename src/main/java/{ => duke}/Duke.java (67%) create mode 100644 src/main/java/duke/exceptions/DukeException.java create mode 100644 src/main/java/duke/exceptions/DukeInvalidArgumentException.java rename src/main/java/{ => duke/tasks}/Deadline.java (93%) rename src/main/java/{ => duke/tasks}/Event.java (93%) rename src/main/java/{ => duke/tasks}/Task.java (95%) rename src/main/java/{ => duke/tasks}/Todo.java (90%) diff --git a/src/main/java/Duke.java b/src/main/java/duke/Duke.java similarity index 67% rename from src/main/java/Duke.java rename to src/main/java/duke/Duke.java index a95afdbbac..d21fcc8ffb 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/duke/Duke.java @@ -1,5 +1,7 @@ -//package DukeTaskBot; -import java.util.Locale; +package duke; + +import duke.exceptions.DukeInvalidArgumentException; +import duke.tasks.*; import java.util.Scanner; import java.util.ArrayList; @@ -9,7 +11,7 @@ public class Duke { private static Scanner getUserInput; private static void initialize(){ - taskList = new ArrayList<>(); + taskList = new ArrayList(); getUserInput = new Scanner(System.in); } @@ -32,6 +34,14 @@ public static void displayTaskAdd(Task addedTask){ System.out.printf("You now have %d item(s) in your list\n", taskList.size()); } + public static String[] parseArguments(String[] arguments) throws DukeInvalidArgumentException { + if (arguments.length < 2) { + throw new DukeInvalidArgumentException("There appears to be invalid arguments"); + } + + return arguments[1].split(" /([Aa][Tt]|[Bb][Yy]) ", 2); + } + public static void commandProcessor() { String userInput = getUserInput.nextLine(); String[] parsedUserInput = userInput.split(" ", 2); @@ -73,27 +83,40 @@ public static void commandProcessor() { commandProcessor(); break; case "todo": - Todo newTodo = new Todo(parsedUserInput[1]); - taskList.add(newTodo); - displayTaskAdd(newTodo); + try { + String[] parsedArguments = parseArguments(parsedUserInput); + Todo newTodo = new Todo(parsedArguments[0]); + taskList.add(newTodo); + displayTaskAdd(newTodo); + } catch (DukeInvalidArgumentException e) { + System.out.println(e.getMessage()); + } commandProcessor(); break; case "deadline": - String[] deadlineParse = parsedUserInput[1].split(" /[Bb][Yy] ", 2); - Deadline newDeadline = new Deadline(deadlineParse[0], deadlineParse[1]); - taskList.add(newDeadline); - displayTaskAdd(newDeadline); + try { + String[] parsedArguments = parseArguments(parsedUserInput); + Deadline newDeadline = new Deadline(parsedArguments[0], parsedArguments[1]); + taskList.add(newDeadline); + displayTaskAdd(newDeadline); + } catch (DukeInvalidArgumentException e) { + System.out.println(e.getMessage()); + } commandProcessor(); break; case "event": - String[] eventParse = parsedUserInput[1].split(" /[Aa][Tt] ", 2); - Event newEvent = new Event(eventParse[0], eventParse[1]); - taskList.add(newEvent); - displayTaskAdd(newEvent); + try { + String[] parsedArguments = parseArguments(parsedUserInput); + Event newEvent = new Event(parsedArguments[0], parsedArguments[1]); + taskList.add(newEvent); + displayTaskAdd(newEvent); + } catch (DukeInvalidArgumentException e) { + System.out.println(e.getMessage()); + } commandProcessor(); break; default: - System.out.println("I am unable to process your request. Please try again"); + System.out.println("I am unable to comprehend your request. Please try again"); commandProcessor(); } } diff --git a/src/main/java/duke/exceptions/DukeException.java b/src/main/java/duke/exceptions/DukeException.java new file mode 100644 index 0000000000..897d82917e --- /dev/null +++ b/src/main/java/duke/exceptions/DukeException.java @@ -0,0 +1,7 @@ +package duke.exceptions; + +public class DukeException extends Exception{ + public DukeException(String message) { + super(message); + } +} diff --git a/src/main/java/duke/exceptions/DukeInvalidArgumentException.java b/src/main/java/duke/exceptions/DukeInvalidArgumentException.java new file mode 100644 index 0000000000..4b89e6542e --- /dev/null +++ b/src/main/java/duke/exceptions/DukeInvalidArgumentException.java @@ -0,0 +1,7 @@ +package duke.exceptions; + +public class DukeInvalidArgumentException extends DukeException{ + public DukeInvalidArgumentException(String message) { + super(message); + } +} diff --git a/src/main/java/Deadline.java b/src/main/java/duke/tasks/Deadline.java similarity index 93% rename from src/main/java/Deadline.java rename to src/main/java/duke/tasks/Deadline.java index f71479f7d8..a0bd5646d4 100644 --- a/src/main/java/Deadline.java +++ b/src/main/java/duke/tasks/Deadline.java @@ -1,3 +1,5 @@ +package duke.tasks; + public class Deadline extends Task{ private String date; diff --git a/src/main/java/Event.java b/src/main/java/duke/tasks/Event.java similarity index 93% rename from src/main/java/Event.java rename to src/main/java/duke/tasks/Event.java index da32e29a58..afa918fe16 100644 --- a/src/main/java/Event.java +++ b/src/main/java/duke/tasks/Event.java @@ -1,3 +1,5 @@ +package duke.tasks; + public class Event extends Task{ private String date; diff --git a/src/main/java/Task.java b/src/main/java/duke/tasks/Task.java similarity index 95% rename from src/main/java/Task.java rename to src/main/java/duke/tasks/Task.java index 7f6aae79da..6610da48bb 100644 --- a/src/main/java/Task.java +++ b/src/main/java/duke/tasks/Task.java @@ -1,3 +1,5 @@ +package duke.tasks; + public class Task { String content; boolean markedDone = false; diff --git a/src/main/java/Todo.java b/src/main/java/duke/tasks/Todo.java similarity index 90% rename from src/main/java/Todo.java rename to src/main/java/duke/tasks/Todo.java index f9900ac31a..ad7bc6da57 100644 --- a/src/main/java/Todo.java +++ b/src/main/java/duke/tasks/Todo.java @@ -1,3 +1,5 @@ +package duke.tasks; + public class Todo extends Task{ public Todo(String content) { super(content); From eb04bc78803302c0b692e9ad8e369b449f7080fb Mon Sep 17 00:00:00 2001 From: Decaxical Date: Tue, 1 Feb 2022 10:55:23 +0800 Subject: [PATCH 08/50] Added delete commannd Allows for deletion of tasks --- src/main/java/duke/Duke.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java index d21fcc8ffb..e774859fb5 100644 --- a/src/main/java/duke/Duke.java +++ b/src/main/java/duke/Duke.java @@ -34,6 +34,12 @@ public static void displayTaskAdd(Task addedTask){ System.out.printf("You now have %d item(s) in your list\n", taskList.size()); } + public static void displayTaskDelete(Task deletedTask){ + System.out.println("As you wish. The following task has been removed"); + System.out.println(deletedTask.toString()); + System.out.printf("You now have %d item(s) in your list\n", taskList.size()); + } + public static String[] parseArguments(String[] arguments) throws DukeInvalidArgumentException { if (arguments.length < 2) { throw new DukeInvalidArgumentException("There appears to be invalid arguments"); @@ -115,6 +121,18 @@ public static void commandProcessor() { } commandProcessor(); break; + case "delete": + int taskToDeleteNumber = Integer.parseInt(parsedUserInput[1]); + if (taskToDeleteNumber > taskList.size()) { + System.out.println("I am afraid that's an invalid task! Please check your task number"); + commandProcessor(); + break; + } + Task taskToDelete = taskList.get(taskToDeleteNumber - 1); + taskList.remove(taskToDeleteNumber - 1); + displayTaskDelete(taskToDelete); + commandProcessor(); + break; default: System.out.println("I am unable to comprehend your request. Please try again"); commandProcessor(); From 74a00d18f388ce0192fb907ee2bea0da80d9d1d4 Mon Sep 17 00:00:00 2001 From: Decaxical Date: Tue, 8 Feb 2022 18:53:25 +0800 Subject: [PATCH 09/50] Added Saving functionality Duke is now able to save and load the tasklist across different sessions --- src/main/java/duke/Duke.java | 37 ++++++----- src/main/java/duke/storage/Storage.java | 81 +++++++++++++++++++++++++ src/main/java/duke/tasks/Deadline.java | 13 ++++ src/main/java/duke/tasks/Event.java | 13 ++++ src/main/java/duke/tasks/Task.java | 8 ++- src/main/java/duke/tasks/Todo.java | 13 ++++ 6 files changed, 148 insertions(+), 17 deletions(-) create mode 100644 src/main/java/duke/storage/Storage.java diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java index e774859fb5..9149f95138 100644 --- a/src/main/java/duke/Duke.java +++ b/src/main/java/duke/Duke.java @@ -1,6 +1,8 @@ package duke; +import duke.exceptions.DukeException; import duke.exceptions.DukeInvalidArgumentException; +import duke.storage.Storage; import duke.tasks.*; import java.util.Scanner; import java.util.ArrayList; @@ -9,10 +11,16 @@ public class Duke { private static ArrayList taskList; private static Scanner getUserInput; + private static Storage storage; - private static void initialize(){ - taskList = new ArrayList(); + private static void initialize() { + try { + taskList = Storage.loadTasklist(); + } catch (DukeException e) { + System.out.println(e.getMessage()); + } getUserInput = new Scanner(System.in); + storage = new Storage(); } public static void displayTaskList() { @@ -53,40 +61,34 @@ public static void commandProcessor() { String[] parsedUserInput = userInput.split(" ", 2); switch (parsedUserInput[0].toLowerCase()) { case "" : - commandProcessor(); break; case "bye": System.out.println("Till we meet again"); - break; + return; case "list": displayTaskList(); - commandProcessor(); break; case "mark": - int taskToMarkNumber = Integer.parseInt(parsedUserInput[1]); + int taskToMarkNumber = Integer.parseInt(parsedUserInput[1].trim()); if (taskToMarkNumber > taskList.size()) { System.out.println("I am afraid that's an invalid task! Please check your task number"); - commandProcessor(); break; } Task taskToMark = taskList.get(taskToMarkNumber - 1); taskToMark.markAsDone(); System.out.println("Duly noted. The following task has been marked as done"); System.out.println(taskToMark.toString()); - commandProcessor(); break; case "unmark": int taskToUnmarkNumber = Integer.parseInt(parsedUserInput[1]); if (taskToUnmarkNumber > taskList.size()) { System.out.println("I am afraid that's an invalid task! Please check your task number"); - commandProcessor(); break; } Task taskToUnmark = taskList.get(taskToUnmarkNumber - 1); taskToUnmark.markAsNotDone(); System.out.println("Very well. The following task has been marked as undone"); System.out.println(taskToUnmark.toString()); - commandProcessor(); break; case "todo": try { @@ -97,7 +99,6 @@ public static void commandProcessor() { } catch (DukeInvalidArgumentException e) { System.out.println(e.getMessage()); } - commandProcessor(); break; case "deadline": try { @@ -108,7 +109,6 @@ public static void commandProcessor() { } catch (DukeInvalidArgumentException e) { System.out.println(e.getMessage()); } - commandProcessor(); break; case "event": try { @@ -119,24 +119,29 @@ public static void commandProcessor() { } catch (DukeInvalidArgumentException e) { System.out.println(e.getMessage()); } - commandProcessor(); break; case "delete": int taskToDeleteNumber = Integer.parseInt(parsedUserInput[1]); if (taskToDeleteNumber > taskList.size()) { System.out.println("I am afraid that's an invalid task! Please check your task number"); - commandProcessor(); break; } Task taskToDelete = taskList.get(taskToDeleteNumber - 1); taskList.remove(taskToDeleteNumber - 1); displayTaskDelete(taskToDelete); - commandProcessor(); + break; default: System.out.println("I am unable to comprehend your request. Please try again"); - commandProcessor(); + + } + try { + storage.saveTasklist(taskList); + } catch (DukeException e) { + System.out.println(e.getMessage()); } + commandProcessor(); + } public static void main(String[] args) { diff --git a/src/main/java/duke/storage/Storage.java b/src/main/java/duke/storage/Storage.java new file mode 100644 index 0000000000..ae1786eedf --- /dev/null +++ b/src/main/java/duke/storage/Storage.java @@ -0,0 +1,81 @@ +package duke.storage; + +import duke.exceptions.DukeException; +import duke.tasks.*; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.Path; +import java.util.ArrayList; + + +public class Storage { + private static final Path DATA_PATH = Paths.get("data", "duke.txt"); + + private static void initialiseSaveFile() throws DukeException { + try { + if (Files.notExists(DATA_PATH)) { + if(Files.notExists(DATA_PATH.getParent())) { + Files.createDirectory(DATA_PATH.getParent()); + } + Files.createFile(DATA_PATH); + } + } catch (IOException e) { + throw new DukeException("Unable to create a save file"); + } + } + + public void saveTasklist(ArrayList tasklist) throws DukeException { + initialiseSaveFile(); + StringBuilder dataToWrite = new StringBuilder(); + for (Task task : tasklist) { + dataToWrite.append(task.toSaveData()); + } + try { + FileWriter saveFileWriter = new FileWriter(DATA_PATH.toString(), false); + saveFileWriter.write(dataToWrite.toString()); + saveFileWriter.close(); + } catch (IOException e) { + throw new DukeException("Unable to write into save file"); + } + } + + public static ArrayList loadTasklist() throws DukeException{ + initialiseSaveFile(); + String strCurrentLine; + Task currentTask; + ArrayList tasklist = new ArrayList<>(); + try { + BufferedReader saveFilereader = new BufferedReader(new FileReader(DATA_PATH.toString())); + while ((strCurrentLine = saveFilereader.readLine()) != null) { + switch (strCurrentLine.charAt(0)) { + case 'T': + currentTask = Todo.createFromData(strCurrentLine); + tasklist.add(currentTask); + break; + case 'E': + currentTask = Event.createFromData(strCurrentLine); + tasklist.add(currentTask); + break; + case 'D': + currentTask = Deadline.createFromData(strCurrentLine); + tasklist.add(currentTask); + break; + } + } + saveFilereader.close(); + } catch (IOException e) { + throw new DukeException("Unable to load save file"); + } + + return tasklist; + } + + + +} + diff --git a/src/main/java/duke/tasks/Deadline.java b/src/main/java/duke/tasks/Deadline.java index a0bd5646d4..c43bcd997d 100644 --- a/src/main/java/duke/tasks/Deadline.java +++ b/src/main/java/duke/tasks/Deadline.java @@ -13,4 +13,17 @@ public Deadline(String content, String date) { public String toString() { return String.format("[D]%s (by: %s)", super.toString(), this.date); } + + public String toSaveData() { + return String.format("D|%s|%s\n", super.toSaveData(), this.date); + } + + public static Deadline createFromData(String savedData) { + String[] parsedSavedData = savedData.split("\\|"); + Deadline newDeadline = new Deadline(parsedSavedData[2], parsedSavedData[3]); + if (parsedSavedData[1].equals("1")) { + newDeadline.markAsDone(); + } + return newDeadline; + } } diff --git a/src/main/java/duke/tasks/Event.java b/src/main/java/duke/tasks/Event.java index afa918fe16..241d498a6a 100644 --- a/src/main/java/duke/tasks/Event.java +++ b/src/main/java/duke/tasks/Event.java @@ -13,4 +13,17 @@ public Event(String content, String date) { public String toString() { return String.format("[E]%s (at: %s)", super.toString(), this.date); } + + public String toSaveData() { + return String.format("E|%s|%s\n", super.toSaveData(), this.date); + } + + public static Event createFromData(String savedData) { + String[] parsedSavedData = savedData.split("\\|"); + Event newEvent = new Event(parsedSavedData[2], parsedSavedData[3]); + if (parsedSavedData[1].equals("1")) { + newEvent.markAsDone(); + } + return newEvent; + } } diff --git a/src/main/java/duke/tasks/Task.java b/src/main/java/duke/tasks/Task.java index 6610da48bb..f8bd2f3af9 100644 --- a/src/main/java/duke/tasks/Task.java +++ b/src/main/java/duke/tasks/Task.java @@ -18,7 +18,13 @@ public void markAsNotDone() { @Override public String toString() { - return "[" + (this.markedDone ? "X" : " ") + "] " + this.content; + String markedDoneIndicator = this.markedDone ? "X" : " "; + return String.format("[%s] %s", markedDoneIndicator, this.content); + } + + public String toSaveData() { + String markedDoneIndicator = this.markedDone ? "1" : "0"; + return String.format("%s|%s", markedDoneIndicator, this.content); } } diff --git a/src/main/java/duke/tasks/Todo.java b/src/main/java/duke/tasks/Todo.java index ad7bc6da57..ba58314840 100644 --- a/src/main/java/duke/tasks/Todo.java +++ b/src/main/java/duke/tasks/Todo.java @@ -9,4 +9,17 @@ public Todo(String content) { public String toString() { return String.format("[T]%s", super.toString()); } + + public String toSaveData() { + return String.format("T|%s\n",super.toSaveData()); + } + + public static Todo createFromData(String savedData) { + String[] parsedSavedData = savedData.split("\\|"); + Todo newTodo = new Todo(parsedSavedData[2]); + if (parsedSavedData[1].equals("1")) { + newTodo.markAsDone(); + } + return newTodo; + } } From 738ca509d4efdfc7981a69aef90aac99a1ed6b5d Mon Sep 17 00:00:00 2001 From: Decaxical Date: Fri, 11 Feb 2022 17:48:43 +0800 Subject: [PATCH 10/50] Update Duke to recognize dates Deadline and Event tasks now take in LocalDateTime --- src/main/java/duke/Duke.java | 11 +++++++++-- src/main/java/duke/tasks/Deadline.java | 6 ++++-- src/main/java/duke/tasks/Event.java | 6 ++++-- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java index e774859fb5..78b9d52c17 100644 --- a/src/main/java/duke/Duke.java +++ b/src/main/java/duke/Duke.java @@ -2,6 +2,8 @@ import duke.exceptions.DukeInvalidArgumentException; import duke.tasks.*; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.Scanner; import java.util.ArrayList; @@ -48,6 +50,11 @@ public static String[] parseArguments(String[] arguments) throws DukeInvalidArgu return arguments[1].split(" /([Aa][Tt]|[Bb][Yy]) ", 2); } + private static LocalDateTime parseDateTime(String datetime) { + DateTimeFormatter datetimePattern = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm"); + return LocalDateTime.parse(datetime, datetimePattern); + } + public static void commandProcessor() { String userInput = getUserInput.nextLine(); String[] parsedUserInput = userInput.split(" ", 2); @@ -102,7 +109,7 @@ public static void commandProcessor() { case "deadline": try { String[] parsedArguments = parseArguments(parsedUserInput); - Deadline newDeadline = new Deadline(parsedArguments[0], parsedArguments[1]); + Deadline newDeadline = new Deadline(parsedArguments[0], parseDateTime(parsedArguments[1])); taskList.add(newDeadline); displayTaskAdd(newDeadline); } catch (DukeInvalidArgumentException e) { @@ -113,7 +120,7 @@ public static void commandProcessor() { case "event": try { String[] parsedArguments = parseArguments(parsedUserInput); - Event newEvent = new Event(parsedArguments[0], parsedArguments[1]); + Event newEvent = new Event(parsedArguments[0], parseDateTime(parsedArguments[1])); taskList.add(newEvent); displayTaskAdd(newEvent); } catch (DukeInvalidArgumentException e) { diff --git a/src/main/java/duke/tasks/Deadline.java b/src/main/java/duke/tasks/Deadline.java index a0bd5646d4..8acac7c1fc 100644 --- a/src/main/java/duke/tasks/Deadline.java +++ b/src/main/java/duke/tasks/Deadline.java @@ -1,10 +1,12 @@ package duke.tasks; +import java.time.LocalDateTime; + public class Deadline extends Task{ - private String date; + private LocalDateTime date; - public Deadline(String content, String date) { + public Deadline(String content, LocalDateTime date) { super(content); this.date = date; } diff --git a/src/main/java/duke/tasks/Event.java b/src/main/java/duke/tasks/Event.java index afa918fe16..53b8a5514b 100644 --- a/src/main/java/duke/tasks/Event.java +++ b/src/main/java/duke/tasks/Event.java @@ -1,10 +1,12 @@ package duke.tasks; +import java.time.LocalDateTime; + public class Event extends Task{ - private String date; + private LocalDateTime date; - public Event(String content, String date) { + public Event(String content, LocalDateTime date) { super(content); this.date = date; } From 3f0f9036486b19e76ad376f27f72aa743ad2ee82 Mon Sep 17 00:00:00 2001 From: Decaxical Date: Mon, 14 Feb 2022 10:32:23 +0800 Subject: [PATCH 11/50] Revert "Merge branch 'branch-Level-8'" This reverts commit a2ce70c3c592418575205755fe644006cba4a8ad, reversing changes made to 74a00d18f388ce0192fb907ee2bea0da80d9d1d4. --- src/main/java/duke/Duke.java | 11 ++--------- src/main/java/duke/tasks/Deadline.java | 6 ++---- src/main/java/duke/tasks/Event.java | 6 ++---- 3 files changed, 6 insertions(+), 17 deletions(-) diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java index 99ffacb476..9149f95138 100644 --- a/src/main/java/duke/Duke.java +++ b/src/main/java/duke/Duke.java @@ -4,8 +4,6 @@ import duke.exceptions.DukeInvalidArgumentException; import duke.storage.Storage; import duke.tasks.*; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; import java.util.Scanner; import java.util.ArrayList; @@ -58,11 +56,6 @@ public static String[] parseArguments(String[] arguments) throws DukeInvalidArgu return arguments[1].split(" /([Aa][Tt]|[Bb][Yy]) ", 2); } - private static LocalDateTime parseDateTime(String datetime) { - DateTimeFormatter datetimePattern = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm"); - return LocalDateTime.parse(datetime, datetimePattern); - } - public static void commandProcessor() { String userInput = getUserInput.nextLine(); String[] parsedUserInput = userInput.split(" ", 2); @@ -110,7 +103,7 @@ public static void commandProcessor() { case "deadline": try { String[] parsedArguments = parseArguments(parsedUserInput); - Deadline newDeadline = new Deadline(parsedArguments[0], parseDateTime(parsedArguments[1])); + Deadline newDeadline = new Deadline(parsedArguments[0], parsedArguments[1]); taskList.add(newDeadline); displayTaskAdd(newDeadline); } catch (DukeInvalidArgumentException e) { @@ -120,7 +113,7 @@ public static void commandProcessor() { case "event": try { String[] parsedArguments = parseArguments(parsedUserInput); - Event newEvent = new Event(parsedArguments[0], parseDateTime(parsedArguments[1])); + Event newEvent = new Event(parsedArguments[0], parsedArguments[1]); taskList.add(newEvent); displayTaskAdd(newEvent); } catch (DukeInvalidArgumentException e) { diff --git a/src/main/java/duke/tasks/Deadline.java b/src/main/java/duke/tasks/Deadline.java index e19e040081..c43bcd997d 100644 --- a/src/main/java/duke/tasks/Deadline.java +++ b/src/main/java/duke/tasks/Deadline.java @@ -1,12 +1,10 @@ package duke.tasks; -import java.time.LocalDateTime; - public class Deadline extends Task{ - private LocalDateTime date; + private String date; - public Deadline(String content, LocalDateTime date) { + public Deadline(String content, String date) { super(content); this.date = date; } diff --git a/src/main/java/duke/tasks/Event.java b/src/main/java/duke/tasks/Event.java index ba95255066..241d498a6a 100644 --- a/src/main/java/duke/tasks/Event.java +++ b/src/main/java/duke/tasks/Event.java @@ -1,12 +1,10 @@ package duke.tasks; -import java.time.LocalDateTime; - public class Event extends Task{ - private LocalDateTime date; + private String date; - public Event(String content, LocalDateTime date) { + public Event(String content, String date) { super(content); this.date = date; } From e6993ef6949ef74e4e0ed77b29f91f6244de9682 Mon Sep 17 00:00:00 2001 From: Decaxical Date: Mon, 14 Feb 2022 10:32:35 +0800 Subject: [PATCH 12/50] Revert "Added Saving functionality" This reverts commit 74a00d18f388ce0192fb907ee2bea0da80d9d1d4. --- src/main/java/duke/Duke.java | 37 +++++------ src/main/java/duke/storage/Storage.java | 81 ------------------------- src/main/java/duke/tasks/Deadline.java | 13 ---- src/main/java/duke/tasks/Event.java | 13 ---- src/main/java/duke/tasks/Task.java | 8 +-- src/main/java/duke/tasks/Todo.java | 13 ---- 6 files changed, 17 insertions(+), 148 deletions(-) delete mode 100644 src/main/java/duke/storage/Storage.java diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java index 9149f95138..e774859fb5 100644 --- a/src/main/java/duke/Duke.java +++ b/src/main/java/duke/Duke.java @@ -1,8 +1,6 @@ package duke; -import duke.exceptions.DukeException; import duke.exceptions.DukeInvalidArgumentException; -import duke.storage.Storage; import duke.tasks.*; import java.util.Scanner; import java.util.ArrayList; @@ -11,16 +9,10 @@ public class Duke { private static ArrayList taskList; private static Scanner getUserInput; - private static Storage storage; - private static void initialize() { - try { - taskList = Storage.loadTasklist(); - } catch (DukeException e) { - System.out.println(e.getMessage()); - } + private static void initialize(){ + taskList = new ArrayList(); getUserInput = new Scanner(System.in); - storage = new Storage(); } public static void displayTaskList() { @@ -61,34 +53,40 @@ public static void commandProcessor() { String[] parsedUserInput = userInput.split(" ", 2); switch (parsedUserInput[0].toLowerCase()) { case "" : + commandProcessor(); break; case "bye": System.out.println("Till we meet again"); - return; + break; case "list": displayTaskList(); + commandProcessor(); break; case "mark": - int taskToMarkNumber = Integer.parseInt(parsedUserInput[1].trim()); + int taskToMarkNumber = Integer.parseInt(parsedUserInput[1]); if (taskToMarkNumber > taskList.size()) { System.out.println("I am afraid that's an invalid task! Please check your task number"); + commandProcessor(); break; } Task taskToMark = taskList.get(taskToMarkNumber - 1); taskToMark.markAsDone(); System.out.println("Duly noted. The following task has been marked as done"); System.out.println(taskToMark.toString()); + commandProcessor(); break; case "unmark": int taskToUnmarkNumber = Integer.parseInt(parsedUserInput[1]); if (taskToUnmarkNumber > taskList.size()) { System.out.println("I am afraid that's an invalid task! Please check your task number"); + commandProcessor(); break; } Task taskToUnmark = taskList.get(taskToUnmarkNumber - 1); taskToUnmark.markAsNotDone(); System.out.println("Very well. The following task has been marked as undone"); System.out.println(taskToUnmark.toString()); + commandProcessor(); break; case "todo": try { @@ -99,6 +97,7 @@ public static void commandProcessor() { } catch (DukeInvalidArgumentException e) { System.out.println(e.getMessage()); } + commandProcessor(); break; case "deadline": try { @@ -109,6 +108,7 @@ public static void commandProcessor() { } catch (DukeInvalidArgumentException e) { System.out.println(e.getMessage()); } + commandProcessor(); break; case "event": try { @@ -119,29 +119,24 @@ public static void commandProcessor() { } catch (DukeInvalidArgumentException e) { System.out.println(e.getMessage()); } + commandProcessor(); break; case "delete": int taskToDeleteNumber = Integer.parseInt(parsedUserInput[1]); if (taskToDeleteNumber > taskList.size()) { System.out.println("I am afraid that's an invalid task! Please check your task number"); + commandProcessor(); break; } Task taskToDelete = taskList.get(taskToDeleteNumber - 1); taskList.remove(taskToDeleteNumber - 1); displayTaskDelete(taskToDelete); - + commandProcessor(); break; default: System.out.println("I am unable to comprehend your request. Please try again"); - - } - try { - storage.saveTasklist(taskList); - } catch (DukeException e) { - System.out.println(e.getMessage()); + commandProcessor(); } - commandProcessor(); - } public static void main(String[] args) { diff --git a/src/main/java/duke/storage/Storage.java b/src/main/java/duke/storage/Storage.java deleted file mode 100644 index ae1786eedf..0000000000 --- a/src/main/java/duke/storage/Storage.java +++ /dev/null @@ -1,81 +0,0 @@ -package duke.storage; - -import duke.exceptions.DukeException; -import duke.tasks.*; - -import java.io.BufferedReader; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.nio.file.Path; -import java.util.ArrayList; - - -public class Storage { - private static final Path DATA_PATH = Paths.get("data", "duke.txt"); - - private static void initialiseSaveFile() throws DukeException { - try { - if (Files.notExists(DATA_PATH)) { - if(Files.notExists(DATA_PATH.getParent())) { - Files.createDirectory(DATA_PATH.getParent()); - } - Files.createFile(DATA_PATH); - } - } catch (IOException e) { - throw new DukeException("Unable to create a save file"); - } - } - - public void saveTasklist(ArrayList tasklist) throws DukeException { - initialiseSaveFile(); - StringBuilder dataToWrite = new StringBuilder(); - for (Task task : tasklist) { - dataToWrite.append(task.toSaveData()); - } - try { - FileWriter saveFileWriter = new FileWriter(DATA_PATH.toString(), false); - saveFileWriter.write(dataToWrite.toString()); - saveFileWriter.close(); - } catch (IOException e) { - throw new DukeException("Unable to write into save file"); - } - } - - public static ArrayList loadTasklist() throws DukeException{ - initialiseSaveFile(); - String strCurrentLine; - Task currentTask; - ArrayList tasklist = new ArrayList<>(); - try { - BufferedReader saveFilereader = new BufferedReader(new FileReader(DATA_PATH.toString())); - while ((strCurrentLine = saveFilereader.readLine()) != null) { - switch (strCurrentLine.charAt(0)) { - case 'T': - currentTask = Todo.createFromData(strCurrentLine); - tasklist.add(currentTask); - break; - case 'E': - currentTask = Event.createFromData(strCurrentLine); - tasklist.add(currentTask); - break; - case 'D': - currentTask = Deadline.createFromData(strCurrentLine); - tasklist.add(currentTask); - break; - } - } - saveFilereader.close(); - } catch (IOException e) { - throw new DukeException("Unable to load save file"); - } - - return tasklist; - } - - - -} - diff --git a/src/main/java/duke/tasks/Deadline.java b/src/main/java/duke/tasks/Deadline.java index c43bcd997d..a0bd5646d4 100644 --- a/src/main/java/duke/tasks/Deadline.java +++ b/src/main/java/duke/tasks/Deadline.java @@ -13,17 +13,4 @@ public Deadline(String content, String date) { public String toString() { return String.format("[D]%s (by: %s)", super.toString(), this.date); } - - public String toSaveData() { - return String.format("D|%s|%s\n", super.toSaveData(), this.date); - } - - public static Deadline createFromData(String savedData) { - String[] parsedSavedData = savedData.split("\\|"); - Deadline newDeadline = new Deadline(parsedSavedData[2], parsedSavedData[3]); - if (parsedSavedData[1].equals("1")) { - newDeadline.markAsDone(); - } - return newDeadline; - } } diff --git a/src/main/java/duke/tasks/Event.java b/src/main/java/duke/tasks/Event.java index 241d498a6a..afa918fe16 100644 --- a/src/main/java/duke/tasks/Event.java +++ b/src/main/java/duke/tasks/Event.java @@ -13,17 +13,4 @@ public Event(String content, String date) { public String toString() { return String.format("[E]%s (at: %s)", super.toString(), this.date); } - - public String toSaveData() { - return String.format("E|%s|%s\n", super.toSaveData(), this.date); - } - - public static Event createFromData(String savedData) { - String[] parsedSavedData = savedData.split("\\|"); - Event newEvent = new Event(parsedSavedData[2], parsedSavedData[3]); - if (parsedSavedData[1].equals("1")) { - newEvent.markAsDone(); - } - return newEvent; - } } diff --git a/src/main/java/duke/tasks/Task.java b/src/main/java/duke/tasks/Task.java index f8bd2f3af9..6610da48bb 100644 --- a/src/main/java/duke/tasks/Task.java +++ b/src/main/java/duke/tasks/Task.java @@ -18,13 +18,7 @@ public void markAsNotDone() { @Override public String toString() { - String markedDoneIndicator = this.markedDone ? "X" : " "; - return String.format("[%s] %s", markedDoneIndicator, this.content); - } - - public String toSaveData() { - String markedDoneIndicator = this.markedDone ? "1" : "0"; - return String.format("%s|%s", markedDoneIndicator, this.content); + return "[" + (this.markedDone ? "X" : " ") + "] " + this.content; } } diff --git a/src/main/java/duke/tasks/Todo.java b/src/main/java/duke/tasks/Todo.java index ba58314840..ad7bc6da57 100644 --- a/src/main/java/duke/tasks/Todo.java +++ b/src/main/java/duke/tasks/Todo.java @@ -9,17 +9,4 @@ public Todo(String content) { public String toString() { return String.format("[T]%s", super.toString()); } - - public String toSaveData() { - return String.format("T|%s\n",super.toSaveData()); - } - - public static Todo createFromData(String savedData) { - String[] parsedSavedData = savedData.split("\\|"); - Todo newTodo = new Todo(parsedSavedData[2]); - if (parsedSavedData[1].equals("1")) { - newTodo.markAsDone(); - } - return newTodo; - } } From 7f7c12f3cec0c19da7a09803ba5da2ce30802dc2 Mon Sep 17 00:00:00 2001 From: Decaxical Date: Mon, 14 Feb 2022 10:37:51 +0800 Subject: [PATCH 13/50] Revert "Update Duke to recognize dates" This reverts commit 738ca509d4efdfc7981a69aef90aac99a1ed6b5d. --- src/main/java/duke/Duke.java | 11 ++--------- src/main/java/duke/tasks/Deadline.java | 6 ++---- src/main/java/duke/tasks/Event.java | 6 ++---- 3 files changed, 6 insertions(+), 17 deletions(-) diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java index 99ffacb476..9149f95138 100644 --- a/src/main/java/duke/Duke.java +++ b/src/main/java/duke/Duke.java @@ -4,8 +4,6 @@ import duke.exceptions.DukeInvalidArgumentException; import duke.storage.Storage; import duke.tasks.*; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; import java.util.Scanner; import java.util.ArrayList; @@ -58,11 +56,6 @@ public static String[] parseArguments(String[] arguments) throws DukeInvalidArgu return arguments[1].split(" /([Aa][Tt]|[Bb][Yy]) ", 2); } - private static LocalDateTime parseDateTime(String datetime) { - DateTimeFormatter datetimePattern = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm"); - return LocalDateTime.parse(datetime, datetimePattern); - } - public static void commandProcessor() { String userInput = getUserInput.nextLine(); String[] parsedUserInput = userInput.split(" ", 2); @@ -110,7 +103,7 @@ public static void commandProcessor() { case "deadline": try { String[] parsedArguments = parseArguments(parsedUserInput); - Deadline newDeadline = new Deadline(parsedArguments[0], parseDateTime(parsedArguments[1])); + Deadline newDeadline = new Deadline(parsedArguments[0], parsedArguments[1]); taskList.add(newDeadline); displayTaskAdd(newDeadline); } catch (DukeInvalidArgumentException e) { @@ -120,7 +113,7 @@ public static void commandProcessor() { case "event": try { String[] parsedArguments = parseArguments(parsedUserInput); - Event newEvent = new Event(parsedArguments[0], parseDateTime(parsedArguments[1])); + Event newEvent = new Event(parsedArguments[0], parsedArguments[1]); taskList.add(newEvent); displayTaskAdd(newEvent); } catch (DukeInvalidArgumentException e) { diff --git a/src/main/java/duke/tasks/Deadline.java b/src/main/java/duke/tasks/Deadline.java index e19e040081..c43bcd997d 100644 --- a/src/main/java/duke/tasks/Deadline.java +++ b/src/main/java/duke/tasks/Deadline.java @@ -1,12 +1,10 @@ package duke.tasks; -import java.time.LocalDateTime; - public class Deadline extends Task{ - private LocalDateTime date; + private String date; - public Deadline(String content, LocalDateTime date) { + public Deadline(String content, String date) { super(content); this.date = date; } diff --git a/src/main/java/duke/tasks/Event.java b/src/main/java/duke/tasks/Event.java index ba95255066..241d498a6a 100644 --- a/src/main/java/duke/tasks/Event.java +++ b/src/main/java/duke/tasks/Event.java @@ -1,12 +1,10 @@ package duke.tasks; -import java.time.LocalDateTime; - public class Event extends Task{ - private LocalDateTime date; + private String date; - public Event(String content, LocalDateTime date) { + public Event(String content, String date) { super(content); this.date = date; } From 12cc23ec5d5388ff5b358779b1cc2b9cd5ba15ad Mon Sep 17 00:00:00 2001 From: Decaxical Date: Mon, 14 Feb 2022 17:08:52 +0800 Subject: [PATCH 14/50] Revert "Revert "Merge branch 'branch-Level-8'"" This reverts commit 3f0f9036486b19e76ad376f27f72aa743ad2ee82. --- src/main/java/duke/Duke.java | 11 +++++++++-- src/main/java/duke/tasks/Deadline.java | 6 ++++-- src/main/java/duke/tasks/Event.java | 6 ++++-- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java index e774859fb5..78b9d52c17 100644 --- a/src/main/java/duke/Duke.java +++ b/src/main/java/duke/Duke.java @@ -2,6 +2,8 @@ import duke.exceptions.DukeInvalidArgumentException; import duke.tasks.*; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.Scanner; import java.util.ArrayList; @@ -48,6 +50,11 @@ public static String[] parseArguments(String[] arguments) throws DukeInvalidArgu return arguments[1].split(" /([Aa][Tt]|[Bb][Yy]) ", 2); } + private static LocalDateTime parseDateTime(String datetime) { + DateTimeFormatter datetimePattern = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm"); + return LocalDateTime.parse(datetime, datetimePattern); + } + public static void commandProcessor() { String userInput = getUserInput.nextLine(); String[] parsedUserInput = userInput.split(" ", 2); @@ -102,7 +109,7 @@ public static void commandProcessor() { case "deadline": try { String[] parsedArguments = parseArguments(parsedUserInput); - Deadline newDeadline = new Deadline(parsedArguments[0], parsedArguments[1]); + Deadline newDeadline = new Deadline(parsedArguments[0], parseDateTime(parsedArguments[1])); taskList.add(newDeadline); displayTaskAdd(newDeadline); } catch (DukeInvalidArgumentException e) { @@ -113,7 +120,7 @@ public static void commandProcessor() { case "event": try { String[] parsedArguments = parseArguments(parsedUserInput); - Event newEvent = new Event(parsedArguments[0], parsedArguments[1]); + Event newEvent = new Event(parsedArguments[0], parseDateTime(parsedArguments[1])); taskList.add(newEvent); displayTaskAdd(newEvent); } catch (DukeInvalidArgumentException e) { diff --git a/src/main/java/duke/tasks/Deadline.java b/src/main/java/duke/tasks/Deadline.java index a0bd5646d4..8acac7c1fc 100644 --- a/src/main/java/duke/tasks/Deadline.java +++ b/src/main/java/duke/tasks/Deadline.java @@ -1,10 +1,12 @@ package duke.tasks; +import java.time.LocalDateTime; + public class Deadline extends Task{ - private String date; + private LocalDateTime date; - public Deadline(String content, String date) { + public Deadline(String content, LocalDateTime date) { super(content); this.date = date; } diff --git a/src/main/java/duke/tasks/Event.java b/src/main/java/duke/tasks/Event.java index afa918fe16..53b8a5514b 100644 --- a/src/main/java/duke/tasks/Event.java +++ b/src/main/java/duke/tasks/Event.java @@ -1,10 +1,12 @@ package duke.tasks; +import java.time.LocalDateTime; + public class Event extends Task{ - private String date; + private LocalDateTime date; - public Event(String content, String date) { + public Event(String content, LocalDateTime date) { super(content); this.date = date; } From 5aef82a2efcb9a213f7c4ffd003d4ec32c441666 Mon Sep 17 00:00:00 2001 From: Decaxical Date: Mon, 14 Feb 2022 17:08:59 +0800 Subject: [PATCH 15/50] Revert "Revert "Added Saving functionality"" This reverts commit e6993ef6949ef74e4e0ed77b29f91f6244de9682. --- src/main/java/duke/Duke.java | 37 ++++++----- src/main/java/duke/storage/Storage.java | 81 +++++++++++++++++++++++++ src/main/java/duke/tasks/Deadline.java | 13 ++++ src/main/java/duke/tasks/Event.java | 13 ++++ src/main/java/duke/tasks/Task.java | 8 ++- src/main/java/duke/tasks/Todo.java | 13 ++++ 6 files changed, 148 insertions(+), 17 deletions(-) create mode 100644 src/main/java/duke/storage/Storage.java diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java index 78b9d52c17..99ffacb476 100644 --- a/src/main/java/duke/Duke.java +++ b/src/main/java/duke/Duke.java @@ -1,6 +1,8 @@ package duke; +import duke.exceptions.DukeException; import duke.exceptions.DukeInvalidArgumentException; +import duke.storage.Storage; import duke.tasks.*; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; @@ -11,10 +13,16 @@ public class Duke { private static ArrayList taskList; private static Scanner getUserInput; + private static Storage storage; - private static void initialize(){ - taskList = new ArrayList(); + private static void initialize() { + try { + taskList = Storage.loadTasklist(); + } catch (DukeException e) { + System.out.println(e.getMessage()); + } getUserInput = new Scanner(System.in); + storage = new Storage(); } public static void displayTaskList() { @@ -60,40 +68,34 @@ public static void commandProcessor() { String[] parsedUserInput = userInput.split(" ", 2); switch (parsedUserInput[0].toLowerCase()) { case "" : - commandProcessor(); break; case "bye": System.out.println("Till we meet again"); - break; + return; case "list": displayTaskList(); - commandProcessor(); break; case "mark": - int taskToMarkNumber = Integer.parseInt(parsedUserInput[1]); + int taskToMarkNumber = Integer.parseInt(parsedUserInput[1].trim()); if (taskToMarkNumber > taskList.size()) { System.out.println("I am afraid that's an invalid task! Please check your task number"); - commandProcessor(); break; } Task taskToMark = taskList.get(taskToMarkNumber - 1); taskToMark.markAsDone(); System.out.println("Duly noted. The following task has been marked as done"); System.out.println(taskToMark.toString()); - commandProcessor(); break; case "unmark": int taskToUnmarkNumber = Integer.parseInt(parsedUserInput[1]); if (taskToUnmarkNumber > taskList.size()) { System.out.println("I am afraid that's an invalid task! Please check your task number"); - commandProcessor(); break; } Task taskToUnmark = taskList.get(taskToUnmarkNumber - 1); taskToUnmark.markAsNotDone(); System.out.println("Very well. The following task has been marked as undone"); System.out.println(taskToUnmark.toString()); - commandProcessor(); break; case "todo": try { @@ -104,7 +106,6 @@ public static void commandProcessor() { } catch (DukeInvalidArgumentException e) { System.out.println(e.getMessage()); } - commandProcessor(); break; case "deadline": try { @@ -115,7 +116,6 @@ public static void commandProcessor() { } catch (DukeInvalidArgumentException e) { System.out.println(e.getMessage()); } - commandProcessor(); break; case "event": try { @@ -126,24 +126,29 @@ public static void commandProcessor() { } catch (DukeInvalidArgumentException e) { System.out.println(e.getMessage()); } - commandProcessor(); break; case "delete": int taskToDeleteNumber = Integer.parseInt(parsedUserInput[1]); if (taskToDeleteNumber > taskList.size()) { System.out.println("I am afraid that's an invalid task! Please check your task number"); - commandProcessor(); break; } Task taskToDelete = taskList.get(taskToDeleteNumber - 1); taskList.remove(taskToDeleteNumber - 1); displayTaskDelete(taskToDelete); - commandProcessor(); + break; default: System.out.println("I am unable to comprehend your request. Please try again"); - commandProcessor(); + + } + try { + storage.saveTasklist(taskList); + } catch (DukeException e) { + System.out.println(e.getMessage()); } + commandProcessor(); + } public static void main(String[] args) { diff --git a/src/main/java/duke/storage/Storage.java b/src/main/java/duke/storage/Storage.java new file mode 100644 index 0000000000..ae1786eedf --- /dev/null +++ b/src/main/java/duke/storage/Storage.java @@ -0,0 +1,81 @@ +package duke.storage; + +import duke.exceptions.DukeException; +import duke.tasks.*; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.Path; +import java.util.ArrayList; + + +public class Storage { + private static final Path DATA_PATH = Paths.get("data", "duke.txt"); + + private static void initialiseSaveFile() throws DukeException { + try { + if (Files.notExists(DATA_PATH)) { + if(Files.notExists(DATA_PATH.getParent())) { + Files.createDirectory(DATA_PATH.getParent()); + } + Files.createFile(DATA_PATH); + } + } catch (IOException e) { + throw new DukeException("Unable to create a save file"); + } + } + + public void saveTasklist(ArrayList tasklist) throws DukeException { + initialiseSaveFile(); + StringBuilder dataToWrite = new StringBuilder(); + for (Task task : tasklist) { + dataToWrite.append(task.toSaveData()); + } + try { + FileWriter saveFileWriter = new FileWriter(DATA_PATH.toString(), false); + saveFileWriter.write(dataToWrite.toString()); + saveFileWriter.close(); + } catch (IOException e) { + throw new DukeException("Unable to write into save file"); + } + } + + public static ArrayList loadTasklist() throws DukeException{ + initialiseSaveFile(); + String strCurrentLine; + Task currentTask; + ArrayList tasklist = new ArrayList<>(); + try { + BufferedReader saveFilereader = new BufferedReader(new FileReader(DATA_PATH.toString())); + while ((strCurrentLine = saveFilereader.readLine()) != null) { + switch (strCurrentLine.charAt(0)) { + case 'T': + currentTask = Todo.createFromData(strCurrentLine); + tasklist.add(currentTask); + break; + case 'E': + currentTask = Event.createFromData(strCurrentLine); + tasklist.add(currentTask); + break; + case 'D': + currentTask = Deadline.createFromData(strCurrentLine); + tasklist.add(currentTask); + break; + } + } + saveFilereader.close(); + } catch (IOException e) { + throw new DukeException("Unable to load save file"); + } + + return tasklist; + } + + + +} + diff --git a/src/main/java/duke/tasks/Deadline.java b/src/main/java/duke/tasks/Deadline.java index 8acac7c1fc..e19e040081 100644 --- a/src/main/java/duke/tasks/Deadline.java +++ b/src/main/java/duke/tasks/Deadline.java @@ -15,4 +15,17 @@ public Deadline(String content, LocalDateTime date) { public String toString() { return String.format("[D]%s (by: %s)", super.toString(), this.date); } + + public String toSaveData() { + return String.format("D|%s|%s\n", super.toSaveData(), this.date); + } + + public static Deadline createFromData(String savedData) { + String[] parsedSavedData = savedData.split("\\|"); + Deadline newDeadline = new Deadline(parsedSavedData[2], parsedSavedData[3]); + if (parsedSavedData[1].equals("1")) { + newDeadline.markAsDone(); + } + return newDeadline; + } } diff --git a/src/main/java/duke/tasks/Event.java b/src/main/java/duke/tasks/Event.java index 53b8a5514b..ba95255066 100644 --- a/src/main/java/duke/tasks/Event.java +++ b/src/main/java/duke/tasks/Event.java @@ -15,4 +15,17 @@ public Event(String content, LocalDateTime date) { public String toString() { return String.format("[E]%s (at: %s)", super.toString(), this.date); } + + public String toSaveData() { + return String.format("E|%s|%s\n", super.toSaveData(), this.date); + } + + public static Event createFromData(String savedData) { + String[] parsedSavedData = savedData.split("\\|"); + Event newEvent = new Event(parsedSavedData[2], parsedSavedData[3]); + if (parsedSavedData[1].equals("1")) { + newEvent.markAsDone(); + } + return newEvent; + } } diff --git a/src/main/java/duke/tasks/Task.java b/src/main/java/duke/tasks/Task.java index 6610da48bb..f8bd2f3af9 100644 --- a/src/main/java/duke/tasks/Task.java +++ b/src/main/java/duke/tasks/Task.java @@ -18,7 +18,13 @@ public void markAsNotDone() { @Override public String toString() { - return "[" + (this.markedDone ? "X" : " ") + "] " + this.content; + String markedDoneIndicator = this.markedDone ? "X" : " "; + return String.format("[%s] %s", markedDoneIndicator, this.content); + } + + public String toSaveData() { + String markedDoneIndicator = this.markedDone ? "1" : "0"; + return String.format("%s|%s", markedDoneIndicator, this.content); } } diff --git a/src/main/java/duke/tasks/Todo.java b/src/main/java/duke/tasks/Todo.java index ad7bc6da57..ba58314840 100644 --- a/src/main/java/duke/tasks/Todo.java +++ b/src/main/java/duke/tasks/Todo.java @@ -9,4 +9,17 @@ public Todo(String content) { public String toString() { return String.format("[T]%s", super.toString()); } + + public String toSaveData() { + return String.format("T|%s\n",super.toSaveData()); + } + + public static Todo createFromData(String savedData) { + String[] parsedSavedData = savedData.split("\\|"); + Todo newTodo = new Todo(parsedSavedData[2]); + if (parsedSavedData[1].equals("1")) { + newTodo.markAsDone(); + } + return newTodo; + } } From 6925a3a805fe3ad40c1e51f2ce6ab3b659409d0e Mon Sep 17 00:00:00 2001 From: Decaxical Date: Mon, 14 Feb 2022 22:27:31 +0800 Subject: [PATCH 16/50] Storage save and load datetime Added functionality for storage to load tasks time as localdatetime --- data/duke.txt | 3 +++ src/main/java/duke/Duke.java | 1 - src/main/java/duke/storage/Storage.java | 13 +++++++------ src/main/java/duke/tasks/Deadline.java | 12 +++++++++--- src/main/java/duke/tasks/Event.java | 12 +++++++++--- 5 files changed, 28 insertions(+), 13 deletions(-) create mode 100644 data/duke.txt diff --git a/data/duke.txt b/data/duke.txt new file mode 100644 index 0000000000..c897e10b50 --- /dev/null +++ b/data/duke.txt @@ -0,0 +1,3 @@ +T|1|return book +D|0|do this|2000-01-10 10:50 +E|0|bbig event|2000-02-20 14:50 diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java index 99ffacb476..d99cba0904 100644 --- a/src/main/java/duke/Duke.java +++ b/src/main/java/duke/Duke.java @@ -136,7 +136,6 @@ public static void commandProcessor() { Task taskToDelete = taskList.get(taskToDeleteNumber - 1); taskList.remove(taskToDeleteNumber - 1); displayTaskDelete(taskToDelete); - break; default: System.out.println("I am unable to comprehend your request. Please try again"); diff --git a/src/main/java/duke/storage/Storage.java b/src/main/java/duke/storage/Storage.java index ae1786eedf..5b2c6bb9c7 100644 --- a/src/main/java/duke/storage/Storage.java +++ b/src/main/java/duke/storage/Storage.java @@ -21,6 +21,7 @@ private static void initialiseSaveFile() throws DukeException { if (Files.notExists(DATA_PATH)) { if(Files.notExists(DATA_PATH.getParent())) { Files.createDirectory(DATA_PATH.getParent()); + System.out.println("Creating"); } Files.createFile(DATA_PATH); } @@ -53,18 +54,18 @@ public static ArrayList loadTasklist() throws DukeException{ BufferedReader saveFilereader = new BufferedReader(new FileReader(DATA_PATH.toString())); while ((strCurrentLine = saveFilereader.readLine()) != null) { switch (strCurrentLine.charAt(0)) { - case 'T': + case 'T' -> { currentTask = Todo.createFromData(strCurrentLine); tasklist.add(currentTask); - break; - case 'E': + } + case 'E' -> { currentTask = Event.createFromData(strCurrentLine); tasklist.add(currentTask); - break; - case 'D': + } + case 'D' -> { currentTask = Deadline.createFromData(strCurrentLine); tasklist.add(currentTask); - break; + } } } saveFilereader.close(); diff --git a/src/main/java/duke/tasks/Deadline.java b/src/main/java/duke/tasks/Deadline.java index e19e040081..8ef5cacc7e 100644 --- a/src/main/java/duke/tasks/Deadline.java +++ b/src/main/java/duke/tasks/Deadline.java @@ -1,6 +1,7 @@ package duke.tasks; import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; public class Deadline extends Task{ @@ -13,16 +14,21 @@ public Deadline(String content, LocalDateTime date) { @Override public String toString() { - return String.format("[D]%s (by: %s)", super.toString(), this.date); + return String.format("[D]%s (by: %s)", super.toString(), this.date.toString().replace("T", " ")); } public String toSaveData() { - return String.format("D|%s|%s\n", super.toSaveData(), this.date); + return String.format("D|%s|%s\n", super.toSaveData(), this.date.toString().replace("T", " ")); + } + + private static LocalDateTime parseDateTime(String datetime) { + DateTimeFormatter datetimePattern = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); + return LocalDateTime.parse(datetime, datetimePattern); } public static Deadline createFromData(String savedData) { String[] parsedSavedData = savedData.split("\\|"); - Deadline newDeadline = new Deadline(parsedSavedData[2], parsedSavedData[3]); + Deadline newDeadline = new Deadline(parsedSavedData[2], parseDateTime(parsedSavedData[3])); if (parsedSavedData[1].equals("1")) { newDeadline.markAsDone(); } diff --git a/src/main/java/duke/tasks/Event.java b/src/main/java/duke/tasks/Event.java index ba95255066..000fb15781 100644 --- a/src/main/java/duke/tasks/Event.java +++ b/src/main/java/duke/tasks/Event.java @@ -1,6 +1,7 @@ package duke.tasks; import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; public class Event extends Task{ @@ -13,16 +14,21 @@ public Event(String content, LocalDateTime date) { @Override public String toString() { - return String.format("[E]%s (at: %s)", super.toString(), this.date); + return String.format("[E]%s (at: %s)", super.toString(), this.date.toString().replace("T", " ")); } public String toSaveData() { - return String.format("E|%s|%s\n", super.toSaveData(), this.date); + return String.format("E|%s|%s\n", super.toSaveData(), this.date.toString().replace("T", " ")); + } + + private static LocalDateTime parseDateTime(String datetime) { + DateTimeFormatter datetimePattern = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); + return LocalDateTime.parse(datetime, datetimePattern); } public static Event createFromData(String savedData) { String[] parsedSavedData = savedData.split("\\|"); - Event newEvent = new Event(parsedSavedData[2], parsedSavedData[3]); + Event newEvent = new Event(parsedSavedData[2], parseDateTime(parsedSavedData[3])); if (parsedSavedData[1].equals("1")) { newEvent.markAsDone(); } From 53d55f884abd51e42b3dd30aebcd846f89fbda53 Mon Sep 17 00:00:00 2001 From: Decaxical Date: Wed, 16 Feb 2022 18:20:37 +0800 Subject: [PATCH 17/50] Extracted TextUI, Parser, Tasklist and Command into separate classes Extracted TextUI for interactions with user, Storage to load and save tasklist, Parser to parse inputs and Tasklist which contains tasklist operations --- data/duke.txt | 10 +- src/main/java/duke/Duke.java | 159 +++--------------- src/main/java/duke/commands/AddCommand.java | 42 +++++ src/main/java/duke/commands/Command.java | 18 ++ .../java/duke/commands/DeleteCommand.java | 26 +++ src/main/java/duke/commands/ExitCommand.java | 15 ++ .../java/duke/commands/InvalidCommand.java | 11 ++ src/main/java/duke/commands/ListCommand.java | 22 +++ src/main/java/duke/commands/MarkCommand.java | 26 +++ .../java/duke/commands/UnmarkCommand.java | 25 +++ .../DukeUnsupportedOperationException.java | 7 + src/main/java/duke/parser/Parser.java | 60 +++++++ src/main/java/duke/storage/Storage.java | 21 +-- src/main/java/duke/tasks/TaskList.java | 75 +++++++++ src/main/java/duke/ui/TextUI.java | 49 ++++++ 15 files changed, 419 insertions(+), 147 deletions(-) create mode 100644 src/main/java/duke/commands/AddCommand.java create mode 100644 src/main/java/duke/commands/Command.java create mode 100644 src/main/java/duke/commands/DeleteCommand.java create mode 100644 src/main/java/duke/commands/ExitCommand.java create mode 100644 src/main/java/duke/commands/InvalidCommand.java create mode 100644 src/main/java/duke/commands/ListCommand.java create mode 100644 src/main/java/duke/commands/MarkCommand.java create mode 100644 src/main/java/duke/commands/UnmarkCommand.java create mode 100644 src/main/java/duke/exceptions/DukeUnsupportedOperationException.java create mode 100644 src/main/java/duke/parser/Parser.java create mode 100644 src/main/java/duke/tasks/TaskList.java create mode 100644 src/main/java/duke/ui/TextUI.java diff --git a/data/duke.txt b/data/duke.txt index c897e10b50..4559fce942 100644 --- a/data/duke.txt +++ b/data/duke.txt @@ -1,3 +1,7 @@ -T|1|return book -D|0|do this|2000-01-10 10:50 -E|0|bbig event|2000-02-20 14:50 +T|0|return book +D|1|do this|2000-01-10 10:50 +E|1|something|2022-05-20 12:00 +D|0|ip|2022-05-05 23:59 +E|1|tp|2020-12-10 14:25 +D|0|quiz|2010-06-25 10:34 +D|0|homework|2020-01-01 10:45 diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java index d99cba0904..22043c6e6a 100644 --- a/src/main/java/duke/Duke.java +++ b/src/main/java/duke/Duke.java @@ -1,9 +1,14 @@ package duke; +import duke.commands.Command; +import duke.commands.ExitCommand; import duke.exceptions.DukeException; import duke.exceptions.DukeInvalidArgumentException; +import duke.parser.Parser; import duke.storage.Storage; import duke.tasks.*; +import duke.ui.TextUI; + import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.Scanner; @@ -11,154 +16,44 @@ public class Duke { - private static ArrayList taskList; - private static Scanner getUserInput; + private static TaskList taskList; private static Storage storage; + private static TextUI textUI; + private static Parser parser; private static void initialize() { + textUI = new TextUI(); + storage = new Storage(); + parser = new Parser(); + try { taskList = Storage.loadTasklist(); } catch (DukeException e) { + taskList = new TaskList(); System.out.println(e.getMessage()); } - getUserInput = new Scanner(System.in); - storage = new Storage(); - } - - public static void displayTaskList() { - if (taskList.isEmpty()) { - System.out.println("Your current task list is empty"); - return; - } - int taskCounter = 1; - System.out.println("These are the current tasks in your list:"); - for(Task task:taskList) { - System.out.printf("%d. %s \n", taskCounter, task.toString()); - taskCounter++; - } - } - - public static void displayTaskAdd(Task addedTask){ - System.out.println("This task has been added as requested:"); - System.out.println(addedTask.toString()); - System.out.printf("You now have %d item(s) in your list\n", taskList.size()); - } - - public static void displayTaskDelete(Task deletedTask){ - System.out.println("As you wish. The following task has been removed"); - System.out.println(deletedTask.toString()); - System.out.printf("You now have %d item(s) in your list\n", taskList.size()); - } - - public static String[] parseArguments(String[] arguments) throws DukeInvalidArgumentException { - if (arguments.length < 2) { - throw new DukeInvalidArgumentException("There appears to be invalid arguments"); - } - - return arguments[1].split(" /([Aa][Tt]|[Bb][Yy]) ", 2); - } - private static LocalDateTime parseDateTime(String datetime) { - DateTimeFormatter datetimePattern = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm"); - return LocalDateTime.parse(datetime, datetimePattern); + Command.defineTaskList(taskList); + textUI.printWelcomeMessage(); } - public static void commandProcessor() { - String userInput = getUserInput.nextLine(); - String[] parsedUserInput = userInput.split(" ", 2); - switch (parsedUserInput[0].toLowerCase()) { - case "" : - break; - case "bye": - System.out.println("Till we meet again"); - return; - case "list": - displayTaskList(); - break; - case "mark": - int taskToMarkNumber = Integer.parseInt(parsedUserInput[1].trim()); - if (taskToMarkNumber > taskList.size()) { - System.out.println("I am afraid that's an invalid task! Please check your task number"); - break; - } - Task taskToMark = taskList.get(taskToMarkNumber - 1); - taskToMark.markAsDone(); - System.out.println("Duly noted. The following task has been marked as done"); - System.out.println(taskToMark.toString()); - break; - case "unmark": - int taskToUnmarkNumber = Integer.parseInt(parsedUserInput[1]); - if (taskToUnmarkNumber > taskList.size()) { - System.out.println("I am afraid that's an invalid task! Please check your task number"); - break; - } - Task taskToUnmark = taskList.get(taskToUnmarkNumber - 1); - taskToUnmark.markAsNotDone(); - System.out.println("Very well. The following task has been marked as undone"); - System.out.println(taskToUnmark.toString()); - break; - case "todo": - try { - String[] parsedArguments = parseArguments(parsedUserInput); - Todo newTodo = new Todo(parsedArguments[0]); - taskList.add(newTodo); - displayTaskAdd(newTodo); - } catch (DukeInvalidArgumentException e) { - System.out.println(e.getMessage()); - } - break; - case "deadline": - try { - String[] parsedArguments = parseArguments(parsedUserInput); - Deadline newDeadline = new Deadline(parsedArguments[0], parseDateTime(parsedArguments[1])); - taskList.add(newDeadline); - displayTaskAdd(newDeadline); - } catch (DukeInvalidArgumentException e) { - System.out.println(e.getMessage()); - } - break; - case "event": + private static void run() { + Command currCommand = null; + do { + String userInputCommand = textUI.getUserCommand(); try { - String[] parsedArguments = parseArguments(parsedUserInput); - Event newEvent = new Event(parsedArguments[0], parseDateTime(parsedArguments[1])); - taskList.add(newEvent); - displayTaskAdd(newEvent); - } catch (DukeInvalidArgumentException e) { - System.out.println(e.getMessage()); - } - break; - case "delete": - int taskToDeleteNumber = Integer.parseInt(parsedUserInput[1]); - if (taskToDeleteNumber > taskList.size()) { - System.out.println("I am afraid that's an invalid task! Please check your task number"); - break; + currCommand = parser.parseCommands(userInputCommand); + textUI.printMessage(currCommand.execute()); + storage.saveTasklist(taskList); + } catch (DukeException e) { + textUI.printMessage(e.getMessage()); } - Task taskToDelete = taskList.get(taskToDeleteNumber - 1); - taskList.remove(taskToDeleteNumber - 1); - displayTaskDelete(taskToDelete); - break; - default: - System.out.println("I am unable to comprehend your request. Please try again"); - - } - try { - storage.saveTasklist(taskList); - } catch (DukeException e) { - System.out.println(e.getMessage()); - } - commandProcessor(); - + } while (ExitCommand.isRunning()); } + public static void main(String[] args) { - String logo = " ____ _ \n" - + "| _ \\ _ _| | _____ \n" - + "| | | | | | | |/ / _ \\\n" - + "| |_| | |_| | < __/\n" - + "|____/ \\__,_|_|\\_\\___|\n"; - System.out.println("Hello from\n" + logo); - System.out.println("How may I assist you?"); initialize(); - commandProcessor(); + run(); } } diff --git a/src/main/java/duke/commands/AddCommand.java b/src/main/java/duke/commands/AddCommand.java new file mode 100644 index 0000000000..9266314a1e --- /dev/null +++ b/src/main/java/duke/commands/AddCommand.java @@ -0,0 +1,42 @@ +package duke.commands; + +import duke.tasks.Task; +import duke.tasks.Deadline; +import duke.tasks.Event; +import duke.tasks.Todo; + +import java.time.LocalDateTime; +import java.util.Locale; + +public class AddCommand extends Command{ + private String taskType; + private String content; + private LocalDateTime datetime; + + public AddCommand(String taskType, String content, LocalDateTime datetime) { + this.taskType = taskType; + this.content = content; + this.datetime = datetime; + } + + @Override + public String execute() { + Task newTask = null; + switch (taskType.toLowerCase()) { + case "todo": + newTask = new Todo(content); + break; + case "deadline": + newTask = new Deadline(content, datetime); + break; + case "event": + newTask = new Event(content, datetime); + break; + } + taskList.addTask(newTask); + return String.format(""" + This task has been added as requested: + %s + You now have %d item(s) in your list""", newTask, taskList.size()); + } +} \ No newline at end of file diff --git a/src/main/java/duke/commands/Command.java b/src/main/java/duke/commands/Command.java new file mode 100644 index 0000000000..d163a10417 --- /dev/null +++ b/src/main/java/duke/commands/Command.java @@ -0,0 +1,18 @@ +package duke.commands; + +import duke.exceptions.DukeException; +import duke.exceptions.DukeInvalidArgumentException; +import duke.exceptions.DukeUnsupportedOperationException; +import duke.tasks.TaskList; + +public class Command { + static TaskList taskList; + + public static void defineTaskList(TaskList taskList) { + Command.taskList = taskList; + } + + public String execute() throws DukeException{ + throw new DukeUnsupportedOperationException("This method is to be implemented by child classes"); + } +} diff --git a/src/main/java/duke/commands/DeleteCommand.java b/src/main/java/duke/commands/DeleteCommand.java new file mode 100644 index 0000000000..4854675c43 --- /dev/null +++ b/src/main/java/duke/commands/DeleteCommand.java @@ -0,0 +1,26 @@ +package duke.commands; + +import duke.exceptions.DukeInvalidArgumentException; +import duke.tasks.Task; + +public class DeleteCommand extends Command { + + private int index; + + public DeleteCommand(int index) { + this.index = index; + } + + @Override + public String execute() throws DukeInvalidArgumentException { + if (index > taskList.size() || index < 0) { + throw new DukeInvalidArgumentException("I am afraid that's an invalid task!" + + "Please check your task number"); + } + Task deletedTask = taskList.deleteTask(index); + return String.format(""" + As you wish. The following task has been removed + %s + You now have %d item(s) in your list""", deletedTask, taskList.size()); + } +} diff --git a/src/main/java/duke/commands/ExitCommand.java b/src/main/java/duke/commands/ExitCommand.java new file mode 100644 index 0000000000..454e3e08f8 --- /dev/null +++ b/src/main/java/duke/commands/ExitCommand.java @@ -0,0 +1,15 @@ +package duke.commands; + +public class ExitCommand extends Command{ + private static boolean isProgramRunning = true; + + public static boolean isRunning() { + return isProgramRunning; + } + + @Override + public String execute() { + isProgramRunning = false; + return "Till we meet again"; + } +} diff --git a/src/main/java/duke/commands/InvalidCommand.java b/src/main/java/duke/commands/InvalidCommand.java new file mode 100644 index 0000000000..be2567fd34 --- /dev/null +++ b/src/main/java/duke/commands/InvalidCommand.java @@ -0,0 +1,11 @@ +package duke.commands; + +public class InvalidCommand extends Command{ + + final private String MESSAGE = "I am unable to comprehend your request. Please try again"; + + @Override + public String execute(){ + return MESSAGE; + } +} diff --git a/src/main/java/duke/commands/ListCommand.java b/src/main/java/duke/commands/ListCommand.java new file mode 100644 index 0000000000..3bbd05f92a --- /dev/null +++ b/src/main/java/duke/commands/ListCommand.java @@ -0,0 +1,22 @@ +package duke.commands; + +public class ListCommand extends Command { + private String displayTaskList() { + StringBuilder numberedTaskList = new StringBuilder(); + for (int i = 0; i < taskList.size(); i++) { + numberedTaskList.append(String.format("%d. %s \n", i + 1, taskList.getTask(i))); + } + return numberedTaskList.toString().trim(); + } + + @Override + public String execute() { + if (taskList.size() == 0) { + return "Your current task list is empty"; + } + + return String.format(""" + These are the current tasks in your list: + %s""", displayTaskList()); + } +} diff --git a/src/main/java/duke/commands/MarkCommand.java b/src/main/java/duke/commands/MarkCommand.java new file mode 100644 index 0000000000..56f5dff066 --- /dev/null +++ b/src/main/java/duke/commands/MarkCommand.java @@ -0,0 +1,26 @@ +package duke.commands; + +import duke.exceptions.DukeInvalidArgumentException; +import duke.tasks.Task; + +public class MarkCommand extends Command { + private int index; + + public MarkCommand(int index) { + this.index = index; + } + + @Override + public String execute() throws DukeInvalidArgumentException { + if (index > taskList.size() || index < 0) { + throw new DukeInvalidArgumentException("I am afraid that's an invalid task!" + + " Please check your task number"); + } + Task markedTask = taskList.markTask(index); + return String.format(""" + Duly noted. The following task has been marked as done + %s""", markedTask, taskList.size()); + + } + +} diff --git a/src/main/java/duke/commands/UnmarkCommand.java b/src/main/java/duke/commands/UnmarkCommand.java new file mode 100644 index 0000000000..f834ecb91c --- /dev/null +++ b/src/main/java/duke/commands/UnmarkCommand.java @@ -0,0 +1,25 @@ +package duke.commands; + +import duke.exceptions.DukeInvalidArgumentException; +import duke.tasks.Task; + +public class UnmarkCommand extends Command { + private int index; + + public UnmarkCommand(int index) { + this.index = index; + } + + @Override + public String execute() throws DukeInvalidArgumentException { + if (index > taskList.size() || index < 0) { + throw new DukeInvalidArgumentException("I am afraid that's an invalid task!" + + " Please check your task number"); + } + Task unmarkedTask = taskList.unmarkTask(index); + return String.format(""" + Very well. The following task has been marked as undone + %s""", unmarkedTask, taskList.size()); + + } +} diff --git a/src/main/java/duke/exceptions/DukeUnsupportedOperationException.java b/src/main/java/duke/exceptions/DukeUnsupportedOperationException.java new file mode 100644 index 0000000000..0ea4165d6e --- /dev/null +++ b/src/main/java/duke/exceptions/DukeUnsupportedOperationException.java @@ -0,0 +1,7 @@ +package duke.exceptions; + +public class DukeUnsupportedOperationException extends DukeException{ + public DukeUnsupportedOperationException(String message) { + super(message); + } +} diff --git a/src/main/java/duke/parser/Parser.java b/src/main/java/duke/parser/Parser.java new file mode 100644 index 0000000000..bf4290e721 --- /dev/null +++ b/src/main/java/duke/parser/Parser.java @@ -0,0 +1,60 @@ +package duke.parser; + +import duke.commands.*; +import duke.exceptions.DukeInvalidArgumentException; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Locale; + +public class Parser { + private String[] parseArguments(String[] arguments) throws DukeInvalidArgumentException { + if (arguments.length < 2) { + throw new DukeInvalidArgumentException("There appears to be insufficient arguments"); + } + + return arguments[1].split(" /([Aa][Tt]|[Bb][Yy]) ", 2); + } + + private LocalDateTime parseDateTime(String datetime) { + DateTimeFormatter datetimePattern = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm"); + return LocalDateTime.parse(datetime, datetimePattern); + } + + private int parseIndex(String strIndex) { + return Integer.parseInt(strIndex.trim()) - 1; + + } + + public Command parseCommands(String userInput) throws DukeInvalidArgumentException { + String[] parsedUserInput = userInput.split(" ", 2); + String commandType = parsedUserInput[0].toLowerCase(); + String[] parsedArguments; + String content = null; + switch (commandType) { + case "bye": + return new ExitCommand(); + case "list": + return new ListCommand(); + case "mark": + return new MarkCommand(parseIndex(parsedUserInput[1])); + case "unmark": + return new UnmarkCommand(parseIndex(parsedUserInput[1])); + case "delete": + return new DeleteCommand(parseIndex(parsedUserInput[1])); + case "todo": + parsedArguments = parseArguments(parsedUserInput); + content = parsedArguments[0]; + return new AddCommand(commandType, content, null); + case "deadline": + case "event": + parsedArguments = parseArguments(parsedUserInput); + content = parsedArguments[0]; + LocalDateTime datetime = parseDateTime(parsedArguments[1]); + return new AddCommand(commandType, content, datetime); + default: + return new InvalidCommand(); + + } + } +} diff --git a/src/main/java/duke/storage/Storage.java b/src/main/java/duke/storage/Storage.java index 5b2c6bb9c7..2bbdb51c23 100644 --- a/src/main/java/duke/storage/Storage.java +++ b/src/main/java/duke/storage/Storage.java @@ -30,41 +30,38 @@ private static void initialiseSaveFile() throws DukeException { } } - public void saveTasklist(ArrayList tasklist) throws DukeException { + public void saveTasklist(TaskList taskList) throws DukeException { initialiseSaveFile(); - StringBuilder dataToWrite = new StringBuilder(); - for (Task task : tasklist) { - dataToWrite.append(task.toSaveData()); - } + String dataToWrite = taskList.toSaveData(); try { FileWriter saveFileWriter = new FileWriter(DATA_PATH.toString(), false); - saveFileWriter.write(dataToWrite.toString()); + saveFileWriter.write(dataToWrite); saveFileWriter.close(); } catch (IOException e) { throw new DukeException("Unable to write into save file"); } } - public static ArrayList loadTasklist() throws DukeException{ + public static TaskList loadTasklist() throws DukeException{ initialiseSaveFile(); String strCurrentLine; Task currentTask; - ArrayList tasklist = new ArrayList<>(); + TaskList taskList = new TaskList(); try { BufferedReader saveFilereader = new BufferedReader(new FileReader(DATA_PATH.toString())); while ((strCurrentLine = saveFilereader.readLine()) != null) { switch (strCurrentLine.charAt(0)) { case 'T' -> { currentTask = Todo.createFromData(strCurrentLine); - tasklist.add(currentTask); + taskList.addTask(currentTask); } case 'E' -> { currentTask = Event.createFromData(strCurrentLine); - tasklist.add(currentTask); + taskList.addTask(currentTask); } case 'D' -> { currentTask = Deadline.createFromData(strCurrentLine); - tasklist.add(currentTask); + taskList.addTask(currentTask); } } } @@ -73,7 +70,7 @@ public static ArrayList loadTasklist() throws DukeException{ throw new DukeException("Unable to load save file"); } - return tasklist; + return taskList; } diff --git a/src/main/java/duke/tasks/TaskList.java b/src/main/java/duke/tasks/TaskList.java new file mode 100644 index 0000000000..dcea45d8f8 --- /dev/null +++ b/src/main/java/duke/tasks/TaskList.java @@ -0,0 +1,75 @@ +package duke.tasks; + +import java.util.ArrayList; + +public class TaskList { + private final ArrayList taskList; + + public TaskList() { + this.taskList = new ArrayList<>(); + } + + public Task getTask(int index) { + return taskList.get(index); + } + + public void addTask(Task taskToAdd) { + taskList.add(taskToAdd); + } + + public Task deleteTask(int indexTaskToDelete) { + taskList.remove(indexTaskToDelete); + displayTaskDelete(taskList.get(indexTaskToDelete)); + return taskList.get(indexTaskToDelete); + } + + public Task markTask(int indexTaskToMark) { + Task taskToMark = taskList.get(indexTaskToMark); + taskToMark.markAsDone(); + return taskToMark; + } + + public Task unmarkTask(int indexTaskToUnmark) { + Task taskToUnmark = taskList.get(indexTaskToUnmark); + taskToUnmark.markAsNotDone(); + return taskToUnmark; + } + + public int size() { + return taskList.size(); + } + + public String toSaveData() { + StringBuilder dataToWrite = new StringBuilder(); + for (Task task : taskList) { + dataToWrite.append(task.toSaveData()); + } + + return dataToWrite.toString(); + } + + public void displayTaskList() { + if (taskList.isEmpty()) { + System.out.println("Your current task list is empty"); + return; + } + int taskCounter = 1; + System.out.println("These are the current tasks in your list:"); + for(Task task:taskList) { + System.out.printf("%d. %s \n", taskCounter, task.toString()); + taskCounter++; + } + } + + public void displayTaskAdd(Task addedTask){ + System.out.println("This task has been added as requested:"); + System.out.println(addedTask.toString()); + System.out.printf("You now have %d item(s) in your list\n", taskList.size()); + } + + public void displayTaskDelete(Task deletedTask){ + System.out.println("As you wish. The following task has been removed"); + System.out.println(deletedTask.toString()); + System.out.printf("You now have %d item(s) in your list\n", taskList.size()); + } +} diff --git a/src/main/java/duke/ui/TextUI.java b/src/main/java/duke/ui/TextUI.java new file mode 100644 index 0000000000..7d1339153f --- /dev/null +++ b/src/main/java/duke/ui/TextUI.java @@ -0,0 +1,49 @@ +package duke.ui; + +import java.io.InputStream; +import java.io.PrintStream; +import java.util.Scanner; + +public class TextUI { + private final Scanner in; + private final PrintStream out; + + public TextUI() { + this(System.in, System.out); + } + + public TextUI(InputStream in, PrintStream out){ + this.in = new Scanner(in); + this.out = out; + } + + public boolean shouldIgnore(String rawInputLine) { + return rawInputLine.trim().isEmpty(); + } + + public String getUserCommand() { + String currInput = in.nextLine().trim(); + while (shouldIgnore(currInput)) { + currInput = in.nextLine().trim(); + } + + return currInput; + } + + public void printMessage(String message) { + String textBorder = "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"; + String textToPrint = textBorder + message + "\n" + textBorder; + out.print(textToPrint); + } + + public void printWelcomeMessage() { + String logo = " ____ _ \n" + + "| _ \\ _ _| | _____ \n" + + "| | | | | | | |/ / _ \\\n" + + "| |_| | |_| | < __/\n" + + "|____/ \\__,_|_|\\_\\___|\n"; + out.println("Hello from\n" + logo); + out.println("How may I assist you?"); + } + +} From 5ecd72675e3da18af2b34dab6fcbacd938ce7f0d Mon Sep 17 00:00:00 2001 From: Decaxical Date: Wed, 16 Feb 2022 18:25:52 +0800 Subject: [PATCH 18/50] Cleaned up imports and packages Removed unnecessary imports and fixed formatting --- src/main/java/duke/Duke.java | 5 ----- src/main/java/duke/commands/AddCommand.java | 2 -- src/main/java/duke/commands/Command.java | 1 - src/main/java/duke/parser/Parser.java | 2 -- src/main/java/duke/storage/Storage.java | 2 -- 5 files changed, 12 deletions(-) diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java index 22043c6e6a..56ed1affbf 100644 --- a/src/main/java/duke/Duke.java +++ b/src/main/java/duke/Duke.java @@ -3,16 +3,11 @@ import duke.commands.Command; import duke.commands.ExitCommand; import duke.exceptions.DukeException; -import duke.exceptions.DukeInvalidArgumentException; import duke.parser.Parser; import duke.storage.Storage; import duke.tasks.*; import duke.ui.TextUI; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.util.Scanner; -import java.util.ArrayList; public class Duke { diff --git a/src/main/java/duke/commands/AddCommand.java b/src/main/java/duke/commands/AddCommand.java index 9266314a1e..b18aebd22e 100644 --- a/src/main/java/duke/commands/AddCommand.java +++ b/src/main/java/duke/commands/AddCommand.java @@ -4,9 +4,7 @@ import duke.tasks.Deadline; import duke.tasks.Event; import duke.tasks.Todo; - import java.time.LocalDateTime; -import java.util.Locale; public class AddCommand extends Command{ private String taskType; diff --git a/src/main/java/duke/commands/Command.java b/src/main/java/duke/commands/Command.java index d163a10417..3f2a68548f 100644 --- a/src/main/java/duke/commands/Command.java +++ b/src/main/java/duke/commands/Command.java @@ -1,7 +1,6 @@ package duke.commands; import duke.exceptions.DukeException; -import duke.exceptions.DukeInvalidArgumentException; import duke.exceptions.DukeUnsupportedOperationException; import duke.tasks.TaskList; diff --git a/src/main/java/duke/parser/Parser.java b/src/main/java/duke/parser/Parser.java index bf4290e721..4d3ca3038d 100644 --- a/src/main/java/duke/parser/Parser.java +++ b/src/main/java/duke/parser/Parser.java @@ -2,10 +2,8 @@ import duke.commands.*; import duke.exceptions.DukeInvalidArgumentException; - import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; -import java.util.Locale; public class Parser { private String[] parseArguments(String[] arguments) throws DukeInvalidArgumentException { diff --git a/src/main/java/duke/storage/Storage.java b/src/main/java/duke/storage/Storage.java index 2bbdb51c23..58f63e272e 100644 --- a/src/main/java/duke/storage/Storage.java +++ b/src/main/java/duke/storage/Storage.java @@ -2,7 +2,6 @@ import duke.exceptions.DukeException; import duke.tasks.*; - import java.io.BufferedReader; import java.io.FileReader; import java.io.FileWriter; @@ -10,7 +9,6 @@ import java.nio.file.Files; import java.nio.file.Paths; import java.nio.file.Path; -import java.util.ArrayList; public class Storage { From c910dac78ffd10930f2cc663753e74bf9c910cd6 Mon Sep 17 00:00:00 2001 From: Decaxical Date: Thu, 17 Feb 2022 16:18:29 +0800 Subject: [PATCH 19/50] Added JUnit tests for parser and Task Added JUnit test for Parser parseCommand() and all functions in Task. Also removed redundant functions from TaskList --- src/main/java/duke/tasks/Task.java | 4 +- src/main/java/duke/tasks/TaskList.java | 19 -------- src/test/java/duke/parser/ParserTest.java | 54 +++++++++++++++++++++++ src/test/java/duke/tasks/TaskTest.java | 41 +++++++++++++++++ 4 files changed, 97 insertions(+), 21 deletions(-) create mode 100644 src/test/java/duke/parser/ParserTest.java create mode 100644 src/test/java/duke/tasks/TaskTest.java diff --git a/src/main/java/duke/tasks/Task.java b/src/main/java/duke/tasks/Task.java index f8bd2f3af9..5d2f4aadb7 100644 --- a/src/main/java/duke/tasks/Task.java +++ b/src/main/java/duke/tasks/Task.java @@ -1,8 +1,8 @@ package duke.tasks; public class Task { - String content; - boolean markedDone = false; + private String content; + private boolean markedDone = false; public Task(String content) { this.content = content; diff --git a/src/main/java/duke/tasks/TaskList.java b/src/main/java/duke/tasks/TaskList.java index dcea45d8f8..c341314a5e 100644 --- a/src/main/java/duke/tasks/TaskList.java +++ b/src/main/java/duke/tasks/TaskList.java @@ -48,25 +48,6 @@ public String toSaveData() { return dataToWrite.toString(); } - public void displayTaskList() { - if (taskList.isEmpty()) { - System.out.println("Your current task list is empty"); - return; - } - int taskCounter = 1; - System.out.println("These are the current tasks in your list:"); - for(Task task:taskList) { - System.out.printf("%d. %s \n", taskCounter, task.toString()); - taskCounter++; - } - } - - public void displayTaskAdd(Task addedTask){ - System.out.println("This task has been added as requested:"); - System.out.println(addedTask.toString()); - System.out.printf("You now have %d item(s) in your list\n", taskList.size()); - } - public void displayTaskDelete(Task deletedTask){ System.out.println("As you wish. The following task has been removed"); System.out.println(deletedTask.toString()); diff --git a/src/test/java/duke/parser/ParserTest.java b/src/test/java/duke/parser/ParserTest.java new file mode 100644 index 0000000000..93cc7b98d0 --- /dev/null +++ b/src/test/java/duke/parser/ParserTest.java @@ -0,0 +1,54 @@ +package duke.parser; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import duke.commands.*; +import duke.exceptions.DukeException; +import duke.exceptions.DukeInvalidArgumentException; +import duke.tasks.Deadline; +import org.junit.jupiter.api.Test; + +public class ParserTest { + private Parser parser = new Parser(); + + @Test + public void parseExitCommandsTest() throws DukeInvalidArgumentException{ + assertTrue(parser.parseCommands("bye") instanceof ExitCommand); + } + + @Test + public void parseListCommandsTest() throws DukeInvalidArgumentException{ + assertTrue(parser.parseCommands("list") instanceof ListCommand); + } + + @Test + public void parseMarkCommandsTest() throws DukeInvalidArgumentException{ + assertTrue(parser.parseCommands("mark 1") instanceof MarkCommand); + } + + @Test + public void parseUnmarkCommandsTest() throws DukeInvalidArgumentException{ + assertTrue(parser.parseCommands("unmark 1") instanceof UnmarkCommand); + } + + @Test + public void parseDeleteCommandsTest() throws DukeInvalidArgumentException{ + assertTrue(parser.parseCommands("delete 1") instanceof DeleteCommand); + } + + @Test + public void parseTodoCommandsTest() throws DukeInvalidArgumentException{ + assertTrue(parser.parseCommands("TODO return book") instanceof AddCommand); + } + + @Test + public void parseDeadlineCommandsTest() throws DukeInvalidArgumentException{ + assertTrue(parser.parseCommands("DeADLINE return book /by 01/01/2000 10:10") instanceof AddCommand); + } + + @Test + public void parseEventCommandsTest() throws DukeInvalidArgumentException{ + assertTrue(parser.parseCommands("EvEnt return book /at 01/01/2000 10:10") instanceof AddCommand); + } +} diff --git a/src/test/java/duke/tasks/TaskTest.java b/src/test/java/duke/tasks/TaskTest.java new file mode 100644 index 0000000000..cb65efec13 --- /dev/null +++ b/src/test/java/duke/tasks/TaskTest.java @@ -0,0 +1,41 @@ +package duke.tasks; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +public class TaskTest { + private Task task = new Task("testing task"); + + @Test + void toStringTest() { + + String expected = "[ ] testing task"; + assertEquals(expected, task.toString()); + } + + @Test + void markAsDoneTest() { + task.markAsDone(); + String expectedMarked = "[X] testing task"; + assertEquals(expectedMarked, task.toString()); + } + + @Test + void markAsNotDoneTest() { + task.markAsDone(); + task.markAsNotDone(); + String expectedUnmarked = "[ ] testing task"; + assertEquals(expectedUnmarked, task.toString()); + } + + @Test + void toSaveDataTest() { + task.markAsDone(); + String expectedMarked = "1|testing task"; + assertEquals(expectedMarked, task.toSaveData()); + task.markAsNotDone(); + String expectedUnmarked = "0|testing task"; + assertEquals(expectedUnmarked, task.toSaveData()); + } +} From c3ab2f13a62a896b3abc5366363fe4722cf0eb94 Mon Sep 17 00:00:00 2001 From: Decaxical Date: Thu, 17 Feb 2022 18:15:13 +0800 Subject: [PATCH 20/50] Changed compile version from java 15 to java 11 Rectified mistake in Intellij compiler and fixed related bugs like text blocks. fixed minor bugs like mark, unmark and delete allowing exceed of size. Improve UI --- data/duke.txt | 2 +- src/main/java/META-INF/MANIFEST.MF | 3 +++ src/main/java/duke/commands/AddCommand.java | 6 ++---- src/main/java/duke/commands/DeleteCommand.java | 8 +++----- src/main/java/duke/commands/ListCommand.java | 4 +--- src/main/java/duke/commands/MarkCommand.java | 7 +++---- src/main/java/duke/commands/UnmarkCommand.java | 7 +++---- src/main/java/duke/storage/Storage.java | 10 ++++++---- src/main/java/duke/ui/TextUI.java | 3 ++- src/test/java/duke/parser/ParserTest.java | 3 --- 10 files changed, 24 insertions(+), 29 deletions(-) create mode 100644 src/main/java/META-INF/MANIFEST.MF diff --git a/data/duke.txt b/data/duke.txt index 4559fce942..a42dbf9c85 100644 --- a/data/duke.txt +++ b/data/duke.txt @@ -1,4 +1,4 @@ -T|0|return book +T|1|return book D|1|do this|2000-01-10 10:50 E|1|something|2022-05-20 12:00 D|0|ip|2022-05-05 23:59 diff --git a/src/main/java/META-INF/MANIFEST.MF b/src/main/java/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..2c9a9745c5 --- /dev/null +++ b/src/main/java/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: duke.Duke + diff --git a/src/main/java/duke/commands/AddCommand.java b/src/main/java/duke/commands/AddCommand.java index b18aebd22e..fba7f1255b 100644 --- a/src/main/java/duke/commands/AddCommand.java +++ b/src/main/java/duke/commands/AddCommand.java @@ -32,9 +32,7 @@ public String execute() { break; } taskList.addTask(newTask); - return String.format(""" - This task has been added as requested: - %s - You now have %d item(s) in your list""", newTask, taskList.size()); + return String.format("This task has been added as requested:\n" + + "%s\n" + " You now have %d item(s) in your list", newTask, taskList.size()); } } \ No newline at end of file diff --git a/src/main/java/duke/commands/DeleteCommand.java b/src/main/java/duke/commands/DeleteCommand.java index 4854675c43..440ada757c 100644 --- a/src/main/java/duke/commands/DeleteCommand.java +++ b/src/main/java/duke/commands/DeleteCommand.java @@ -13,14 +13,12 @@ public DeleteCommand(int index) { @Override public String execute() throws DukeInvalidArgumentException { - if (index > taskList.size() || index < 0) { + if (index > taskList.size() - 1 || index < 0) { throw new DukeInvalidArgumentException("I am afraid that's an invalid task!" + "Please check your task number"); } Task deletedTask = taskList.deleteTask(index); - return String.format(""" - As you wish. The following task has been removed - %s - You now have %d item(s) in your list""", deletedTask, taskList.size()); + return String.format("As you wish. The following task has been removed:\n" + + "%s\n" + "You now have %d item(s) in your list", deletedTask, taskList.size()); } } diff --git a/src/main/java/duke/commands/ListCommand.java b/src/main/java/duke/commands/ListCommand.java index 3bbd05f92a..c5d1c740bd 100644 --- a/src/main/java/duke/commands/ListCommand.java +++ b/src/main/java/duke/commands/ListCommand.java @@ -15,8 +15,6 @@ public String execute() { return "Your current task list is empty"; } - return String.format(""" - These are the current tasks in your list: - %s""", displayTaskList()); + return String.format("These are the current tasks in your list:\n%s", displayTaskList()); } } diff --git a/src/main/java/duke/commands/MarkCommand.java b/src/main/java/duke/commands/MarkCommand.java index 56f5dff066..064511e7bb 100644 --- a/src/main/java/duke/commands/MarkCommand.java +++ b/src/main/java/duke/commands/MarkCommand.java @@ -12,14 +12,13 @@ public MarkCommand(int index) { @Override public String execute() throws DukeInvalidArgumentException { - if (index > taskList.size() || index < 0) { + if (index > taskList.size() - 1 || index < 0) { throw new DukeInvalidArgumentException("I am afraid that's an invalid task!" + " Please check your task number"); } Task markedTask = taskList.markTask(index); - return String.format(""" - Duly noted. The following task has been marked as done - %s""", markedTask, taskList.size()); + return String.format("Duly noted. The following task has been marked as done:\n" + + "%s", markedTask); } diff --git a/src/main/java/duke/commands/UnmarkCommand.java b/src/main/java/duke/commands/UnmarkCommand.java index f834ecb91c..8dbb5b1168 100644 --- a/src/main/java/duke/commands/UnmarkCommand.java +++ b/src/main/java/duke/commands/UnmarkCommand.java @@ -12,14 +12,13 @@ public UnmarkCommand(int index) { @Override public String execute() throws DukeInvalidArgumentException { - if (index > taskList.size() || index < 0) { + if (index > taskList.size() - 1 || index < 0) { throw new DukeInvalidArgumentException("I am afraid that's an invalid task!" + " Please check your task number"); } Task unmarkedTask = taskList.unmarkTask(index); - return String.format(""" - Very well. The following task has been marked as undone - %s""", unmarkedTask, taskList.size()); + return String.format("Very well. The following task has been marked as not done:" + + "%s", unmarkedTask); } } diff --git a/src/main/java/duke/storage/Storage.java b/src/main/java/duke/storage/Storage.java index 58f63e272e..5e1bd40c1e 100644 --- a/src/main/java/duke/storage/Storage.java +++ b/src/main/java/duke/storage/Storage.java @@ -19,7 +19,6 @@ private static void initialiseSaveFile() throws DukeException { if (Files.notExists(DATA_PATH)) { if(Files.notExists(DATA_PATH.getParent())) { Files.createDirectory(DATA_PATH.getParent()); - System.out.println("Creating"); } Files.createFile(DATA_PATH); } @@ -49,17 +48,20 @@ public static TaskList loadTasklist() throws DukeException{ BufferedReader saveFilereader = new BufferedReader(new FileReader(DATA_PATH.toString())); while ((strCurrentLine = saveFilereader.readLine()) != null) { switch (strCurrentLine.charAt(0)) { - case 'T' -> { + case 'T' : { currentTask = Todo.createFromData(strCurrentLine); taskList.addTask(currentTask); + break; } - case 'E' -> { + case 'E' : { currentTask = Event.createFromData(strCurrentLine); taskList.addTask(currentTask); + break; } - case 'D' -> { + case 'D' : { currentTask = Deadline.createFromData(strCurrentLine); taskList.addTask(currentTask); + break; } } } diff --git a/src/main/java/duke/ui/TextUI.java b/src/main/java/duke/ui/TextUI.java index 7d1339153f..f57ae701ff 100644 --- a/src/main/java/duke/ui/TextUI.java +++ b/src/main/java/duke/ui/TextUI.java @@ -32,7 +32,7 @@ public String getUserCommand() { public void printMessage(String message) { String textBorder = "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"; - String textToPrint = textBorder + message + "\n" + textBorder; + String textToPrint = "\n" + textBorder + message + "\n" + textBorder + "\n"; out.print(textToPrint); } @@ -44,6 +44,7 @@ public void printWelcomeMessage() { + "|____/ \\__,_|_|\\_\\___|\n"; out.println("Hello from\n" + logo); out.println("How may I assist you?"); + out.print("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n\n"); } } diff --git a/src/test/java/duke/parser/ParserTest.java b/src/test/java/duke/parser/ParserTest.java index 93cc7b98d0..e7e4833890 100644 --- a/src/test/java/duke/parser/ParserTest.java +++ b/src/test/java/duke/parser/ParserTest.java @@ -1,12 +1,9 @@ package duke.parser; -import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import duke.commands.*; -import duke.exceptions.DukeException; import duke.exceptions.DukeInvalidArgumentException; -import duke.tasks.Deadline; import org.junit.jupiter.api.Test; public class ParserTest { From 0ccd1dcb9531bd96fef722c9e66b4dc191971b49 Mon Sep 17 00:00:00 2001 From: Decaxical Date: Thu, 17 Feb 2022 18:22:37 +0800 Subject: [PATCH 21/50] minor UI improvement --- src/main/java/duke/ui/TextUI.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/duke/ui/TextUI.java b/src/main/java/duke/ui/TextUI.java index f57ae701ff..ce1777502f 100644 --- a/src/main/java/duke/ui/TextUI.java +++ b/src/main/java/duke/ui/TextUI.java @@ -42,7 +42,8 @@ public void printWelcomeMessage() { + "| | | | | | | |/ / _ \\\n" + "| |_| | |_| | < __/\n" + "|____/ \\__,_|_|\\_\\___|\n"; - out.println("Hello from\n" + logo); + out.print("\n+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); + out.println("\nGreetings from\n" + logo); out.println("How may I assist you?"); out.print("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n\n"); } From 788eebde9c1765f7a1304268a618ff7d5855bd19 Mon Sep 17 00:00:00 2001 From: Decaxical Date: Thu, 17 Feb 2022 23:06:43 +0800 Subject: [PATCH 22/50] Added Java documentation Added Java documentation and fixed a bug: delete command displaying wrong task being deleted. --- data/duke.txt | 2 - src/main/java/duke/Duke.java | 7 ++- src/main/java/duke/commands/AddCommand.java | 16 ++++++ src/main/java/duke/commands/Command.java | 14 +++++ .../java/duke/commands/DeleteCommand.java | 14 +++++ src/main/java/duke/commands/ExitCommand.java | 13 +++++ .../java/duke/commands/InvalidCommand.java | 8 +++ src/main/java/duke/commands/ListCommand.java | 8 +++ src/main/java/duke/commands/MarkCommand.java | 14 +++++ .../java/duke/commands/UnmarkCommand.java | 14 +++++ .../java/duke/exceptions/DukeException.java | 8 +++ .../DukeInvalidArgumentException.java | 8 +++ .../DukeUnsupportedOperationException.java | 8 +++ src/main/java/duke/parser/Parser.java | 12 +++- src/main/java/duke/storage/Storage.java | 16 +++++- src/main/java/duke/tasks/Deadline.java | 31 +++++++++++ src/main/java/duke/tasks/Event.java | 33 ++++++++++- src/main/java/duke/tasks/Task.java | 25 +++++++++ src/main/java/duke/tasks/TaskList.java | 55 ++++++++++++++++--- src/main/java/duke/tasks/Todo.java | 25 +++++++++ src/main/java/duke/ui/TextUI.java | 36 ++++++++++-- 21 files changed, 345 insertions(+), 22 deletions(-) diff --git a/data/duke.txt b/data/duke.txt index a42dbf9c85..1da4c20263 100644 --- a/data/duke.txt +++ b/data/duke.txt @@ -1,7 +1,5 @@ T|1|return book D|1|do this|2000-01-10 10:50 E|1|something|2022-05-20 12:00 -D|0|ip|2022-05-05 23:59 E|1|tp|2020-12-10 14:25 -D|0|quiz|2010-06-25 10:34 D|0|homework|2020-01-01 10:45 diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java index 56ed1affbf..66ce6dafa2 100644 --- a/src/main/java/duke/Duke.java +++ b/src/main/java/duke/Duke.java @@ -9,6 +9,10 @@ import duke.ui.TextUI; +/** + * Entry point of DUke. + * Initializes the application and initiates contact with user. + */ public class Duke { private static TaskList taskList; @@ -45,8 +49,7 @@ private static void run() { } } while (ExitCommand.isRunning()); } - - + public static void main(String[] args) { initialize(); run(); diff --git a/src/main/java/duke/commands/AddCommand.java b/src/main/java/duke/commands/AddCommand.java index fba7f1255b..7b2d53aeb9 100644 --- a/src/main/java/duke/commands/AddCommand.java +++ b/src/main/java/duke/commands/AddCommand.java @@ -6,17 +6,33 @@ import duke.tasks.Todo; import java.time.LocalDateTime; +/** + * Command that adds a Task to the TaskList. + */ + public class AddCommand extends Command{ private String taskType; private String content; private LocalDateTime datetime; + /** + * Constructor for AddCommand + * + * @param taskType string representing subclass of Task to add. + * @param content description of Task to add. + * @param datetime date and time of task to add. + */ public AddCommand(String taskType, String content, LocalDateTime datetime) { this.taskType = taskType; this.content = content; this.datetime = datetime; } + /** + * Creates respective Task depending on taskType which is then added to the TaskList. + * + * @return Message for completing the command which is displayed to user. + */ @Override public String execute() { Task newTask = null; diff --git a/src/main/java/duke/commands/Command.java b/src/main/java/duke/commands/Command.java index 3f2a68548f..9e5ab9071d 100644 --- a/src/main/java/duke/commands/Command.java +++ b/src/main/java/duke/commands/Command.java @@ -4,13 +4,27 @@ import duke.exceptions.DukeUnsupportedOperationException; import duke.tasks.TaskList; +/** + * Parent class of all duke commands. + */ public class Command { static TaskList taskList; + /** + * Defines the TaskList shared with all commands. + * + * @param taskList TaskList defined and used by all commands. + */ public static void defineTaskList(TaskList taskList) { Command.taskList = taskList; } + /** + * Carries out the command. + * + * @return Message for completing the command which is displayed to user. + * @throws DukeException If arguments passed to the commands are invalid. + */ public String execute() throws DukeException{ throw new DukeUnsupportedOperationException("This method is to be implemented by child classes"); } diff --git a/src/main/java/duke/commands/DeleteCommand.java b/src/main/java/duke/commands/DeleteCommand.java index 440ada757c..2774e7e92d 100644 --- a/src/main/java/duke/commands/DeleteCommand.java +++ b/src/main/java/duke/commands/DeleteCommand.java @@ -3,14 +3,28 @@ import duke.exceptions.DukeInvalidArgumentException; import duke.tasks.Task; +/** + * Command that deletes a Task from TaskList. + */ public class DeleteCommand extends Command { private int index; + /** + * Constructor for DeleteCommand. + * + * @param index index of Task to delete. + */ public DeleteCommand(int index) { this.index = index; } + /** + * Deletes Task from TaskList + * + * @return Message for completing the command which is displayed to user. + * @throws DukeInvalidArgumentException If index is not within TaskList. + */ @Override public String execute() throws DukeInvalidArgumentException { if (index > taskList.size() - 1 || index < 0) { diff --git a/src/main/java/duke/commands/ExitCommand.java b/src/main/java/duke/commands/ExitCommand.java index 454e3e08f8..538a32555c 100644 --- a/src/main/java/duke/commands/ExitCommand.java +++ b/src/main/java/duke/commands/ExitCommand.java @@ -1,12 +1,25 @@ package duke.commands; +/** + * Command that indicates exit of program. + */ public class ExitCommand extends Command{ private static boolean isProgramRunning = true; + /** + * returns true if the program should be running and false otherwise. + * + * @return whether program should be running. + */ public static boolean isRunning() { return isProgramRunning; } + /** + * Sets isProgramRunning to false. + * + * @return Message for completing the command which is displayed to user. + */ @Override public String execute() { isProgramRunning = false; diff --git a/src/main/java/duke/commands/InvalidCommand.java b/src/main/java/duke/commands/InvalidCommand.java index be2567fd34..1c621d7d67 100644 --- a/src/main/java/duke/commands/InvalidCommand.java +++ b/src/main/java/duke/commands/InvalidCommand.java @@ -1,9 +1,17 @@ package duke.commands; +/** + * Command for any unknown commands. + */ public class InvalidCommand extends Command{ final private String MESSAGE = "I am unable to comprehend your request. Please try again"; + /** + * returns String to tell user command is unknown. + * + * @return Message for completing the command which is displayed to user. + */ @Override public String execute(){ return MESSAGE; diff --git a/src/main/java/duke/commands/ListCommand.java b/src/main/java/duke/commands/ListCommand.java index c5d1c740bd..ba3490988b 100644 --- a/src/main/java/duke/commands/ListCommand.java +++ b/src/main/java/duke/commands/ListCommand.java @@ -1,5 +1,8 @@ package duke.commands; +/** + * Command that displays all Task in TaskList. + */ public class ListCommand extends Command { private String displayTaskList() { StringBuilder numberedTaskList = new StringBuilder(); @@ -9,6 +12,11 @@ private String displayTaskList() { return numberedTaskList.toString().trim(); } + /** + * Checks if TaskList is empty, otherwise displays all Task. + * + * @return All Task in TaskList and message for completing the command which is displayed to user. + */ @Override public String execute() { if (taskList.size() == 0) { diff --git a/src/main/java/duke/commands/MarkCommand.java b/src/main/java/duke/commands/MarkCommand.java index 064511e7bb..c67e8fdd32 100644 --- a/src/main/java/duke/commands/MarkCommand.java +++ b/src/main/java/duke/commands/MarkCommand.java @@ -3,13 +3,27 @@ import duke.exceptions.DukeInvalidArgumentException; import duke.tasks.Task; +/** + * Command that marks Task from TaskList as done. + */ public class MarkCommand extends Command { private int index; + /** + * Constructor for MarkCommand. + * + * @param index index of Task to mark. + */ public MarkCommand(int index) { this.index = index; } + /** + * Marks Task from TaskList as done. + * + * @return Message for completing the command which is displayed to user. + * @throws DukeInvalidArgumentException If index is not within TaskList. + */ @Override public String execute() throws DukeInvalidArgumentException { if (index > taskList.size() - 1 || index < 0) { diff --git a/src/main/java/duke/commands/UnmarkCommand.java b/src/main/java/duke/commands/UnmarkCommand.java index 8dbb5b1168..2b58adbef9 100644 --- a/src/main/java/duke/commands/UnmarkCommand.java +++ b/src/main/java/duke/commands/UnmarkCommand.java @@ -3,13 +3,27 @@ import duke.exceptions.DukeInvalidArgumentException; import duke.tasks.Task; +/** + * Command that unmarks a Task from TaskList + */ public class UnmarkCommand extends Command { private int index; + /** + * Constructor for UnmarkCommand. + * + * @param index index of Task to unmark. + */ public UnmarkCommand(int index) { this.index = index; } + /** + * Unmarks Task from TaskList. + * + * @return Message for completing the command which is displayed to user. + * @throws DukeInvalidArgumentException If index is not within TaskList. + */ @Override public String execute() throws DukeInvalidArgumentException { if (index > taskList.size() - 1 || index < 0) { diff --git a/src/main/java/duke/exceptions/DukeException.java b/src/main/java/duke/exceptions/DukeException.java index 897d82917e..48850c1ae3 100644 --- a/src/main/java/duke/exceptions/DukeException.java +++ b/src/main/java/duke/exceptions/DukeException.java @@ -1,6 +1,14 @@ package duke.exceptions; +/** + * Parent class of all duke exceptions. + */ public class DukeException extends Exception{ + /** + * Constructor for DukeException. + * + * @param message Contains information of the exception. + */ public DukeException(String message) { super(message); } diff --git a/src/main/java/duke/exceptions/DukeInvalidArgumentException.java b/src/main/java/duke/exceptions/DukeInvalidArgumentException.java index 4b89e6542e..f690823290 100644 --- a/src/main/java/duke/exceptions/DukeInvalidArgumentException.java +++ b/src/main/java/duke/exceptions/DukeInvalidArgumentException.java @@ -1,6 +1,14 @@ package duke.exceptions; +/** + * DukeException for invalid arguments inputted. + */ public class DukeInvalidArgumentException extends DukeException{ + /** + * Constructor for DukeInvalidArgumentException. + * + * @param message Contains information of the exception. + */ public DukeInvalidArgumentException(String message) { super(message); } diff --git a/src/main/java/duke/exceptions/DukeUnsupportedOperationException.java b/src/main/java/duke/exceptions/DukeUnsupportedOperationException.java index 0ea4165d6e..11ceb531da 100644 --- a/src/main/java/duke/exceptions/DukeUnsupportedOperationException.java +++ b/src/main/java/duke/exceptions/DukeUnsupportedOperationException.java @@ -1,6 +1,14 @@ package duke.exceptions; +/** + * DukeException for operations that cannot be carried out. + */ public class DukeUnsupportedOperationException extends DukeException{ + /** + * Constructor for DukeUnsupportedOperationException. + * + * @param message Contains information of the exception. + */ public DukeUnsupportedOperationException(String message) { super(message); } diff --git a/src/main/java/duke/parser/Parser.java b/src/main/java/duke/parser/Parser.java index 4d3ca3038d..0b39dd68b1 100644 --- a/src/main/java/duke/parser/Parser.java +++ b/src/main/java/duke/parser/Parser.java @@ -5,6 +5,9 @@ import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; +/** + * Parses user inputs for commands. + */ public class Parser { private String[] parseArguments(String[] arguments) throws DukeInvalidArgumentException { if (arguments.length < 2) { @@ -21,9 +24,15 @@ private LocalDateTime parseDateTime(String datetime) { private int parseIndex(String strIndex) { return Integer.parseInt(strIndex.trim()) - 1; - } + /** + * Parses user input for specified commands. + * + * @param userInput raw input from user. + * @return Command parsed from user input. + * @throws DukeInvalidArgumentException If user input invalid arguments. + */ public Command parseCommands(String userInput) throws DukeInvalidArgumentException { String[] parsedUserInput = userInput.split(" ", 2); String commandType = parsedUserInput[0].toLowerCase(); @@ -52,7 +61,6 @@ public Command parseCommands(String userInput) throws DukeInvalidArgumentExcepti return new AddCommand(commandType, content, datetime); default: return new InvalidCommand(); - } } } diff --git a/src/main/java/duke/storage/Storage.java b/src/main/java/duke/storage/Storage.java index 5e1bd40c1e..1110b1b135 100644 --- a/src/main/java/duke/storage/Storage.java +++ b/src/main/java/duke/storage/Storage.java @@ -11,6 +11,9 @@ import java.nio.file.Path; +/** + * This class saves and loads data from save file. + */ public class Storage { private static final Path DATA_PATH = Paths.get("data", "duke.txt"); @@ -27,6 +30,12 @@ private static void initialiseSaveFile() throws DukeException { } } + /** + * Writes TaskList data to save file. + * + * @param taskList TaskList to write to save file. + * @throws DukeException If there is an error writing to save file. + */ public void saveTasklist(TaskList taskList) throws DukeException { initialiseSaveFile(); String dataToWrite = taskList.toSaveData(); @@ -39,6 +48,12 @@ public void saveTasklist(TaskList taskList) throws DukeException { } } + /** + * Loads TaskList data from save file. + * + * @return new TaskList recreated from data. + * @throws DukeException If data cannot be loaded from save file. + */ public static TaskList loadTasklist() throws DukeException{ initialiseSaveFile(); String strCurrentLine; @@ -74,6 +89,5 @@ public static TaskList loadTasklist() throws DukeException{ } - } diff --git a/src/main/java/duke/tasks/Deadline.java b/src/main/java/duke/tasks/Deadline.java index 8ef5cacc7e..eea0e3ef4d 100644 --- a/src/main/java/duke/tasks/Deadline.java +++ b/src/main/java/duke/tasks/Deadline.java @@ -3,29 +3,60 @@ import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; +/** + * Deadlines are tasks due on a certain date. + */ public class Deadline extends Task{ private LocalDateTime date; + /** + * Constructor for Deadline. + * + * @param content Description of Deadline. + * @param date date and time Deadline is due. + */ public Deadline(String content, LocalDateTime date) { super(content); this.date = date; } + /** + * Adds Deadline indicator at the front and the date time to the back of Task string. + * + * @return Formatted string representation of Deadline. + */ @Override public String toString() { return String.format("[D]%s (by: %s)", super.toString(), this.date.toString().replace("T", " ")); } + /** + * Adds Deadline indicator and date time to save data. + * + * @return Data to write into save file. + */ public String toSaveData() { return String.format("D|%s|%s\n", super.toSaveData(), this.date.toString().replace("T", " ")); } + /** + * Converts String in a pattern into LocalDateTime object. + * + * @param datetime String to be converted into LocalDateTime. + * @return LocalDateTime representing the date and time. + */ private static LocalDateTime parseDateTime(String datetime) { DateTimeFormatter datetimePattern = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); return LocalDateTime.parse(datetime, datetimePattern); } + /** + * Recreate Deadline from save data. + * + * @param savedData Deadline Data in save file. + * @return Deadline that was saved. + */ public static Deadline createFromData(String savedData) { String[] parsedSavedData = savedData.split("\\|"); Deadline newDeadline = new Deadline(parsedSavedData[2], parseDateTime(parsedSavedData[3])); diff --git a/src/main/java/duke/tasks/Event.java b/src/main/java/duke/tasks/Event.java index 000fb15781..425b378636 100644 --- a/src/main/java/duke/tasks/Event.java +++ b/src/main/java/duke/tasks/Event.java @@ -3,29 +3,60 @@ import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; -public class Event extends Task{ +/** + * Events are tasks happening at a point in time. + */ +public class Event extends Task { private LocalDateTime date; + /** + * Constructor for Event. + * + * @param content Description of Event. + * @param date date and time of Event. + */ public Event(String content, LocalDateTime date) { super(content); this.date = date; } + /** + * Adds Event indicator at the front and the date time to the back of Task string. + * + * @return Formatted string representation of Event. + */ @Override public String toString() { return String.format("[E]%s (at: %s)", super.toString(), this.date.toString().replace("T", " ")); } + /** + * Adds Event indicator and date time to save data. + * + * @return Data to write into save file. + */ public String toSaveData() { return String.format("E|%s|%s\n", super.toSaveData(), this.date.toString().replace("T", " ")); } + /** + * Converts String in a pattern into LocalDateTime object. + * + * @param datetime String to be converted into LocalDateTime. + * @return LocalDateTime representing the date and time. + */ private static LocalDateTime parseDateTime(String datetime) { DateTimeFormatter datetimePattern = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); return LocalDateTime.parse(datetime, datetimePattern); } + /** + * Recreate Event from save data. + * + * @param savedData Event Data in save file. + * @return Event that was saved. + */ public static Event createFromData(String savedData) { String[] parsedSavedData = savedData.split("\\|"); Event newEvent = new Event(parsedSavedData[2], parseDateTime(parsedSavedData[3])); diff --git a/src/main/java/duke/tasks/Task.java b/src/main/java/duke/tasks/Task.java index 5d2f4aadb7..d001f53786 100644 --- a/src/main/java/duke/tasks/Task.java +++ b/src/main/java/duke/tasks/Task.java @@ -1,27 +1,52 @@ package duke.tasks; +/** + * Parent Class of all duke tasks. + */ public class Task { private String content; private boolean markedDone = false; + /** + * Constructor for Task. + * + * @param content Description of Task. + */ public Task(String content) { this.content = content; } + /** + * Marks task as done. + */ public void markAsDone() { this.markedDone = true; } + /** + * Unmarks task as not done. + */ public void markAsNotDone() { this.markedDone = false; } + /** + * Formats Task indicating done tasks with an X followed by content of task. + * + * @return Formatted string representation of task. + */ @Override public String toString() { String markedDoneIndicator = this.markedDone ? "X" : " "; return String.format("[%s] %s", markedDoneIndicator, this.content); } + /** + * Formats Task to write into save file. + * Marked done tasks are denoted by 1 and 0 otherwise. + * + * @return Data to write into save file. + */ public String toSaveData() { String markedDoneIndicator = this.markedDone ? "1" : "0"; return String.format("%s|%s", markedDoneIndicator, this.content); diff --git a/src/main/java/duke/tasks/TaskList.java b/src/main/java/duke/tasks/TaskList.java index c341314a5e..1b33e6b60c 100644 --- a/src/main/java/duke/tasks/TaskList.java +++ b/src/main/java/duke/tasks/TaskList.java @@ -2,43 +2,86 @@ import java.util.ArrayList; +/** + * ArrayList of Task objects. + */ public class TaskList { private final ArrayList taskList; + /** + * Constructor for TaskList. + */ public TaskList() { this.taskList = new ArrayList<>(); } + /** + * Get task at given index. + * + * @param index Index of task to get. + * @return Task at given index. + */ public Task getTask(int index) { return taskList.get(index); } + /** + * Adds Task to TaskList. + * + * @param taskToAdd Task to add to TaskList. + */ public void addTask(Task taskToAdd) { taskList.add(taskToAdd); } + /** + * Deletes Task from Tasklist specified by given index. + * + * @param indexTaskToDelete Index of Task to delete. + * @return Deleted task. + */ public Task deleteTask(int indexTaskToDelete) { - taskList.remove(indexTaskToDelete); - displayTaskDelete(taskList.get(indexTaskToDelete)); - return taskList.get(indexTaskToDelete); + return taskList.remove(indexTaskToDelete); } + /** + * Marks Task from TaskList specified by given index. + * + * @param indexTaskToMark Index of Task to mark. + * @return Marked task + */ public Task markTask(int indexTaskToMark) { Task taskToMark = taskList.get(indexTaskToMark); taskToMark.markAsDone(); return taskToMark; } + /** + * Unmarks Task from TaskList specified by given index. + * + * @param indexTaskToUnmark Index of Task to Unmark. + * @return Unmarked task + */ public Task unmarkTask(int indexTaskToUnmark) { Task taskToUnmark = taskList.get(indexTaskToUnmark); taskToUnmark.markAsNotDone(); return taskToUnmark; } + /** + * Returns number of tasks in TaskList. + * + * @return size of TaskList. + */ public int size() { return taskList.size(); } + /** + * Formats each Task in TaskList to write into save file. + * + * @return Data to write into save file. + */ public String toSaveData() { StringBuilder dataToWrite = new StringBuilder(); for (Task task : taskList) { @@ -47,10 +90,4 @@ public String toSaveData() { return dataToWrite.toString(); } - - public void displayTaskDelete(Task deletedTask){ - System.out.println("As you wish. The following task has been removed"); - System.out.println(deletedTask.toString()); - System.out.printf("You now have %d item(s) in your list\n", taskList.size()); - } } diff --git a/src/main/java/duke/tasks/Todo.java b/src/main/java/duke/tasks/Todo.java index ba58314840..2011bb2ae8 100644 --- a/src/main/java/duke/tasks/Todo.java +++ b/src/main/java/duke/tasks/Todo.java @@ -1,19 +1,44 @@ package duke.tasks; +/** + * Todos are tasks that have no dates involved. + */ public class Todo extends Task{ + + /** + * Constructor for Todo. + * + * @param content Description of Todo. + */ public Todo(String content) { super(content); } + /** + * Adds Todo indicator to the front of Task string. + * + * @return Formatted string representation of Event. + */ @Override public String toString() { return String.format("[T]%s", super.toString()); } + /** + * Adds Todo indicator and date time to save data. + * + * @return Data to write into save file. + */ public String toSaveData() { return String.format("T|%s\n",super.toSaveData()); } + /** + * Recreate Todo from save data. + * + * @param savedData Todo Data in save file. + * @return Todo that was saved. + */ public static Todo createFromData(String savedData) { String[] parsedSavedData = savedData.split("\\|"); Todo newTodo = new Todo(parsedSavedData[2]); diff --git a/src/main/java/duke/ui/TextUI.java b/src/main/java/duke/ui/TextUI.java index ce1777502f..6d1caedd57 100644 --- a/src/main/java/duke/ui/TextUI.java +++ b/src/main/java/duke/ui/TextUI.java @@ -4,23 +4,41 @@ import java.io.PrintStream; import java.util.Scanner; +/** + * Class that handles input and output with user. + */ public class TextUI { private final Scanner in; private final PrintStream out; - public TextUI() { - this(System.in, System.out); - } - + /** + * Constructor for TextUI. + * + * @param in To receive user input by scanning. + * @param out output to print to. + */ public TextUI(InputStream in, PrintStream out){ this.in = new Scanner(in); this.out = out; } - public boolean shouldIgnore(String rawInputLine) { + /** + * Constructor for TextUI with default System in and out. + */ + public TextUI() { + this(System.in, System.out); + } + + private boolean shouldIgnore(String rawInputLine) { return rawInputLine.trim().isEmpty(); } + /** + * Gets next line entered by user. + * Ignores empty lines. + * + * @return raw user input + */ public String getUserCommand() { String currInput = in.nextLine().trim(); while (shouldIgnore(currInput)) { @@ -30,12 +48,20 @@ public String getUserCommand() { return currInput; } + /** + * Formats the message with borders and prints it. + * + * @param message Message to be printed. + */ public void printMessage(String message) { String textBorder = "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"; String textToPrint = "\n" + textBorder + message + "\n" + textBorder + "\n"; out.print(textToPrint); } + /** + * Generates and print the welcome message upon the start of the application. + */ public void printWelcomeMessage() { String logo = " ____ _ \n" + "| _ \\ _ _| | _____ \n" From cef55d4eb54d2d27775a601e1e49a0bd5f192e59 Mon Sep 17 00:00:00 2001 From: Decaxical Date: Fri, 18 Feb 2022 00:26:45 +0800 Subject: [PATCH 23/50] Updated to uphold Coding Standard Deleted unnecessary lines. Shortened code. Renamed variables. --- src/main/java/duke/Duke.java | 5 +---- src/main/java/duke/commands/AddCommand.java | 19 ++++++++++--------- src/main/java/duke/commands/Command.java | 1 + src/main/java/duke/commands/ExitCommand.java | 1 + .../java/duke/commands/InvalidCommand.java | 4 +--- src/main/java/duke/commands/ListCommand.java | 2 +- src/main/java/duke/commands/MarkCommand.java | 3 +-- .../java/duke/commands/UnmarkCommand.java | 2 +- .../java/duke/exceptions/DukeException.java | 1 + .../DukeInvalidArgumentException.java | 1 + .../DukeUnsupportedOperationException.java | 1 + src/main/java/duke/parser/Parser.java | 16 ++++++---------- src/main/java/duke/storage/Storage.java | 13 ++++--------- src/main/java/duke/tasks/Deadline.java | 13 +++++-------- src/main/java/duke/tasks/Event.java | 13 +++++-------- src/main/java/duke/tasks/Task.java | 11 ++++++----- src/main/java/duke/tasks/TaskList.java | 4 ++-- src/main/java/duke/tasks/Todo.java | 1 + src/main/java/duke/ui/TextUI.java | 5 ++--- 19 files changed, 51 insertions(+), 65 deletions(-) diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java index 56ed1affbf..cc5f5b0346 100644 --- a/src/main/java/duke/Duke.java +++ b/src/main/java/duke/Duke.java @@ -20,24 +20,21 @@ private static void initialize() { textUI = new TextUI(); storage = new Storage(); parser = new Parser(); - try { taskList = Storage.loadTasklist(); } catch (DukeException e) { taskList = new TaskList(); System.out.println(e.getMessage()); } - Command.defineTaskList(taskList); textUI.printWelcomeMessage(); } private static void run() { - Command currCommand = null; do { String userInputCommand = textUI.getUserCommand(); try { - currCommand = parser.parseCommands(userInputCommand); + Command currCommand = parser.parseCommands(userInputCommand); textUI.printMessage(currCommand.execute()); storage.saveTasklist(taskList); } catch (DukeException e) { diff --git a/src/main/java/duke/commands/AddCommand.java b/src/main/java/duke/commands/AddCommand.java index fba7f1255b..445e48b6a9 100644 --- a/src/main/java/duke/commands/AddCommand.java +++ b/src/main/java/duke/commands/AddCommand.java @@ -7,6 +7,7 @@ import java.time.LocalDateTime; public class AddCommand extends Command{ + private String taskType; private String content; private LocalDateTime datetime; @@ -21,15 +22,15 @@ public AddCommand(String taskType, String content, LocalDateTime datetime) { public String execute() { Task newTask = null; switch (taskType.toLowerCase()) { - case "todo": - newTask = new Todo(content); - break; - case "deadline": - newTask = new Deadline(content, datetime); - break; - case "event": - newTask = new Event(content, datetime); - break; + case "todo": + newTask = new Todo(content); + break; + case "deadline": + newTask = new Deadline(content, datetime); + break; + case "event": + newTask = new Event(content, datetime); + break; } taskList.addTask(newTask); return String.format("This task has been added as requested:\n" + diff --git a/src/main/java/duke/commands/Command.java b/src/main/java/duke/commands/Command.java index 3f2a68548f..2d399dcbb1 100644 --- a/src/main/java/duke/commands/Command.java +++ b/src/main/java/duke/commands/Command.java @@ -5,6 +5,7 @@ import duke.tasks.TaskList; public class Command { + static TaskList taskList; public static void defineTaskList(TaskList taskList) { diff --git a/src/main/java/duke/commands/ExitCommand.java b/src/main/java/duke/commands/ExitCommand.java index 454e3e08f8..619d5a1724 100644 --- a/src/main/java/duke/commands/ExitCommand.java +++ b/src/main/java/duke/commands/ExitCommand.java @@ -1,6 +1,7 @@ package duke.commands; public class ExitCommand extends Command{ + private static boolean isProgramRunning = true; public static boolean isRunning() { diff --git a/src/main/java/duke/commands/InvalidCommand.java b/src/main/java/duke/commands/InvalidCommand.java index be2567fd34..c8f9345c02 100644 --- a/src/main/java/duke/commands/InvalidCommand.java +++ b/src/main/java/duke/commands/InvalidCommand.java @@ -2,10 +2,8 @@ public class InvalidCommand extends Command{ - final private String MESSAGE = "I am unable to comprehend your request. Please try again"; - @Override public String execute(){ - return MESSAGE; + return "I am unable to comprehend your request. Please try again"; } } diff --git a/src/main/java/duke/commands/ListCommand.java b/src/main/java/duke/commands/ListCommand.java index c5d1c740bd..1a119462e7 100644 --- a/src/main/java/duke/commands/ListCommand.java +++ b/src/main/java/duke/commands/ListCommand.java @@ -1,6 +1,7 @@ package duke.commands; public class ListCommand extends Command { + private String displayTaskList() { StringBuilder numberedTaskList = new StringBuilder(); for (int i = 0; i < taskList.size(); i++) { @@ -14,7 +15,6 @@ public String execute() { if (taskList.size() == 0) { return "Your current task list is empty"; } - return String.format("These are the current tasks in your list:\n%s", displayTaskList()); } } diff --git a/src/main/java/duke/commands/MarkCommand.java b/src/main/java/duke/commands/MarkCommand.java index 064511e7bb..8ea1c80349 100644 --- a/src/main/java/duke/commands/MarkCommand.java +++ b/src/main/java/duke/commands/MarkCommand.java @@ -4,6 +4,7 @@ import duke.tasks.Task; public class MarkCommand extends Command { + private int index; public MarkCommand(int index) { @@ -19,7 +20,5 @@ public String execute() throws DukeInvalidArgumentException { Task markedTask = taskList.markTask(index); return String.format("Duly noted. The following task has been marked as done:\n" + "%s", markedTask); - } - } diff --git a/src/main/java/duke/commands/UnmarkCommand.java b/src/main/java/duke/commands/UnmarkCommand.java index 8dbb5b1168..43819f8643 100644 --- a/src/main/java/duke/commands/UnmarkCommand.java +++ b/src/main/java/duke/commands/UnmarkCommand.java @@ -4,6 +4,7 @@ import duke.tasks.Task; public class UnmarkCommand extends Command { + private int index; public UnmarkCommand(int index) { @@ -19,6 +20,5 @@ public String execute() throws DukeInvalidArgumentException { Task unmarkedTask = taskList.unmarkTask(index); return String.format("Very well. The following task has been marked as not done:" + "%s", unmarkedTask); - } } diff --git a/src/main/java/duke/exceptions/DukeException.java b/src/main/java/duke/exceptions/DukeException.java index 897d82917e..a096fb52de 100644 --- a/src/main/java/duke/exceptions/DukeException.java +++ b/src/main/java/duke/exceptions/DukeException.java @@ -1,6 +1,7 @@ package duke.exceptions; public class DukeException extends Exception{ + public DukeException(String message) { super(message); } diff --git a/src/main/java/duke/exceptions/DukeInvalidArgumentException.java b/src/main/java/duke/exceptions/DukeInvalidArgumentException.java index 4b89e6542e..314467936c 100644 --- a/src/main/java/duke/exceptions/DukeInvalidArgumentException.java +++ b/src/main/java/duke/exceptions/DukeInvalidArgumentException.java @@ -1,6 +1,7 @@ package duke.exceptions; public class DukeInvalidArgumentException extends DukeException{ + public DukeInvalidArgumentException(String message) { super(message); } diff --git a/src/main/java/duke/exceptions/DukeUnsupportedOperationException.java b/src/main/java/duke/exceptions/DukeUnsupportedOperationException.java index 0ea4165d6e..04b437b5b4 100644 --- a/src/main/java/duke/exceptions/DukeUnsupportedOperationException.java +++ b/src/main/java/duke/exceptions/DukeUnsupportedOperationException.java @@ -1,6 +1,7 @@ package duke.exceptions; public class DukeUnsupportedOperationException extends DukeException{ + public DukeUnsupportedOperationException(String message) { super(message); } diff --git a/src/main/java/duke/parser/Parser.java b/src/main/java/duke/parser/Parser.java index 4d3ca3038d..c1af15bf18 100644 --- a/src/main/java/duke/parser/Parser.java +++ b/src/main/java/duke/parser/Parser.java @@ -6,29 +6,26 @@ import java.time.format.DateTimeFormatter; public class Parser { + private String[] parseArguments(String[] arguments) throws DukeInvalidArgumentException { if (arguments.length < 2) { throw new DukeInvalidArgumentException("There appears to be insufficient arguments"); } - return arguments[1].split(" /([Aa][Tt]|[Bb][Yy]) ", 2); } - private LocalDateTime parseDateTime(String datetime) { + public LocalDateTime parseDateTime(String datetime) { DateTimeFormatter datetimePattern = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm"); return LocalDateTime.parse(datetime, datetimePattern); } private int parseIndex(String strIndex) { return Integer.parseInt(strIndex.trim()) - 1; - } public Command parseCommands(String userInput) throws DukeInvalidArgumentException { String[] parsedUserInput = userInput.split(" ", 2); String commandType = parsedUserInput[0].toLowerCase(); - String[] parsedArguments; - String content = null; switch (commandType) { case "bye": return new ExitCommand(); @@ -41,18 +38,17 @@ public Command parseCommands(String userInput) throws DukeInvalidArgumentExcepti case "delete": return new DeleteCommand(parseIndex(parsedUserInput[1])); case "todo": - parsedArguments = parseArguments(parsedUserInput); - content = parsedArguments[0]; + String[] todoParsedArguments = parseArguments(parsedUserInput); + String content = todoParsedArguments[0]; return new AddCommand(commandType, content, null); case "deadline": case "event": - parsedArguments = parseArguments(parsedUserInput); + String[] parsedArguments = parseArguments(parsedUserInput); content = parsedArguments[0]; LocalDateTime datetime = parseDateTime(parsedArguments[1]); return new AddCommand(commandType, content, datetime); default: return new InvalidCommand(); - } } -} +} \ No newline at end of file diff --git a/src/main/java/duke/storage/Storage.java b/src/main/java/duke/storage/Storage.java index 5e1bd40c1e..a095992a51 100644 --- a/src/main/java/duke/storage/Storage.java +++ b/src/main/java/duke/storage/Storage.java @@ -12,6 +12,7 @@ public class Storage { + private static final Path DATA_PATH = Paths.get("data", "duke.txt"); private static void initialiseSaveFile() throws DukeException { @@ -39,10 +40,10 @@ public void saveTasklist(TaskList taskList) throws DukeException { } } - public static TaskList loadTasklist() throws DukeException{ + public static TaskList loadTasklist() throws DukeException { initialiseSaveFile(); String strCurrentLine; - Task currentTask; + Task currentTask = null; TaskList taskList = new TaskList(); try { BufferedReader saveFilereader = new BufferedReader(new FileReader(DATA_PATH.toString())); @@ -50,30 +51,24 @@ public static TaskList loadTasklist() throws DukeException{ switch (strCurrentLine.charAt(0)) { case 'T' : { currentTask = Todo.createFromData(strCurrentLine); - taskList.addTask(currentTask); break; } case 'E' : { currentTask = Event.createFromData(strCurrentLine); - taskList.addTask(currentTask); break; } case 'D' : { currentTask = Deadline.createFromData(strCurrentLine); - taskList.addTask(currentTask); break; } } + taskList.addTask(currentTask); } saveFilereader.close(); } catch (IOException e) { throw new DukeException("Unable to load save file"); } - return taskList; } - - - } diff --git a/src/main/java/duke/tasks/Deadline.java b/src/main/java/duke/tasks/Deadline.java index 8ef5cacc7e..d049a10351 100644 --- a/src/main/java/duke/tasks/Deadline.java +++ b/src/main/java/duke/tasks/Deadline.java @@ -1,9 +1,10 @@ package duke.tasks; +import duke.parser.Parser; + import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -public class Deadline extends Task{ +public class Deadline extends Task { private LocalDateTime date; @@ -21,14 +22,10 @@ public String toSaveData() { return String.format("D|%s|%s\n", super.toSaveData(), this.date.toString().replace("T", " ")); } - private static LocalDateTime parseDateTime(String datetime) { - DateTimeFormatter datetimePattern = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); - return LocalDateTime.parse(datetime, datetimePattern); - } - public static Deadline createFromData(String savedData) { + Parser parser = new Parser(); String[] parsedSavedData = savedData.split("\\|"); - Deadline newDeadline = new Deadline(parsedSavedData[2], parseDateTime(parsedSavedData[3])); + Deadline newDeadline = new Deadline(parsedSavedData[2], parser.parseDateTime(parsedSavedData[3])); if (parsedSavedData[1].equals("1")) { newDeadline.markAsDone(); } diff --git a/src/main/java/duke/tasks/Event.java b/src/main/java/duke/tasks/Event.java index 000fb15781..c0413bdd8f 100644 --- a/src/main/java/duke/tasks/Event.java +++ b/src/main/java/duke/tasks/Event.java @@ -1,9 +1,10 @@ package duke.tasks; +import duke.parser.Parser; + import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -public class Event extends Task{ +public class Event extends Task { private LocalDateTime date; @@ -21,14 +22,10 @@ public String toSaveData() { return String.format("E|%s|%s\n", super.toSaveData(), this.date.toString().replace("T", " ")); } - private static LocalDateTime parseDateTime(String datetime) { - DateTimeFormatter datetimePattern = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); - return LocalDateTime.parse(datetime, datetimePattern); - } - public static Event createFromData(String savedData) { + Parser parser = new Parser(); String[] parsedSavedData = savedData.split("\\|"); - Event newEvent = new Event(parsedSavedData[2], parseDateTime(parsedSavedData[3])); + Event newEvent = new Event(parsedSavedData[2], parser.parseDateTime(parsedSavedData[3])); if (parsedSavedData[1].equals("1")) { newEvent.markAsDone(); } diff --git a/src/main/java/duke/tasks/Task.java b/src/main/java/duke/tasks/Task.java index 5d2f4aadb7..3cbe4763f4 100644 --- a/src/main/java/duke/tasks/Task.java +++ b/src/main/java/duke/tasks/Task.java @@ -1,29 +1,30 @@ package duke.tasks; public class Task { + private String content; - private boolean markedDone = false; + private boolean isDone = false; public Task(String content) { this.content = content; } public void markAsDone() { - this.markedDone = true; + this.isDone = true; } public void markAsNotDone() { - this.markedDone = false; + this.isDone = false; } @Override public String toString() { - String markedDoneIndicator = this.markedDone ? "X" : " "; + String markedDoneIndicator = this.isDone ? "X" : " "; return String.format("[%s] %s", markedDoneIndicator, this.content); } public String toSaveData() { - String markedDoneIndicator = this.markedDone ? "1" : "0"; + String markedDoneIndicator = this.isDone ? "1" : "0"; return String.format("%s|%s", markedDoneIndicator, this.content); } diff --git a/src/main/java/duke/tasks/TaskList.java b/src/main/java/duke/tasks/TaskList.java index c341314a5e..392697afee 100644 --- a/src/main/java/duke/tasks/TaskList.java +++ b/src/main/java/duke/tasks/TaskList.java @@ -3,6 +3,7 @@ import java.util.ArrayList; public class TaskList { + private final ArrayList taskList; public TaskList() { @@ -44,11 +45,10 @@ public String toSaveData() { for (Task task : taskList) { dataToWrite.append(task.toSaveData()); } - return dataToWrite.toString(); } - public void displayTaskDelete(Task deletedTask){ + public void displayTaskDelete(Task deletedTask) { System.out.println("As you wish. The following task has been removed"); System.out.println(deletedTask.toString()); System.out.printf("You now have %d item(s) in your list\n", taskList.size()); diff --git a/src/main/java/duke/tasks/Todo.java b/src/main/java/duke/tasks/Todo.java index ba58314840..f5b6972a75 100644 --- a/src/main/java/duke/tasks/Todo.java +++ b/src/main/java/duke/tasks/Todo.java @@ -1,6 +1,7 @@ package duke.tasks; public class Todo extends Task{ + public Todo(String content) { super(content); } diff --git a/src/main/java/duke/ui/TextUI.java b/src/main/java/duke/ui/TextUI.java index ce1777502f..374ff4e504 100644 --- a/src/main/java/duke/ui/TextUI.java +++ b/src/main/java/duke/ui/TextUI.java @@ -5,6 +5,7 @@ import java.util.Scanner; public class TextUI { + private final Scanner in; private final PrintStream out; @@ -12,7 +13,7 @@ public TextUI() { this(System.in, System.out); } - public TextUI(InputStream in, PrintStream out){ + public TextUI(InputStream in, PrintStream out) { this.in = new Scanner(in); this.out = out; } @@ -26,7 +27,6 @@ public String getUserCommand() { while (shouldIgnore(currInput)) { currInput = in.nextLine().trim(); } - return currInput; } @@ -47,5 +47,4 @@ public void printWelcomeMessage() { out.println("How may I assist you?"); out.print("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n\n"); } - } From 2cccc2968ae578c949d6ebc0eb8d3144849a2d92 Mon Sep 17 00:00:00 2001 From: Decaxical Date: Fri, 18 Feb 2022 00:40:44 +0800 Subject: [PATCH 24/50] Added parseSaveDateTime Accommodate different time format in saveData --- src/main/java/duke/parser/Parser.java | 7 ++++++- src/main/java/duke/tasks/Deadline.java | 2 +- src/main/java/duke/tasks/Event.java | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/main/java/duke/parser/Parser.java b/src/main/java/duke/parser/Parser.java index c1af15bf18..26ffe00be2 100644 --- a/src/main/java/duke/parser/Parser.java +++ b/src/main/java/duke/parser/Parser.java @@ -14,11 +14,16 @@ private String[] parseArguments(String[] arguments) throws DukeInvalidArgumentEx return arguments[1].split(" /([Aa][Tt]|[Bb][Yy]) ", 2); } - public LocalDateTime parseDateTime(String datetime) { + private LocalDateTime parseDateTime(String datetime) { DateTimeFormatter datetimePattern = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm"); return LocalDateTime.parse(datetime, datetimePattern); } + public LocalDateTime parseSaveDateTime(String datetime) { + DateTimeFormatter datetimePattern = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); + return LocalDateTime.parse(datetime, datetimePattern); + } + private int parseIndex(String strIndex) { return Integer.parseInt(strIndex.trim()) - 1; } diff --git a/src/main/java/duke/tasks/Deadline.java b/src/main/java/duke/tasks/Deadline.java index d049a10351..32cc5f99ab 100644 --- a/src/main/java/duke/tasks/Deadline.java +++ b/src/main/java/duke/tasks/Deadline.java @@ -25,7 +25,7 @@ public String toSaveData() { public static Deadline createFromData(String savedData) { Parser parser = new Parser(); String[] parsedSavedData = savedData.split("\\|"); - Deadline newDeadline = new Deadline(parsedSavedData[2], parser.parseDateTime(parsedSavedData[3])); + Deadline newDeadline = new Deadline(parsedSavedData[2], parser.parseSaveDateTime(parsedSavedData[3])); if (parsedSavedData[1].equals("1")) { newDeadline.markAsDone(); } diff --git a/src/main/java/duke/tasks/Event.java b/src/main/java/duke/tasks/Event.java index c0413bdd8f..215305e5b6 100644 --- a/src/main/java/duke/tasks/Event.java +++ b/src/main/java/duke/tasks/Event.java @@ -25,7 +25,7 @@ public String toSaveData() { public static Event createFromData(String savedData) { Parser parser = new Parser(); String[] parsedSavedData = savedData.split("\\|"); - Event newEvent = new Event(parsedSavedData[2], parser.parseDateTime(parsedSavedData[3])); + Event newEvent = new Event(parsedSavedData[2], parser.parseSaveDateTime(parsedSavedData[3])); if (parsedSavedData[1].equals("1")) { newEvent.markAsDone(); } From 299caf5df03d97f8b45cfb667c6d1df2f788fc39 Mon Sep 17 00:00:00 2001 From: Decaxical Date: Fri, 18 Feb 2022 02:09:00 +0800 Subject: [PATCH 25/50] Added FindCommand Allows users to search for tasks based on content. Added a toString() for TaskList and removed DisplayTaskList() from ListCommand --- src/main/java/duke/commands/FindCommand.java | 28 ++++++++++++++++++++ src/main/java/duke/commands/ListCommand.java | 13 +-------- src/main/java/duke/parser/Parser.java | 2 ++ src/main/java/duke/tasks/Task.java | 4 +++ src/main/java/duke/tasks/TaskList.java | 16 +++++++++++ 5 files changed, 51 insertions(+), 12 deletions(-) create mode 100644 src/main/java/duke/commands/FindCommand.java diff --git a/src/main/java/duke/commands/FindCommand.java b/src/main/java/duke/commands/FindCommand.java new file mode 100644 index 0000000000..b9bad04e09 --- /dev/null +++ b/src/main/java/duke/commands/FindCommand.java @@ -0,0 +1,28 @@ +package duke.commands; + +import duke.tasks.TaskList; + +public class FindCommand extends Command { + + private String searchStr; + + public FindCommand(String searchStr) { + this.searchStr = searchStr; + } + + @Override + public String execute() { + TaskList foundTasks = new TaskList(); + for (int i = 0; i < taskList.size(); i++) { + if (taskList.getTaskContent(i).toLowerCase().contains(searchStr)) { + foundTasks.addTask(taskList.getTask(i)); + } + } + + if (foundTasks.size() == 0) { + return "Apologies, no task matches what you are looking for"; + } + + return String.format("These are the results of my search:\n%s", foundTasks.toString()); + } +} diff --git a/src/main/java/duke/commands/ListCommand.java b/src/main/java/duke/commands/ListCommand.java index c5d1c740bd..5dd31dbe1a 100644 --- a/src/main/java/duke/commands/ListCommand.java +++ b/src/main/java/duke/commands/ListCommand.java @@ -1,20 +1,9 @@ package duke.commands; public class ListCommand extends Command { - private String displayTaskList() { - StringBuilder numberedTaskList = new StringBuilder(); - for (int i = 0; i < taskList.size(); i++) { - numberedTaskList.append(String.format("%d. %s \n", i + 1, taskList.getTask(i))); - } - return numberedTaskList.toString().trim(); - } @Override public String execute() { - if (taskList.size() == 0) { - return "Your current task list is empty"; - } - - return String.format("These are the current tasks in your list:\n%s", displayTaskList()); + return taskList.toString(); } } diff --git a/src/main/java/duke/parser/Parser.java b/src/main/java/duke/parser/Parser.java index 4d3ca3038d..9946b99379 100644 --- a/src/main/java/duke/parser/Parser.java +++ b/src/main/java/duke/parser/Parser.java @@ -40,6 +40,8 @@ public Command parseCommands(String userInput) throws DukeInvalidArgumentExcepti return new UnmarkCommand(parseIndex(parsedUserInput[1])); case "delete": return new DeleteCommand(parseIndex(parsedUserInput[1])); + case "find": + return new FindCommand(parsedUserInput[1].trim()); case "todo": parsedArguments = parseArguments(parsedUserInput); content = parsedArguments[0]; diff --git a/src/main/java/duke/tasks/Task.java b/src/main/java/duke/tasks/Task.java index 5d2f4aadb7..419bc8a92f 100644 --- a/src/main/java/duke/tasks/Task.java +++ b/src/main/java/duke/tasks/Task.java @@ -16,6 +16,10 @@ public void markAsNotDone() { this.markedDone = false; } + public String getContent() { + return content; + } + @Override public String toString() { String markedDoneIndicator = this.markedDone ? "X" : " "; diff --git a/src/main/java/duke/tasks/TaskList.java b/src/main/java/duke/tasks/TaskList.java index c341314a5e..fb615b740e 100644 --- a/src/main/java/duke/tasks/TaskList.java +++ b/src/main/java/duke/tasks/TaskList.java @@ -9,6 +9,10 @@ public TaskList() { this.taskList = new ArrayList<>(); } + public String getTaskContent(int index) { + return taskList.get(index).getContent(); + } + public Task getTask(int index) { return taskList.get(index); } @@ -48,6 +52,18 @@ public String toSaveData() { return dataToWrite.toString(); } + @Override + public String toString() { + if (taskList.size() == 0) { + return "Your current task list is empty"; + } + StringBuilder numberedTaskList = new StringBuilder(); + for (int i = 0; i < taskList.size(); i++) { + numberedTaskList.append(String.format("%d. %s \n", i + 1, taskList.get(i))); + } + return numberedTaskList.toString().trim(); + } + public void displayTaskDelete(Task deletedTask){ System.out.println("As you wish. The following task has been removed"); System.out.println(deletedTask.toString()); From 8c1190418c79bb06239af901c72cf4e6d3dcbaf6 Mon Sep 17 00:00:00 2001 From: Decaxical Date: Fri, 18 Feb 2022 10:22:19 +0800 Subject: [PATCH 26/50] Updated Javadoc Javadoc for Find Command and related changes --- data/duke.txt | 1 + src/main/java/duke/commands/AddCommand.java | 2 +- src/main/java/duke/commands/FindCommand.java | 13 +++++++++++++ src/main/java/duke/parser/Parser.java | 6 ++++++ src/main/java/duke/tasks/TaskList.java | 12 ++++++++++++ 5 files changed, 33 insertions(+), 1 deletion(-) diff --git a/data/duke.txt b/data/duke.txt index 1da4c20263..1c3c6d382e 100644 --- a/data/duke.txt +++ b/data/duke.txt @@ -3,3 +3,4 @@ D|1|do this|2000-01-10 10:50 E|1|something|2022-05-20 12:00 E|1|tp|2020-12-10 14:25 D|0|homework|2020-01-01 10:45 +T|0|more ip diff --git a/src/main/java/duke/commands/AddCommand.java b/src/main/java/duke/commands/AddCommand.java index 198fdc9a6c..8b745cbc8c 100644 --- a/src/main/java/duke/commands/AddCommand.java +++ b/src/main/java/duke/commands/AddCommand.java @@ -17,7 +17,7 @@ public class AddCommand extends Command{ private LocalDateTime datetime; /** - * Constructor for AddCommand + * Constructor for AddCommand. * * @param taskType string representing subclass of Task to add. * @param content description of Task to add. diff --git a/src/main/java/duke/commands/FindCommand.java b/src/main/java/duke/commands/FindCommand.java index b9bad04e09..cf05c748b2 100644 --- a/src/main/java/duke/commands/FindCommand.java +++ b/src/main/java/duke/commands/FindCommand.java @@ -2,14 +2,27 @@ import duke.tasks.TaskList; +/** + * Command that finds a string in Tasks in TaskList. + */ public class FindCommand extends Command { private String searchStr; + /** + * Constructor for FindCommand. + * + * @param searchStr string to be searched in Task content. + */ public FindCommand(String searchStr) { this.searchStr = searchStr; } + /** + * Iterates through each Task in TaskList and searches for given string. + * + * @return List of Task found according to search. + */ @Override public String execute() { TaskList foundTasks = new TaskList(); diff --git a/src/main/java/duke/parser/Parser.java b/src/main/java/duke/parser/Parser.java index a24c185afc..da9bd8954d 100644 --- a/src/main/java/duke/parser/Parser.java +++ b/src/main/java/duke/parser/Parser.java @@ -22,6 +22,12 @@ private LocalDateTime parseDateTime(String datetime) { return LocalDateTime.parse(datetime, datetimePattern); } + /** + * Parses date and time from data in savefile. + * + * @param datetime date and time to be parsed. + * @return LocalDateTime object based on given date time. + */ public LocalDateTime parseSaveDateTime(String datetime) { DateTimeFormatter datetimePattern = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); return LocalDateTime.parse(datetime, datetimePattern); diff --git a/src/main/java/duke/tasks/TaskList.java b/src/main/java/duke/tasks/TaskList.java index a412b20356..ddebd1403c 100644 --- a/src/main/java/duke/tasks/TaskList.java +++ b/src/main/java/duke/tasks/TaskList.java @@ -26,6 +26,12 @@ public Task getTask(int index) { return taskList.get(index); } + /** + * Get content of task at given index. + * + * @param index Index of task to get content. + * @return Content of task at given index. + */ public String getTaskContent(int index) { return taskList.get(index).getContent(); } @@ -95,6 +101,12 @@ public String toSaveData() { return dataToWrite.toString(); } + /** + * Returns string indicating empty TaskList if empty. + * Else return numbered list of task. + * + * @return String representation of TaskList. + */ @Override public String toString() { if (taskList.size() == 0) { From 7812b2595dfe1aeff9c98a716521b79f4e0e9932 Mon Sep 17 00:00:00 2001 From: Decaxical Date: Fri, 18 Feb 2022 11:52:31 +0800 Subject: [PATCH 27/50] Updated gradle Changed mainClassName in build.gradle --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 20c0521cc7..dda938027d 100644 --- a/build.gradle +++ b/build.gradle @@ -29,7 +29,7 @@ test { } application { - mainClassName = "seedu.duke.Duke" + mainClassName = "duke.Duke" } shadowJar { From 1fc28b2ba793ca578d35779a073cdc5e90e1fefc Mon Sep 17 00:00:00 2001 From: Decaxical Date: Sat, 19 Feb 2022 09:54:32 +0800 Subject: [PATCH 28/50] Add GUI prototype use FXML. Added resources and images. --- build.gradle | 14 +++++ data/duke.txt | 3 +- src/main/java/duke/Duke.java | 36 ++++++++++- src/main/java/duke/Launcher.java | 12 ++++ src/main/java/duke/commands/AddCommand.java | 2 +- src/main/java/duke/ui/TextUI.java | 9 +++ src/main/java/duke/ui/gui/DialogBox.java | 65 ++++++++++++++++++++ src/main/java/duke/ui/gui/Main.java | 32 ++++++++++ src/main/java/duke/ui/gui/MainWindow.java | 62 +++++++++++++++++++ src/main/resources/images/DaDuke.png | Bin 0 -> 68352 bytes src/main/resources/images/DaUser.jpg | Bin 0 -> 43623 bytes src/main/resources/view/DialogBox.fxml | 16 +++++ src/main/resources/view/MainWindow.fxml | 19 ++++++ 13 files changed, 267 insertions(+), 3 deletions(-) create mode 100644 src/main/java/duke/Launcher.java create mode 100644 src/main/java/duke/ui/gui/DialogBox.java create mode 100644 src/main/java/duke/ui/gui/Main.java create mode 100644 src/main/java/duke/ui/gui/MainWindow.java create mode 100644 src/main/resources/images/DaDuke.png create mode 100644 src/main/resources/images/DaUser.jpg create mode 100644 src/main/resources/view/DialogBox.fxml create mode 100644 src/main/resources/view/MainWindow.fxml diff --git a/build.gradle b/build.gradle index dda938027d..b813f3e102 100644 --- a/build.gradle +++ b/build.gradle @@ -10,6 +10,20 @@ repositories { } dependencies { + String javaFxVersion = '11' + + implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'win' + implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'mac' + implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'linux' + implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'win' + implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'mac' + implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'linux' + implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'win' + implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'mac' + implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'linux' + implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'win' + implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'mac' + implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'linux' testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.5.0' testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.5.0' } diff --git a/data/duke.txt b/data/duke.txt index 1c3c6d382e..8b8da89ce3 100644 --- a/data/duke.txt +++ b/data/duke.txt @@ -3,4 +3,5 @@ D|1|do this|2000-01-10 10:50 E|1|something|2022-05-20 12:00 E|1|tp|2020-12-10 14:25 D|0|homework|2020-01-01 10:45 -T|0|more ip +T|1|more ip +E|0|basketball|2000-12-10 12:23 diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java index 0f164e4a11..826acf5d9f 100644 --- a/src/main/java/duke/Duke.java +++ b/src/main/java/duke/Duke.java @@ -7,6 +7,20 @@ import duke.storage.Storage; import duke.tasks.*; import duke.ui.TextUI; +import duke.ui.gui.DialogBox; +import javafx.application.Application; +import javafx.scene.Scene; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.ScrollPane; +import javafx.scene.control.TextField; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.AnchorPane; +import javafx.scene.layout.Region; +import javafx.scene.layout.VBox; +import javafx.stage.Stage; + /** @@ -20,6 +34,10 @@ public class Duke { private static TextUI textUI; private static Parser parser; + public Duke() { + initialize(); + } + private static void initialize() { textUI = new TextUI(); storage = new Storage(); @@ -31,10 +49,10 @@ private static void initialize() { System.out.println(e.getMessage()); } Command.defineTaskList(taskList); - textUI.printWelcomeMessage(); } private static void run() { + textUI.printWelcomeMessage(); do { String userInputCommand = textUI.getUserCommand(); try { @@ -50,5 +68,21 @@ private static void run() { public static void main(String[] args) { initialize(); run(); + + } + + /** + * You should have your own function to generate a response to user input. + * Replace this stub with your completed method. + */ + public static String getResponse(String input) { + try { + Command currCommand = parser.parseCommands(input); + String outputToUser = currCommand.execute(); + storage.saveTasklist(taskList); + return outputToUser; + } catch (DukeException e) { + return e.getMessage(); + } } } diff --git a/src/main/java/duke/Launcher.java b/src/main/java/duke/Launcher.java new file mode 100644 index 0000000000..d4b928a05e --- /dev/null +++ b/src/main/java/duke/Launcher.java @@ -0,0 +1,12 @@ +package duke; + +import javafx.application.Application; + +/** + * A launcher class to workaround classpath issues. + */ +public class Launcher { + public static void main(String[] args) { + Application.launch(duke.ui.gui.Main.class, args); + } +} \ No newline at end of file diff --git a/src/main/java/duke/commands/AddCommand.java b/src/main/java/duke/commands/AddCommand.java index 8b745cbc8c..499937115c 100644 --- a/src/main/java/duke/commands/AddCommand.java +++ b/src/main/java/duke/commands/AddCommand.java @@ -50,6 +50,6 @@ public String execute() { } taskList.addTask(newTask); return String.format("This task has been added as requested:\n" + - "%s\n" + " You now have %d item(s) in your list", newTask, taskList.size()); + "%s\n" + "You now have %d item(s) in your list", newTask, taskList.size()); } } \ No newline at end of file diff --git a/src/main/java/duke/ui/TextUI.java b/src/main/java/duke/ui/TextUI.java index 8065ca282d..10ae9bf894 100644 --- a/src/main/java/duke/ui/TextUI.java +++ b/src/main/java/duke/ui/TextUI.java @@ -73,4 +73,13 @@ public void printWelcomeMessage() { out.println("How may I assist you?"); out.print("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n\n"); } + + /** + * Generates the welcome message upon the start of the application. + * + * @return String of welcome message. + */ + public String getWelcomeMessage() { + return "Greetings from Duke. \nHow may I assist you today?"; + } } diff --git a/src/main/java/duke/ui/gui/DialogBox.java b/src/main/java/duke/ui/gui/DialogBox.java new file mode 100644 index 0000000000..dc34731edf --- /dev/null +++ b/src/main/java/duke/ui/gui/DialogBox.java @@ -0,0 +1,65 @@ +package duke.ui.gui; + +import java.io.IOException; +import java.util.Collections; + +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.control.Label; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Region; + +/** + * An example of a custom control using FXML. + * This control represents a dialog box consisting of an ImageView to represent the speaker's face and a label + * containing text from the speaker. + */ +public class DialogBox extends HBox { + @FXML + private Label dialog; + @FXML + private ImageView displayPicture; + + private DialogBox(String text, Image img) { + try { + FXMLLoader fxmlLoader = new FXMLLoader(MainWindow.class.getResource("/view/DialogBox.fxml")); + fxmlLoader.setController(this); + fxmlLoader.setRoot(this); + fxmlLoader.load(); + } catch (IOException e) { + e.printStackTrace(); + } + + dialog.setText(text); + displayPicture.setImage(img); + } + + /** + * Flips the dialog box such that the ImageView is on the left and text on the right. + */ + private void flip() { + ObservableList tmp = FXCollections.observableArrayList(this.getChildren()); + Collections.reverse(tmp); + getChildren().setAll(tmp); + setAlignment(Pos.TOP_LEFT); + } + + public static DialogBox getUserDialog(String text, Image img) { + DialogBox newdb = new DialogBox(text, img); + newdb.setMinHeight(Region.USE_PREF_SIZE); + return newdb; + } + + public static DialogBox getDukeDialog(String text, Image img) { + var db = new DialogBox(text, img); + db.flip(); + db.setMinHeight(Region.USE_PREF_SIZE); + return db; + } +} \ No newline at end of file diff --git a/src/main/java/duke/ui/gui/Main.java b/src/main/java/duke/ui/gui/Main.java new file mode 100644 index 0000000000..a3e86aea25 --- /dev/null +++ b/src/main/java/duke/ui/gui/Main.java @@ -0,0 +1,32 @@ +package duke.ui.gui; + +import java.io.IOException; + +import duke.Duke; +import javafx.application.Application; +import javafx.fxml.FXMLLoader; +import javafx.scene.Scene; +import javafx.scene.layout.AnchorPane; +import javafx.stage.Stage; + +/** + * A GUI for Duke using FXML. + */ +public class Main extends Application { + + private Duke duke = new Duke(); + + @Override + public void start(Stage stage) { + try { + FXMLLoader fxmlLoader = new FXMLLoader(Main.class.getResource("/view/MainWindow.fxml")); + AnchorPane ap = fxmlLoader.load(); + Scene scene = new Scene(ap); + stage.setScene(scene); + fxmlLoader.getController().setDuke(duke); + stage.show(); + } catch (IOException e) { + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/src/main/java/duke/ui/gui/MainWindow.java b/src/main/java/duke/ui/gui/MainWindow.java new file mode 100644 index 0000000000..7e9e40b827 --- /dev/null +++ b/src/main/java/duke/ui/gui/MainWindow.java @@ -0,0 +1,62 @@ +package duke.ui.gui; + +import duke.Duke; +import duke.ui.TextUI; +import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.control.ScrollPane; +import javafx.scene.control.TextField; +import javafx.scene.image.Image; +import javafx.scene.layout.AnchorPane; +import javafx.scene.layout.VBox; + +/** + * Controller for MainWindow. Provides the layout for the other controls. + */ +public class MainWindow extends AnchorPane { + @FXML + private ScrollPane scrollPane; + @FXML + private VBox dialogContainer; + @FXML + private TextField userInput; + @FXML + private Button sendButton; + + private Duke duke; + + private Image userImage = new Image(this.getClass().getResourceAsStream("/images/DaUser.jpg")); + private Image dukeImage = new Image(this.getClass().getResourceAsStream("/images/DaDuke.png")); + + @FXML + public void initialize() { + TextUI tempTextUI = new TextUI(); + scrollPane.vvalueProperty().bind(dialogContainer.heightProperty()); + dialogContainer.getChildren().addAll( + DialogBox.getDukeDialog(tempTextUI.getWelcomeMessage(), dukeImage) + ); + } + + public void setDuke(Duke d) { + duke = d; + } + + /** + * Creates two dialog boxes, one echoing user input and the other containing Duke's reply and then appends them to + * the dialog container. Clears the user input after processing. + */ + @FXML + private void handleUserInput() { + String input = userInput.getText(); + String response = Duke.getResponse(input); + dialogContainer.getChildren().addAll( + DialogBox.getUserDialog(input, userImage), + DialogBox.getDukeDialog(response, dukeImage) + ); + userInput.clear(); + if (input.equals("bye")) { + System.exit(0); + } + } +} + diff --git a/src/main/resources/images/DaDuke.png b/src/main/resources/images/DaDuke.png new file mode 100644 index 0000000000000000000000000000000000000000..e27af8f65130fa07adf04987d4fe5ba308fdeda4 GIT binary patch literal 68352 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�E?^o5i76}yK?ufHEp zd3&;!(wV89ibhZT2sysN7>L&ZIgfS+L259ij5pzlDq^YhY;lD)Zr#GtqWcYkVK0eb zr9{JXvTnH9*6lvEHk)+#AkBrqJI5mr*CembnRhBYr&2mrDl3NwEYm47vYjjQt~+&s z<}V__=l;!h+PWgT{Z2ZpJJUdL83EloA~$AP27L$Z`*9sj~8qh#Ku49}zE@V?C$PF(lK79w86wV34*5rgb3MB1Up zW9;0DDOWw8pmU3j)B3}!Yne!{NJXoY1F0zLpbpJVR87QJs9}sUJgCW7Pej6^VS@l@(8Yv`(hhk>H% zNwUpkM76xv?`MjfRa=P;J423&j3lmn3Jp+(F0VG<*@~a6MwiGk20*zm%31l6fQVr0 zF)sxpF^*!+@~<}Th*38A?9Pd%-m@Hz(b7PTdkQXULOV5De3as2(TIYORM@UQdYP=j zWUYMJZuXERmY|gy16;TB&iMugh6Zkn6e^y7Xat7odP+IL7K(E$)6KKdjA7sfe1hm z@HkyzKm^2A1&-%kuc}ZD>e44XY=$>2=uYywsbe^I;S_EL^llfjzUfN4GK!`s-pDHB zad!W~27#;zmgJP>ejv~Ub`F-1>Q}iZy>u)+AY5i?4pHO5KY*kbo!6x9&7IExUN$m# zUXei{ShSLU`Q5__ai=6au|fF$QR^C9nlIaZK*zs6&}M4E2DuM-w0{|C!h-d3HaWzh zaX6oA9uyfk64xP{^TDR8Fdid+ooe}6!(H-ASkXI^6|A#MiHy=*j2uH&WOrLw$;(q`MLe);cq6H^Tr6Fx+@K*983drmv~ zCbO{?&dEP^iY&iX2E{VIHYYq$ZK8rOW5EM{Wp>{l2&6#%gihZ`XOl585Rr&S1-zLv zjE%=C9L+P^t=DczkN#SmaR{{0jgwr;c_Or-Y}%jW+WcXzI=XTDV&F)2h#_`nucZiY zbI^QaplM}r_r6YC9RSq z2mS_cSMRMvY@M2~iN5gyZbT@LTxmC8rvG7yrNJN&J!3}ids-PJmR^`1SxcQKmM-Dv zEsARE{JIHiSHYSUABK5XC0nab$jg{(3=JTBIF&-MR2*uuD zMzZ2|43LiREUW9Rn#xD>-p0>*5^=l=c;DGVG=Q_w0e303;A4>=(NC#}&Y+uttStcbf`h&A;2BXoxB zM+9%^CAT(lH$bZYl-b4OO{-wz*%BZ}`U2aq^jeC9?pB^S2U|Hht?1w8OeDmGJy6@| zBg4l^Cs=rndqGBzF*8w;zX_jAUhpH&}0pjnJAkZXU3r#NEN*(RmVc) zErbj+-{I_aplN^kU|Ulx50MJG9ijAmXwC8DqL1m!v39;A%;af7e^Zm$Hespm(+ z-GpL(xcjyQTqnw;R3_3PsYX(2n?as3ObGEborgn1wQ*P>tX*qdMs#j=j$rIQ=&|}pD)AJ?jK4Aua|MS1 z1wniV#05i#v=)hlWY0M`0diLgX#mBZyl6v3+^fk`w?>koiG9qPQJOCb^VVd5bdOj& zp%HsVHie$&wwGj=z;!Yxr33JJ0|5AWa*kb6*FD;JWu0W@6CD==3>USwrT+cK{h*jA z_`tLR)4WT-NMZzSjt5zct@A9M)-d0Y6?3;P#4-vE9p(RwXvgd;fZsQ zog_fhhV~gB?jd!Pn=y-&PASwCPfjBcj zWKHp3*e>4_;pSt14LkqK#(brmL2>44te+rS8NalW#Vmd4zdYKq{i-d7Fc_%cvfC&V zv$0fdvB9qIJpN?IYAU6!Gr^3I?2rv|8Z|BJ<44oS4a*2U!S* zM4lZ-j~+;UlK9-B-Bo8G1_Cmlixq-qOZx%^vBW3sYOIf&H0`6f(LY3ne0krmwmNdj z=YPiSp!y+wk@X=Vs#l@Xbn(y`vrsY8cAi+4nil60!i$PvS-U2}ke=@$iQBkaUjG`9 zyaYbWki*9}OLJ$n1RpK*ZAUVPnGSqne>_Bb$i0Bq(i4+hkNJ{qO_f4bdu9Q_3rk#T zCSy#lP_hC|&5hYTu{Z~$UWCM6COd38--qmwx7^HiqV(_tyvo)u4himz-*gS}J)RMBu=C_zjp>0$=wc757G(@5WtwmTgQF|P* z7nM0qFUdIlLV{JuU7W}XL1*OkcJ16j3hvZ54L_rC_d?694q88wxIgUUiT@;6!0OBNiya$D3h4ik{hp4kedt61D4V89x z#ld>$-c_Am>Jz*Z3m-8BA0vD~_uTscYI92ZIh;Rh)am%tB$hXtoQm^$B$*2bBP?rB z4HLNsOAJ3Ln9@=)z~Dm)2R(bB=63SJ>5(}P4Kats8sf(Xfxq8BPzaaQ)ca(;rKJD9 zVLiFNN)T<+xzqggW=*6D+7=lnF|*pL`$@lWZ6f3GgD$UpRaQ<7RH9RphkBtzYpr4N zw!j zDG~UI-4BJx7A%ZlC1DHp5y?LIrj1N*cr4kup69I2FQG24kNeSf^SrLtSui<7?5R9b zo-Kw@(qa1ke*v0fr#$*DI|944T#7ADn5ssA0yCMUqADmO8E#nb4lEi71DjZkJXY%$ z(8+#%OcRz8cU>sjf8nOhO~(>ypn+ZEx?j&>Qdb!sC#exSOJib8`9fU-g;27a@WsW& zjuP_#J^C++@+=u%`Vu#GRc$s(J4y0r45jw8dr=uTgbX8fY6i&4ei&Vx6=AR(M3HFg zy~3T2s_7E?@phoqldBG$R&^e?=Q1#kIM+};`{C5ATmQoAuTy_R*jBNtsM$fdOxYzH zv^X&y6^l(k2v~>lkCWE^31S#_&|_h24(^5$UrKRAPREF_sL10Y)FV(2g~>|>4%J#l z%c@BiowHwzNT&yqVP6#opZ#8h?eC+-x4;q7o>#1S`=y_MbZI|?e0r$| z*5b#%)6MTS0GyN!Ef!352G53x4AM+Kdia1HyNLBa6=%2r-d8i>Eq^pQap&*%=#$S)u z4$K%cWAW9WT!py=R+b7oPMSVuKN!xF3gY`_dlzm-6Q>KOZ=wG**}VM9Wv(_=*c9#v zkxyf2f7ZsX)-p2NNvp#8)$MH)V3C4kmql(eSeC%SN@iC$0TP?H}$o z1gdF8$men~w#N!AX=gXF_sh*_@~lq7VrTPVsY)H#ckv%*<`1=g>y7th$-E8A4V5Yt zX2gWX+%Eu>;eY-R`v>B%Ht%3WM}6ad*aoEAvWVGH-*oV0&PzRum-HzASyrrsCzGU> z)jJ|1rH1e5z*6mhY!1W^AJHfFx^3@tw+SFkagHF=TspH%YqYXC46@FyrEW?s#k8o( z+`as8a_^OO8mPq!lKLI|n{QE*REpv|H(DcrswpoSS~sLg3r5CV&j<2==`p{yzSyBt z`vm{1Nk>;Qk3z@Hg*DHm*G{IPQpx2IVL98ieO2=;x7ppIxKzf4QG2yq57^J!o}Kh} zc*82ja0~j-Wi^@+sz;lLWc%V^Aq45|u`R9`MpU^sU9XVYRWAkxuRLlNq2w5W(hDAz zUXOc)y0jMo0s^{!YR&(bM|(Y~)?0WA2h4+f1ib|cnacXxq$9Cj=jxRwZDAX0zpnEB z@hJAR*M5hbUN1e-P(b#O49tn*0HQim0vm1r8=@JjVt2=lh8ieuEHD~`J?gZVJ;!3Q z6QXOJ9?ltx0A9C=+Ey28VLyH)e0Rhb8bdEh5&H3@{$I8)H0RECE$5Tb59$_=1pVlI zd1&9%)z8r!H{`Toz<$fB$!2>YphiGGWh)znPPW&x@s+&Q4`bj*5);NbE%Tlc$RD}9^P zP@2BWTUmpHb;BT8r^x0O&R@i%AW6r@x;mEPg4rP>&hn00lb?0#2}zj^j?>&;E_!`d z1-`G|Q_+tv8tTb2_SWiX-Rtv1DfW;5a+0> z<8focc(e+E8nQ$5SO^3|W|wI>FNZ0~X+mj6u`uEL43g6HKRrfbug3-!|NByKyUKS5 zBRk)ni`;QyCR@2G!5l-M5x=X}xG@?=l=V`U za$HIFCb6|6Cpx^yY3V7c2x_-%6XEZ_;IePbc(XlEeGa7*BXJioqwUzI)MyP$eI|~xN{(gJCzz0Q#`-?e92wHCk4EP!WgL z@{90bz`J@O4PIz}nYecLg=&u^)f2SDTWS>bIV}IJR~8G93HdFzmLUkB`J>}*;-464 z+pZlgMqU|GmhmsSHHAP7&VCL_RUsBzLkDGo_XewDKndA%aIvK9A-sQ-nUFP$xriQJ zt6zp8K5J2zTTF?~vFUALHlqaS&>mD5WIdZs9QqSs@1EUGlyc;2FnkIx374u__Rjox z=V2XP(;{eeV=m>C*Wo@leH25rDs4<>g+zgS;FbO%@MkC4Fxb%A&SLrEVm51tXOYj* zJMXAr;51&4>iux{m&&|L)5r1ACT$W;yHoe_rbjKuQIV6-yUm}C zOWYx6L+KzC3kvQllE$TEE()YOWN1_;nvo>kMjQt}rVIp2_EVs-7e?;dp|<#M&j8YK z`)zB3s`7s`!}S!H#mzpRDpn^EDQUIi(|Ucv=G!#>+b^6ja*G|bAymNA{2C)O?-V8s z?l8HDRt}Ae&kjhMxKwQiICEi?>S1vs+E-Z2tT2GM{K#r#tyc8w?5dvxe%*q{lw2ZD zhwASXZgF4qK~tALtpV7`yFQ2sDXNdL@YeYR##gM^cd@~UV(wduPmzu?ZMHz%K#niq zv%{X(jo(~5(@f3X?5StS7uv@4kjm2Y+oIE!AAI=Yei=;ctk?*cObWUBel`nq-Uew( z2Hw&}m5dH`=IWIye>Le=*RDWsVe~>>)qWDiza9EK(c^d`$_Yfo?cYg5I2b!|x@?k~ zyIl^0UT9%W)gB(jo=m`)gEtz^EjqrS-Q(Ps3un$|4d zPQ6wx-#r{dQOi89MvPM=SyxBr_3d!{Pfd5wJ8+6f$Pc*v>Esv6^k>nCrCaRk*8KT3 zsAhihxlPL|NYK6Y?|5zAA0>}e@`)cDL+X)^fH4^G1r(zSJcC_ky4)MecBD@iEjeFN zo_|F%d79xY-2KVck9&F6dyI@qifdQY#R^wEDNMUy}!6`FrZu!5M zf4qEb98cba+$pxd>Cla*uQr|tCXL}A!< z+q4-FtJFY++r_7`LT$feseL86UiY+ZclzbOyb5kGp+>tDL|`2=V~~v9E>cYAA7!|w z*}nBreBe*I6n;@ZoP;A#biF|EudbG*{P^|~W5O&D#NEo21*FoN7>-)!w63@*yhR-! z3MHW$xbb@Hq(t03X22U1_*dW1uv(oA)8v(h!}W4who{RZ+@LjhzkHBVii%1u@*q52 zK6!E)-1sgY$U~@y6r5gv?|5)7M0|rrpUBM=(MIz22J$Z|T+rJjmc3hCeG1(c-HT*}}K(hdqtMbWTPC)~n58Aq!|KyO8} zERL;G&t_+VY|m}ziM6paRL+P2Mm_tEc=c(}rdP#xl4VH8c9cMB32QoCK?Q59cpZn8 zol;*3&R6|Kl^^Wy!+kUl{}MAEw9oz_Pw^&VpiKlYfDYWU?VB1&JS0s4hMSYFM8$+3 zFYc;5u(pIm%mvEh90k_;Uq?=>s$1kx?qb{wSLo`$Tt1FlO;0DJ)2-6)(lArnu9Nu# zW`09M)Ti`{P}PG}$6?!sYoN`TCRvAIcND=^WotF6F2zr2Rg8oQ19IP<40QX$eq0*n zTvYu6d(G@Sj;GySf`At%%ind{VlcpWQz8#>**k`{(^ z8=mi(B-fiJM>Ld{tP*sNjb;}}F}XRjp_{Zka;tnS>C#8~+fi{c1xS7&TtCCuO65A$j%P%ii5E`U9?wnF9{7j`6TW#_+S8#0xtWGC# zrDH4OkStSawnELwILQNLQEM)Ud3vNij#3-2jEXR;oT)PcM$y1pT?*}hZr|#T+)2xr z!q<4tu;{AajAYJ>Fgo08DH^OP8nz%npVV3it6p^0MoL&MGtdq_3;PGupHlIaG?5uH zx)|-?h7kb;7h6l_L!nInvQIQ!`rKeiZ(xi8w2j65RhqEJGmt4wux53*>#;Rw{-b@yjR}dmfFYKwda+7uhK1y ztc=X{n8mfi-D1`nbBF-)*kwZMhtT&XrQ8PGMnDRZWRSd2#-#qyBM3 zT@$q&7`+AQVsjm1%ROHZ9;Uu3V5y6woq5;PGP!u!duS{#^G8gXRuo%;9wvs~H&?Ph zF*&y=E}Ruib5>V`F}H9ftxlFpdhvK|ZhjHlxKf&A=lmQq78;eiZ{c}oCnrT?S_iSC z$isr0%8`xNYI7LWpW?Lb!%j8?(FDjTu1!e z3{)&v;)?ldUS$Y*=1lDUiqZ2*ROr|ecI zn**1qdTk{Ab6?r0yQlrzj(p4M1Aw-7M7kUn1@;o{EmGdVB{HMsKz}zebw>9tycI_W zH_@eymb489T~QA`pyZOb3#UQre_yb0*pYcnJI)sHv>@x2o6@i$3aALD=~oH;=)Kl`nASERz2 z@1h1r+kM(`ELpbTF8CY0E?z+L1`E4ZJvceJ9=ROyPTokpkC;_%shM2K4x~}m44k;? z!RVL%$JxE+$Xez{xlI;5obVLUF&U>UWvctk&rxP3WD#STgz9-*9~iie)DG?v?512g z3>~1dvf}WJK&GXDkh>oR3H(nK*OZauu@RG^7ef%ade{hE-#hNmn!t}5s$VhHWYH6d zr7U?3WE>xaKxjn$)s9^SDy!AbB8DkijwvhLzjIlCXX(j!)B+%@&cNBeT74bH-~cpy z_0+!Gey&of{wBkG1@9-wT9^8NT@R3mo%_If_d~shv|I)>cmwYPi!N8bA%PAV!YPH6D!EgeSIo>ng{A$17- z6p37X^z+}91-qraHnHyfNvHp0GcX7>^Y){>lNzGMFl4~BTnVl9ijLYp&<~{O zbo5Rg*yn)PhxvHDdN@dj1<$Zn3}r`WCx*+Y_AN5SeUB7os{mTqq?Pc&79vTq`VuLa z*bR|Oz=oyM%L!QXO=^uQ;Lp(pKynCSH-#mkq07Ke5jqgT8uEJIwQl+==tdkc_7uhL;R_nA__KvZYKeQrz_ABV6MSlTKP6wL4o z?&*^6uL4^@Z*VLFTxtWET1i)y3xe!}bQrf1KWxD)jcJ5~SYPCQfDn*Bh$R*<)PM(B z3>0?R9#`d2!0x*OH?9f+wkFiOKxKa+8*%-SQt5-wffiu=;5YL>+1C2=dSGHFK_dXrTk*@!=gy$a4FS{y_ zN#TC;>!JHgXF!0S`3vSg?96x3m=vNK&ur-#>M~LVDUh`uEhpl!QtU}(XD6!GciKNjefx1N)Rr+IV zV01h}CVFl;qkNaW$x03z3u74fVeD0=wdgkTARu4Z%zf`*{ZEVBI4P&Ph|DHJr?3?V zlFr$Jju;Dz-Q;L@okd*EwgOYWTh@(m*KBWqtL(>~l7bf^$- zW$MjVNREuP;_xiGp7nBam@k2W}VS}naeYop3y+&F9^YNpq=f4O_4 z261*Nu9M)4O<@~B;{i}uM`$k}rH7sqzj~X?{!}_j208-BGBIl2pZXB31*bio52kyn z%T0*hNR3=JA91NhrAuzr=(Rn(&Yn**>!BuS-$k+N8L5G!tZ$;A{l{9;sI)-fdG(S3 z0+<&hDn?Zl_a4jcR58~>K?x?)IIM6XJRqXh zqttW&S(njTv)iJurZ-;`BTliPdVY=+YsG4H9^4=7<@Xm{I>@9@kbh4z(xxHi#!rM% zI^kby%pO{@dkUObagot|IF&-%D^jaK^0UsPBP*wm8=6 z0i1-jlt9j>@f_w_FeIYZzI^b*$Rz*yY{y+i)Vg?r0haT42i6v|xFdvBg!#wPa5AgZ z0ZRxhfy~GGD8aRWPw~6;uKfbF3&wLW?ynaf(t$j)A@=?c0xXmMa$*5!gr8#;vB@!9 z{dNb$N=|0kB0R`GvxL5tvyCCi77?aP(2F`~+AeDB;dB#h@rP%L0X-V#Qo5A=Tn!vq z@OFS1(UI&ct12XE4MM*8ML6T8j~jcc$Q|V}zG`zxQtUy*6NFDF9(UM_cydbXMsZVg zN#F(FlhONY4YuN72jS&;AzIw9B;kTGQr}ORnhx0{LeVY=H4S7}9FP+F6EJN7k6pnm z*aBdprj*$EA|9j0gHyb&rhneUg(T(I9<6ue63U^(nPwUpGABI&oN;G%fHJxZ?f2Zd zSp#S++{qT*Fk_>ooyXG+cuZP`>&eZbcA9SV#x6a1IBG6yBD>yx7EnRUY}RId)#Gz7 zqF>6B@N8>-vs0=o2Ko378rNVv`m&*SQt4hi3u@7gXZYXMN_c6!a@#?HE3_4np)Fdp zLD85&rU2l@j05gGf*&{ii>2H6k~9qwS}>j_p=yWfPhag4JH@p0g;(l@8xdPf2IPHr}8W|M_xhTwOyrk{$Qocl%$Lm^GM`yS?7e00l zGrgl#u^d>fb>slw!;M`7h!R(xEX6-X*vX1>LMP^|I*d#>*_Oo`$9q4|K(r{ms#*cz zB5I0WlerG{Ua6zJLF#6c;>S>$7iWI;y6K;Tnu5fXco@^l8tCj9f0i_M9h-;>9-f|9 zN+$_z{`LABk1=@9R?HA|=yLxspR7t$&#-OMEtwGQKzq}I0E)&1Lk1Lxr0PZ3ho-aG z`+B%piKGJ6_y!>Anl7<5HdE~azG(<6ak`n2!m za-UqV@{UIKB_2B&U`f+J*Y+0U;e6TP2tWvJtf4X&X1xI~kF?cHJJxisCpE{TVT!c9 zPa@Z%;k0xxUJ^mmMKvcy1_%Ty9rTV6bhP4;8BbO%mHo=F-H6g;IYSblq4+-lOF*>0 zVqETR6|mp~0vd}>u*;;O%Nar!t9K}}kSKgs`9VM0O!yr~|FUEA;Og}GKcCu_q=Erq zDqTo&s3L%+(~!nV7Rw8RDW((zRmG$n_otvZBiihAn0$;U(;;$LDTM0DVgKQTvSU+4 zJSr@VSy5o}YXe;2IDe(L+}~SxG%O|63^4+W1!&$-6;|Up zUiva*zd_)P{-xsmW?#t31k=cGuiv&BqEuwKAyU1E0@`wzDINGw4!)spcumr?!PHmY z8koG*sB$ECr0?E(Q63>+JqTb$@ruHEvB07n#olD0aO~XqR!n5U%obz28KHSD29tRn z+{Kj;7;{CJN6-!Q!vw7M&4jBx{gnICm(xW+DWp{|q)p0?hQX`zU>V7 zF5L~?aoG$EQOz)2y2#j%Wv{T_)A`}opTDc-v&~l7Aw%uJP(36KB1hlXi&-1I8(vfU zgTZ{e#8qU&LJ5Z4z4h+5*?AOM4{G)L>atSlC=}Ak!k&}+PXGV;2D!_r2^(8sTWji6 zmE<^UaPlCCQ7&{*^XeG}*6z)PD~eWy-f~fhh?k)fP!y7?#eM?YqsQmAozVuvjL9iFr2E0kH0eE!ui6{qyBG{eJ#Bky_q3_6D8qAT6#%E*?u$Tks7`lB}h z03ZNKL_t(CM#w)f7-9&vl1NRp%yY>w#0yffQAwMcG{z{#-W)>6L)2gkTX*<&Iu@Lu=GlYm89l!5K4AAO9A5j z1x(L&#v5^!?lCJ4;KKxO6Jt6-7jgNdJQ=5uT}5TA9rKdyJr9#e2?`$6qZ=<7hr_7t z+4f}KZ|N8f>EgZbsx>DPNObxq<3r3G1Ql2rE!~~w8h7W%^bMcsCW&~(C?(Zhg^@5b zIPr{mLuNw-7NEtWVR@i+d9--%zIo*@e?9j63DP5{-abAosgTzlfI@b_EeipY&59Rx zQi((qA1x~pI&`#S^rJ5^UiGA7-MT@8`+nqR%%7SjX6*oy4_fE08`0 z=to0-1+6>!YTOqor*i-<)OGaq`)4`=S4Up`(>t#X6uRXa$tj0kys)+Gqjh*M{pw>9 z!OAKpv*oB~#-GDL7AdVb_nU-C+F4dUZ*h4*G!eIrcSFmz@7|N;l4D9NLrv~*0inpi z#Hps~i)s8QM;?hB#5#QMjP%sh`5Y%S{7w>Zg?P1hNV-*K8DQy~;HnQ69Ju%T>AT*0 z^GbVw#S$w7X@jX;QO}~3VgVAhJWQ&Bl#cR(TXskyR;K`qI~JwB(sDsiHPDAP#Q>e1 zds(_mu@x&*M#d9Kn84z?9Hu_o#-3F+tHKHp9PUEakE*j6v#Kd4*#8DETAT>zv-Wz?T>Eqsz|vHBsZ57rF10~TnpRx3 z2Uv%7_B<)xkG_4XBiM#Bzy9Md)7{uCl~vaz zT(w^A#M9+JX_lwin@MQclNKjYIRlMRBq|rAW4``G9;6+ov$c0FY65lBSj0AM>2hAIv-(A5AuH?sOh-59_GR2A6?{Skvk#+gY z|Ni|Zi+71vIN@;f2rdtfHswq00@mwl`ie2a=vD0fP~zRj(q#E{NLi((K8dJQV78>h zt}grddvA2ak?_smzw%m7&p>xftq5@kYE3Gi4K$783bCbO3O1sK6~zQt9Euq_B*zoB zmzVm{P9!+)7EP$$FG}OJ=Ay!n7w*Cz z&t9-Y37Eaom>SX~p1!4A_mC8o|G_78b(riNHP)FAfBOOWt8A08YWj#HD}t@*hkw2R z3vM8m_5q`8I+LZtO9M|DR}TSN++v_abLFHCQ~28m7jLYNlyu}v!&N2KLRo9D9>4Hf zO?^UkDV5a?Eyy|y7IVb|>#T(ZMOL-0fc5qC@{Xtu{PxzL-;oN7wJ2hh+=LR`vj|?SwX6lc$hmI7YXjDNLc$%|jyUM}S#!PDQ4Nw4NxJy&XMe79Aq zo)gP*v(c58dq0IP*8 z0;??b70FO~%qq4Ft`M@?0jxKFLpNbquSn5hQP5{ogq*OsbjDJHJBuU3Qlf;qx{jah zgckH+ZkFol>D4Viz*AvB(juy=Y#$d7%UAp58xpZ>f2m2>7(p6=kOIyNtH%sdq<(_e z?ekc=^knhg>Wl!Zo=NR1lyRDbRwP&2eCU3=3@2shLMpPuFT`IZ5Ro)ks;+Y>hw^fHJ>Jkp7Y^YP+d4>)2xJhJvhOwJ(1^L)tBe!_t z?m{UQ2|7YLPHG=rg8*y!w(CA_jF(b5xUNTd7F7G>ine1UWL0XT+beVK`gpEI!tcjt z39vqzbMJ3nkY|gib71O%{NUn9OP@76GqJU~x-xfbeRePFfQa?4UQ;6UYcDnCyqNHUvB-(YTL*%1x{qCLDy1^ay_4A@-xnUTa zhx^hb|FU`wQM~K0Ej88&OI7XRFlSbQAnoE<+Q+hJ^@n(7S~?~hEHiR5bM@4NHv#+@16Rv}*^sY!<+!5M}tDy6~36L)Uq>}D-MXYE&KjSPPB#9eVe zUz@^8m55UZp&{{VB%sfl*t)iMTYluj#@1d69>6Ma%XfcM+gHez(Ko!(wi?Tv2@jE# z_HStg7>g|ru4}57!51Wmg`%OOr{C`c`RL2Pc%`Si;IlHyCYxQuXDjdE5^e*MVW{~E}O@bCu_$r#2nW?SO#_9?l^W@8&?HvM3QsGz1@MW7@wg$@oyyT0OKf82g>A3?7;?b_I z{IJ;}gIcRNDmM__dqnyU`jvNZchP~^5^O<+4-5)kePOExO?JdepEnn9nYiNGR zy|vnyE|m-;n&P|sRV$5e-ns6&^F#CQcC~V#rgXelz$&DBVp_Tv1_sPN#h9LY`gBhjOI6SfeoaN( zc-+f`6wgJgI$s}7=53pLSxc9LwVKfEKtJ9@2RajA-ZRaPq2GaabVX97y6Vmi32xkt z`)kYNC0z|&snlxnX=%3c^y_&9n4!6i&D!_P8xmJzr5VYr`fRJ~*DlC2)X$TN2Y0&l z<@)Nwv+{ijk)J=>8r|cqd~JG5faR|Xic(yXy4h|%rhKv6O- z86K~Q^0Op5)ba`eHZ0j;r70gKuU`KLhwIOsYf2j&HSTkE5LgwTVp4IIUdmqogYcr`Tfdx=8aHS;=E>S|GF-!hD_f+^M0#=t5vPmUC^Tw&W zxZcmUzuui}4^NAEbf8anhJ%sTSOk-)NPCGRO@&yB*Q=eLLTm}_uZ;$k%>yB9W#G3O z)d4V8mzZ(merQk-q#cHh2dSpQ8~3T139g^m<2st5cobvO<4+}I{hzrjYHj1pqJdyX zRtlSLb}4MbwrR8UB?JmdHZOrb>|6fNWULuaXC%g!A|?(NGDg@C64cFBGcqI&ii8F9}$`#C4e8td$#ctzdOHKz0STb|0&&sYmOZ$Gckr zUnWX_*n2+H?KE)z)_7wbsZe$S__5YpF}yz_>mef6Z+ZxKN? z+RS<(>Pf_`tW(4j#~0B;4jrsX@hcSC%s>CpnpqUCsAsH~5{=UM8Qb!z%KH0%kqiU; zizCvg$fX{`!3~5L0zrLYc>89f{L7oHw{K9*5^B$5lm$6sP*R* zXCd2gu|E`ykO~I}M>M&88eIp*sFLup#-w&f;|4XB&yY--jHN;{wkS}{Q#=6rkxnu6 zL-{hJx2nBn-7oLP)&UAw_ZGV?O%B_#hlBjyZXo~Q5}%gkf#<^-BEd@xwPj`~F>9ea z8;+~PLPi}k@2F&`z6&42?W+N_{1NJ7dG*!I?Y6Lk%%c^qRJ>!vDvfbaSSaZ{h~;Po zEOZ@~e%n)EUA}+~=mB<~eOoVU($0?(kv1HST%qgwIHZS8Q5E{BGgtb9mJDE}(<5T} zDs2Z69O5w{F-BHtGjvH!#t<4UEvF)TURhDk0hSn?ZHjx0(;BTmKmG6vLxg`~->LwNHgjgT!EwJE{e5^7s>Bt$|74j&bq5M$Ad$n3| zsut;_Hd_(Jl-n;Q7E@t?Hg`Pl5Jsc)g%y(Dv}_m_2&{_ba0nTC8?cBP&SYEBRC%2IP8&^0US_Ga}dL zl^gRSnC1)awdY^?Fm-$|@;hJl#`Zz59nx zPTB)0IctM}1tBspNby2dnmd&1q-ukzu~bE`&V+rlQmBAc8cZ`XCz3>$;&L<|&N$une zHk5Df?4k(LxvCATK#(xANUri>yF0{{rp&9WHO9BUlZz3l`qTWj`s%@4r!W`oGMYF*)NU`BHqN^*}JRzt1`gGhZRrj;$!#aROna~&UQB+qbx_rKMvPk|}DF$S9 zB%~4MU1OwkRY$B%10=6gcv~|?BeS^!l1#0!_dgy1lR-=V80>COG~nl}U4382Rz`ib zsR64X))?RULE&_{JMyWk4exHx%pK6rQn-rpcQPgwB8o2oNr+hLzfD4{sc!g&H0Ov`ShPt^{#=ujHLx;CiR6waUKigF zLLG~@w_gkg8dk%m8VZ7~{k@wF8n5OtQSMNaG{{;&yowcNGMiqlaqsDFpktu99u-D(v<`~iu{f6pE zQS8oWkjcSl*76^@(je93h7Mrmqb}|3 zS8JOYeKc(E8!qJUB=xp3pyQ0M@BRE``)Yw)t+jJ&>YxJdoc0~}q{dRmo6=f+rQ^|* zb+Ey7FC*3ol?YQsR9IMt3dIpw+sTo9mF4~B9*a-rB^bP5HuTL7v;a%SU)-P2Tn6a{ zUYFjxETw?x2U9{Tc2_0uO6FFUert(xg-h#R2h^HJRgQGn$TATt%15zjT!+(%aAInn z*{x@eQ*db9nR)i|@$S|tP%ymp-HZJvdmD?icgh&pyhf*VAro`yJ?a#BQTdCBiTU;K zw_D$KT)-3GI2x7VcF77u_zcxH)xxCN^E4gR@D^m31C4vPbzqQ5KIUqOM#V-+U5b+ z0W9Yi7sv1IJ$v%9)oT5;z4P_N&BX?K^fV{Y?t=KPjtYJulS%GqP>^e5f)k#N+h6Z& z|J2&wZ~eTzvp4g6qgy`<(3+!vAqu^W0BidC8a8!UU)6OQtSelV3fI%>uJsC7Cw}+Y znUmKhXA!V$r)mkGlFc421-nLdMMj2b_o!QLiGI z;|CUaP>W|e81r3PG-XPNB$Su)j8~**O>A&OY+{WLS_4ofLr8 zKbepbE1hoh8OEqcAp8(bm@x-K&}LjxVcGgEO0*Jwtb&qnX|4?Q-X$&iG-;Av!_}*C z@$MzP>Dv`mELl`*%gYdLn;xxENSDczIg>}rGm~gfcv`i)9kUEszP;!gmFK@mt{cuJ z9|v?wrxvtLwY0zhthJ>jqACU!aW#5nxByW!wcAp=zO zTD5loCBw&^LlogVl-cr0y}mrN>HM#7p_6zO|LAgKFtOO6VdWf=Yo}7#)X9%O>>o2ZGlb6R z^f#?1gWMy}$(fMNi0P4fD1SlA){8o>R=2g{-%(u3sS!;HG*c;Klvr1lRH&_&yPUpi z@=KynVkx@IWXJQ8d{ZxBMyF>*23NY>iW=XGYUTMi(pFaJ0>kme-yskV9U6nx#8fD(D%yqHS^svEG+aI9IWT0PWO?f ztu#m>J6b5930jI9S7>34YW^R$3)dc6JltY>z`v6Nodzz4i0wEC9TmN;s^WD82jPmV zX*06^rAIm$q4Eh7_^A(wJm>*ewHoqcO+%+fY-sCV5J|rF1mr!d_j(ZgJztQwt7w_tOFQ2;j z@o9DV0j@xM^Ig}sO)cw?De6-@n00)mf^l>u>pGQe%FXss6U$JOWr5=Q81r92do7H~ zz_nD$O&3aEtu?FmEP&;M3u}qpCv_vKxGG$~Eap3*dIL$V#Xz|7WHcmDI*F-#vSJ+rBi;NK{4lz)u^F7)5q+p}m|EKEK4kr9i)T3K0I0k(3u zNd+|BRXI_5J75hB9XbB~g^OoS+Q*#9Foo@Thq@T7KX99!ih7?~l>V^HY}%rOfa9xT zf3lxScby6gCPayfE$F0$LZM`Mq`9@`!^ubfBuDE-?5u_yS?R?iyQt-{oY0l9&4!C5 zR0q1)lbYNv-n}RxV;dRE0OLgQf99^{wT=7?*9b+Ek2cBLCCvwpo$TU^n1RpTU**w zk3IH%p7-|~jbz77b}yRvOVQYg#_znJ&-*+!x}}y1q?hSq4y~$}1=C(`1HYM-K_43urKfdahYiqiXDTg@y@0DZ8H=dfA zTbwP_eJ3bU>Wk1MUgH3l7|2}kf1uZsaO{uhu;nM*1anHI3rjOcC(2_TIfOKw7ibL# z8GKc4uvuCbQyV-JtLl0|3-%PaoTQTvD{3dYNWpM9qUQw=;4}G6di0}IO`D;JBI$yx@M5$}CbL|kiR*`{ss!D!Ey1|Kn0Sy7iFFJ*b zbMH-#!!pq18Zs=T?uLGpX2yC4X4OrixNBde7x=^>v%#P;vSMwK3N$M9IQuWE1RBt= zzO)3SIdsE5w46M z4K|V`b2#+fVKeeQM~{hFEzC|QVpjmUgJCq`@S;w&+5iJ+yXzGIv&4n-2s&AQ5^YD0 z<6f8?)qpI=Is$}@Tp*;Om5kY4tZne}dAA!yE!7u~v9OB4GJ$-t4{|x+8v?F9ljau1 zpzSsgxD`VP^GmCvGh$d_ZX}o=O54_ZnvU}qsRYVcvmwl{Bkr}=UCEK&hD~w<_29A{ zi7)Tct~NJ6|5}rG>$CbcPf+-F2Vz4othbeg#`!1So1s}1>Yn3BB!niP_Zz*d7$i$-ckFY+;+|HDsma!{C*8~1sG3ft zJ>8&Yw$>xb2SuH-vsBiSad5Xeg8X}YpxQ6&D($8EBdW{t574fRVP&Ckurh=iv3{0x zqVvwL&wmG>aq9Txxuu2K`9i(B<@j}n1m`~a>%geS{ToVQ0VXO3gdjlzBKNpFXv?3# zbL#a88WWBTp~*jng%+Pjt8*XLVRYugkoG!zz zFpz#QOy2RKOioQ5rebO@meuI|^q0RncmC|jV<(Qjq31Yy;_S@jYqu8Py)f-0Ny&F2 z2e~;pYL&B=cP=7e5*W!7Wba~10K##{j#?BYaaix4og{~)RUy-aH3@|^&8>iFd-mMj z_T#a4| zKR$9~?Z@w2y>#>axijZxXkI4{a$hHo9Xok;=7YJV#jE11#H`#RMEj6XMeTq)o4_@I zZl%ppPBd&r2f82Zw!OO4Ome3?ZZbbv8J1$+*&1Cj>>m~49Qu;7`)*5F8o+MplZS$m zo>*)1yjY?=n0l4}(xqDia|O~cf`ok4Xsk2GTK&|FbaY|WaLwehp>)`$vQxrdn*D~u zOvT9xXNDv4O-B2$7v`i?dP+6=hMKG!>aTjXpwwPP*nD9|hb9#Ek-HDTyC%m9Rs(eL zL@wE(wYC2A{FT|+tCyCRZl1X;$IS7Qr}jHeo28V-68#zuQ8P;SuEIWioqfhyH zzyURQ9`6NNi;3J4zH}_KC+lOeLaSE&zCDq=Tw(RWa}X;8snT zQ#lFu)OHz_Z5WR0H-%&4ozV(#__J)2YdMendvahjlss#vDMq!Mc~0@G%?*on$a$>6 z3VVE&@=Buu*mk3)K<@Qg{|n!73WfRk`70L}78e&U-8!@HF?aLQ;^M-^EA!KZ?R#?F zN@7$}4iXf@T_^0=f%Kd=H79~t*CZRYXJo)4?wtd)>r9rA+z5iS+`wXegCcS(>(8VV z^tKI}-BlU}#QZo?&;}b>3ZFqys4RbxDF>xe^a9n324`u|Rdj<%-a!hY>+@-K*n~`n zp)k#rdFdWy=+LtM<#Q`T>1~&OEIdN3_5dB}$78kOj@8A~vLZ~En;Q@I8rFc-4Hn07 zxzf4VfNzwhnUo~xGKlv>8``JlrEn{iRyd>XSS!I3UYeg$1EjP3{+k`c1e8#s#Ua5 z@UARtY+Z4v6)TY>*DU4B?X5p$>Z+h1{rA%}+a|QrK(nxFT~KQK?rA>7>V;X!sQQ^{ zMpT>jGOyO-q%p)PVfA6!+n*2q{$pDn4lV0`Q)zHa>c3n~#b0H}zej&C?S_FR5wk4s zETUD~s$bmlbPeE+3$Hoax`Nq~RKjWbUCJ-%ydqJFiJ0ZJuBwvFoeVQ=w4Hs5 zUkXWuTbNy%tdcMbg&ornt#!)JwvsLgKjhA^`miyYbW!XvA9sxcQxp@(fIG)x z{Ubkt%p7trARAB^#?f{guo+z}yt}&kufIRdaG7KAE*$Af<pS=$5tDnrq1s$s!j=_nPNLs;5j-%qzrY7zhque$bAvk3$%Mii^wb?G%%H^NZI` zO_;;7TRH&u0gg3z)pc8LptWu6(lpSQgCUXU(l?+PfERswvV;Vy)bwr31*m%zs0wVS zzO|Lnaf@Mn^PhkI?pup<3dfim!o6*C(>(|eXtsw3x8cKGv%2$t__NGDPR9S98oN@< zvW7J%>p~L-6iUle0sezjz#SM?pyU=X2FD#5SfOogsmS-hkqp-DCaeN|*Obzln{wGJ ziWmW6-p8)W%0y^Uvmn%KALH3#F)7U6Jb(D`Slf7|&s8`Om1h+`!c2FrIyU{OHmfF#S?l26)3ToIr@NCy!~4+jO>_DLz2*i7(nQf%!|H?Hc15T2 z<+6bnL197teMJn*H{{vb3Oy=6mj`MoVZ(7`B>Z#n}Kz&4gD@g0`d|dH2551 z=m0G;KL{5$QH&Cs4!$SW>&-8IFlm9%ZbH|%jZ=Qv^89W>Kdh7{$Rx!9C7g$n*M!O@ z$^adC2^)DxJJFU$;gVqUTgyhZKeJ+gci71K{Hc*P-RovX1e?a^Hq~KHKknf4AQXOh zJj{}_YL1I$-%hF6Rhq|(il1!mjOa+KVTr%0bfBxS-YM5WzE-1o)x=v>5DVe4Skr-Q zfErysIGxZrPk{UgGiG)k>2hGg-Aui6T~9L&&X#qik6W0o(Ue&kyxNW=4kB>lmschMCaO*Lc*!Y@bu+3;c zHByWtP6@Wh1O)yI0Rf^qtJM)M?tD8T%dtlCs_?b((AdP(^&5IzpOQ1|gBw#-V_Hwf zGI(oQj{ywa&5fJhV?)VYoJ0fL_Su)ZUG1gm0}3JWscR3d85ItM5gx=cyXIe z14OpSS8aArwHR0%L6jccY8HA68Lztbc~s;pHZ4*xD4KBxPlgUfv2@|m1OZ1!Jk}a+ zxt0F&M9P#{HKy3!gn~;FE1x?F>m%i(@RS*(9)P;nQ;8F9LE}`_TO~aySq)pNSE#Y@ z)78~Kqu=n*wmEb9OWH`tUZD<|4 z4j6Qy(Bs+-ia<~4hx{!iBfxaoC(kAYAc^Z^L5O?`xfOcS0ib@sjG{a0`t7#gD&3o2 zICJs`lWACzysxeFx4M!{N?nJpZX%IBan*`E#Vu%%S5h^sR7mv~n9d8QJ@DG%*ke^b z@$5FZJ7k+-K>X$}lD#)~cgI%ghZy&v`DDF#v$SJcR-?S#_S4jLv8qo_fA||5zdilY z?VsHFk$Ldp=}&&~LztGatnp6i|CqbJ*Er5AD#3p|n z;JH;D?M01-qq(umS1+9(+`wA-UGu(4 zlTD?SvV`CoiI+AtgqGt8hC2Vb^RRJrvj2Mtt?D%TRbyG%YI@Q{RkgzAs8ARwFD{m= z>XZtF%52$&R==FJ**NN6=rRAa#@!QaJJu)wUHZ*UX;qU>LM_QV1=?EN01+6q$_%IVtIU3A;m-w{`s4n7m!?sQPF-N6)?a z!Nu2y1~#y6{Hf_DO=KfF!FmL;WM~3KRasDkOyzj!L}=s>QYn&dOu||MnV#?-QuV00 z`^9foU5T}N{qgfZ|LUO=^4N={(@^VZ`1Mjnqc%a=fmv;#Bb(Y3SEZTxx$4MJ2g@l` ztCeonQ?FaLW-_ z!C)3xws>EA@+jF3%_Vw@9&I#hx5%30#MDCe=;uk)%AE5QFSJRXD(_x1y|kcCNUK_rlLD!^qk=Orn}v`q`tkRF zP#D<2dV<;DHXkVLNQUxVQhOI`=4=}1dIziHG%L1pt4eUH7<{enQ2Je_bLj#03JGNC zw^h379KDoO936ugYJFeZ_&T!bsytE{>V*i80fy#PWp-lWLh;x@dI$fIjw|PpDeLa` z*<`)5W5sQ6(7~$3z-mdVZiNKOh-BGj$a4bZfWgtG-C(Fl6cMypbt~t-jC$ zeoEsHkVwp?7eH&c^h5H^WbVJ;(3G_~-FFZnCE zFQ&}!S&YZalu}X|=Kw;+E-8vJP#ZB(6ywj^-u=Rk3ftbjpC3j&avo84Ub1C-)XUCl z50z_Oymy>owc_-`#BAkE*IF&lkDE$MN;FnK>&PCMNmjAP)eDLICDzKz_*y;6CM`m7Zc9{3M^KA?bU_4 z#i{8y%?-B&)(_7Q4QyaN%H^9{Y9`tlXL_Q1f#|xP0BYg_uVT3&q=fTSg(9hOUnGmA zx#m91+ikm%4yQUMu)h5I#ivn+RURE9zjq)Ad4Y+R)!&8{$Kd!>dE~4YTUlD1oL16O zTs3-tdmPUX`tacIG^{8H=g$`s|1owcpq~Uo6>G* zOJrS>D|9!M9-Xpt)2A17aaEd}FIUcfwT0Qah4GR@N_VU`wbRly>FYtC4GR-jH7C4A z3)(G>aA>r;0;P*}?Vhad9|Sa!fJIkE@C8xBnLLVBpEo%a4N?L`o|T3xD8DQyJ67GCAr*N?|k&VL5(Xo;^oLO^EFNo`${E%9+kv0{bKInvO7Uf z!lOT+`0s^FQtdl?!2$S%e8F4H}PQHHq@i+ha{II90+KZ0cfOWdVsJo=S1C_E*yBcBHcr^;xYz(LP)>VYPVnW6)i4r8+TX+Cx)n zHF~#P&99q%w!%!lirV6~TMiK2T4{@jNj>Z)ocBy%`L>4O>J|`o6)4XkcPWjBBv7*(1(Q1AE?eUj2<%xH3&Aulbp+KkEUa9e=u+)taiS-c;&;fbks8S zMYS@Q95ZeEik?)y^`!g}Fhw4VQ%V}eI0Ko-L;h)+gJDo6#$$j+$7C!EyIX?8^~cZu z`TIky2==i%iTWOkoddJc8Q(0T8T{WrDod|T&0H|CHSDMiz}us}#%7;=L(r9L%Qj;X zzmhK9mbNdUj0L;_Rqz*CXXVLx-+a4;YFb8MqE@cliWK>72N+V*9POjX z@~yUQY<*^=7?tzl{H=2)uD&y{adp+iRUXU>U<0f<)h6@y1lDND^DKpirW-oyeZ2&) zqwd=;r?#_78k6WLZkFD=GqM z9r`#ALz*5du|bU|5$Z>~G*ne6YPq5b5@kZ96eSyVK~Slg8=ViaJu%Sv%EZ;ZeCQt} zp}clusUe$E5xEyF3f64mgp1zTga+vvR#aZb3d=V)2G^XV*a9P%>S5ij%OW$}&Lm?5 zzryRnNgx05A5Rav<=498ZM$o&=mfZR)TkB57pCSpzIo+|H}dN5SE{q+iTSC8nNrPp zU~KkTk~VRLlD^yWWQ9(9H#vMp^$utYpP5f_6oLSmg&Lls4YVzePh&KFjY@q!T?cW( zSwrnq%A#0p!bT2zz>t-HOw;y^Dv6%AolEkg>0sxpD~PL{zs1F0YI3K(vMKB97l%>QBkcF`NnzC83^t16^X1vu zk;*I2z`{^mKHA|D-9MF+QTh$i57L( zzlSIx-7yd~JC(757;Bv5%WJ{rck_*qJY>}woQk2OAebX&7vF%Z!u$jVhWUYxtHLD{ zSGV$ha~l9bsA;?D`_fF%RY0CcjLlPx-Ay7RT8F|)7UMYV5<)V5ER&s30v58k7cB3# zbgtXHh5uHc|NHJ?w7l1YidtcYjrP)wSTx$SkKE*^v`{|7#f{8O&dgWO@Po5cCB*Aq zZKsc}gNZA_vXPVHZqaXChu>{yGj!8#RJ2x1#?mT0pmbBYBk|)1M9rF!P!z~w0X2Ex zIX^Ge4cw}a6FW!q?FukXgoI+j=5-S1Ja5$1R|5*UzwyyKZ>9M#M>&%qpw|R9xI8B5 zI1wYwPQGwA0uE{7kZ1!2Kd|>owA0E8Goiu`Y%9=8`?3Us`HtZ%=)V&^Enp!%;LsOobE>6y!3PhO9Hb2d`-RZ-F$9jd+id0v)w$`$C z3KZs9Z@DdByS1}_kfpK8b)ZiP?iIoX#ZefGFkLzJBOmaEK)yIPxS0BIo-uwBcpBH_fvpr;KnxoVHj+UvK;{-8pK_ZYV z;nA1|v6!N`iL3*7`FKFXSQIY)B#C}j=iM^j5nJE<^_Pcj5%sQVVD$3gAkV_#(&QNc z(dy#(@bL8f(itLfq2%J~`0ftkDzg0Mqjpya-4wu9T%W)hczYd%)(WNSh`h@Z#x~7b zLJ3UTN29D=z$B5>h3GH>t5OwJ#0zof{JPT{1N6h4J5!Y8gVB5(4|KkI{oVK8Ja;Q- zVpeR@pzGffmi&+D!|)>=IJ^iW z^tg0;*!TH--W$!xPJ2~EN`o?ro$+_x`@YZj^FtI;7-!Mj*Iu)aQ(^aJaWZtXorjOV zzB82lde5^(V^4dJi_kea6cs#X`{u%Pmw%-#zxMp456OA|<;rT+S~oti6&Ux1hbSyQ zx8K~Lv+G%3WA#{@jB{LB0W+&F!*XfAR`~n9eIvL$$7IKG*ikKD&B&`A7(_;AQEq}M zb#m-AoUv#KV3g!Z`vW2FK;+)u=4Mc@oBFBK7iV@KY%#SgtJkBQOaoEdkF#VlIDSL| zuACMCWs+-QN5O^i#KNMEmeQV9GRopOdZtBYnq`4s*yJ{IukF=eHw#@w`{92!c87yO z=diP2{AA+jkd?LgYjq_Q^;gy`)D;M$hd73O4*9A~aR#NWaLu8j6oIWU(0Iii3DIz2 z#Y%a)qjCa|YRI%32UcYnUD-`2C6l2!4+W?oyKzS#h9y?{bWfJ{>b0ZHKH0(y~l$wOlbAWyTybd)$dIc9wt&9*|t zy@YNnMEn{rv`%(B-dL;8>tGcu>?O&w}i*zP7f8<~@ouTt%;yM|mXA0qDY6 zPsl@!V5>$`*U1}WjyP@~wW+1Rn`)%~!Ke%r59uO6Z--p59FBjKW3Gc^5O54zSk5Z43cufc z^!Q7V-#ZR$FIf|DW2_h<7qEouvo2k~Q6?f!*nH1?blt93Lq7sqxbn%;GY4z1)dHjR z^2=PW4$&KK&>uH0r@s2af-_d1_(GrH13LM>ldi7r?cW87I3(9LK-drtd$2jCuXIS> zaTHR|D{d)Mp6x1TpXkiojR;Kumk6>@1{uI@z*SD0je7m$`S;&@u{Nu9)vBGa8({D8@MabmB{-3^Bd`bv@h2SWJQZ{(wTLeGeT;d295yFTN<% zlkoR;w|npY&!0XR#@>*$cNl%t7?17#-hLp~G1jP2K*KPNaQgCJn1&R7l{2@8-#Q>U7t6d5VyAS{I z-5+*`B>=t*wHIC>W$TZ)#2dYI9ip5HZ{h0FCupz6{&O7>moG0}ox1Sajit+1RDg$g z(cC5^8kfasek){j2hasMkglp}XBWS+jjd2KRpAG?KLOQ+&QRMF&X2CBAiPn=w&U~} z=beZfs&3Z)+Nv9v*UrCr=9L$Y)n@mFn8mp!ju^DhrWh5Y&rH-I$KP;}a1uBXuFOCr zyqAsuy0rd_`Aw4)M>r-Sg9?*t^&i zg|)ujUuE{*vWMNJrP!8jB#?LT@QeiTVd&JnLa!o{X!1b(HEe_SR$*Zai5ohk83RKQ zY@p01yxNSmn)T+~sq+`lo@mYPdW93=`FT@s1_^*WV+zVXCAgwsJ41JEgSHdP112H_ zg*rS7yul9ItB_o*NJrE<<-^Ab!wpH z{6wHsp$p5K;Jh2obGW^!mjJca&>T1oMS$VE*d}vQ*=RhCUv6TE&+~ytgAYu!(P&_~ zI{xeoFIO#Yg!Y>?O(Xt>f(1jFF!333AcG)wjp9iVjf_mzm`xEn8n-5LZof#bc?sW^0p}ch2YWw@+f8BvzG=9S5xw=@D3T}*gJc8P~U!+~JLT@n>ieSZ}NmJ=j z@{}q%A%(cH4xKiRmn3Eu@dtoA(M}jNV0ml1tBYsfI$E3Q*Xwp8H1(}|=n>yUXA^J! zoa9kLz|#nRvCka^Z6h_6-0b8Hg3U6cUMEPM_={k261X58ENdvNNkKWKPTRln*^l4; z^$rC0o$_+jbMcsiUd7vCk`+C%Sw6DhUq>pb#UfSuj$OVWwJA>9l&V^sU~o=_fx261&q{LFaW!15@PzPbzr~V;xZeRyZR4tf(MR|8SAZ<6VXCu<7@ciz z3?l7LpIaerL_`^i_a#WElrxHe2}tE*oC#UTQqeoHSHycpvV&>bA5+6NS0~?m`?qJ` zYR&d?RXh6n#nO0|_1ilSF=CsWI}?aXkN!k7MrSzT`$2 z-5?wWFnNq@C$R<2d%MC;20q$#Mr^jS{%kAjR?)#9I0gDF3fcQ9(4zcaR*RO2w=YYE`>D5x?5R84(1nwZ4~v?d@w?Px&&a z4Vl6fMDF7`C!&nm5F>TajtIx0H>{&zDyc`N8Pywgmeq-4wON0?WEU*hVv>*@NcTW$ zHU~B%k<=2pf|1jKYD+ow8HZWXtv%N*CU+eje2TZIeB#N7cCFkX001BWNklEQ zTdYOZz0~(v2e7okL>pF!DPZYGD`1q=X5UG`m~q?(=biFqB@ISWRJgmxb2pJJbQokX zWIjriCiw|v^LW9yN4?d1$6stc4Rv+w?As^pDjV)(^4yg~GRLqT{ZV??u%BcIuVIv> z;k+-9sVeSGp0f?5n>nEdJbeg&mb4Xg5zMUV)tx}o>mB_(G}^Ar47=1uKl<qJ5-5OR}f2LNnLE$!8^6%D3u@c7<3(vCMR@^B;8-w!KcUvLTn0Oqt zg|)ruh@{(Ol%kp6+ZVT(15^Ubsckb;Xf8*95K?>hNRCWh>O_v)M^tBInlM(*>vbG} zn)9d7TfOk?(OT{4Sg_ulYc!GPl?S3?=lpj9pA(3Z$sRxl=70)bdrXeR;wBl8SLOjd zZk782{R#HMQ0m{%xC9;sSeYU~pz9H=uH$F5y*B#hR}a7W?$bNSvFS*l>XcxEax&8- zC8gK_ayvRv+ zFofQT;Fpd5;;FtXeo~0ti3;mGNDamOP+w245^pB)0m|uJoly0F=ZY_1Z!PSZB*Z=8Pr!mCfgN$~&VUEga|=@}N{IFm%st+s-?tFCO_3+v*dCKLoO_Nx28 zlv0>;4moGeIh=5!;V>;UI2Xe#3v(r<+1@B&z>9@gNw!vqCQ|mIblFvl7e!<*w58DR zdEW2W8RJEvAlZDz$z9Np)lsoDLSQDcOavZ_FItj-55jcQPMH}kQoguYn4);ZJ!M^?Jf2u#mQ{rg%iAj0M;qgGk zID<>aw4AoXfHCSGERnyp03cu6la?+c@S5zwv* zlr$nH&KW$)MYyFvxw$^V8x{+Txa1&*mZNGw<@92~`wI|~od(^^kF<2Joe|nGbY}P? z`SWtP-d=n8^fMI?uajM9?hW*}V{P#<*j73=#D1;Y@CJo*FO3^*Q&QThuw(F}iyDor zOlz<-5B;yH&ec_AO0<}!GOC8$Z8+VNh7&!(sHUktj3KXWz^G=UDUWlTO9+K(vs3cuO(O!Oenw`blSt98uo8(P&1vlg$mpEWhJs3 zP&Wf!yM$N;S4t}GryHF`jflgJpSVT&CxZql+yG@>Zwr} z4Z^PBY4e4iq`H$CpU;h}rJ+scuGbCcFWlZhFX@P`CTqK;8z#kg9hQmL^A?vZ&)Uc#!6G!Sc8^^FWkddJVckTKQTe=%+qHfoq6~GBjDuD zGOIoNFP=HoS1EwX9Sac~l%;xE=EfQ-XFExvQ5^*bfT(18Dh__R+Sw?D!=#iGQImp}h)OhZdS(di(fVN-8iSqjv!1QJP^NW51w`ex<~CDb&M6(2x}>D4 ztK7OZ39%X>Zd&IX!Na4GNvA}O)#YVr`g#*BHJi``&S)UkqG62`?EB)v&wl#rPcNOF znVAti!b689nu&NQ=eG1IsAqWUz0)%@XD@yFkus`d?;PB-1FcG(1Il3m=+0hyK|~(; zV)96YV1nd9Smyk!xm6ZH=+)Y3<>IM#mXN{E@E5AshrwVRvGX8cKkz(hpkK{rWi}vYc8%54 ziXlwv(Kp{d`_uiK_eUJxr8l}@uhM(dVrlsJ(~6ZtLpthO6;{jV z))h{-E@d@gv0W)dySlZ-AGCR3Jusl#sk0EYF+f$8b#{YQ>`aN;=5 z`J-1Zz2RIrc~M;e&FKBp(_&OR(yG+Ce01he+-j1kfj~UrsV#GXP?dP^&GjZ*m&t}D~J z`|{P(2Y>nerWhB8Et_+5H|CUy@oaWee7muU+f*J)=QcO>(Pu9mxjC2O ziY{;T`^@=glkc&KCsX^r>ep_%A@tQn0lkZ}LekE*LucRAA`Hu#$3b=WA31j74TmcC z2feMKoqHs8*ThYE30~f)sO+>#&{mON)JcqCLCQt>E3(#YltduQb{uIlwTxb*$+C)= zZPQBQ)G!K)L`x^jJl7PuxsEsE(SB^1a+&QXYcC$Ydiv}O7}w2_Lrf_n(|^Yv`hT8l z*Is}3k=ZLm&aRBLf_lMX@E1g&K@VS=rXfhtbNt!NS5-m1Bvbo^oP+;;yQy5DEK&o2ixNp7Ut7 zpi%`{xn)b;;B^^lNtfwr8EF)_t><4o{O8}FK7Q~=TG!h>_iz5;AA}|gBM3B3a4Ssj z3mhOW{uqWezQ6dUp5hO{qBIaoMZ%y}NOsj15~e;Wnnbjk$SiD4pvTY;42f+r3|3YJ zg4EfNRUF}t#O_5b#L23FjN^X6K0`lAw9aZA6FL&#ks)*#nkJTMJY?Lk$ZU^G4-@Si zaXs5wTYG-@>wkaq>TlmZef<5iXAj=y`KySHQ*eCs);4!nSAY4*fgg&w{BM!4(Q07T zG!Bf&20^4O5ex2g74TuXs1L@(0``L5DjPMO#U+M9unIsyG$^$4g0N;008z%I3el?2 z6yK4maM{COg}$$<105W%vV_g`_3Zas-#uA-{`~HvuV21=_;$~uueLku?%tz!KRmYU z3~O4|gjK8AV?|hU8dFwC)%(H;g9ur2YDlV4EqS86+MPcyqMRPg!?5sdEX3~tg+GOE zAQvTU5kA2vx)gcCzTSks-5xV6`YX7sb{4vyUwr>3CmV5mo*5o1>~f+65K4wRm;2-{ur*h>kU;~tm7~L$Rq7+@80&VG^}G+F0>l0COMxI$mL*XOPWqWRY6V_1LGB@@Mwv~ zr79S!Vbs4j5NTRf7j9Hi@#V6z3XMl)QUI$FCs}d%Frvyp38x5I``FA1LmxS#_wCzm zdT2+~o<-^2Def;@uE|hWj-i8d8OXD>M3bs5+kG=*w|boe@1T(tp=Z}^e|o7+-_g^z zJyf-OU;Vc2y?euK7aA6T4J*x-%BG13?Hg^l*kJpyzzi=Gh(bE7EQyA}aCK2gHgUT_ zUnKkAr6^P-AhRIATh`|ylC4nI0x)@83GRl>u-clB(?&#xPqsXznS%oAMnvcyXlMSI z(d*gUSZgoM+CH7G$Nbi={ZhXX;zeukJq%3I{S#_)PyJuAJ3ZFH^Ji5}*zA!4CYBly zU3S4I1VYDMLjER}sZC7w&^sIRBFVQP$-5RnDMfG`@iHdvD$<&Jd8CPENLRoe0YH;) zkAG|~)e2qnA*_Rz>pmj%2iA4md{{RuR~>|H|1HDXZ}qOr?8=bwL1BGV5Z2nduJu-1 z2~n@wjfQpk=;?{5l?O)YB}VEFUOvi`R6$ael;WslIh8YHWo#?=t`3&w$z#5x3@eYx zQwsR0(1akFXA~@R?om@mlZ;!y(Zr;xgC_K{r_z*VF3gA@@O+uhSa@T%r;WF$S&8$3 zp>ar_p?JP1v~DGHIh=1h_O5XGwZ%W&)=$}Lg8*StYe?P*J`!|Dk`Hv z@`@tm)&%XM;wjBd^tQ^Nm)yD4A=4&NNDCP02;+`k(;>4mL}`iYHq=H5VKaOd_md&^ z3Nw$6+o0c_7YcpeTWxxw3o^EKYLcBSv)1A+b644rmD$(U9hvvEd)v$d=DWxonkTb% z-J|-&1uxu{p%5unt7!GW3qzlxsy7f73EQa1e2EqSIHQS6h=&*v0>-u=+fAw}%sHv1 zI0{#vbNtv3OxHAF10J>o${sEKnDi`ba_C2w%mzUryw%arvm%#B*J4np{ZQtC2kX($ z`Il`THLR6>!alaz;p{C8{Qziuqbo$L0m5VL${g$BnL}ku(rgT&EA~et(OZwn^$736 zvdMlwpMCU!?=Bnt2;-ytdg(f(te%~q^$H39R>A{IbD_U$k%f@tWkZlxr^yy`-q-tZIpLSX*Bl_h$CG%tsp5>cO!7T5!bK?_s-^@zK8ukKC>_to^ey zW=}P#gr+@_g*J9Vsnb>D;$kFyQgLkvht**)T)b*J@3sRfa7TS1GP7H>m7WSgDNIs_KopYb0_vHM6MLL~0apIJ(-@W(TbI(zkwO-lpq+p>D z$aK{ndxf4s8dNL;Kqd3@YktlIkf|h5-5s=eNl=kX99S~ZaZJeBIZ3$#8*GYP6aS*P zpbzOk9?Uw=RQUJ5{`RN(1AK=2g6o2)tje7F0$w7sD72}ob1p{YH4dynaT>O1mtc@` z5g!FsNiQ^YYp)51k=8}hXsvn|XboLpxf5$`B%TFoVu`D537fd-LzG_)%J4$?Qi3HM^Kuq=rn3n2hKr0Ri5@ROkZh>;Te_Km78qKbraj>7PpIgRFmti zBUxXf(YbqnmZ|XL&;R_@db`wtte$y8aYO^%21}hNYpIoWwt2V&SLWvW>O$)*mkJBL zTM6bUew4c(MKo13EY-ZoeKHPxNa*TD8KW3Fl9AyTY0ya2n~i1md_Em=Qbj@--`!`m zTCexd?s~zy=SSSUiBC+CNcAQFGbA}pr!t*)Q7)Va)$YU+IlI96%g?|6WV83Gx;+%! zDzk%njcAuK!uiPilCP2nWTRsqs;x>KCOCc(p4>WOA)|balam((FqQn*TdnQ zCCYzcDJ=tZe{u~mw%P2TUk}^6tgrjNZ{5|mRo~b4ZhLSi*SC0p9N-mE%NGoOWLktA zrvt;uX2w4#In(0(zyJQnPqkK1(5B!-uu}JDZ+*$muv7+M3%H=`A9N?h+k0Ri6` zZEWy9)_wr;fK@U26%O!auuV8Y2$Gx}So7XYg7U{u!*oPf`LkE%@#S#Ww}_}N%Nj^Z zSodHWSLfA@yZZY3;d#FaTh3D+>l|2+0K_mxWb9Srr4TvCuJDIH|L>0vRvSQwsnHD9 z1xGPtL8U1V!nPb2c3&_|0P!)U3 z6(%~})6&~5sB;>2oQ{^#YSbI0xehrt=QQJRBpcBTVf=um$K!1}RIYskt{nP=(CVp%IfL^4^(Y-bsLF4d1!h z-{0lwuFD!9;GAaK)RTJ@{IFe`?wTSyJZ~oARTxYnV|6FfH%NenyhVidjl~%j?;2QE zm$wSCJ!>zz&Gm>vod7JgJPNLZl|ZpT^1Gr!!Q$cy4ARo;O8Y$vdQ+83yGcFUM&;fW z#40Gn=H0)>vnJXi4Cj9`h1=*{p{Vj*D8zZY1XRpqZ$>b zMTuoXu&{0iM^P?Q5ckX|B#D^~-?)8|QBRDgVV!4#7awaks?Egw0txmD;{nS=#~fKR zBFS4bJ3mKEWG!p+ymg)6E>-<~iu3ChHZ4c|t07lM#wP2U{_ZtdB@&!G1I2JUg5G*` zBVZd$eLSiqXB$`*_8_Pzu2f>~m1-qUsVu+{*0OSfxL=Mf)tf7IX}_Y_^sQ<)s601i z-*Yw6A@L6%szFhns&SP{)1b!MNKA~8h}SnucoNVOY$?2# zQVtRdMpX_qWm-+le;$@53QiB=EfFTeso9DaQrNJgIDuz(Om0b9+;14bU z*!6h0b?yGrHZ8iU>GJZhpJv!*1~kOLe1wArNmHV~AvtOb9=v3rW z!DH;30*0bzNB;mrB1+alPURXZP)FoHnhHSdp#TV$6P=)WfK@j-FPKGgJc(LOPG^c) z2AK%QLG}?5na%0U330{)mU^qpgYLZQ5my|kE60o;NoqUX>(GgHBzN4PBbT~#m>nJ` z7)oZ9mdtbDoRcau`s(@CSnsWhIHC#EKuRk=Q?{8_A;6tVb;fZYK7fKn6bmIhRK~!^ zqLr`DrkP);AXCs%<{dX$tGm(o3Z7lU4I*KTh=lqe!B=G9w}hE4q&-EvVLftOeYGpg zt^`n*Lb@xpbe+@^ODPzZ;pL5SnI2t(=+3M#3rfJ>o3<3A?F$nwVVJn)$NkQXANw{FO8z>@~q=z>HXj27$?$B8cMH_1^h?ZOkCqi22l*N%#fp;l+}NtH zD*XUObJq}F-FkKdmMKyanvn)=0q40AZv~TUUc&&|1(Jn_41kSFy^gW|6)U<+FnS}# zK5c}V2#+@=K)Ov>X$=S7W`C%=yl&797WK|{T~~G8j&EIuL18w`4fTKScGsw4aN2aP zHwA5PcrIUmT)VhzlC&KQq zd;~rUg>wWJiJ@>gEOXkR;8@@RhNjS}r}*-pANw7V;wEp3tswwHz`oG>(;b*(mFwB<q^bEN%W&%AlQM~Qi!^%kV)>`q&-stQmA4?|O;R>T~y?VZDn~v^dP3f}tB*D&Q z$ZLu^F11wTvFmR6dfdTaH*IXwANEP~v%_vxW=fV5ktWz5o4$IMv>6PcEAOH+hbXCAK4AmD&s;Ce*OI)_A+OJfZp!J9b7NhKjn8~%j4L98! zo6gmQY16cKFA?q$Fbbp4I-xz7h}ESdf^!Tk&}Ke$d8y+LSdWy=nX;l`wW{>!@+W4ncQ@lobEQwc& zBig%>Bv>jPNuu+S&Uo7kDAXx``R+3rVwITf9MtflJnBe@#tS!`VOOX`zpMkY2|Tpa!5OvwT{zTSt*320_N1Y= z;Le)v^W{=ah}2VidAU4x7(nN#T9I=Q=uWtNFw#lsMNz5goJwiA8p{#pE4**tFBowDuAqWP*$H#n&-G#PRhb$fBibBt0<$cwj&n=f4sMf;{| zKK-A(t9flBy~BpAiAoAv*gf^OZDDUclx%N>{t^9GG&3+`W-?-I6cw`|cn^avc`+== z=xFBRB~mRU`~k5J@`9C9FoB+oF?JRLN#E!By(7IN+1cJTU?;LIOGZDvzpv+GHnvU0 z5`$-cEcq1*hhHi9DqHk*)NTMYIkStHNK~@96O3}+5IlmccUawH`a^zwb9-A5Su|sq zWML$fv0N6r5$(MMg~MCKIgkS#vZ4n{OPj#5dJI)iQ|vNR7ZQo;dw`AeFTOslquO6B&Iqx@!6KPNk^q!`SJv-1MJ7O{*3y4KHjg;uVc6StH_m<)V0{T z-&)pK2&^QmB}og;CiGSh!#h2ICdq-ns+DimUH^7suYKZlJ5xKMpJ<*uo?Xl&~NX zIPJ2)5fVBj~$m3|ETKceSxlWBF@ISWUf}m^KqSETClMz?NXC z5MOd|S-i5T$&N}MG$Eu&pZtlK001BWNklZ~wocO`U~`58r?DvX**c+KcLnvS~?5B@j9ZV`X5Lg(Chp;BZjKE6xVMxx2LqdQ;%F^AGPL%XRRkFi+g^GTN zCBOh9zM82gvhKKlf*T%Nf0DsiZSiIIP{#NVQmI_#>Vm3sc-6ms_io=_2(8Yj9`{80 zZ~n?&?nRo9XQB&{oT!}A0qj74!{V&A09e|yg&6rop*F2BN!q3W)PX9_kE>LnczkpH z%DFz>O~>&n`LNo^`d`Is8CYNc^Z912rllSMeWe9vY9w~49BmQ2Zk@nLkVrCA-y&Rg3v*g>_p4O9QFJN4^$|){>%3|Q{aT~BO#1dv}r2-xfWI*mnc~WRgqJ`x7(AwiWB;uq*$hgoVgvwH)g;;^@C(IE{L)&6N@kkR@6nSSUZ#H&P;dpxe zYW2Fqqx%c`R~5m-zhpgClb?P2*Y9ekE%eBr2nDGN94K+6Bm@TF-ot*^qn0GeHp)xX zX@l?vnl$ACIu)(>h^{+0>j>hKWueuGEX@S6Bv3jZj9vP}LX5itNGYeK-QE3%uKRMm z!`#`cpX@0O+iFZ?xn@$qP@8A0m8T)p;DKweJriF_o8ShaQj;i+PZ5{x*nGCM#QnU< z8{It+SFb+ZjN(OC7|)T?3kum0ief{_6o2JTwlp{yurA(FwaTxKG3xwuOeeJ-m z50w{c6IlQYfMQQQ_%tEvovwx0GK2Oipb44or(7A*!h*zo9Su(AIdBdn^%p|??jA9o zK6GI5$eJF{i8`#^bD+IU7a?OamFfP$(f@HxRAx>oY@R6Llnjf36$**#4;5H88D6Q7lUAi|uZ9mESf+k|f9&A#4rd8U zED)d5oT)vSoY`%2XB)tVt!+u**hM$D1ptJ%N8_l_;)^G4>e>dDoS>td2jdDymgCFh zJIL0Oo4=kX7R+?M%W6+Gy}3xq5nKWV9KhXzMr0^@MvM|@A5-tZBoBc8#F>IW&=OJa zvggCBA|v-D6ZHoIlSAR?B%neE7t{LEdX39D2hBGxwz{2n4@cJh$OYQ?Gfx9^m|0V6 zo%Lb)vu%eXSQ!dPrr9CJy2*8ClgOF_rG=_yBFmIy#o*+y{Iw5PSgf)}%TjR_7>&QC zmM4HGKY#MH_7wX6M74xMIcLQM(~>;$WGUSed}%1y^%O5!tItX4B(a6E@+gtzX^g~h z!i6LeCX|IhV+JNa&^PD_S~^N*j=e-&FAV@HpxJ3Gh zSl6~J1+mB3wi`ky61F*s1Nz4tW@mk!QlWx==(^ZDIV=O_OM!J<+6Yv9#Y#5CTIyrT zx)8b0t0kpBeao(5*dfEjv!5&p>_%EBUYR~3<6ylOVA1AVjEoZvZUEGxmdH-S|eusl{`nIfy}*H`2x76TBBAJ+23+W4Kxg<)7@ z4&;`v#cnR3ga$V`VaCxZTlRpuexe|0UNjY&bl8|6IR>H1iaguPqCD>xg%Z=tz%*bK z2Mk3jSwy}qz-AZ@DxMEjuaXM-_f>4{H(dv>~N6V#q}jqFL|-1CtnP##U6SVsRGFTFv@tUsv`>+wU|*HQcyJ6wunEI1a}ct zSgH4QW?|UoO@-d#uxtt*53D-`mcOjN=DTJWYZ_R;|Ka;@o|y7o=9-Dv2nYgR7HkME zmf$UkG`den&4ljU6icBL`o){qFJ8R(`St6!zx?zshF8(=BRdi+;SEvEC(y5v3>)ca zc+p*!z;;uOmLY1`|<5B_ViMD-&`ghGaiNtUOlMf zR1o~<&~@EiF(`5Hz*qhKhcAp9N>sBcX=W{L*Mx$B&b*^tMA0@%bPN~(%Hq*ws(1vK zAhJwdf7Z_u8L~lO#{|{@snGw;;{AW@T}^8o*%cMUjmkI+8)r3RCNs`rvKSnO88RVZ zAe&@61hUHis1H#k>O(vkO@n95fV6EKy^f&k0EzyEo zeVL|M+JhxN5J}|fB}kDb5^7;kz6Nc;^GLAh$51A$wNBjWtWkJ%4i1pMUOd12JL0R0 z=*m*Kw?d36Li66kqE2WV3L5jO?wq+^Uc6b{ARYbZSWkBs5Ppo9j)jhY8fE(@8@RUd z-}W}$ZqvgZb&uyxj)uZR&t7Soph3#*1{Vy9;_dtTSVdS%zH91m<#G1b(q^ocI}aW` zv|5(Mb^+))2*%oKaXBJJysv1>9#c+e`v&K|eh@{J91vIsh^r3&g6psoAIR&l3NJB~ z)e*%}9vmZ(NQ*_%8@91f!Gn^4yReb<4i z-kzSSk9ZDmsr z*YF^poxfQ$gidCmzFj{!>!zsGkn8h=PZVf>gp?a~h4`M5r98T-D~jl`N7)z%i{K;m zZ}Z%r7JGFMVYWDB(X3GKx!aAE>E#9Qw5;>cTD8bdB9Zxu1peAIIK~+coB$G}kq1Jo z%C|i>2xv3m1XTweD$ZCEV0E;M9;njTL1~OTGQ1dkbpsh)=X)W|j+N+wTT?G>-P43R z5l0Im>!)gt&8cE<@-)vqRnqYdVz@&y8cZq!NBP`Ia0qEXPQuI)u3mv_}L9zLyLG(i*)Oa@XtyetN z8d*Mbu4x)htB)kO1ZG&k4hc+|W`$Iz5~0VuJWoYM$yd|D1$?ZlBGi;47i>X>OC4AW zWwj#a`9V^YD;_cU(1wQ1M8pof;O!+uwp7GYUdiE%wWdNSR$&!uVHNA~Cc}%e*NYdI zuU}t}-QxHd;ibvOgmq6|Jvp1~8aeC7CqK!!ss(6hic(DT(TG$CseqHmT|%@VU_uaq z6#VkoKb=S&0rQ0-);~dM&qw_mVE0O8TmH%O4AQHDxecx<+HEMqEpaL2gQ2iI3;(iE zISxv7ed1F|5F*fBXp@Y!=dt+-28vLGk33qn%G9Z_j-NP=&ALeWtNQdBKM}`=GJPSu zUXP2(acw83pR_oeg){fR@17{uyZrEG8|2~8T>7&wMCzs3;-L9AoF@VnJ)s{3A=*gC zLNK`us`k`uk3a;Bs12NuND4UbgZczP5#NZcS65>dSGH*htjTt{x7;PpSe&vX%4*Tf zCQ&XZKCQ4uvUGSP5rV;U!1Bs%>UAch^1!}f+-~43Me!6H)iAE_%fMP&WAugWg&P@O z&t>+yrrId8S2>lgExy9R%kvYpr}O6B=EcjI;h;ma-@)Vt)521T$@lYip7;40_J8Ke zMcyX$37`NcN&Smz8MW+zj<4RqkU?*uU9fNO!C`QT)%Z{#^df}ID(iV zR>u6iZjZX!(5Yt^%WUA0!DDDW%KLDqivJ!KT) zGiFiS>ndCE?DhQhbz!T$)UwvVCp?_f zmsD9|ueiz5G@><-NG2@o6G1ebr6!ohuuF0|yUfzUoDlSe-J>9BF!#p{G{6) z*hL|eX<_zq>yATBEmO5{sZWI^$wA0-A!IzrB@TRI^1kGCyRu!Xk`z5fV#@)~4ZSL3 zQQ*W?{FFgd2bPw~7<3th6L?EuFT7LwdVYC%UFhTL(6nrFH3iz9J(b`+7X;O#fY=Qi z8|z@rkj5H#GMiwL?rt%K2KS&QZ*B~8m>yslk4iXeSlAmP6Jf8~gtTjJwV^bqymXd4 zux{V|^3m6;5@i9X^QjQ)#BGofuwNKtgsKooiTu~k7>Hpgov1aMSzM#I3Io8$=pN}=!Ze11L)@1;pF?80=@;0?TB~DCESQTq`oh4?NGP<))nxs$& z*kHxTot@3y(-AGKf-2UZ7MlEbMTAjLsD^IXw7#rOHYz3YrDc%T`2C~L@8`bdSnQi4 znEoz!Kf);`*o5+N2)!7hbI>Ed!_mE1lrh2rw#iDCUUEVZuh^Uf@$Wx4ygcre8r`LUw_UGMlyJy( zd&NbNIw_&SG#YLw{wU=q*2q!o6j;&Ot>q*4Q?lF1{oL=Ksd5+Eb7GWpxvB-NgGUq1TG6ISY2PT6{wv6B!wr%{@OTu>+?H3U|V!8T5Wp=}b>;Jq^!MzNlI zYBaC$ z^ZTM@r7hreA(U}|k`#?d;>U?tIfJ)%z$axTHODcB(6QEFh#T|hI9`mT;`h}{x{(=c zBG3AJ1H0!ob>Pb&D3SE+Or)tui4K~I;SqI6fBrh!PjmW9rvWw!?S|!Mbpot~0JPN) zS9{#BnY-n>U;Xtj-!5}tt=zuz>)(BIU#waZWgvJ2tuzY~$a1K+MecBdq#sF6hIIRg z86cllvqC*H%{SbQNn#Uy%{|mQsxq*i-At#`vx)5vs@K%j)s^c;DT-lEUWM2$9OeBi z==b}e-)FR;CU5y;KgCT3`R8p=P|b#=8!x30K)n1u~{;n3F9aKHN7 zcXwBo`nr9G0emaT1zR&Y%Bcc06FB(t_!+}#05DQ)BQsX{`gJL=s_v(eisEX5IMRr&eDXQ#g3j&7#slir}Gp{vk!o6OVMhz$gqEg~Q#`?#1ca}V`R_;D{ z^!2J^N$i^_?HGa17D;@tv@(}#{aCRU$o!^dR{e*Sc*I;M*v?C{wT zdNDy?JpEzf&KW4#rgJY*lvCO?YdcKlBgS#SepGN37Wn=%X48PQMJkvnj1A1bdT9Cu zyY_qBR_5$l2)x@L0t+zf-XFerxQcET3v45RfPv}83rfLmDusUL`@YY5SjcWQ#)=oV z6BhIt;s)xPk4PP3JsUS%^S33rlv{a=6%|ZZVHTZ?J zc8sv>iMK+&)X~0r5<(VZ0QLtF=|P8uB_+Nk*k{Z8n~!8lD%fe^yt3+c*VG;S3rgn{ z;5P;hsJFpRz?({xB4y)O)A$4^h6-PTY)PxmiXd)ZPVnGi4#EN(F7CcU_FE6N$S$Ve^3dfyEkxBr& z8p2$_^LzHiuYWccRy?yFn#!8E05F?}DIpGE;v7Sq5xmR%g}WDFH}sC3K5|c|3!ea7 zmf!$|Rm#R1-I#)I+vfh3%moE??& zwI)Bt1r~;}KBF;Y$@?*YuY$Y-3hT>1{CupbSXoC8kK_^Pc3hrUjrNg<;BhEaxnNe% zi-E7ZA2(<{F!UrSUiU>iak4P*y_&Sb1&p5NU@q8zORaDD;j;MpCN3){y->iZ0hZqZ*uX$^5 zV>Y$Y$?G-Ab5dEfLGn|Gb++Be6-?nVegafrKu?r5O$uVLn+8G{+tuRwMy$EsKhUDp zkmm;*ZVfzadErK9EG$x4zxu_|g9kXLYATG1mT2VHfYBq=TW+Iz3&bf!RR!>_DQzz@ z`n13JX+7ij!CB;+#+zaMBd+4GuuK)$2s=|@24=~6o3Q|0MY@r#gJpJurPaZnssOZz zV|ep_hxxBEjTKZp2DHE0+`h*pr1C#Qg-`%Kf3-C%*!;}Cn-YW%=u_n~@${QNjS!2l zv;O|KA3c09K`S6Qw7`zkrtjLUFqmV3^Qg5-2JJ-{km>;lrTY-8_s8@Q4=WH&?X3`k zQ*eGR8`(hny2;p4q8Qo{HY&yRLvVqE7{l7;d{z@1E6}39`%1zJ@?uF_st@R-(|jTL zft3ge(*SbeNHgQ5kUoC$o6kQyI06e|pp)j#K+(kll;B1R9nnRHn9sXhPzEXGD)70~ zz=cn1RzVz#g+Gdg1)Be|F612c!Q>a)+BdK01>wzgNlp_TgQ_%7HG(b`<{t+_jhDi-uns>Qb@>j%2c@%%1WQtU z($v--p++nZ+SWR{&2Vyp?$?YSxCVN1R_~y5ziTlTax7p_09OiwoaB8BJ&brd%X+KC z%iHVCqAXT(Y~9ex!7OA|E;e_UgTk$pk<5OmU?%i}L@qLiTRgVDc>ZK8ELK?Ohi^c( z(v@}{J;9Fynj;KOr8ADig$T-88H3bUR62SepjstZUJoo3wPiOLjD`D3=_0+#rk&?^ z>yQQ^nDB~hdzR*5j;))!>&^Y5&MjZRUTikkx0jdMx?f9zo>7rn7&@f88LE)s8?98m zYqAPstmi)+3yT%j>*?{kIo#E)9Y4fUz>OVLI_7GYmv)+kaR6jMo4*1RnG^2@I#JMr zBlb_Pr}Y5ba;;FJzX#kN3UrTXov@TH?LZwT#2i4EMmKu%)^!K0Ji;*-MDHNNgvo#I zOE|pN7a9DOU1TU03nO$zYtf%bz1%24EW4DS%R0mrBJTz1kLFVN*;r1ju#Ue2kLvH+ z4%3Tjn7`*`9+TJR$ofMfpt&qs8>4@EnX2X^PRdKxGro{cseyWs5^oC&bD!!06}6CA zV9@s+JwT9Y$8K`ufDutylW2T=0w<->Q#F^$QUV{hbSH-!4Z}lG;ft@v6?9Tqk08=$ z`tEJFtJ(rg*9xS}$$2G^^DZ%A$7Rfc>(7LN_Y{ryv6J4fPt|%qyTOJVVB(KN$EDqFb$=7u zmdFxJlrh9jS|rmykhB#c5>pSsQUL@R^os#AUIO&pc=Xwq&&N$+im?u-XK1Z|{_gD# zDr@2uIq2O0Bur_;2w|)hz`O3R2#1-YdQjauu&)k8zZ#hhDCq~KKky6N)#7%|mW5$$ z%#J5^UQs?o7HRk+c>n+)07*naR8f*MJr31oT?JJ}k`%+jJ04k%ULn#*Sjan3BgEPR z-a(swa&mI@{mNkYIi~2?_&K!MpCgaOS{n`880ns9XO>X?_6*{wjKaY!B>GuWh22(S zG*8#o+lv68qQ7L48R*J~?O>R)StRg?4H-y&l!xd8M`PbR^&rche)H$C5vHxshDDy7 zoS#n((%O}1m4{3kiFx$0s1fdzv9NS+8?#SQpOl@Zh(GzwAf~7>h8}t$?2b!wWENff z3JPmU{bw?2L&KiaWlS7zikPl?LWQ02-X@z<~SWhm1I+_>ho&%ts4RIeFAFIyoX0owMrV5i#U)?R) z2hN4dA@Wp3$&FByqb?GsD?vh@6Y{YN-dWdy)xt6KQ`L%6nr3KjS#C>SjWewXJ@7p!Y`&DzBKp4)uL`O z^x3+wp>YUQR$e+Wg=R++qrB@r5uUQK;u)ut3xIj$TemAjDku~*y5N*W-I>B#5`_Z^ zl8cL9hsa%Kj{4PeAFJp)&=>2!K- z?uQ@RGOxhn6B2GQOcAcVU z;-f9tOp{_ST6@vY-KU+WrfW=$6V~4Dx$`4Y6uHB+K^%b5%=qXP)*%MlLPqzwX@xdM z^5oQf`A`7IPH+gy$M^^lO+l19@TfF3E_$-`RRZ8mU5$MAVcN_gPTs*1_7qF(?Bw(m zB9x&aR+C99?Otbs>D+|qN4I=^f*<)p4;c8dUp41r;SE$aHiQY@cL(~yHKC{rhPksO zi9}`5gpWh|o^W39Q~;H6rn^wo1Jxx35X({lk#g$kiyykt%mCIBXbfg)qUw4v3k` zcr^^c-B)kk?iz@)?;woVdXVaGHRt&eBX^w`-)cS()ye!TsCMj^R;5!`s0swaj0Cff zN!89LIBig2LL~yBic*FZkwkiMoHnoT^qKGQ566ppio zhaTY&g@HymT@C@e1nH>Q3ZuP$+#@T7yi_b0!G8v2f+mKeg6Y4q!1fb#DG4tg z92{hiUyQ?s^zqprzy96H^cbCBU!I+~8{unfZ9O&p@f7`s|MQQ3Zx$%6il!hs5k9lH zrliFYX@%~Ib2K%nvA054flKRD0{4ctZMGlTa!>u2z3X{x>&n6#A*d2a$;9m<$ugO7 z216la7Ht~HOlK3^FiE;mwtZt80@OAz>s0URYWQLqXuRHwncdV3N&v7I7e% ze;{}_|3K#6``&%`JLf*7=^*dkOWN47EpHCzp8K8eM7_9@?^^2m@p=je3Q>-9!G7xA3m3TFu- z5($newMb4`5hfD-9JSDkf_&8T#>S-8d_D!-QXy@I?Fo5;gjDe`2AAww3gHVG2&NS! zhVMa9_;m%lmpq?+e(UzqxL&Wjaca|E2HnEYfm-9uj<2gNe>D2S>WxOOwthey3mnx% zofz;;Hsz#IBdm-H`Iir;cOiTsxzL4v@zZ5U(xVDi<5c zf(;SxpE^2rJJ`K)@|!Wf+m_{^EWgdMhvAb>hGnh$RJP90jas&_Mg!ZlMuS1G_vTk4 z^9g5?l1+-VOMV|Jbn+Ri?d@V5NV>b`Y!_O`N0Hyj4E>9to3T6-be+5Nv8_zF^kIu5 zp|p?Rs#%(x`?;E~(9w^ztns)WvO;`1X*O>;!t&VGR(=%v^5KQI;cUBNYXS4X6U+LTa*%9mJgZtI!KI{4NtL3GwdcD&aI<&!d zsjbb;&5+mK>DU6ZGu9x~)*DEsNJ5&7VGHIy`ZAdQEVvZOH#u#_<#X-qbi2pi=N+RU z2>colVJEo~RAA}=gi~NJbNGrP*%^*UBCx#0JE&h1I__w763!g6E?d-`V8o7*~7&V~y;*<-F&99mFHaHm*m1PU#v zJPQXj8Cpm*k~I+=j}i0t6u(LV{jtir@aXo^u;XU+VHn@nJ5RRP*SCFqw=b-4G4!{> z{-<(9P5<|Cm9tx+v*bIlWp#2iMK(-Y6_BLMY(RLH1k@XJxXo)$*Vc#XJ9v(kGIXQYdjVoc1 zyrntCoh5R~E#R!Q!O}yIvFNkiAaTPPz%FW}ul}P#-GBRTc;)Bi8%qm~_2IBSth=Yt zaDTVQjq&MV(W6)ce-!4_WYotS4uqOw0bMx12d6*eY~cr?LVtb#>gZ^H`V{AxB={S* z%cyt$j`Bj%Sghgv~uh!)*M{2oAzpKM30n-3~=&L?!ObC+-ZdHKf0rG*7M!`JJ> zVaHe3urYpey4YJ3aDz!)ZFxYwDfLYb>AoeIbS59(-@kl4b#9MLft=VJbBAL}CZvGL zbL+oc7ELI%&jf?SVT>3wr{X%AUpU?9UNx*ws;tk>U%2(tz1z07mhLQ!8x8lLt*geu z!s%#nu$Uc&05{0GFiEbZNs~}YVR$6^y?;4Pu5B6tc3t?0YUnh&Frq2gdvV>Pld(y# zwv-^-FexiC3UyAuar);f<>b?!bJs3?|I@vP50|fB#ODuL#~KNMw3OK=!Y&P16v_BY zaaqh(I`5CBD)n$@mVM&-M`(6MigBq37@$f~I=L&z{37-_2w*w6-nX*~9R0n|`D+(0 zUHbmfcktZ%<3AS{dk%dcgy9_wlX+({LKrQ~ArpBRAK_QsQMeC8VQFdwh99w73NJPR zrK0PVh98H}E@E#CtWgpxXlC(NQ&q$Izxvj>&%eEPAwF0B^4CRMS-!M-Inht@*_kK@ zwG~F>)hFL?m>kg^g@RnJq*=CNoaA^WG81-UoIZv9PSWOydn+r=a$G6Rw5Q4mWG>I; zzxl!%IHF&`v1FJtwj`*hD8olFj!9f1V={$53Q5H3s;J4)fr3nN$V%wO#PZ>E5;YJk z88ow)i57su_?Ew^$40Y;RUL)%D6C>vxC)9wW`kw=Nzfd~qZxKuT3F9~$J!V6S5$Hi zGD|Bh&9b8PF%gN-8^z8$IC0r8#5dqybIa!%RT$Pho-cS|A z5?y^7L7sj`LWc0>w*NgLjCUhZP@1#**acF999pGZ7ZP(?BrHfq7eD&6Mz*uZ+`Z_l zItS-fSR)6%a~#X00I49qn^F(>BqS_rTW(jl@s^%aYMBsWa4w_a=CeJ#l z#In&$`wmB+7RdrU7zbUFRYL2ckh_VjXy;~ox5~Yo>x=~}9eLKJa_D|Z6sDP-g%T20 zyL-pEeuBV-Bjq#5rL)#5B>-w9WtGqb3lAhs=y8e?{dl`{Z&%Y)qpOwG+MEk(kaw(7 zhA7XW;L^eHCDWhrqmk&hx6`$iwNIR?&WsoQ3Xsal?!un|H#$JvB9>hN?xfLXjon9M z427TE?|xY|ta;8@8S-veI6aREFbO1TM8K>nz-`D)~q#3}Z6^IB4 zN${~IwJs|-PPh@~T419Ech8!4hy3PG6>)UVg*D2DcO${hg5_rzK-vfNfzxE5g_!_L zWXTkJ%@>p15ATkqiRGE%c{k|0!04U)+DMW_%B!%T(ojMQBxL<%ztm&yKi;pPhO?Tn zWYBoR`x6FOXct+cwl9W#*Rgh*?H7~1cduUW^GS$6(SYmWWO$+yDHl;$BphEmE8^Q} z2%*b;CTsREv#8AwYeGgCl=a}DXNgi*Xxvs2d1 z2lp%AqB$4VU{n-Vzl2Q1=kR{2tB~HL$sKVu2v%*!YERaju5ilr4Wt#stTO%ssU&1V zC$=GhqNUNUfpNHyyG6*x%CJ%I3|V!oxfa%7H0UARAoa~AQnW+{CZY{qu-a`o zgXWdV%FfQp;oGBqPVLk(Nf40sLKH?bXz-9dKt(KldN}~T7x&f5TtKQD;d~2gkS(EC zIZITUh$gE+BaXyWkI0CAu46eT?v>_FYqHbYJAO4~tw|#*MuRkvlrVG*2~3HG3!QO; zKfETv^kPPlfurNRxBp&A3FqFi!mSXQ$0j)nL6F0kTE)1}KMM(AMRc#r4Db=Ju4nCb z4^PyT#6>Uhh$KRvz9Ma$qG(>^hHHf+FH~-b%zH$~YRcXSzo^c^xzAXmQKTjd8IEMo z1e%N_UPZD^Ldhxs(lsB#x#BW7+rDX?fNUquL*Oeab*LmG<>I&>$?KX8QJPE5sK}KI zI-eS8=UPVtkwY>y=BMm5I@|u z^Tykt(+Z9ie&JyK)a9Ocw<<&y`ru%F5OixBw7)TW&Ar+_vBJ|~&LEW%crq9%Cyb(q zn202a<`<`fBd@k|F!Y=IhoRT?F>FaNuP7@Fy-8nTGY+#3lWiX(Y$ghH0&6$Gs+;<` z)@#Ry$A{Zzs9S8Yvp@rJz6^m!+IcZQ>fK8Ce|C?)_WDbtrOwE`$SjV_x6vKxmQ9 zG6vJYB7#~ffxu859(9gR%8R@} zK%5=5x81aw4%H(vw|2qxx*j!6M#5p!(ZOq_%-=d|Fw=aKfwqaRR%1LO~>0L{tb_is`Vk9QLFbcys6WChI)7flWx$#EjXKVV& zW+%wC(AZjTx)--eU;X{h|LnGV?UJ$L>WN$35^>=vj+rB5FF@y@HSlXo!A!Fuv2@;T!2Xri1S*5! zCx(qJC78w%9OL*>{BL?(x}LVL~VdF%*RXw$@rp}%umh{ z5u5!q!>V$*te6?LI>CqQt^Kxix((Z#^BrIPqjTJM911he>ttC)QjOlqe5~R9`$~Kr zyWn_O@>jbc@X)KCFS{mxjFb`tCklvCz{{e8L>7UJM3%weRSJr^Smb$LydxpM49^DB zZP{kuQuneoL$AkZQ&c)^OZutXM0k64`}E@9j~)&*X6YhJl)(8r(eaNttB*fY2j8JucIe+-*!51B>ZpLoNTv#lT7Q2aa^vJ4jE1K)NuoSaMM~JBm`KDmXccI& zhu}F8gDp0^r>cg&SuvfRg{RBQ>q+n7H}}8zS;tqq1(rh)Pw{ow$=uSAQI=KCe03wo z&A4W>COES8B28bV92=+WV05)AG$a;S*{m33w(n0f(ZYB{)R@l`YYwz*$yvRMb2yGY|x=JV}daGAD2m zEb68-jdb#ck^5bkJ=&VO3ewqNaCUlrez}@Yq%Hcoi-Wtj8){3mX09>L8NgY+6#(?R^o?rR+<_}dYlZ>0LGTICQX7QPjb3J zT7c`~{B%H?YdT%uciPNIZD#Q{E#79cvst*jxHwr|PpnJ}+wb*&tM2>Xb*?aOMu24% zEj3y_gV8l^gNo-m)uAvO`^?2l$`W2KHqvqRDJ2w{z{0UI%u9h(){@|&Uq#SC8I6d5 zDyd5zlTO#?d6L*dNwb*GR~P5Y<=|{KJKE@6TlItRDj{Y7)nK{208vduT9AC(>-YQb zI=;GzP#DLhKN?pc$tw6{aaJuCGj|)EDKFt7ywy_hXK@uE0WBQFUY}N<{)5Hi^Ld(> zML74upknGUuyK^npD>b;mc_#g4hwm zY=-sYz`dB3nreA*a&k#L70E)%LM8Mei+-^8uH&m4%N1rVvnr0u8RYSJyhVXk8ow4^ z)vK%;Twb{s^N)mt`Fs+jsUXp0g;a)hJ4*hDn=G9o!LFoYIZvy?z|arsmr39glUdwP z;nGr61TGRe&zT3s^2_&6;ed|X^!UanTF`SnCAC5xg6@Lv;=_f=~8;^CwF z9j1svVx{_<_jori(wtOHLBc&J3~7Q2^g4V6#i3D(h`~i? zB%_N_NB0@JEJ%-WWguO`f-(X+z+EP#+hmcdU@@5hW8QI%Gg^~kqa#RZ3FW0p=LH;30Z&wD(pH*11{-no z1Ae&f&xJ&G9k4ZwBc`T^NT)P~NTX3JAHnOgh?($J12nFY0oIs=$AZ*TZgZIv*61x@ z2zkbWPT)@%#8$DV`=TFpe05WdwLkV3ep!>r@xxtZYPBtf(yOmI%e{~5PnZ`36%-=F zX$YXL3>}&{%b@a|C@CUxVjC;sN_e^#u~6V0U5HBel#`1<5!+y3G6EZ{)zWr7&;SY}xZd5N2gzvU2{m1@CWY`aDPv8tZE6rPc}*B#BO**MpooGck(lCQ zF3ESpQzgvOCll(3+7$a^MjI0Obh|OU`b^p3=)+}rclWn{xZlOWoga5zzj{92Z%VS7 z(c`?T^L1BN7j4Cr!{tB}`wm20A+TI$&Qp*Kec>P-u#9sMKu2giqfqW3L1aW#2F?R2 z9|Qv-Vh|#sD6#*-GMgb`O)m{LR3k3Zr|`;=;RJikI&uqGV-eWs@8cs>zfW}47k7X2 z!?(ZdzW1FUKY#iXB8z|b_hXNlvWA^p{L6fslud`YIoG5Wvv%^DLm|@*#UjliNk`H! zeCUcq28SfJ#=Z*074dY*Di-)$woF)z5JItCEFvtiRS)gN32o`N?8E;e83nt7OS=Sp zEZyx=kpxPqCSA~i zzT&bSn=?E;Q)|Q8YGs4QO$L$0d&+SsU;za(vI^@zR`UF;`5oKwh7rMnTevN)E^{bA zRJajvgYtrOS9CxBPs0m7Y|L=W0sd?J=fHYIc!mVM=$l^u?yvszw_kVrCT{5X#k1Eh z-@JYCqD0qz2`d*J$Jzd7GH|>tTi815U73G`3_^byNNrO_IHEAcb$*hO#4LjqVVcTR z(p3$8q)P4~eWsX#ICV`drc7B60kQ&(S<768n2MGo3}MAgW+2S^GVjxZ@ZooV{r0Qw z3%@y;_2si4pS*neuQzWWKYmQ`a_qHVN5^s9++kfpH6p&eo{c#JRFwpx?q;4^He2;| z-2ea}07*naRHe{n28I?^Y!sVZvW6)L=7ObHY?H#=vMvS9yIN(W6?78ZEEr9ZeSKY8-< z&8t^$A2WMB->(kGV%feY)!nKwt3A~+q3F_vS={&!1g!tEcQvhXTv^o6RClQ*7}=67 zh=gs)_6Qq)ig>I=WQJr6Ax>-v$||dbS@dc zE&@mYXzn?;^kvV&tBhULQ!KTr)HXzid(S=h+*>5j>JwF`s52zhtlIP@*f9a4Z@U?ydUYl2siB_BM*MRRcu$|ZF^&u~DQWakfVPTKk6Oh7HW3$)} zW1F-VFRiT3H*V3t9$E+g$0w%N5WOBr^!n<_(`Uc@a)_?YtH;i}mcS#a{@o)HD|KW& ziE?Wkt23$~*eMG;L#ZL5zNwZOL0v{DGQfFL(JZ~-0^npQi3*A!QCQAcQ?n1LTt`~W zjEhWcqqz0?@~wr_ja&5p1+PPxO->8E5Wb#2|LWveg52FXE(^Q-rI{0NvB zs9UBaE{S|69y45BXjF!e24JTqr{+$dd;I9pA-5;G);F)NZyqCHM;Y(Tgy{h8yIL+GG zmimqT4vUi;Y04(F+E1J?w zrvRjtlCx?E8DZ>k$G4WMaMd8|;{=*y$79_7g_e#Iy^hl2vEcRVkstx(9fDNI)W-t8 z1*ILk*W{~}(2_}pLo=C#30-MQQSt*J8PQVZSW>cTRFW=K4Ayz{g9L{LEgLxG0kTn$ zH=_3^_C$?-A5*L&1{^BAjtb=XD(u%xmRc0E#i6hEm9AE>Nb zhqf`BdzAu_D8EPK!Yj(5sPPQ3Mdt4f45!}8e;VGv-{6_2?jQ(@L!3w!Tz+_`5g9(2 zEIBznHTNF1zq(GH{_3lfcAK5;)Ceh}O%Fw&=avSLDj(qcV@9hg#!yv=auGWveM(=J zkQOr1l%1l$63EQs(U3)e&f z!`EoU)*t{JtRU0?SIdpm{t2TD)SkIfxc##)*V$b>8WY2lOEgIe+&rU_;jkEz8kMR5GVg_K1$L|}!5)8SqUK{~h$y&_%}^qj@T;GGXgbcH z`Vne>?%cV@51#zz?b~WHjP0F2htBV+5l>1v1Ex+iA4cZC9U+c_)|NUTMKXclO#izg|NH5zt`*K-Mj%-y&~32L6aS7!*~eOFnh!FbfyPgWchv@z@pa4 zF)mB{lqwRm^wF*rIAkce;xG@##4s^I7<%+`D$8j`1K}_k4*{#9SN8IvNriQbSYar+ z3rr^&qQ0{nNfnk&-={-62a9AXs~@}4j8T?p&k0+n3x-4XO5CknN^MZLjk7ckLIs0e z%VsDy`Ho#P&R+k%*X#Fi+6}Pk7O~7OOvw6JLjKC(IIz^slawP}sQYwPGK~&gjm0^_ zl(9(Q<*J8ABNXWtKnzQJv~CRkZZANjIx4h{Pd;QO+<&uI$mt|xyn-bvaAI|fR+!w4+r4b zhVgj#`j0nT{oX)u)yvCX1FZT*EQjSEnEyk+7=VH!9ex&Ps-B5sH|lE_p+2?v7teup*v>T;;iZ>UA4n)huH9Yz#{k7b26X z17qml!AnKvjRjd8;YzsPJ>f8GLL*FuIHr#nNO%ugMXKH_j@`>^Jm87LKIt&S@+{%& zzwd37{i4_?fGjYqB5xvAt$=k`faS+XZ7IDA-0dN;DI;gfbSaT;b?3?ttKKPf`33d# zWqbq*yjyG;!o8Py-3_8}OyGjZh7d7!$3T^UX&{B5e3S!HEIC^Zu<8aZY!{+%4u2@e zvoMk6xTq+_ARzC_ODr*h8_&dsJ?H?N0w6_o3#pNlr?A&}3hg?*%8WXeGT^r%GT@fL z37C@4rJ!pg?=xoQ4X|o-=2q{uJck5R>wE=-p#B7eDs%#YI?q;(r+GN)#MOzC&N$_I z7(-;aVJG2rEDeoJjMid0hDa)?LIQlV2Q2jlITK)62)8Qo-j;-{yx(xF`kaYV^AFF* zJ{f~TIfR>_k5L87_T2QL+toPzg?mv7&_o?QF#)6)I|N&&6Y--HC-E3TZM-{n1XUri zDM#LuC^abZg6JxG8*)t|7=ZO-W16W6ur91D1+<&F#E+`D7dUwf7nN~X0?7#*RkEI_(E5s~~RUq(rQIf%T zyT$!4ZcjJAlvmMsPH`B? zNl1E`lcS>&>$bZ$zL{-?C~6e3xJp6YRMyah7pez8LmEXk z5VZOw(_*1&R+(=MD8Wm>k|@^bqxCuL=x`;P*Jn+jt>+V+Mdh+=qmPN8xk@r&>X%k# zKV+-I+U>s!#X>dMXULL5u*?Z4e77aA8uZAp@D=yl-TPnMZuHT5WWrN(7caL`t83U9 zwJ`1s!95$vOAf4Z=*Hq9IcXAi#?kp(^B)4Nxu36{Z5MFFKog}q2Gm`y;15W=e63nL z1#%>S_1$#yOR2}1e|SFf&SMpf(`N)YSdOzy-Razf%o{oj5l6eN%NMVF2(V^RId7 zvgiXNUHK&7&x;{3aqJ`xIPW@n#))0TCPgYw+{C0xmtQcI5J&4$Ej8^~X*#z`dox<@1wyzS zW!Luv)-ouTM`wY3cTR24f=ACvKf=h6(;XsCjx4mX#$U-`fOQxZK`Q*cq$MbcRw36w zdPO2E2l-rBu!ndwiPD>U0_(-sy=h}yqX!jGlCMt4IzB>Ai#s~r7$cX$$K$VL z7`R$o5@6MnUM{18Pe#(uc{Pk_wMSuA0h7oi3hH|TYyE81hmMrpgRXblb;x@m7MMKn zgh_NIb+QUgINiM%!vcl^to4JPOK_}M=Y{Og>RA$eXeX= z>`uebYv+@c%6nT8T`YZ8H**AF6=gNngq>ggICA$v0V{}51G%GxtP`xH7NqMjykscG zDlyS1vm#2$op<*z-P`&i)ICJ~gPvVbRiRUARq&4QDs+$%=&6H88*94vbz^kk9tyA? z9WBIZl=OkkIIo}~<(@o-(JAx4kQk2m=j>Y8*nNQY;O(awSd(gFSPWa+%Nf`zZFI)t zY}Zje3Ssi;`?n)^9}2KuJbkt>pG1@$tDOvt)#zvy_v`Rfk?OvDEdTRfz*_paH*Jlp zl%Q*$!Ktt>XA9nU3M}@wu?7RIt#^lU9i=*dMx;riS3s$PH7suHR26?E zBX^VQptw2waOVvAp&VFMXhYSwvt#ARx4KG6Rc?Dm4`l<48*CW5)h|n9B^(N{Hutx` z&jaic_GyC&_Xp?9Zl0s>K*Le&tP1hEhT{F%U2Uwz#Vt9oAnNOnDyon3+oqMS({rVQ z`q38Rht8Yn?#0Rotf92AHh*9H9t4v#?PGN{7NAUoQ89*>5xulzhl^1b#NXFm{_*e* zw645)KdUN8`dr6ORSPi|i=qFaCUp?~(Q5|mKD3}%%j0ikD8Tvyz=||9HPuNWsv*4w5Rm0&ktDugdm1S8yy+GiFuea=BIm+EbClqUJj}8e~ zbr6(uuqfIWWjYvCEph?VESUN+GQ5nhqxf!MEiQeNLWpz7_DeWWH0ZXo(09uX9o<>A zeOYV;W#Qh(rLhnWg<_o?zg&|`;WbSm6PWU)B=IRtwlmr_WGNHrDa(qIyMe_*h%sRf zfhbpWPzQ70$RE#cLj$?8>SnBk(jhd}>Fy{?9#FU8^>giyrkWxM7{M(v&A`^xJ(Rok zfR((C=HIvXf30|5-aK3N)_7_cFn(@wDrCskq07R%PVa;bwOOu_TA0s1-(ylVKL01c zT6%XlnMZY>5>dc&h$(|Oxv;l7S3h?+{U=OOinAvlwtfYy<@Hxm2z#+8fW`J9rh|P)6 zZFuynrhwpT_p}O)%PXN-Er-mv>k_%`Jt39AE16dtZh;v#zeZpU23Q9>mqm0Lt7l)P zZbmU@J6QkXd@#{i3JA5LtX?=e-uUefTp44HZCl^9mMp6ye$X8CO$TeNo@H@YwZU?| z$+`J80&6J1+T7ocD=_g&rw3eii?$o1eg|0)X8L0?VCAyf_r5UIw zg-6FHzs8j@URzfj9hy(KSb-s_1eq-xnIvZXuWB5Ej?{m|-(Q$21 z&x@ze;X}*J5(X_HnUWFW$b%~w3!TL3ja9^D5ERAs!TQgEwRi$tg~F~pjkX=6?rf9# zp1flL+IuN{*jlwMd3#HdR%KSl?&y$?tjDjPMAwrDu@e{!W^`_^6V0kj$hz2v$guwf zAMP?b{L9kM&c5H4AHV$~yxp2A?1wo(61cfV^NI#ox=+zknhbZp{=VqLmfg`2S%U%A z`oT_o8KlfkW%To0Svyda7FkB6U)-De#W1&x4qre139J@3*1vvQJq;W0Oy>nPot#(j z8-t38H|8MR6}|C$pl9U(qYxnevP< zuxL_8PyP#7z=Kr5H)p%EsWa@SL&IR(zDKHCsvuJ=eY&;kdpjff&uti*e7buvQuiTU z3g5n5yH11aBCWYMDD@B{Lq@5_+|ilGS=vi#Mw%mS>^u6@LBhCgouTmH`QncGO$bG@sR*4qEo{>C8!Vrt?kiF$IluT2X&Uz z$gB9@YAm8^@xjK@`2}Dl5OIcB5yW868Ap?Ix}Ms4b;fcYy;9HnAy>hiYmAdh_-fRS z4hdKgyvIS53VyJZN(pJ1!5FK^xJ?n$h&$0kD@~&`+1_7YhH)(`>B-90`NgYGIIY64 zGcIiMTg4SR?hO~bw8swbKG#(MTTj`k0ko~DoSnUYI|>_y1gx!t!yt`{K17MGA5dY% z>fl$PMG9Ziw9c6390y4)z(T)i@!`pft<5)IzX+;kQw>xMbT!pk?PT@3_tqks$y<|G zvvKWfSP$f*^GS56IXd*W)mKG5$67t`Rjax|gXkwW_1e*wi;Hh(pWYKxQ)8RPcF33T zUK70pFt($%olR1%47PpG9T?MI1K+mvb+FUDSEFENP?hlH5x1b#NhZw@ayd^lKb3k0 z9TpaJ3n8Bmf;#%^o;{KM|OEquo&YL&}?${dajK)sQVy z+zKm50Oi0MgP8`#-CsXhNFohj5^7%K3fQO5$HLyZSuxiH6zqT%#Z3^!e@>@UFOULh z3LU*_jk|T%#&U$y$ca9M0${qWey-`i_e(k~kkxo#4GvjL9}W=?r(3BEq-WR(%VCY= zR0tXh+!M>VPD$v4t3O)-Rc^r6o#{>0upCjzU&0CGs?t6whlAJ~Y}EqGG67n%Pbzg# zcDWo_Bf}aPcR$#Pf&gMZK@@B6>{@WMwLJq%Ee~2M0TBT^G-knn$=i{k}Hb%EG9P?LtFZ9 zGhP+TUSMAkV};g^SHi(P8^_NUgvR9|j5M1qmBO2)H%1FlKBh$x-jyK zq*Z*Wd+Xfuv950&sC&c?WUEa3MU5-UDz&L+FLn9c*zt$&}@`flM5*P!~W2Q1TdP*6o~3Qm=jf}IJ^I_7e&e1 zl*ZJEp3t%=G^HM)E<|Bri%6Syco>yszP>4%rf7P9RrxkY`T}aFmm;e0DR^yzdTd3E z+K9AJ);iTD>njChvAmqO&yzcEfBAlAy-0iwNfHxK1tVzzz)00N`m0I>pZ826!0LOs zi3ANTHZC%POL6iF9?8rW$A5&Xa*`y#wR9T@T5)`S{9$&pomwOO%hx|Xi=rr}T{4VD z5lko`JiZv_6=q$gHNY(vT)wJrHyscyj#mZemlNbAs=YNW+oufCed?$>2IpNUYaHoa4m&k%i#N14P?diMM$hKsz6T;YeJg#6^*3l_>U<% z;qvTsPR^NLCwvSM^dezq0K|h3rlOn}*PBDS+A-0$=AtJnk#t|*fC5Sh1UsI%YzwYc ziS${*2&=GR-YlJaA`C@%EBgMJ4j8Z=%@Ee~&hvjh+exC8FvcE#>m0_KBgIsBwA-z4)uHCw}T0|1FCMxpzl% zT}|-H@*~z_k?5S_K@DSfoikD#3BGi-9g%&45MLqE_@4RYHYCowwg?xH6qqd}p!cCc zlJv(lA!|u)vNjZ3Oa$xw)jVKL@ci}g2f(9{)a$Oyw32Iz3qw+8KyT;-gP>>?GuP^F z6CBQLC5P>x!xJ#P31z1<0Ied+o%UFGBNl?n6BsR0umg85PoK~K3X?>!eg-_cqJM2J zF*>7g`bvcOg6n|x=tnDZOJU7c-c$_=#}B0SMp#2?FF9YDBxQs0LU%M;uY6%ySGY|$j=-S}pLxDH zHoVN7JO&2|qG<88--zkSf=^SIrpvSIxvnOPV*T{3uPZ|dJp|9x=iq=TssLwk!(*`0 zp~;`l)cU_ov59r|^&+u2g=OK;Ta-+9_fUKGVV`K3+)KG?TtM&jZVo1#>WKC7X`+)z zb9#`Sb(K+)1=cI&K|)bg2!Vxrv#xTCG*jNYKS=q`hX=o~Op zPWD*x_;2)Sk@~v2m3 zR)i33P&qx3aKdj=$h|JE=GF5=&y!!D?a&u1hu0cR8x$GH zeEyaAe#Ss(&>NJJ1jF)X6OcMc&)cLe1^m6CJfhloB%@6ZqS|qru#*Ag2pjh}mHTS0 ztLb*aZx?>V0y*Y0*nD*f*eawlm5|$y+F;s zwPR_s2Ie1GqVns$K>}u|s`I(7rd(LQ6PA%$8>I~;IL2tuMNOHHxSTMwXHcrv2s&3AjzxWZcx zG6~M?3Kv!xA}KPuH^97z_I|v`)^`oKGQ#d_hmd0uD4|X!twLhs&@+1%?6%=5)3~9C zEi^eF4(Ga>Fxc?#f9ym_1{ta`WnFSY2L=jTcgYYS4q@Qq0Pr-cSNZ3PfO{ClIi$Bi zHNiM05^4$pSN;brm8sQ6bq|}6$}KOiA3dJ`_fPhKGBcWl)XXUsw?uEga-rQCmo-EG`JOuPX$Btv|uvN(48B+xS6-IiBBdskJ9HrYV9hhrf}w zY1+1ayqfno(>{-UCqy27Ddx50%4o&lF97fquI3OLip>nR((7)0XVK2++g^nb01-~m zk%6J%He}Whz33*Go{E5a|7m&r@o*;gP5Vvwua{4gMUrfM)v``gkxE>wg}VR%2E|E4 zK~zFA4MCJ<9A<}v@mdrWU!eT5(AeN+k_FD@M*0KIa&7o90DGqrtcZu$4hOquACDf- zt}>H8Z+$0>661TE;SvzCi4IRdbU|7sD=~YAEh+u6{Jiz$-bo%D2duCJ#015ms*zB7 zi7_Gnsu9#ZbuLDb_{sb0nb)@!Z^DS)$a!bRk{cTUS-7+ewu4kp06T@!0)=JF`j&C2 zfUB%69-=3>bZ)6}CasT9R?`q)0QJhHHctI@_2TOJd|OSu6Jh}!nHBY3bc8Hb26}rA zE;4+w6lH`!A{0IlllXkcxGu;h09&~s^g!3RAgbU1UlGTWK&H5geZ|EGOMhMM&s*oM zcoRm^3a>svLXlKYdn_2c19niIpS&=20XQvlt(7Y8dwB^CLLqIO`;%aY$pJ$^M+G-^ zy}zpb*zV3xa9z!9aPkLi_njzNz?MjhSc0MnKeiKm7jP8MLTbPan11=X{1kHF1V|W| zGiYs7N%He1CeE=JHrCJUjZM?o9W0N3dp(1q+i;L`l9(ijp0$xmf^&md_i5}2YnXs! z%*SMGuUXyFhr!=XvQtJ`NiS>~8z`a$gO|`4Q#$}=I6xQtus`o`w&Fbb73&WLxoXcY%6^=p|u0_~)UmBvh5z;R9y&<;mqo zcENdW--5%@JxVAXq<8H|4K(gATvpuXj3kz3V@~d$&h_v26<>e^9IzB@gMOlSB3>Pa z2j1Th!}>NpUmm~zFb`MT(+R;HjSyv0o0=xuAdULlOT*Q@_TMGoPD`U)w$gs?THlfw zYVE^-4#o_Dbt>$OV8b1!xU2kVb?%#>zpdusYHQ9Ta!09u))eGG=3GhwCfrDKDps}9 zurva=Wwcu5pYOfj35fq_M|0iP7z*FKSeOuiNTh>!&^z|BZF$EmeF2o5&& z@4(&Tix00Ky`9Ty>n^Nhkwj#S20czLdO}zh)t$uE8*uwfDN%FTI{SQE48e(y`g#UV z#B{le;}jtQRaM1)u-ZMo{LNoh^Jukg=j(62+o==1GQ6MwUD0C{4i3Hx8veng#R&^y z3jA0@0xjt!^yQ0(G)~i=Rb^?vR;A7t)ydh#yX&i?8MfNOv;XE*QjQp{I_zqY3gGLD zCDws=1*Zn^u*Qts8GoB4W~HM~zJTHsVu={8X=#wr`_|a{QQhBE%ah|v-vRfZyq$M~ z+j(JqzgKHaSG50tt2-_#IJ)O1*LkM`)&Nv%WbrNXMW$|>z9)^Zsr*;hww3>5?Ez|P z_ryN|FW#MA?LV12;C7y`zS{rkRh>sLFEXlAzO3Nm2k}Im(<&0KM!3FI2ZnN|Oqt|S zR^QwK0c~g&1M|LvbALxIaZMecy?^oX`fC5^$vmxZ@c}qm`*|Is6uIqG4q{_S0R>uL zUD6Ol)oR3Dw#t%hwfCRh|3AL(;ku; zzJL$01kyt&`ORv$L}^gW1j7A@8@ZX__X_IcM=m1WIJ2~z2endjDOl@I2N^F#j$@&tY=tjsB_oK(%F ziNxeN@hPqG=Q;A@U{=XBjXr!G?wXX=_m3GQ3AB4yHrJ&uq9(`AaM+m3G^_2GvZ67is@5Z<*K55++Ei0xg8e%W|+KQsf3BZ~o>L!B3Pbcv*%LO9&SW zwCxI6vU=UnlcPN$0LPMbJ?qHwIfGn*Kds@@xFZ+nRSEv#!pFm_PV{4V?f?J)00000 m00000000000002M$?yfOrDiTbZ`p+a0000#I|jBoJ?%noY+n#*2K1LCzE7iO^l8)v29y7&-1?bTi>s{*4@1h z*6BKRYFE`R?$4#qZGeophm|=1ATJM~0{{Rp00=NVz_+hEu&;v^4FCV!^McU;ApZLt z{OkPR0mkrk`GWhO>*p#!6aWSJ4eA>t6x25;XlN)HI21TISXej=BxD2>Yz!P6Yz!Vn!B58Wu_#TAKeL0fUByhJ%4ahl4|>!NbC%`TspW z`v9mg;9B5X5MX2ga8xh|RItwh0R9)L5MW>9f2scu?cfk!^g@6AiSd6w{vUwP6#xPR z7yujv0_6+xSxD&ryayQomu58N|ceayM~ik+db3VRI_?Y^04% zEJe5BB`L^XLI5c=$N(8J3MUE?F)B!@0KnG(=i$38inSNh8FHJ2)YIS`*m!6Q-h?oS z92qW3ZrU}rC<`8oO~f2;b}0y}+K=-*bj_hj6apjwNl5?<0Pep46aY!$7aq+ir{sT` zDMDGh#vQv<)wLErX9muR*YZ(CA`2j6U%nr)h?O=HkoTa2LOgf0wDWAAw;lF{APH|&QFl0LGn)%CA_6v%0suggN&o=of4O6BfQ=i&ZWIo zCwVIhqqz*Csfd%TU(#q_QzZxp_&R^F5DL#T_$B2Yj#-p|_jz239*v4jy2(^#=RSc^ z=A4U`mF9OpQ*|tn-y|D%v-q)am#4j*Ehp}I_#6&zJ6{#C!juXn$(JgSM}H~AmrTVD zoY)=|CTuEVy>3$vyP;U%mNaIJe*77TIxHw%KGC5nG#)fwAm?}HX?v{bjWefm)2qqC zZMSu9u9(PEFlRp9r(qAbaZq8#?JB5!{tmw8ngpx?9Yl63sE?S2$@r*rsx_^T01(0dgH|s z(CT+|%ho6)Ti$2H=X^y$MV??glQg1o9t)pH9X4JEP=V|!grVa2F@FFo;6FNmN`?+b z0zhSPeidMz&GF&qlQc}(Jj^i5ExuD#MKag`Z!S)YzRnp zOE`#r>8jnceM%Jnxy&CbJ4897%hTFTH4`cFkg{ce`snPI;-2x)E$79_4J#v|)X`Oe zH+k=T{O0C#m)^FKz4(A_+CrWU29K6{+F@#%0)Pg9{t_kt08wYvrQTbi@2G2)2=5jt$ngLr= zda<6XtaI9ICFSDgu$gO*UXDj!=%pZn|AU`YbYpH}hu72jfaC0jSD{;n zMioz2mFk&TxQPi6|0M<3ucZSJyGAjPjusr3?t)o4>dc49F zn~q$OW2_ylQmE<>Wc#+|+8&G6O@pcrHnkX+ zw}0kZWZdQQte52-{SpG8iAchHnHMr)UFjA>W>nB%O608P#J~D;tC<1ax~%HiOr_mh zUpZuILDBR+2TF6(h#Z)e4nzy%c7p*;I|c7!3Y~doYvEe!jO%+R)ZFahmgU1o?2;2F zlOrU1g;u^i!@-9L3IOClfMcT27xREqmBW+AJ>{Nner35PwF0B7gEg}ECT-O^3IrW( z3QP(gqM7WNDKX5lcvkYVrwW0^()n1$SdqQvnoKot&Q^z+yVCsKot17ri?h!bSZnkA zj6M^HuWh`D0RS{`Ntmx?0sx?q`?&G8Z2djB{q7m-U%E37Dk4gJRTa7Yaj*z6xwjfG zPcmy|ykcRZyKhqG#~)i|RKbxwajNXKWx0xcl29Urd+j(_*KbTt!LLz4k5> zfn0^Z(&%Wgfd5fwS6|Jjvs|vc^Jj~^3s2qb4gZ>bLc$FP?M*&C=o(_4G2h%C`g8Q{ z`yC_sBbP&KLS&QaTYgby z;`LhvW_K7CP_e{aJqZ{I7`^}dHjdo{w$vQ0tV3Yj%JgFwOQG`hY`zp zL>5(}!x?ja$}@Ur5?)G$-(EYn?{uI1rVoz~`Rr~g)>Ab(7SoC&HAU$qopKlxLcR99 z40^(jvJP{DSMC^7T+skj6aZN0|9lAz>mA~D)Aiwl`Se5WdA#EZsV@JfR<|l>M!=sb z*7*4}AtztFNTl7une4a7b87QX@|A0E#e&<{R^;z_wjjHZ33}x@jpBQk3*!V(vAM%S z|BBn4MLj6Zg0v|S02u(FAOHZQVFQ6Ah|U#vZ#?&T^ut{WLLUE?&&a zKioUr;{|{VeHmv*G$C{}0JyPKl<>@nhe5&Z{P_Xv#ops2?j7G;R8n1flxF^zuYpNs zp6Wiq+b2MAKi5LAW}krjL8;Fi{w13*Meln|G*| zgOF-f4VZG-X71kVl%ju*bPfba0lt2>eRrI{ z&S}43E{zX+vO(M-g9dvg3xU^>MJ|bBUfx!2Jadp&_Q7)<0%_8OZlz4JYxiZaVK&sg zWc14`Pyjq{0000ifQ(Uf_?~Y{=$4;}Daog5&1rjeA7fDE#L|GOgjpANrI{Ws5&l#k zjM)=8Gnb@h|jebt>eSh62F;e#H-8mJ$GA?V5|p`-BuHIeNtF$(#V1s*xds4Nqju z&N5?Fp&B@<$Bs&xY5~evsW|Av&&kEmYq1xJv~14sc)u_yH2u!hi=2?5f|rB+QWF3~ z0Jv0q1ONblceSYK-FwM3@|t#tc@AlqFLe=_{zXag?;qJ5g!FtAl$NUtX6BksytXve zIw3T(gQ2#*E!BM+P#-Q)g&E4N+dTM7BLGN{0bj@f;J!?D$kbWWyWA#K@n)Sk;zuGB zHLh)`QJ78lwE7%uod@#F33?79&FS=<$G|(r6;18mD-H4uN#;M9St%+|vFLM?sg{qx zNWOv&p)Y&@fUE1(L$=;VUZ%_T+?XV1dV=&Xa|Wy+>B+%%Pp|05{pmSGXL_9jS{C`5 zBV4yl6^;l-kKd8KTw_CvB~b>=DD@bNWMuPfi-hpwuwTJr-+z&U)oRdA_#(+MPqKDX zQbDCo4#-2L!Hw^^DmdySD65O-?7v!-r(-v3GWuNTQsBvHHQi3n=%PD{AF1*;0;ddI znmr%CoIW(nf3bZ#rnqtUEO~MtC=*!DkQ+r8=G`sOu1+0i)-GVvrk3@BBD}6ZcS83B z8Wd9X-Pc=YVg6BCmAkOwXk!=VIaVd$1+tv(1c3Sy2$GvBnwmtpLB} zgM`GvT@ak$gv5S<|0iu@_=-Eg!5{(90I+ZWo4kR6qe7sdkpdynNyu1*gq6OLv#^O^ zh*ErIY%pJW9N0JT56rztz9S-6#B08hTw7#ba1hw{4}WLMR8-0xoW1?B9Su#sWR2`X z9`o@1C@#ro^I5*9#L4A@QDlZa`#aY^2i2>C)92Y_QFJ0IJYvobtSTQ8E=rU+^({v= z%IYOnEtxBvj*IF^HAP7Bpr?Pctme*wt`E^3xor~LPw~7bPMToq%*um(jWCg>7I6bAS^mjJ4B=z!DxP+pT`krs zVD72yTG&F!Ft>kmYP?DNC#BVn2a~LYKiSTLMj@Nk@M_sv_dIT|J-y>C4vzA*82Bbx z=sJttL`D-M%;WgM@{st5A8lo%l0tM0D*^A5foXwCBrJMr9$*?0=Tlu9)&q zd`y%+Zk?t8Ln8sNA(D9X@ug$s;E_f$)iL*A5EtLlnV})3*kBIpiz!$#y2V2kNqS_4 z#Nrq8C^r-g(Ft(YD-1pd*cw)Lu0 z(P37Z4Gq5_L{~fbvs!wL-{#D)inWhN{O4_@*wy68H?6O)#VlG9*1r9_i?|aL9Is-J zIw6dlT$knEskGZG7Kf=ZcPveDX!?$_q@s(MdDz@TeJ++Ja%0-=7U}zjT#_`!!}R*t zk*Rvcjq*^GdgTmR>;4Kc z5_Xi5Z?cUI^x;mpwL~pP^{f*kD&(X}Q!`lFVq0ONYAT7TdkGs&MgNZX_9Cz^^?jqu zLSl@@-Ukc?$Rl{*Q!vlcS#XvGjiCZa zIClk(N_p^d_S+9swKmH!iCgd2`dpJt3dx4uh6KrB?Mv83Wj46&7+J5JVGZFK7|s;SHW#+z zYL>|O7ZszCXqv`)el#_Cmk`Tzh)32nv+b+#(>}%wWRenVmP#!_B$u#Ol@r=;MW(}# z&k*Nv%(R)z{pUo)?5g--unq3ijhHNB`cM3*v#FrwNEL>{xJQHpi#D)A67TWdHab!4 zVCmfeQ?FA;X&{{3tU@F@XePWsNV$L@f-LfoT>Rl^ixM9* zxRi(I%uhY1r;%P@S5rm62nxbDK8UG9jT~u-RZ88zH-So*J#b* z2{VNzRAGPL;nj}{Zd_lO?#zzD#4=6u(Bkttum|fu0Y&Sm@(J<94u=C`L9OqWgZt6j zF0sT6BN4~%yikhCO7Zcb(nu6vvY`<_Y7&_}>R|B84dp?1%|dJI^>*g9+8}5h6+2Sl z!YOGpe)6?tbsA-m5nvP065-kB3lfo!@Z|nZK8vcOob=1|Pmjp#fOxo1j?Kucj?$1c zg3LI7QcTY?TQ8YZ!xZvO+~VMnBz4;)(8W1xx$Wtzq+n);O0U@4pqKOsK$`{Kxm5|$ zhrbe(fCPc0&LwN=C4@^iNn(Gl>K~cwLccrhJqtjCg7p%0S-N*f@#AmEv_Z+S(nIqp zUK&;6g=Q(0=sSius|5d+D`yh6299^1K%F9~YtKJ2vO<`)@vQ|6IPTwiOzY>(dVgOn zb&lsU@0+^T5|M+jP>l(oqPu#;#K;oV+)HjvUG=ak*pg**&A1fg|DL7Up|~+H$F6n7 z+eaLhkIItW=K%XE$|&S=K5hmFFy%>KbR`Ial}%4km1+cN-A5zBNklV1KxV4~iw#ON|^bBHuWUGP>{#+ zA)st__In&v+vbd3XiK<+w_#17t`v29@GqTmh^QHk=94WVKVWrA8YM>2kfVa(o1%ga z_f+JG^|8k{i>jJIPJAcCX~5Yx{WnKVFE|qA-G<45@XIQ)!tq)TgjkefOn#AQPj&K> zo*Yjlz3mm4x@?r0?IUh`4cTE464%2Oo=HwgYq7jP71Yoa*;sTHVS(p&6pcpAz5h?L zZQNLqH*M;?F6Z!Jq z#WV~yX6AE~)X^cmR)@5hl>OnGhc*>Ht}%P%(M*jU8I29#U#*F-)F}q7Y7ebz$Lqux z>yAFq!`_7#8S_d)Oa#qdWDCsN`^X5_+1YA4`u27M(vF<}*{cdEv%@EVZ<9eJY4sBz zEp3w7nc>t})`wjS#hW+q@*sSGb89r+CeG89{&h zDN*pnx56#bU}ZgunLG~V*)F++0Zm5Mip%7#cv8-Tnthv0s|4*Q*U-9gxJ3RFp;{MV zxoTF-5OexS2cuzAMI~K?eYJfY(w)WodnGow_m$mRSNT8|OD_i(3`6Xw>s_#3xQ8?w zk>G_%uy!gPk0TLzgxLgQOfvru3HhorfsOLW))f=);Pvbc?lx5MuJ}yVY}gwQKlTKJ zPe98jfQZOisX=AU!%IO$mY`v#T}80$3D%>tjgM)R0p6Vbhu`saCeJQ}fEh#jo8H!q zf{JlWj54D#yx9%gJ@98q)5?q!8B@5Oi7p$1JrBXpz0LZIwKuL2i_2BzM#u-#@nqc{ z$5F9P**3GrzfV5ed|Y>KI8SxhczJNJ)3>d$3ZezaA`#EugVXNO z4s0^eYzSIc?b7~x^HZ9a*spc0jXz{S1>nA)$?unceK`zH8FYjb<0i^Ba8KE z0iB_MI*p9_d)DaC4cj&-9Auw%Di!Ihm?*2TxTjOjIH(h;YXpjP!g!38P)r&8^FBYH z*YxBzhBNqxo7i%p*#B@fF^oP+e@naH0iteq-kF*WThtMlei4M!M{`OxRFtfI`Yws4 zM35s*NArw5?9ktrg!Azr+P|5?aiLK_M2RB_=jq=)(IOqlC79yQ$yuf+HubjzjL9Uw6dK>|q$p zdQElA5K~wo$}1`kZ|HaOZ>Xe}f6h*yXzbT%Bm{^Vq|aw9-xhBTN8Ja9gRYrvkK@7` z2JZZVZEXi5Fb9dNX1i<+9q`%8FP^8!>}(&{?Mx0Ok7a{v7AizdGglbgVN6=a6~o_Y zU2wEYQoATNz&1vA@5On;! zHmc3J9ttF+?E3YZFrm6)4UQi)>e`O-U?ktxU&yM1X-kGnt7e<(T~59DN$FozQpPUv zACA&v2SNINIlWiuT{OQMQ16s=G@6dPwL+?9&}NQja5qpl7Zt;l>e-37te^Zq{|!2b^fHwpj@0vr+o8Up;=SGng43m5>E z6dZ^mtZalvLdL=>q~sKs03lMKQjc!jJF^W*&USVEtMGp-KTv|;H@e$y{~bjBjqm|P%Dh=Fn<+r#>Wxw;>UX8jDD7Fq^y4#ue6+o^} zt@;M~v=sw8Z`qOzTzyQMFzwrfCrRIE0!;;FmKdRsH9wg0a;0xZ63Y7dlfmXji6;4ct-LoyIE7r`kv}9I5E!X`TD zOMCl-FQ~I@l+qG8dPcAI8va94Q}d~BUjfBWJ?R-eg@{RgY@`a)&FvFFN(AceICzzjr-~7oVeYE?LtB9{{5sa94+{I5QVVnb?nC4gP&4{XU$4rjFv}Wa znV+=?Y*)_@qbMz)8GY1Vp-f5KFnF`wx}S#LjXF=Z80#`w1L6%0}mGvyv*~n@QP(v<{$Dwfrv@bVKZ-9P^V7a!NDyv+g#|*s=^X z*v_$X=uxS%tFW)KL!V$bTj-Ls8613t8^s&Lt2_qqPN!UDEwko#@>hs$;wL!&wpH^|~VWHHTUWVB`2+?)Ar}+a@%f%N3O7v+}z}PVw&XxYD&) ztG~Fb#_@x4D%ZJpReMK>>o%Ny&oG0te0}bKM-ruMITBXX3-eez5jYYT?Y|&5PJL3t zT;zmqDgRc*d?hGsf}*Ar)4hghg1Rfa1yiIe#VMwU&F+O;S4{hR1PMzeWHK%X~>CN>4Bk;g;$r`Z1Hh8g$dn)(HOHyVK@ zMWCN1ck4B$xbATg`D!|xy^->r)vNe3rD1almXfy2yz>-=^Y49358t#Wd95dX_FMJ) z9`P<81f#-~_VB%R;K8Fx*6(tUUkaY3m@0~;?CMI9d(OVRE>-1EQo0pEAijpO-Q*OO zjxi{d^rrxE29DvQyM%sOuPP&P;_?Ud)v>If44!c;FUk2nJa|kQqmC^G-n2e8FJ&}D zViM%wd1+w-P}1#!2?_`{Ftv*@aHTSY@XDPFh3cIA71Dq%=6#1gb4<*F5<7NKiX zqixrSmKKt7lY}yvB609Iij+xP+mS~o58~D8Oa?)f+eB-*t)nS8UHa$fPhPYNnrG-W zn*VCA`hWMBKOMDqtCjZtj;etZw3B2=LznS8o^qqq=4$UKsKh}KX~;vdekYYRS|p}qm{Bc#!&q)M2CZ!)q)J!Fo*qmJ-0xmZO}m^*(FIWFK>7c z91Foo42S3%@kJ0QI*I7ir@TqF7z=JpfgKqO&O$8qNR9zTkJY^)GWrwnPp#!QPi0TI zM|>zANf)b1QR>)|Vb+Ylngx_Wcv!Mk^B1A%F44;^?MV9ZmDrfYiAd8E=G0bA%n zkAg#?vJ{cp27|Sn^i8tNF~<2VuN`t9L!@EMgbF+;daoXZgWYWep0BWrWLOtS4e2 zyOx!qO2e4(YEU&XfzlQ% z>0>V`eyMNS`06T&traM_@#yoOLs4Ycr{mATcdK&LSG7%Ylc?TB!;m(Rcdna}?+gahdoxaw*Y zicsJS=Rc49RQ1MOasLs3CWlW~RTH(tV{j_b!vn-6_2o}}`W4&8Y=*7CvS>&#GZV4tsW&#!zf?WyrJ~Py2Ih^3hgC1VSao^@jH8FA80+1WZ$7v*{W;}CYXy( z4S{ONDsKlf+xuQV2Xp7v?j?)<6DHE@gsY0AK_I*O*J{0WX^Njx;SpEiop2BBAF;zq zCY*+)e5;U3x3mN&)2b?xxOcbyk_XA4eHJQ*c8pnqoW+xMR#!#iw^#_xB-(>heo=l^ zk?lu4VJxOF_zJmS&B%MU>t{IhuQa6@P3oBaO8F|xAIdhgLvICjV?&d%R?*-cQ{yOZ z13}(}8cPbOL{j=rTDj@%7GNwF0nKU)igO7T`fhC#P2&0RGPa@A4PkeNA;j<^SZk$e zf6)jmgUg2716N1As@nste{fpY(n(dJzl596%zH1}=51L8?XN%%s>_S$Ch;+p5NbSa zLM!k6-Z(wZoI=Hdt85J@_8opyI$YrS1PmMy%0WDfF)myqPnmODtHOnS0%YZR>@&CR z_UlxO)YWEbr%Zn~v@g->t7Jdm@0!hKT|gZVd$Sahs*9m6^|g$}(S|8l6ED$Om5f@H z(^hTK=$b1pC>p`ohgU5V+ULNwmli&6g|Ks%?at>*<}bcc za}-L*i1^3$*_JKfS>L;TrykKyLvZ4%S4}+bpG)UmY+P52_gB|0Ir%Wg{w9`buu=%< znr8UBs;*SKOS#~Z7|k36iK^Bh5FMfr`)7MlT#rdWRVX#2sGvL;vBQ6LG!SYtL~@H+!hIewk!W{3IzO0fKZ$Q zg%S$tztWzoYZ4`v|F_*ONcsub*`4#F)a$XNeiDxQ=H>8!KKUws9l(hE32^T8n(OI; zZ10}IQ{hh>3$S~P{w+tV@h+nWe0~)-guQljB~!BX%-M#TF?#$2oM`^p=p$cUF|HTZ zaQJ8%I0bhLLRRq(t_f5sky4e_^!HITz^z~SC)W=@9A7=UO& zSug8{Z{jb=u&67kFx24mw~G85?mRyCKKQCYpK2`XN4>?Jr7yJIPd`2uHJLZwznTZE z2RcZqteCea5AYZiy4yU3W3A4Uq4w_gvDJ3C1IInOjrn#NS85uW;|`Eur|eCz{GSIl zC|qc)&Cb>U%zkG2F(}5b^GJH4KiTGc#`K2=3Icn_t3}`Pjo1AS6z+fh(y4d$P)sge z()^>wZ(nL&wRtCu$J;-;PZM?d2|&H3LAkOh|3?lg|J{^{EijjPIJ6@=rAj7iW=Ej z{GUbzT3!Ecc5?WY<~?ToS&FiNTXeE?csBa+ASo$duO+_I!uFgc)53`JOCwJ?mUe6fC+^W5`? zr|{#Sd4xsIUR$7m?_=F6ku3 zS0@1$LP1Z-R305;=6S{?|EIi4|igjt|Te> zBoFyRC=kd8^-n?$p%I&g(!~m)%gW@7`&7Mi&?$zJ{0}UGCvd zW{XoP@|$82Yy1QR4$}JRWN_LEcfeh9wX()Tqw-_!sGY-9Jf%QUMNjmmLlc$R_LrwH z?bsS_&ag8IP~Y*qFU3i&x0&GRQP@7q=`lVVPxv65KM%6GLpeP|P6eHfC%?+1<@$Ak z>rJ+KL}SDPchGdad??+xQ*eh1m~qqQtNVbQDUgBSc+s#)GpHqRbn3%`f2R&xP?h_Wp`v}{6T1_X=xADBAR4Qfqrd}(LwL#}&GVBy zJ7HfCFht~o9K_S;D{j3bOhqQ3B$80YbOg40-jw)g<_Ew+pf7q#~FEMzc z2P~76UkM9a^^=JL=;oJyvwE^Wsx0VD))i!SWNynfmm!iNypLHHS7|PH7G67>qp_bQ zQs;mQn^(_?NS|xLv>BPY{G2s>NnC$)K!KZ;9(ABshZfTp}Lke1+k*L zL$2IUWlSALv9wO+3i#(Qu}|6x{zJgJ6itja|RQKKhWP?^!gGlrc|v8 zG8{}FBp3Mh15ZebI^BRU&2par5m-8+3(6R_H9`sH$P>CMf0j*p?K9|bM+A4^Q8M3z zi=*>cwjz&v^_YIVa;xe*!Gb7~(W29{a1hIGn>+k9_ad?4D3*jFl{HNBjo-)(5?Sg- zjbdjL`z|>a1i=q&6W}~!dU1r#xT<^X=!KuuuC-YvvNNMxH%?CY1S6e3f4t+)RI%V) z5Up`P>m5?ONr4MXRX4!p7N7zONoTws=;W((l*1=Qd(LacwST_G+^M;6)+>)ekC?Pa zl-sYLLIwdmB3m1Gb~GGzAdTUcG45!L^dxapcJ}pk`(X#Uwu9@#(h*xm)q+A}vnaj% zuG=9DV5%+4)-w3U2}+^4Q&vP;vxaMI1fh!b zHaM)z%w!Sq@N0RuA8FsvN`$^E=n|Xfw4RO(vsLfVhjDe&aagK*ZYZ7g#8Ps6&#)5C z!U?8^8Oc~5#ZIq;sXw?p6jv~UPL?XeM_Ah=!WG3(Lpi^_NuJ>2u7I%m5tg zlnYk3;e0`K7#BQ~*(;k4<;K=bJ+?#Jw|z*Pomwn^37s?amG64)o~bOz7-)A76)8AR zdNwF!_h@hO;tD^OH%pc>rNMGJ5_jnRA#jMd@y(ZY1NVG-wf#&qcLcJ`BRzt`>rQ-) z5$Ohvi{>h~WNCcYyBFaCAR+wjsJ%)7f^XBPE)Ra8mXp!6kMai*FBUX?ymF zJj7XJ?b@z1ik^C>k|kHj{z*CcUS?p1W1Kxfw+RGxdP@?SjPJ038{KmtnP8|P9$&Za z|AXeI+S%K1V;NGm#?I_XJTdb>Q-mzPHl~Y3GAVet!*tr99v}%qYJcyYC(+r=_*v3% zioU~#$t!yB&G2`+$OeIMr0BNZ%J@z1^J}F*{WZXVq<2cmDQ8#`d7N!ru0P^jv;m)L zIDHMJJ}-2OX(|*}cGIbTQ`*QoBeyJ0a`#=N+>3v$nu#AsAMPHUa+z}r&w0ctaJ|^9 zb&Jrg|J3H2FRRrlKsBUw+{y%Es5K|J;2DRz$5}->P1f6b4CHzYymp9)|F}x*(H0rq zQFb-NMhH`Me(Ar&?H>u)L+<0EY}Sw$pnj zF0w+|)=4%On}3km>PLA&d*)>b_c|!W@Ih_NIQJL;^jP!o3}f;nlds3IO$9Q1GvDgH z8-dMQEBN_GC=fAH6>A8ZK@2|T;s;naosB8T`2pwRQl-A}xxC7F#Gpu0D!?Lzf2ZSB_k$0U-)pOs5Qzh;FSykslGtH?d|p zkrpW6Q(7I%_ME^iMNRcO`^FY%9D#CNdt(Rd8f{)y6&s@RDvkX@cAVpG714t`%i8rv zdL>WfUvIRDx-KVCmCKB4+JH4>IN|fn?E&0h8Rp9L6yss2piD7DV57t#1w3g<;Q>sI z@<3JNrI-^u=C2E=N71=A8Hk9#BWoB3w2Mny4kqj7dSUOk7{H<-@}Qs{$EiaUBL9Ka zuoXczCiA6C=(S-2lUD6+vru$4vwN1}u%gmZgAWp_wOj59mPYVz4&2|y-$X)uv@BVsUMfOs>n69_ zPHg7Dcs)r9xfr!xWrAe6Mt9&TJ?Kom%)#J1Ey!759L?U89i3UU#KwDlGrV{|0ljy! zKTG4({@y%#1PPDIG~z;fuE}q9uKFdql6UrZsabXP3`n>;zstHjgpjMG+c^*eQ)RTR z9OQkwM7DU$q@k-wf98`H4_fr`2i20{*z%_6jIy6>+vpZgpz5@TqS{|pY!lIj(4qcn z^mtF=8}n4HMf1=9p53A?dr7I;GAjdEO1G*!ECiP(}!3mF>TY; z6Uf&vvc2Wp(KF$(&2Z!2L)^J#t9N70aLPzTd{HA$^`Jr&5zUw&b)<1(OTUtLA2^#z z^bX%uF3FS!Yb$3r)|=nwMm5TvQ{WT(&Et-%$QtE>LkG9!0`m#Ll@mV?G|zAA68AVX zRB#Vw+=|*`S0>JkgU7qZ`FHDq-Fj4Q0i-v*7800)<7V;t&U#kX;7KB`UXc(=cAk@< z2OCcGqYzU&Kv;{S#l$Ri5d5Y@ME`)WaWZ?-aIMr zR@{blwCWLPcoc=oRMPaCL3AkiCVE5|?gR2LI>0)CTSL5t`@K8fJQc34;7OF<)(@@5 zkG3X0t_M0ew74e3?rlr_*fXSb2b-*=Bw&lKmWj~Xi@bUY7xtA{u%aS4B~}P+9`v<- zRVg8x_+@$P9jT9;&142bDKV)Be@k<*`Bk(coXh_X9jg2ZNWwm6v8RuM85|es$UX8D zFxq!vRc~7w{)6?NzuI7iew<-YU$kV{ zz+G^ov&V_%=FWsJ33iU0>csp?q!rFWirg52y+3NzHt_rkr+6>^>GTDq2T2OxM|3+t zl3XK*s`rFb;ylO3a6ZM1Yx@NqiN3e_undYrhie|-D9(@c{j@K`TdS?iuZ_?EUu0{7 z$~#48O{MYpQM#yg3+IrEr1{bKoqgOmPGs%Zoe*!jIdkcycI@C+?PA~)@KFD)Xq)GU znl0w0Q5AnNU|NZwLskXnNW0EsSy-W#n1s%rpQ)$QfxnKWb^Cf5)m2JhP9e0yU9F%$&z&xIsaJe zKuvpq0g&EhM*WD5hBvvow=mXO@kw+Nhb&!fx+gfY#&dja%)=-hTsbMX6g*@wF{gF^ zqb<6?F6%&}K_#?jO_Bk(&*K{6#Xq9pd&N9uKcc743wC3AiVJs|Qi4vJdyvcZ@i!Ag zMcWw0ruiakkLxw-YYR3%Bfch;toG(A=dogKk2Ht$%h`$2$~AFoa#MFmW&|1xvs;&= z?jVEs@0rLMS;4K@X>ujI+?i3kL98||8UNPmH>k(e6S!M0$LsZ~-1}JweAKlRTUJkY04p&+2jiJp1Na?sbsH0gW^l{HVtfBSzU0V)sewlkN*!LZyna;8@`Q?7$7-f zFp)-(7%)1VbV*2eH&PNxDBWEW15rx4dvy2cDIp4sP?4U}=x?9z_jrGQzVC7D*dM!g z?|F7TcU;GLo#*+?kgdHB#$?I&lSFiqR3(`lb6SQgx9P5nwkQ(X3=XgX4zfHor@ zj>YvfUOZSE^qBs;jdloaFe1rF?OB35G$b`FK|l9_MEfc3vG2$-e^`in^uvc%;(R~| zB(0s5Vtw_yG8!w2*|OBi0^6He*yw-R{)o3}7NYUC<7_jb*uvQ-mQ%oGrJW$gW8wSl zGm8DYSTeu`)tu}#$Nb0R*n75LL@Me=yX(!9M%;j@Ri=}-Asf)sGAVpW)O7F|lyz=54Djts~AW{<}0vU-f9rU_?MNZD`|!;vZ~+7qUNTajw+9YQ>+pr3u$V>duqT0_x%l_gw=; zk0pK=I{F&9gQmAf=n>oVYd6Et6BMj(lC)02$}xp3K79nKF>8-$1PS%=_0p1YLKm=h6O(fc$k&D*!Apv#;eyRM&ba#f$G6zTj=Y3nPa zGnf6c>r;Al8-XlrMV241O)1j3-VRib-nWj$Nj9SRMd^_1hK|fSK_AK)PZtjf(jjO1 zQWnL1ags*_k47HVUcF|#aLgWpS$@8% zzxIejGrs_!Blh*pRLE*&9F;5RlhS-~A7{jN!5p-J2ygi5Y>P+=SGU>r-Cu4@BqgBv z5OCij>?cAa{Q{Y`LJT-RVyNF<=tHJS?%3Rgatp`a#_8unBx-J_Y7a(h|FW<*PKgem z=LzxW;Xk>SBVsiwyB$%y?0m;>cGG-`L~$)i^dHd7_mOf=TNC}d$@bT-IKXZvJmce8 z;p#T`4>*Ovi3G)%&h}otd<}-?52i@}?hi_~-bGD4rLG%B}N!@-if z>L0)-zSz`Bh`0wZ-_jC~|0R;>5p2)M%fnP<5vxrla!%z6_=3d~Ht#11XWEK2%Qi?> z)lUjH!=|A<`AIt?qF7H-JCHWth@6!+M&@|-CFcgTQoufkKLQit^`b+2P_Evj2x#>+7)E+oh8>EvE7mOGd;N4xb{)kxp=^_%@ zVKKNkDi~AOpB|XcY|VneDT{y67lH#L7%K8!SyOz|Q^XS<3Q@k**_~BpWytN{&Sl+uH<$62FSaidklWt*<63u4)UVX0 zk$++{d#2f^7=6(j!mn$UcP`$M-;A|+Cc6$l)0WDSD2PLF2l(2kaIRUsy00pIo^r-P z*-L*)e=R;zQ#YLcg4-_M65!RwJ6>{p%tK+knr1)r-S%oyGBDf2)R{gQJ;WNV$=c4SvwihQSUoMt%vDrQUaeEvb}o!G6m+ZJt}eohni~O zRz2tkXEkYYO6_r4M4~2oFvM$Bzo1z4?h;Sg^Zjj$)%!-uuyI@CEf_iXV zgy(ZTzU~I3yv(SG&B(!54l-5I?vNlUnRsZ|oswfq4#d8=t9>rg*48xeO}s8M1;J&m z82)TmE;&%`ybw=S^B|G*vGj=xo8r+w0GJ%{N9?+>D%-ipfp{ENdsdSD6<^4zD_d#b z-Fqk~Zs_gvOB&{ox32IooD8A+di0B+le)G_!%)$=bSc9x<>fq7pk ztxj(X^Q?A51@_qAOF!EF7NkODT^0XAHaaB=WClbw-HyluySGTfceMu=yy*&I3*Uc5 zUCgpO*6DSoP`H4B+IFp}y1z$i1AzAL0thX?d$$tln8p#wGYsyTF30ZFk#T!ly%{sh zaJ}cE2y$6vph=-+7h#YVy@?eZ3H=#B9PL5U;mm9BRw9>4_aJuDV#Be~T8^g`Tqh3x zu3OlNxXCI>eQ=oyj@4Xu^WYx32QJ&==`h1lLcWMXBUCQ;O*4@%j$MZ zH(K3D*C_Y49p0i2ldJ;h$6_cli=UtOx$vgd)wdCyTe&Q}rPDJe|08_6^flo%E7^mR zKQF8AS_H?HWEYPnXF8iY%XF|dh>6usHEN%lO6H!S_n&IDk^<0lh(}-7_1?H$SaTWd z3d1kte2()I;!`;1_2EBK%vGN?~ow{oD~`I&?jT&Ysx z1zgLy#jNAA`*sdfZc;;F5_9EcwmX3;`(t9cebUeCb$dNi&Qe#h8|y>0o)!&QygKqP zhZi}!?dPvqBZ#qRfw$pU0T&^R6;AENnHxPRYdc%tB3JG`=cM@JGE(#KAHbzir9z4J zAAoI}mXP*ZiE}kS+vvhc3sxbDz?;Qbx`~6Ul2!`_fh*6Y<5Vx8B?pP!Nr%O=>O~dS zGgJ8ap4)2_+;0wZ8I+79emg$XseL){C(0cd)AJ7yb(091qW@L`43-Gx;Hl|=w~z#X z3}n#R7XZWL@K!J5I}}~Cm78B)h*An;!ESB0Y7h-MsA_+w&6IaQLa^w)H`xgXvi1Y3 zlg)UR49&jhDLu}{t9>QEl-^@yaE&!GsAU>fIEV7R@LJj{1^8E$B;BooU?m>0H8~%^ z1r0K+%FSwjmPXiNdpQ9a?M+AdRSDpUDiRLHJWefzxc_9mJLO@CA0>iW+nmBYHmt42 z)obpDrUMNg_^kK0kLT(F{xlbz=Q_vC$gO3Y3-~rpwWPHU4>Tx7?am>Z)+KKg@*`II z^J49{WzU*`uP(AD`bC?Yq$M2x0q)(7#eb4y#Hp*&8n<8GDY? z>iw)Tw#t1zD4FA5w;~&5=8@Rz2_RKH_6H(05-B*Ke#0isq7G2Dw}N>GL>P;N_kFi;p_a< zpL)xsI(MvE^GPX6Aks45Qt7KK^0!u@_BNEx0mnRIHYvka3FXE&^8O+*=cVmnN-p1T z%P36>CXE`jZgrew4$i*FN?}}A*NJ-Ew??Q}O$pZhJXT~9ChX!F-RZe4c(+@*J{I=T za%!qXPiup0m1zSbjwP^$kolO2obnO8Tzu{T^t!2(U{y6hv?@jExcJV>(Y#w`%%(HH z!N7z=xWP4;Y9a!b#JQT^Ghvqw(gh!Xc*L!Q!E7$*Iih_wY^X~kC`;K~28fkMYgUUz z-SCV_zt3!^T9V(7Ctv2Op-frdA|BBtwRFBKPTDK&B3s1u zycF3?lL;D0BHK1fx?^Ht{-31tlGxl)FO63dtMVx{ohM&Q63yBiQ;XIffh`Q~Ptl>J z+o4Ln+o7?ZIDF&hv2kvqkl#x&M;m4tX9#f@WG8}O9EG$GP+zNo(^!#aCqMm?!4T!OIj zn49S?mHVeNZ&djk;@!I?CAzXqE&$>$Xx8&WcYdCn3I(=*E$al`#o&XPy8BT6o;fp6&e8d7^S>A&53 zW+RD_;?+rM(b(=>sQm4IAzjaD`RqYr4J*l%HPgX96zPx<;RI<9w{yE4lf}uE8ozMV z_T7~URlREr)*>d0+d%RO>-i$v8Oyt?ETRw}^{zf}&c>CIr`E5Uy!4{{zHg(oZ`2X$ zq9!^BnOgVS+7FR8lxDKa0x90SdGZ;E2cTSjjInZ(*c}Y9>@n!shD5)3lDuB*^u?MZ z$k__n`6l-a1E}@aODzrH+XTikjzI5Iu<=TG)+9J|>w~Cqz&DZWMxk(ykJIsZLTp>X zu{D?Lr6_}49rvlEu+sXT#~*-uC|6`Tw^-?BI9csJ@Ro~!mKY&PsbrB0n+w+5DimFF zLF~z0QB}f7zX~-F+F#)pGPhml>RWrdulvzFFdn!4u|=2EK2N&Q>b}Fz*dK@&F8v0P z_1Tu?0)6sJa>VaE^;^-mCep4Pf8#QON$YtnCkcL_US3j}G;>&O(>jaWV??tk{h;2= zp0#?(>~7%Xn1seuM#Tj`@3=TY0JLnm=lOuOkS@z>OKT9!vT}(rO6}EEB#zO9vovUQ z;g*TD*|Wy_3?VLppZVY%aRz#IDx4}8_U6?NS@CSW*wy6ZV8(Xs*h38OKI8F0)}zu0 ze4yT&YDwlMj4ys+kOyzUc*Od2#&S@6O(~ z-9-Ah6jHGs`=yoi{<+8vdhfwvX7bJ}D4srh0mD!0@jPJ6jg4`HnCM%%SzT9-+z`}i zTmRh`)`V;+dgYCQe!sgb1fxibW0E=h^Y6{XgnT_ITack&5%FZl$KV!8)cJC$k|gOW zcP{AT!h$F!-Z*87v5-4-w_y-zuE_hQumTe(dpG=2CU$Ha6Qt^MzjvBSX`k%z4OiXR zaDpiHXDebkk;-WA(Lc0$PEjo_$KrU^ofLa)Pv03K>&q#eE@cu6d~#8Ht60)Ff4iyH z!a#51Si@G*YzGUQ9%*S(oAC>N>6&Rjf>!TA-N@pzXPnnAzIjrod^>&Avm1e*Q$UeD zT0V+KPV488D07td9zE0l(@bhCi zRdrE|MHna|43F^hJ7Nv&Da_N<@3l2YU2P@ePF0&V!azJ@dIh1km8&6Q!8*i);0fyh z-}FM)HDiuiAXP1LY5M}zI>(eu7pWND*1x8yO5TU z3_XUVET7~uq3+vdV0QlyMevA=yI>yN5I+6~sO$$}J6i|?r1IVU+&MML7>V>8@MZTD9!yKnOO4uEQJtgZp`X?l~oQO{(}E&&L>BE{9!bWUN}h4YxRkWmqj8? z5!L-zHp?aNk7b`rwQ;|a7Z9Zf{=3I0D%^z@9DBh$u0w*`HW+LI6_F1Rnsr)5BX$W0 zC+97@*8a+xi0iM$sIAmnrC=>e)-x(9 z-Pb)wPDEq2l%@(YikL#jGUYAQx15!>QA=0mzr`jA)y}JfIxs8|-`{Di6_s(Z!QB^KyS_yWK3mHFxASiLMRY`tP zSwR-6HO68*G;Hvl_U;=U@|L8)?K};u8LYbA+hc0}IdA5%l8x_39_IrSuS)cyV`oX`nvmh<4Z6z%}s<@qvFw|tvL1y}Qr<>C*Z{09)` zvmiixn&0j$Vvm+)fA40&Ki4CAC|(sH4$-or7cN z{*$}W&O+wN;RA|NSUmV!0ys7vLQ4f1o`av@VuU1_;e_&okVrDv$t=WglFn`bHcSEe zpMiuT>V#Y2aEEwM41w>Sdj!m8EjD!gb0Gthh zuyaz_F}6%Cy2v4N+USSaD8k5irc#_86eYZo5RRSU8H^yriy>c_f%y z4;ROwG^*qgI{(cL-0Lh_%uk1B5ue6I2_f)Eg zklf&Zu85su!yCZm5Pk+=^P6LeB!=US!*QSdUnH^riDp6nPtolEeuMXa8RP#^#&N^` zn^pgbX8&W1`$T{;irH|CaoE<0{OSKs7zd^OO^o{?Td~-5tS3Lkvb|z*U+w+3YO3`M z^2)D`3i5H>C6>K2&qB}m6>OX|THc8MvHRVC4&nc$^Q%(hP8>(c``a^e6PUBBiE6H& z>#Mpt-3oGnQjsDt5@G!PMx+fDh#a=4AuV1t~%PyVq%Jf#nTOdG_Z64-nanm%c z&|#MM87_XAvidS9Hj1HF=bIb*;%lW}HoDiW8cuR0MH&(JY%~ye;D3M*6>VM7D}4db z-+{_{4R1YAG`oFV1Ao5pnSx(CAzCz57j28?ybURte59*`XvS6i!bGCE#Q6(FB583% z(GjMa?)aQX?k-CuCR+=NX)ML={`N`%6~(~;^!<@2u>fU(#2`EitHA{{R2Cb8B@Zo} zRP}idjvHsy$o?%G;l2DrHXEO&NaH%v>Ay|oB87+Yj4K;({#_-3sYC(qho%*B3*$5Z|r;cBp!I0?%q>5_^tIEU}AYo*bx4yU|Txz zJw1|f&nD`ff*WKBpt$zw!yiepotBH7kI3>gVkm>sX8TFX&Eve_GO%Uck06I2hT)6w z@CC2$ZxJE*nFmijZeZHT~|& z#M)z;KE(77fN~vk?Rzp7B}o1&_gF|cJb(Bfz)cSb>YJmf^4kM|QeX)Ro5@ z1W%inkgXV#MA=3#5z@rQu_nz-^L`IqhLGo{GHuI#CpGOIO1>+zoL}noddMWOj(pu3 ztS$(ufzh8@705O@563?`7frmpZC*Ev zeq7t|%@**$mr3QLe2^szN$u0zL4m*p2<(8l+d7%LCdcj97!CE-sls~SC*ORzv?hvF zn)hqI=g#%~az0Wg%K91Eoy1XP8}Se98#O!Hj$DpQ`OZ-Qq`UvE;!H_9D@uYal+sQ` zdksabM<7>==F+$Z>!+Q{nfwUNlvBa8dhiG6c1pzHoN|zRwRGr{4l%uv2Rp~e+UY%} z!kBSx22atNvutu@ee!2L==j55pO$s2HT=`|V9z$$sM(*WVVbBofSBXr`#O{E=08A_u(FHno0yMJ zc;t{$pv~qLS$)Rtzv+h-NSH!LEf&f9BZ$o*kU6w83rai`!!c73wV(% zZ4b;!Zk6zyC>fG<@SLyV%0(-_#6Bluf!x)iMowQZgj~Als{dd}ArY!cpX6;AicXjY zry$k2OLFdj-)hS&nxD`{&6Aqvf#Fa}XjeQ<3dj7}si1n?Q+k)kLjp`r?-O_R^5q-? zVGFfQ4Jn3j^?*jwnh(!B?>$d=Bv*9Jy6bt(`uWb-B|)Q=c8@Ta;#`4)Vp`610luK~ z0r5HCU<#oID=#Xa5|PCw+RsazmZGF<--_SGyG?gWFTOXE zrdvI5AIL^r;78K1BFbyrmsFYF5ixkQi|M`=KhJr6KVK)xI|ud>CPVW@r2*01dA7p} zROf06P_~(VQHrE5Jib>-MdH3^nM7seL<_0S9CQCmAyLT zBIuB4+cH!~qQ54V0#ub*EYpJSCs>yv?)1sq3MrvCTSugB@6qro(s5-e(qF1_MKGA)H(kp6Vswcyyk4~E z`Ylk|PCE15_UwGvnIPN5xRZgRL_K)sq5`c!RI>8(8}6`CX3+{v;rc z8R!{`5Q0yCaifrQVsV?fAD2Ph$h?_tK`WjUM*b1{peFH{u?f-igRMYFwKv42Ed*C+t7Ybx65e z*HC92V*N_#D71?9I%xbTqC{ZDBUv!!Dxg%(xBLj!fqxZVV{TSSe@sHIUrhR-Cia8{ z<5>GX9UH{8!N7p=3EFqhSIi@lVM7s*SkN~?c1(tS_y8496)y0*N(Y#gJ-^$`wm6@w z>QAPj0Y?YdLYn!=fm~uAnjfs0P$$FRefH_HZ%}oH1?~NrygKJ=o<>1UVVSl}DO*~3 zUybfE@%5#tE7Ky%ltgth;;TDs<%l8X`*Dq0yA1`wm_^kO&`1pjxQ`FuV*uyv0lvK(NP6nfDz84XZxo$t{$w}dO4J+Y- z<+x=X%PGvdZUZ*|66-bs_wJ zOy+S*e*YNucIOK!l)QUX3gPy=q_badca-|>XcIc&sSXD039v#Ux!bQ41ak?}_H7^V zOp?@CUEqDl_PZ;!D2`vLUWU(#*S~WzBS2YIUpsLx?Fsl!pO2U$Yui%sUL^QRcp&$` zR+l0~@wJ*A`9D?^#Eb6qKUhBhuzWt8rVzZ`tf?jihyUbG<Q>hhjG3v??KCUf&93j@`@<{#XvAPd32%dC2fPBE3zTA;2D=zX6tB5^@a z;r>Uq;_CPHe}Qy@O%TuHb^iFIVzJICKM)%1)w0jF7TxB@n~}7f zK==r1047>)tG8sOo^jDAdZNX=6exu5wR6?#k%~w%&tk|$cbQ79TEwLb`K%Z1mAq8A z$Q91t&1!C&>P{gNVv7%d;Ju`!I6bcAp`pq*Q?*V_N}OLgKg$r^9U+?e_4Iz7nsTjw zdV+RP@@q5dRa}<{CBNQ=lIRk23VvM;xPsjkS$wA(M%NOjQxpz^q-4%Mg80?^4S`)P z6Qd;)2SW$Gyry)*`4B43P_?J=+TiXhW$1)%?eD|H2jI{l#dMyDREXf0NduVg(!y`q zihbFvsW2-TTI|28UFWZ++OfCp|i?Zbhe2d#XS2F(~LNU*!vn&>>S@+8NvKyaF|?NxY00QnqX z_%QcZpvW*>ve56%ZmM-$SYU?T_S~LuxHEa^;+D(N-lYKFqf_u>f)a7pIMb-=g}1;d z;)fM-q3nGT-fN^uW&lIA?y|?#6bQaxzX;u8P`B`;wGF71Xcx*(3(BaX$VJp|`@ z_hJWpfPymuI%~Wf`Axu829%;)kS)+w()1tTfS+6UU_>kGD5-Kxt7}-#EuLGJ)2P|E z5bZ^%g{OnlYm(`*wxpq+KaW`nxga3M(FUU&iDWoW+~1ypO&Hj3?ng$IhUQ-88EIBA zz2A^6b>c|LeM*|Zv9oiT6kl~7!6tqY|CzQk*P~(!7~xLO$fi$}{AVG7@4yzOKvjXL z^S}37Htuu(uon3U5_}!Uq{`;BS<|&XGiavYxP6^S{`ffCf6Q36{o^Kk5v|*#6%_=r zG(f7?Xw2A$vvMPs$IM_?3xW~@>!c;$yq@Z z!A?nB`=JP?!#_v@d)BE3qhC9@$(J^#pZFx%a>?y%Dt@G!6rC%^io;1t`e*bcvRDy# zfFvGeGrTXB9#tDf&_a6)19KTcen~+Kd2sCsE4jZ!{EJs8KG0|laCg%Zs*?F>Fp%rb z_IfuETII*0YBR~Vw9?4L`|}m8E;T*Zed5`bNy4^PWNypxQ(p_Kc`;48%KE@#7^rQg za(SeRoap9UJH029m*43-)f(MUxbIF_VE&_+zw6_#Fe|d^?2!BHLK!!T5=4l8iKSy6 zblG0+$@J&%imMppVX0SC%z&vDJQ~V z>!ht;vPZ9TvlgU$RergwW&y=sP0~cR!$-HCT2s%l=}+}_;n19l#j>!?9ShMxUay$R z;KyOEqv}OQ;CHY8=-0lt?YrCKCnAqw`m)%SyDTr_+Iok3WCtY`JBk2L`lY&vmpi8k zSq}%0ij=xPZpR(Iyc);5)f_61;5%&Z*=u^B$h$EQVv9{bSBSc5$8Fh85q26A*)}uVk`?b?~`T5t(JU}_w z%p08ZJ@U-;ud`G~+692&h0Q7SX|^4~PHLT`&UP#(y!f2+dsg!T>{K!8UQeEjjQ?VFof`}tyKLL72i(X z(Utru*Jp&zg!!&Wu#ntD?gBbwqN}LYoUq7>}r|XTrQb#LTnZ!FYg6$s^8Fu|Vhwrh&`vSfnTOv=!85fVL^ohASo%MekWHMBfocZD%p79bC-6LQ1p^Z&zgp-_Zd^3 z=d=vPNY`J!5Y@ZMe}EOSkZc-r*MbkuZd+2(+_!(OVi#AIwA80~9jooNjDALzSVxc* zx=b?pvr?$NwRxkDp_k@Ak0%tJQQY4^tul-ZS}6^?X4XCa@t;q`JQyRo}$SQ5G{@bQ7DP-nbYl2Qv!t{&B9V zn*2WA*%(YW)P}Jx_Q`iM?LFA=d9ZVN&%iRGkes-aSm1S{2@l)UIY!T}i$|q+0SS(R z#?H0QsNTdXeK3&}YEq0@BjZRU&85I6=40!8U+Ul8uT|2nKtJ~lNIRniPX1aWYb#^r zDdOe4h8WX~-qVq+PA2TgMYKj!!N)*=$>ETf!;UNlx~5cYtcXB-Mhp+Hy?dqBT1vWc zTg+K(&qiFRdaI9bG@C?u6^qj+Lsv^f0bU~GFAc?iO^s#6}it1?6 z0o0QGu$}UnQi?;+&%E!C$ObDSky)gdWJryeRzbWh8KIa^6aMgewOs4+cY^spkMIfk z?`tG8h6bh>Gi0m}s%9KyKUVrXqOIVLZf*3+%1iqlzNg?D?aKZ~HX^MoEKk2prM{YC zOp9tTAS}Vi6vV>Be-XKMXe*R7lX0(xeCqYsrU_{2??jQgv5%Q;<*AiDJ0Q1#S%bg{ zNW>?O6Sw{WUkU$UYyVY@isnvOLOksvnAGkO{i4l?e4kNGsH*cTj{z1yc!bl=21-m4 zFZ?PB#An5LA#5j@(sY}AkEDI6xUovnL!;g920n5s1e&g7x)64 zmoA;hsC^iT*(-zR7!`(jzoc!yqk4oi>Ldf}I2tz|R9wbSwtRLzVb2ZBCV06G5}^E5 zNK25vHdqqp`DZ)NIr1hBZD2&UMU+PUp14lAv|-Q4Z>{t&AhFVi@fSjCL<_F)fNq~K z!t)mre@GhR0TCXeu=C4iI55lDi+Bk?^^yOvXedi3m@)DZO?0KrmLurr&*}?e3c+iL zb-_Drqa@Z^TgNw+A`RsNJXteA#+bjhI21AueI9|=6!0{fs*hhn7UFtvQ17s+vNhpz zp51FZD%OahrN;j_(G?6r<2u<)$fpt3vL7qm zZ^3*f`?@U%P~topi)jpyckxxxDXEp%y0$$Ded?%9h;qS(y{!n=<_NIaz<|$Jh$ttx zNui2aDgBNCh7)vy9r|x{+sGstG|nVpt&~SJWJ(39HJ&ehHB~;Ae%7Vju4984VX0J_ zKwGmf?h)!{y^05%OYE3>ovq=jy_IR#gQmM-)y4C`!eoe`b70i

^S1< z$|WFDNy*w%7m&*zbrHQn>6g)fpgC@b0qHpF98SGSs3Gky%4yl#{6jFLolbqWp=OOo zV1S{87r$w$3Bg&I$c))V6bx5!__A+tHF@-HkLB;`y-RaCGX40~3Bxsn)J7{Cc=~2X zsdaE3nwL5$@gXIow{EfK!HD)!&w)3PkJaYPEmlepOf1~GB&LY zZF22q@~feW2-&Gd#erb$vn|$$SZ6N((87QyCoaC5K1{jS^q}=|ab}6By!GZ@=l&V1XUc_kEfBgU z)}RS{UI^!ymFdB}FJrY9y28yY;`9@A1V#wh+-4`Z5(9AknN%Li)r&o6-Y{+sQ(3EE zsC<5 zkyJ3W9Fjy1sPvgtx^5=d6YHM5crrYYEaIixM9Ha8tJ^C~(B;f8`kO4mrW{A5yL11k zr7+nP%CHU*kB#kdQ5J`Pa~RrO?6kBm_Arw26FTfV;SCkhGI@kt=VYJDF!qZ}|xK6PKeq|Mz?hx6hBIz%fZ1#<$-%Wo{sTf(NT4OH@eEhD~QB{G?JZUU6ZolDV`Ev!8zy zG#G53nJ!(Q8>egS&k{DP!&>{t`CZ0)DzUH!{{Xs1CH$T^b_rPwBT}a9I>Pr0jMtAe z1}j+~FaFGhI(17t{P35sBS5oNEM3B)^!s>19W0Pa_ zM?D)4%a!ltFRXn7@Q|iw(Pj1TqIW;S%N#KHpOmJgkr6xK^{(x@)(iZ%q~B5E63!q` zH)?r;51W#`Gf576T-R6#FE2mr2QTp*n-{>&rn+AxEU_eJp?g^GrnrL>u{cF~DWB$O z=8@YwKMpHE0X=<;qH#O9{?L(llkbsrS7%l zs2{{qW=@Xd{-Q~Z)Xm#=s}$82cDF}5Y?<|9&6A!j6q=s%jU&T{2*pn^91Dg@rN|{Gx87|mWWvG)ai>OeD(v?BrKP^;yUR2?_xOu; zj1SCc$9td@S737VkL2gj&^zvkc@-3F)S zY|@p7?}3HiQ@NkzHBI|H9a#%M8+%3kl~h1x+gpfW6N%SvY=xu~t33-*)%E(jGnECC zPHeubNP-u(hLB~~MlG@-;*)`b<>@W-syr9MQxMYkQON8*jYtMs&!2lT4=mXsP~PFk zF?@lUMN_BAK`7uaM>0-l%P^RqfWYK0tk6$>KGIJqull_$*k1AdqL@{&Q&|05`dCun z@xET0R=~`#G@fl;;O$`YpMwY`fg8mm3~c40K9+vf=YczCp2v;JCI2m9XxtB74a{zp zi;(=M&XUuP_$)6G({6v8);btR3uivM(>>^GQ;b{l>WJ5F!QR%c5{678czwoC^h$XX zxG&mXU$+m*5rW?fJ=lyCf;gx7ym49;uUcsQiE0Ge3_9Qz8etDngRsG6_9)D0O zL!^%8pP!*WFy`2)WD`G~;E=|m<#j=i4RTK3R%SdVAK2=vLDM~Bt?n*J~3opTM$Bb|3TB#DlC(P{hoE@2P<1UTz4HjE!NJSdWOt;fy{9yI_hPlNENB%untgd>KNXw^ogf ziTL4(PvLy%+uQbvl8L2w*s_d8&96K)c4E63-cQec_()BRqy0v`xYQGbAsu| zn49QK+lEK9Iet9{wOxHuoc!spQBNHsM8B= zAE2b~AEY9g*PqP`yyW1Z@1Wlv zW^Ct-mcQs3+TH_wWfCsBFY(63jw?er-k~^wjw=LXX3z(OAaZ1-H%}*EzNS3%{DSJTg zQ9mJ;3}RT;PY0}6IAHN&%`y^$VPp8mkvN5G?-A*~akX~#uXChD`a8Foe}EA5hR`mPRhaDBE>0?^k%lCO$)5F9=mM=v&Zi8`PuxxmlwBw41C8U5QeRYZM$Ro9HvEj!%w=%jlWK-k4!g0`g4As43H06 zSix(1jKv?;h(V>D(?m?BZz`|8~x?_^G~ zC_V44n*JY^T6?hG^LI;vG>80Y+~s~LO7THi;ipn?sh=~WTQO&^pWvTt-HfN4WjIQN zj!NtI)=;sh2mYz5kO#R{`*g6{8|OO7zZ6?Q_m=5ajjr@^?>RpEoFPPEmh7NC>qcSY zesTtC0k%rp#1&d&Ow_Uk)s9X;f1gZW**dpP?vF&!n*QBJCI}#s6%8n&3L(36bj)KGj>Yq zG9#H$OU5PZBn~v5rL7CFe6YAQmaSok1uccqdY7&TV@%Fk4g0e$V$mIg#&Pq+Y*fV? zauGb$*NT*4DQ!y}JfZlPnJht8Ofcv+#I`XrnV7HPvs- z$=2HUXD#7YXVj|(q1R?`xjD0sh)fuRx?^{`bDlYm)I}S6#I9J4jpiB@t6IaF6T~L+ zo4SnECJSd7+#5g?G;Qgef_@Y85CMg{$|q%i5Du?B zk8yylxa6-}CIzHgg4l)3r|`tJAPnrRSOo4oo~mIq5!r;!pPsT z9~tfngk|55psdy8hm@5LOIVV$oo7Z&`;0OONJd4QJmtf@kzKO0Or`s`fr+Kc%>3haKOyt%_rWK%+t*oHvTe>q)&bZxm2o}`!sC_HweyjfgB}+G} zM>WK*kXJs;BEX^eV>MjDAWJCkv-^eW>R_|yP`Yls<_>;k+Uk##s^?f|;$2-OXs4V9 z{g|U0c8H60%Vtt&1~~|;LC9^Hz}B7E{{UNvH(ikOSAK}jtOYtF0ySxVpxh0kONDen zu*Fs72D(9uVegc(601fiY5PWZe1e(vGbx2$U)-xXm^_?6GPD{J)2Wi~)Je&R=SyS6 zaDWMiE+Cn*D0x19BTypp9q{~ORK+%7s3|O|dEb~)EdXwlLPi%uePgTt0K7oDtqp8& zxTmh*jU-jgHn>H52&z;#aM!~uCWzGAwKZ<J4x^C=c!$fa7u}gfGU76ep z{FQs{3m)z(Uum~$XDoA!#Gnf8@+M7H)H{X}WL)&TTbQ)SH5w{A!(4tMf)t<%%rJ0@ zHcll0EwzQt!W=`Xs^8H1BtKn!5Ao_#@4!oG$V$AxC9R4I<->mvQ4u9yJ`Nk_h$ES# zCsOa?AudDt8{9UIItq1YSCe+aWupZK(_(V{ss@xw6sO1)%~QQgCB`sF*gB(w)W1IDf_`SE{Rb@M2e z-5kp0M#zao0*rq1AYL~Tg7RlkvEo>4it2Ks$GE&gd)`}q2}*$6DY2%!W;j~H&7&6p zLc%Id89Mv^AsK<9aUBpFq+9p$MB;Je9pqs_W&?Ns05R-f6;0x9 z*WXgmGgw^wRb-%JNr?T-sUL7rpkHy=O^x4FV4&fh1v`P!vLvmot;4a&rWoplmqSC_ z*YO5f5t|C#UbF63rJxmylJFj?EqNeTCFea#w9Rf^8J5_n!nAS+6JbOi z!2aZ-J@VV=P9bS*2po8)_?Khw#9eLTEf5hNPS2PojE%fz7~HU$?a?%rqZ1t45&%oNM2Hx8bokep36@5d}kX2JVYsB5wKkUXC zYT4JSpyt{&D^XIp17qa>0FA(9)Y2Ducg1JsYbVI)Qm*aq_LVuRt-u?txR_1dM7tP; zaBR4xR=DB9B}!X!4|jP%mf#~5di%uA67E26O~v{wr&~9r+2UQd;&3$-DQkhrY+#fD zSADUy~?sK*{z1bd4Rxeo8pKDMC>uUiPKQB*1-07sHqrI(ar<%lL9h= z*3NDV2nYyP6?p&;3?#EE+BKcn#>IZ}%yC61Q8-Xf`w?4;!9u{ua&F0eD{#sE-t+DX zI2z(bAo6jKm;@@3m?5H(EUsYGPPwq)Q#N-=T*qTrpDGN|@9hbP(#w4R0C6q)QOi~R zP2UlyIlW68fxoEwpHuWdL-Zf0`Y45h&{K;!;{Ig-ot|R>kNIjj zv99Y9t+!DK6zws(nDvAmx;zNg`+-J*%I3Ot=c!_|yB8OHR}iu&O~s^2fTHiEgF{z;&8um_QM)7cF-SOY}8Jy(3nmH<2s zbK@N9pjNdhEVpj_G3Zna8#H0~dL4RnzmUN7vBx^Kp#Id)U7K6}5 zVjp&8#@fxp*c!6={-!BHwD&M;a254XqWf-!hESkJhCE~)rKQOmOhOe` zOE`T)1SexBZEjK*D%e^A+2&;7i`88KV#bTZ9-$gTH~^F!;;`YCmIvA{MDkQ7Q_5Qi zC@qRSnba)|R*ITpm2%8#x>)Q3ht$AjD2vm?g~E|w!ZMr+(rR6j9^W$ttg z#H#Dd%sLd--|8v4a2B7xJ|)2tU@~6}aOJ@N01l=he&y5RTaHEeK4DZ@VQf5CUjG1T zYiX7;J`9zw_Xi~%m>l^CO${5W{-L7P>UjiU!jB9DYY;E*3pPD|_b%uGBW>*mn0EsP z#UO+dT)ajyJoAh|q10AN?)=x{WX)BXK}~mCxo$;Rk))zJwjOI_ACzBF1_p)0gapej zE3tMZyapS()zg^Zs>x&}U6qh>QgtsTz-re)IXr!)Bq|CBzPmp0kd#mkywn@9EWLD< zL*^`B(!Q(pKDG2dmHKP+*V73$)1|BgRA|849KVTtLW?CEbD--G#Hd-Z)!&`Kik7b9 zklCPw2&Al!r zj9ub#8kbYXKe@d_Yzcr`EYKErxG1my7$aYp;AfcH)<3ou;%|1Y9?qa!g8ZFE3z<#K zl}6@_3_iU^QWV1(gwRUnv{R~n=91DgN}SUM}eJxVfTVeNPJ z#7f10hYhf%AjXHzV6a^#_{^&Y#Rgpqb9VdI$xc`$1#HrBQL-l2LxFZ-;DuQ!))3ME z02+$Y1$L((50pM(pVn8Db@^i7n?&No1*zdq8;Dt~Gnh6zmeYvspaSsRbp+bj92xk4 z0>P=S!NomHR5Z#zsj%7JS+p38hi7t%8@LRKuZdX`Z61C6!rKU;vHt+MmIh3!+@QZ0ESYWprlX!LGexW zm>o1?o$;w{Qyl@%M;^G8D8eX(8_?$`EI2ZQ1S+cZ{{RxckfGlpjh)F>yvK*88qC-0 zUt0YY`l?i~)E`S?Xe_~(5}b&G@>F$FD5FCE01$==cqO+i7PZODM7_m70p==JU#kBA z+l{(|T4MG0{h&RQI57g=kLDAS0y0qTm3DEdvCLW$I6D}Lx@ofNjvi~NfI*^j%iuo~ zIvk<}(N`_F7klvy$VS<3CHRi>>!rP__8;6R(y77#zrXK1IcW2lth z7^0km2>UpVg+?QUrRlpjp5c6G9&8oTgJz#F3j>0Rn$IX{{SU^qO0prTPer|!i!p${{Y}Idh-deHNkSCv}+QC7PwGrXBjUq zdXy5;u%%@}gUcQUfCWJ2*60AOuHcHsGAMF~@n10}u5iP%<*WA+{IQ)5==@wIn;_oY zAK26Z6sR_fYv+g)0`A&Bh1^v|JrAml!z*mzQqi*Mg8fXJY?}F%qV}JggfhnrS(}E+ z)$h!yJ{3p*0I;$uU9^Vjbq!@|w%vY1xJa_rjZRMv{lYq0IDfdd9nN}n?g6%kEa5sl zoyT(rV01q}iA7*40a?1v-lBt8<>22>FsZFks=s@PgCc|q`EC%R4UJFVP!L!l8rW?N zQ$Btrrvmj3tqvEOVu&7CV1oW=i3tb?Fz7?R{YAFnYHDb73Vr4RfJ%cmM^w?dO;J?s zGKMUuvF5+TR9-ipBBfHuNy921Q~W3R4M)T^^~1Sht~6Dts+z3^E)o&u4(j8f8?$pnwJUaz{!M1?cMC3RjrA z5mH#4E1la4Qe9%Ax}V(2oT#@OX^l~YGVRgk+_2*+-y2j?2^&lJLy}bhuBgwsfE00f zjddMfNuuql7r=k^TBjP%tBR;Vt$U24a+@?GmWV4dv|c^b6OV?tA44-p$?3VXl1gysYSATU_Sy?fL~{aM3qYU8^` zMUb?!?~*Hei!~sYp`Gu2*C=r?sdhrytI8d^pvKH`UWIhooQIVhz-U!Yr6z{PMss?LwERLbG+ua)Nc1j)(Y;q9W~0&DzTfQ`7)#bKDocqpk_1@iGt4{U*Q1 z&(v%5urfJ$h=IF2+!erfCAceZF0l%CHW$VUdu~|Ugd7y*-*qu_vg<*cF0WF?N}wsT z2MV3uKGMhPCXqnX2xV=J=~piknhjokW-gYS)pd1#5u+0PM8N101a)rW)haO}f%q0T$^x#5d{i`Hf0K>Xu?Q z;8d}`EW}F^93>S`#2+bxL&7TGEE0;@G+W{t61AAjm&neNy^%ujZC!QLy4X{t7tdTT zOu;t5p`p$m&)O*LWfU5FdMXs9vVAPD;}XyUiL=QZgf8R)3P7Tlmo6PqDLa54C&%Q} zBDAm$R|T^5|!d-^dF;7 z@tcmJkD_K8{VofXf@q~)alca0HdRms0=ZtiOFQm%<#_x?Di|u1hwF5`ydq@J#JE%q6?kmyyY+|=rq?U1-y~dBz9kj`(8%A2+Kd%2 z{?M+#tdlhH7K|5aJ2w5f%8kBF$fgU2NdD#zF}!( zmb912o}gn9=34jj5UsiuZhC;Rul51QxuVJumuSb*9Ib)in&4oe%uJdCi|C0}$QYxd|#g%fg|N;8Vd#NngVYC60{6?!T>m#Rhw5{ zIfYMsYXYf5y%+sKaFA;{r+^%E_lSuED;1oMM{bG&Vw{}QOoM#h2n9AvQr;VU=QS+1 zFDT^dqC3dnr_@DQa(VF<#H0YeZZKrDg!IC(uapu9P)S{{X1K*#lY)>%&#a0>uE+lQeyqh&(rC z9%=zoHIU+D0eB{>%rji_UO)R4ZG{|&?YMU0*guF{p1#z7E zPGx|pyEm2}F~R`nBDntmvo1L+v9qa}6#=ES^O;b%nYb31HODYjB;Y{DD9N|X23^;2 zwZK*dY{X1fZV$W{HSzjtALFl}U(gl$nO=3>aMWbdfJRlflycyfv#ea(t<{Hv@fP|U zAAtTLY6)UNPAKyX?Bpa&sm`hN$BR3d&I|{Pcznac!glfpFCWB06uWAC!L$l(=ES=Rt)BkRoMJF{t?{oP6fhS@hb-tQ5~ zvI4lV?S(^1c5&aBiC*dhF3Nu~SXBwk7jrpUyq%61jG)(@(<&$?%ZO?f;>xR(N)Q3! zpzxq%@x4Rmm$%P?3xz7z<$svDVO4pW75Rz74-9BAej>~i5#e}`B(A0u;rbuuRCOu^ ze}UAiJaMV=br@)s<$vARjLbAeBT2h9KF7f+Z|0!(C{a++!+?8NLBSQ4l@+6k4m=Qb zN7A5h*m@3PK@MgVov!K#3p)*%O$tKITiyDI7!1|xF6E_IX27e&JTd_CKk6W5W0Za( zE0*#QAp??^zff#k>~Q}8svANx5G^TmI6QcOsE1(rd&&Du`FtkZjM)3?8-@vRmFD$L zutGZpg~_13IJQs}C^F+i+c0@kfTb4WC$2lp!*C6olxz*(-Y8P@gyix>0Cz(&lA~n+ zbh@$xr=S>8j}UHzTk{1Hh~97JQUX;61$vZPjta-jP+iZMNC9~sVnsMZ2S=FeN#Zu3 zrt=&XgOk^&HeCG0T{OFAYJ9+!-idoE6OnOIhGl&M;8*yo{G-W5L&1RS+#R5jZ?_D! z7GEJQ1}q(IXALbKOr&ZSvp{|>QGH6SqHi3&VHv^__OjrH*l!K4j|Xacg4WYuSzMDr zK;|-$kyO`gr4L7lt%?Pn&`MCYF0=C;-i|IPD$u*)$dh_mb&bNZUPG3upi8mXi2_7z zgt~Cw@dC~CQvprU_rw4ZD8Y8|@9{H(0Q&=m^pHc=&M6veTgRp|Gfr@}o|y3Xj7=1+ z0b5)QZ34G#(;px#_Zb$BQw|i1R`Y)|YP$+=P3zk%unun;c$)?V*>Sa(Sr?NK3PVjt z1v$EIXSs|mUVx5b+o3m&#%WIIAO%=)R{({ZTOQg0#bt_az+vWOHqiAB@mcQ6%6zIc zj>DKM!pfVw?xST&3sX<>0}_w&x>%T^qWHG9=<_VEIH(O!U86Pe7DxbJAhhwig2gB< zRBE;w#AwNi>pmv$+_^%@V0r)?5WQU#=~PPdnIlFkqEg=tMv4rL+xeF)tHH;)bt#)G zmH{dQfiencflK!Y7zJ*?7#22GIDGv6@ybVF&?9~{z&$`BWUEnpnezoYHQPyw;6=*A zD>^&Rs7M%igCpG(*Myb?7H&`%cCPXs$!lFugyR;U20SsV5MbCH#im5GNqC;fBN@A8 zbBr>0yRl6=-&{!s- zsVeJlL^cu0r#0po7AjlfB{W+18>$#$+o9JnD){OwA+}I66^HoM{(awUctJOQU(pE# zB*2TqV7e134CR6+B}L{Pj{&X;Y|@}M9DY_76LS~VKb=GXR|2mndeX8qp}HUH5Y*Er z73hylcBNO|8wD$u+ttgJ27p%t78>Oe^uZ}QmN#PKwrB>14im3(h&IW^;0RF#Y|SWg zc55xBk}y1PIaSZ#k2m_>MlwKJG; zk9@;-O<9%<*~|uSGSwgbO*5=QW~p9DxB4aL7$`Q3Uv3Fln}pLSzL2#Z8k+`&wMQKV zY|Y~J2nObA@L{WP9PTD1K+axog*o$xeQfGo2HwATju^6|U@&-!kjE;lGMh3m8_jF) z7^AfXGc6-I-CLDrwi2NQ-EejO;p-65 znSjvz1J{-`tm2c=;grE`N*Ib%a0N`or6~8fc@hU`F+O@$lIX5m#aCujqDdH3~ zUV66!o<3oqRwf3lDeS*)pyZX^XFknce6sC}D%`_$?bo?s7AQEt$L(>B-4}VH;f)l) zd_WL#QvU!EMmJR)D%E~tZ%`quP!I!3f(JS8<1&_%0n>y1%2ud(ZtnshXf@nw!}BR{ z<$0_Jt9AV);8Iqm0M`wb2VqQn;xFGXbj9ssa>L*pm-%4o(BOUhxM0jHPDe8+KvXUd zHR?3uMy$<6n*#b^T#Ew*%E`T)Vl|anqUE$u9tmiVfUCJ=dP9`>nJ%tZxS6(VVVK5> zPA!xLHC*BhK*!uoMIKT1k#%dc$5Q11L!kcvn}WD6Esd)Dz?1;8^1dS-DZzOq%cbK4 z3Z~cmK)9Y#mz+#Mn+>1(fCrQ+Q>dz?0sA%Q8}3@oIu`3!nwsGE6<|$5ArEL~qAs?s z5l>T>ok|c5!io}ug#q>M68L2(ZqRk1nBi5lT=D)E#jlV>+lY#fEFbgKHZy|V0e^-t z34X-i^$BH+Hl2H7V!(iNpcU?_`)|2?S-9SohpuLHAV%gvj^H~Th8sM>x!~rS8~(o0 zhJY3EK5O#=FB5NOJT?%MRD-H#FXCF?iq%ewDpL6a04eg!Mb1HX!@oVo04vcEKnEjv zmStQDh#^?Y4JiJ?AuUrBV-et@aBf}AI10-*9to{P0ySp)fYEE55RQfmR}ciYuyX_{ zz+BC=thcr`+g0z1^#z###>AGX{ZUa@0F5clT)>G}`GZ)ETUnXqvLQF&jC210r%@JM z+-bm{D~<#y$e3}g*`3rx6u~Gde7p}V1vtyXW9}4lWVSVfwe;=t5=eL`z_VSZZ~eiT zF(vYH_U0%{8w<@uAaQwMq7%yT+Eg$AzI%)VX>5Md*`--a=l-Y+y8$iPUO$+YD3)`0 zfYnR}^Ng-pQl%aPxTFdNtpm^9{6wLzR$xjWm4YDb6E{nniltRH5|xXTZ*sKe#t!Ah zmX9wI^0746K4s4NZPPr3OXRJ`5dc#55UV!U=6g$`$Tf*!ZJLW4*mVn`gRbILk~F;& z#{su%6wqY{Bz0GM27{;+PAy;Q7#lLx=BF}(;oq-Pz@e^+xnye_xRr--U?p<;LYllM ziBd2__nQy1H2(n5-9RTW7o&*muGG907re#LB^Ur{o^HtHjDSZRXPVV^9ZEWxQ(0QG zw;vLuD?|#RLDlASbyRpU`B)<3Ag1o+fHM~!I!JU|^~XqJ|I@C!eq+ zXas?A&UN^MR75UbD#T>qOKnr*+4+hQ!Eff_QG$wAnxy*!C{79oguJNQLF)e9KcHe#>EBsH5_WNW?Jvw zgb=rF((G)15Jk{iY|z)lPFBep0;2+o_Ozvi#M0o3^tvRb%D=O4c_H z7az7IG8_kH4{$arrSM3?UhJ{o^%07Ip({<1<~DDl$Sna@bKFVjBMR6!IhY{2Z^wyQ zb`=KJmCVGjPUA(EKQI8^_B)AIhoA8X9GeaZMu1ad#-8T8fkN5LT}GDHI)bni@K*f9 zu2o(g!tH8lW`bFZg)aoO6;o*Gi3Qr#7{z~4t*zudB`>>efKhPeh*i7nmbT0W#1Hg` zGQqiBc$U3<;+F?_SjYZ!7=W%&7xNU&U~0CwnNJi`7R`HUB3p{J5Y_uw+?%4SKlWvr zR%m$w-`*Q8)u#KDw|KQ%Rs6=HitEXVK%<%;ymydT^vt%aP}u8p3Kx}!5dvEpM1oNf zO*w$HFoW%>RoP*a7V(RCm_@62fK^221TjDy)I(yshRRs*8kIF!an;2Ec|A+CIqwmz zQ`%5L@DoL%))`;w3JNqRz>2|uWqbDuxvnp%WjL6A^10Mjp5>r8cJRcu=&8)L%DeX%#{1k-_XG&+tNTGHy4)!gR7~_#XfEAxGv<1V z;NSjJbATk{^Y8YTL}r69Di`iSu)BPQ;UdtXYYx2;FhPZsIF5m&Z#H73EM>-jF$*TH zfw*=QCO!Eg0k0$Q!a-q zh-nM)bU>hW@>*YI2jT?}BKKq#jkR=^TWMPDy+mCMG(CEh92L{cGc5&G9Yk7O>_bya z#s1JD zlgH+6Ax)2&L||YgKX^u^32pT$fVpqQ%%cgE<^rJ|wahe(V7B;#7QM2ulk)i<Z%}L&G+Wsjn!2r9;eCm6<}L9!T2OU=#P1w8+FII+rqT a9OmMuf>g&SxC@R-Di8`SmN_E%pa0ofGaa7* literal 0 HcmV?d00001 diff --git a/src/main/resources/view/DialogBox.fxml b/src/main/resources/view/DialogBox.fxml new file mode 100644 index 0000000000..420978de72 --- /dev/null +++ b/src/main/resources/view/DialogBox.fxml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml new file mode 100644 index 0000000000..41a1c15bd5 --- /dev/null +++ b/src/main/resources/view/MainWindow.fxml @@ -0,0 +1,19 @@ + + + + + + + + + + + +