From 53b69a623032fc246796e12b3e725c3a41c6ba25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=99=A8=E7=8F=96=20=E5=A7=9A?= <1014717807@QQ.com> Date: Tue, 6 Feb 2024 16:55:47 +0800 Subject: [PATCH 01/17] changed name of Duke --- src/main/java/Duke.java | 10 ---------- src/main/java/Qchat.java | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 10 deletions(-) delete mode 100644 src/main/java/Duke.java create mode 100644 src/main/java/Qchat.java diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java deleted file mode 100644 index 5d313334c..000000000 --- a/src/main/java/Duke.java +++ /dev/null @@ -1,10 +0,0 @@ -public class Duke { - public static void main(String[] args) { - String logo = " ____ _ \n" - + "| _ \\ _ _| | _____ \n" - + "| | | | | | | |/ / _ \\\n" - + "| |_| | |_| | < __/\n" - + "|____/ \\__,_|_|\\_\\___|\n"; - System.out.println("Hello from\n" + logo); - } -} diff --git a/src/main/java/Qchat.java b/src/main/java/Qchat.java new file mode 100644 index 000000000..68994825d --- /dev/null +++ b/src/main/java/Qchat.java @@ -0,0 +1,19 @@ +public class Qchat { + + static final String WELCOME_GREETING = new String( + "Qchat ,A truly humanized intelligent voice assisstant \n" + +"knows better about life and better about you\n" + +"What can I do for you?\n" + +"----------------------------------------------------------------\n") ; + static final String GOODBYE_GREETING = new String( + "goodbye\n"+ + "Qchat, your life-long trusted companion\n"); + + public static void main(String[] args) { + + System.out.print(WELCOME_GREETING); + System.out.print(GOODBYE_GREETING); + + } + +} From b813825bbcd2f959b05386f49821ff803d262c90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=99=A8=E7=8F=96=20=E5=A7=9A?= <1014717807@QQ.com> Date: Tue, 6 Feb 2024 20:11:59 +0800 Subject: [PATCH 02/17] added command reader and echo effect --- src/main/java/Qchat.java | 41 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/src/main/java/Qchat.java b/src/main/java/Qchat.java index 68994825d..ad8aa07f9 100644 --- a/src/main/java/Qchat.java +++ b/src/main/java/Qchat.java @@ -1,3 +1,6 @@ +import javax.swing.*; +import java.util.Scanner; + public class Qchat { static final String WELCOME_GREETING = new String( @@ -6,13 +9,43 @@ public class Qchat { +"What can I do for you?\n" +"----------------------------------------------------------------\n") ; static final String GOODBYE_GREETING = new String( - "goodbye\n"+ - "Qchat, your life-long trusted companion\n"); + "--------------------------------------------------------\n" + + "goodbye\n"+ "Qchat, your life-long trusted companion\n"); + + + + + static String CommandReader(){ + + Scanner in = new Scanner(System.in); + String command ; + command = in.nextLine(); + + switch (command){ + case "Bye": + System.out.print(GOODBYE_GREETING); + break; + default: + System.out.print("---------------------------------------------\n"); + System.out.print(command+"\n"); + System.out.print("---------------------------------------------\n"); + break; + } + return command; + + + + } public static void main(String[] args) { - System.out.print(WELCOME_GREETING); - System.out.print(GOODBYE_GREETING); + System.out.print(WELCOME_GREETING); + String command = "" ; + while(!command.equals("Bye")){ + + command = CommandReader(); + + } } From 23f525778a8d0061012b7e908c8552e0b6cbe883 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=99=A8=E7=8F=96=20=E5=A7=9A?= <1014717807@QQ.com> Date: Wed, 7 Feb 2024 00:37:11 +0800 Subject: [PATCH 03/17] added list function --- src/main/java/Qchat.java | 18 +++++++++--- src/main/java/Todolist.java | 56 +++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 4 deletions(-) create mode 100644 src/main/java/Todolist.java diff --git a/src/main/java/Qchat.java b/src/main/java/Qchat.java index ad8aa07f9..e60b0bad5 100644 --- a/src/main/java/Qchat.java +++ b/src/main/java/Qchat.java @@ -25,10 +25,13 @@ static String CommandReader(){ case "Bye": System.out.print(GOODBYE_GREETING); break; + case "list": + Todolist.HandleList(); + break; + + default: - System.out.print("---------------------------------------------\n"); - System.out.print(command+"\n"); - System.out.print("---------------------------------------------\n"); + echo(command); break; } @@ -37,7 +40,14 @@ static String CommandReader(){ } - public static void main(String[] args) { + + private static void echo(String command) { + System.out.print("---------------------------------------------\n"); + System.out.print(command +"\n"); + System.out.print("---------------------------------------------\n"); + } + + public static void main(String[] args) { System.out.print(WELCOME_GREETING); String command = "" ; diff --git a/src/main/java/Todolist.java b/src/main/java/Todolist.java new file mode 100644 index 000000000..28538030f --- /dev/null +++ b/src/main/java/Todolist.java @@ -0,0 +1,56 @@ +import java.util.Scanner; + +public class Todolist { + private static final int MAX_LIST_LENGTH = 100; + static String[] todolist = new String[MAX_LIST_LENGTH]; + static int ListCount= 0; + static Scanner in = new Scanner(System.in); + + public static void AddToList(){ + String Task= in.nextLine(); + todolist[ListCount] = Task; + ListCount++; + return; + } + + + + static void HandleList(){ + PrintList(); + String command =""; + + while(!command.equals("quit")){ + command = in.nextLine(); + switch (command){ + case"add": + AddToList(); + System.out.println("Task added"); + PrintList(); + break; + case"quit": + System.out.println("Task change complete"); + break; + default: + System.out.println("Sorry, I can not understand this command, enter \"help\" for help"); + break; + } + + } + + } + + public static void PrintList(){ + int i=1; + System.out.print("---------------------------------------------\n"); + System.out.println("Here are your current tasks in your list:"); + for (String s :todolist ){ + if(s == null){ + continue; + } + System.out.printf("%d: "+s+"\n",i); + i++; + } + System.out.print("---------------------------------------------\n"); + } + +} From 3091a142ffc6e6cae157d61a203c2ee299c406bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=99=A8=E7=8F=96=20=E5=A7=9A?= <1014717807@QQ.com> Date: Wed, 7 Feb 2024 16:13:45 +0800 Subject: [PATCH 04/17] added the ability to set task as done/not done --- src/main/java/Todolist.java | 79 ++++++++++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 2 deletions(-) diff --git a/src/main/java/Todolist.java b/src/main/java/Todolist.java index 28538030f..3a75e7524 100644 --- a/src/main/java/Todolist.java +++ b/src/main/java/Todolist.java @@ -3,12 +3,15 @@ public class Todolist { private static final int MAX_LIST_LENGTH = 100; static String[] todolist = new String[MAX_LIST_LENGTH]; + static boolean[] isDoneList = new boolean[MAX_LIST_LENGTH]; + static int ListCount= 0; static Scanner in = new Scanner(System.in); public static void AddToList(){ String Task= in.nextLine(); todolist[ListCount] = Task; + isDoneList[ListCount]= false; ListCount++; return; } @@ -30,8 +33,27 @@ static void HandleList(){ case"quit": System.out.println("Task change complete"); break; + case"help": + System.out.print("supported commands: add , quit , help , mark,unmark ,clear, list\n"); + break; + case "clear": + ClearList(); + ClearisDoneList(); + System.out.print("list cleared\n"); + break; + case"mark": + SetDone(); + break; + case"unmark": + SetUndone(); + break; + case"list": + PrintList(); + break; + case"": + break; default: - System.out.println("Sorry, I can not understand this command, enter \"help\" for help"); + System.out.println("Sorry, I can not understand this command, enter \"help\" for help\n"); break; } @@ -47,10 +69,63 @@ public static void PrintList(){ if(s == null){ continue; } - System.out.printf("%d: "+s+"\n",i); + System.out.printf("%d."+GetIcon(i)+s+"\n",i); i++; } System.out.print("---------------------------------------------\n"); } + static void ClearList(){ + int i; + for (i=0;iListCount){ + System.out.println("task do not exist, pleas enter a valid task number "); + number= in.nextInt(); + } + + isDoneList[number-1]=true; + System.out.print("I've marked this task as done:"); + System.out.printf(GetIcon(number)+todolist[number-1]+"\n"); + } + + static void SetUndone(){ + System.out.println("please type the task number you want to set as not done \n"); + PrintList(); + int number= in.nextInt(); + + while(number>ListCount){ + System.out.println("task do not exist, pleas enter a valid task number "); + number= in.nextInt(); + } + + isDoneList[number-1]=false; + System.out.print("I've marked this task as not done:"); + System.out.printf(GetIcon(number)+todolist[number-1]+"\n"); + + } + } + + From b16481dd17a6989c39c0464eddde0e7f6535557c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=99=A8=E7=8F=96=20=E5=A7=9A?= <1014717807@QQ.com> Date: Wed, 14 Feb 2024 22:46:36 +0800 Subject: [PATCH 05/17] added text ui and tested few cases --- src/main/java/Deadline.java | 2 ++ src/main/java/Event.java | 2 ++ src/main/java/{Todolist.java => Listmanager.java} | 4 +++- src/main/java/Todo.java | 2 ++ {text-ui-test => src/main/java/text-ui-test}/EXPECTED.TXT | 0 {text-ui-test => src/main/java/text-ui-test}/input.txt | 0 {text-ui-test => src/main/java/text-ui-test}/runtest.bat | 0 {text-ui-test => src/main/java/text-ui-test}/runtest.sh | 0 8 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 src/main/java/Deadline.java create mode 100644 src/main/java/Event.java rename src/main/java/{Todolist.java => Listmanager.java} (97%) create mode 100644 src/main/java/Todo.java rename {text-ui-test => src/main/java/text-ui-test}/EXPECTED.TXT (100%) rename {text-ui-test => src/main/java/text-ui-test}/input.txt (100%) rename {text-ui-test => src/main/java/text-ui-test}/runtest.bat (100%) rename {text-ui-test => src/main/java/text-ui-test}/runtest.sh (100%) diff --git a/src/main/java/Deadline.java b/src/main/java/Deadline.java new file mode 100644 index 000000000..623a1f49d --- /dev/null +++ b/src/main/java/Deadline.java @@ -0,0 +1,2 @@ +package PACKAGE_NAME;public class Deadline { +} diff --git a/src/main/java/Event.java b/src/main/java/Event.java new file mode 100644 index 000000000..fe6147652 --- /dev/null +++ b/src/main/java/Event.java @@ -0,0 +1,2 @@ +package PACKAGE_NAME;public class Event { +} diff --git a/src/main/java/Todolist.java b/src/main/java/Listmanager.java similarity index 97% rename from src/main/java/Todolist.java rename to src/main/java/Listmanager.java index 3a75e7524..f883131b7 100644 --- a/src/main/java/Todolist.java +++ b/src/main/java/Listmanager.java @@ -1,6 +1,8 @@ import java.util.Scanner; public class Todolist { + + String Icon = "T"; private static final int MAX_LIST_LENGTH = 100; static String[] todolist = new String[MAX_LIST_LENGTH]; static boolean[] isDoneList = new boolean[MAX_LIST_LENGTH]; @@ -69,7 +71,7 @@ public static void PrintList(){ if(s == null){ continue; } - System.out.printf("%d."+GetIcon(i)+s+"\n",i); + System.out.printf("%d."+ GetIcon(i)+s+"\n",i); i++; } System.out.print("---------------------------------------------\n"); diff --git a/src/main/java/Todo.java b/src/main/java/Todo.java new file mode 100644 index 000000000..e5659e7fc --- /dev/null +++ b/src/main/java/Todo.java @@ -0,0 +1,2 @@ +public class Todo { +} diff --git a/text-ui-test/EXPECTED.TXT b/src/main/java/text-ui-test/EXPECTED.TXT similarity index 100% rename from text-ui-test/EXPECTED.TXT rename to src/main/java/text-ui-test/EXPECTED.TXT diff --git a/text-ui-test/input.txt b/src/main/java/text-ui-test/input.txt similarity index 100% rename from text-ui-test/input.txt rename to src/main/java/text-ui-test/input.txt diff --git a/text-ui-test/runtest.bat b/src/main/java/text-ui-test/runtest.bat similarity index 100% rename from text-ui-test/runtest.bat rename to src/main/java/text-ui-test/runtest.bat diff --git a/text-ui-test/runtest.sh b/src/main/java/text-ui-test/runtest.sh similarity index 100% rename from text-ui-test/runtest.sh rename to src/main/java/text-ui-test/runtest.sh From 4c0c74d61f5adfd58b3c0317ba4b46475470a2c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=99=A8=E7=8F=96=20=E5=A7=9A?= <1014717807@QQ.com> Date: Sun, 25 Feb 2024 00:01:43 +0800 Subject: [PATCH 06/17] added delete and save functions --- list.txt | 1 + src/main/java/META-INF/MANIFEST.MF | 3 +++ text-ui-test/EXPECTED.TXT | 7 ++++++ text-ui-test/input.txt | 7 ++++++ text-ui-test/runtest.bat | 22 +++++++++++++++++ text-ui-test/runtest.sh | 38 ++++++++++++++++++++++++++++++ 6 files changed, 78 insertions(+) create mode 100644 list.txt create mode 100644 src/main/java/META-INF/MANIFEST.MF create mode 100644 text-ui-test/EXPECTED.TXT create mode 100644 text-ui-test/input.txt create mode 100644 text-ui-test/runtest.bat create mode 100644 text-ui-test/runtest.sh diff --git a/list.txt b/list.txt new file mode 100644 index 000000000..2aac3a1ea --- /dev/null +++ b/list.txt @@ -0,0 +1 @@ +-1[T][ ] stellaris diff --git a/src/main/java/META-INF/MANIFEST.MF b/src/main/java/META-INF/MANIFEST.MF new file mode 100644 index 000000000..922689772 --- /dev/null +++ b/src/main/java/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: Qchat + diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT new file mode 100644 index 000000000..18067e5e3 --- /dev/null +++ b/text-ui-test/EXPECTED.TXT @@ -0,0 +1,7 @@ +Qchat ,A truly humanized intelligent voice assistant +knows better about life and better about you +What can I do for you? +---------------------------------------------------------------- +--------------------------------------------- +Here are your current tasks in your list: +--------------------------------------------- diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt new file mode 100644 index 000000000..4e55d0655 --- /dev/null +++ b/text-ui-test/input.txt @@ -0,0 +1,7 @@ +list +add +todo stellaris + + + + diff --git a/text-ui-test/runtest.bat b/text-ui-test/runtest.bat new file mode 100644 index 000000000..89bbcccba --- /dev/null +++ b/text-ui-test/runtest.bat @@ -0,0 +1,22 @@ +@ECHO OFF + +REM create bin directory if it doesn't exist +if not exist ..\bin mkdir ..\bin + +REM delete output from previous run +if exist ACTUAL.TXT del ACTUAL.TXT + +javac -cp ..\src\main\java -Xlint:none -d ..\bin ..\src\main\java\*.java +REM compile the code into the bin folder + +IF ERRORLEVEL 1 ( + echo ********** BUILD FAILURE ********** + exit /b 1 +) +REM no error here, errorlevel == 0 + +REM run the program, feed commands from input.txt file and redirect the output to the ACTUAL.TXT +java -classpath ..\bin Qchat < ./input.txt > ./ACTUAL.TXT + +REM compare the output to the expected output +FC ACTUAL.TXT EXPECTED.TXT diff --git a/text-ui-test/runtest.sh b/text-ui-test/runtest.sh new file mode 100644 index 000000000..c9ec87003 --- /dev/null +++ b/text-ui-test/runtest.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash + +# create bin directory if it doesn't exist +if [ ! -d "../bin" ] +then + mkdir ../bin +fi + +# delete output from previous run +if [ -e "./ACTUAL.TXT" ] +then + rm ACTUAL.TXT +fi + +# compile the code into the bin folder, terminates if error occurred +if ! javac -cp ../src/main/java -Xlint:none -d ../bin ../src/main/java/*.java +then + echo "********** BUILD FAILURE **********" + exit 1 +fi + +# run the program, feed commands from input.txt file and redirect the output to the ACTUAL.TXT +java -classpath ../bin Duke < input.txt > ACTUAL.TXT + +# convert to UNIX format +cp EXPECTED.TXT EXPECTED-UNIX.TXT +dos2unix ACTUAL.TXT EXPECTED-UNIX.TXT + +# compare the output to the expected output +diff ACTUAL.TXT EXPECTED-UNIX.TXT +if [ $? -eq 0 ] +then + echo "Test result: PASSED" + exit 0 +else + echo "Test result: FAILED" + exit 1 +fi \ No newline at end of file From 164fe072ba5a24563177d34185c1c0d5970402ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=99=A8=E7=8F=96=20=E5=A7=9A?= <1014717807@QQ.com> Date: Mon, 26 Feb 2024 01:02:21 +0800 Subject: [PATCH 07/17] recovered from mess of git --- list.txt | 2 +- src/main/java/Deadline.java | 16 +- src/main/java/Event.java | 14 +- src/main/java/InvalidTimeForm.java | 2 + src/main/java/ListManager.java | 265 +++++++++++++++++++++++++++++ src/main/java/Listmanager.java | 133 --------------- src/main/java/Qchat.java | 3 +- src/main/java/Todo.java | 18 ++ 8 files changed, 316 insertions(+), 137 deletions(-) create mode 100644 src/main/java/InvalidTimeForm.java create mode 100644 src/main/java/ListManager.java delete mode 100644 src/main/java/Listmanager.java diff --git a/list.txt b/list.txt index 2aac3a1ea..b48d5d9fa 100644 --- a/list.txt +++ b/list.txt @@ -1 +1 @@ --1[T][ ] stellaris +1[T][ ] stellaris diff --git a/src/main/java/Deadline.java b/src/main/java/Deadline.java index 623a1f49d..718a72639 100644 --- a/src/main/java/Deadline.java +++ b/src/main/java/Deadline.java @@ -1,2 +1,16 @@ -package PACKAGE_NAME;public class Deadline { +public class Deadline extends Todo{ + String endtime; + String Icon="D"; + + public Deadline(boolean isDone, String description, String endtime) { + super(isDone, description); + this.endtime = endtime; + } + + @Override + public String toString(){ + String DoneIcon = isDone? "x":" "; + return "["+Icon+"]"+"["+DoneIcon+"]"+ description + "(by:"+ endtime+")"; + } + } diff --git a/src/main/java/Event.java b/src/main/java/Event.java index fe6147652..b7c9724f7 100644 --- a/src/main/java/Event.java +++ b/src/main/java/Event.java @@ -1,2 +1,14 @@ -package PACKAGE_NAME;public class Event { +public class Event extends Deadline{ + String starttime; + String Icon="E"; + public Event(boolean isDone, String description, String endtime, String starttime) { + super(isDone, description, endtime); + this.starttime = starttime; + } + + @Override + public String toString(){ + String DoneIcon = isDone? "x":" "; + return "["+Icon+"]"+"["+DoneIcon+"]"+ " "+ description + "(from: "+starttime+ "):(by: "+endtime+")" ; + } } diff --git a/src/main/java/InvalidTimeForm.java b/src/main/java/InvalidTimeForm.java new file mode 100644 index 000000000..d25b18121 --- /dev/null +++ b/src/main/java/InvalidTimeForm.java @@ -0,0 +1,2 @@ +public class InvalidTimeForm extends Exception { +} diff --git a/src/main/java/ListManager.java b/src/main/java/ListManager.java new file mode 100644 index 000000000..b30e3bc0a --- /dev/null +++ b/src/main/java/ListManager.java @@ -0,0 +1,265 @@ +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Scanner; + +public class ListManager { + + static ArrayList todolist = new ArrayList<>(); + //static boolean[] isDoneList = new boolean[MAX_LIST_LENGTH]; + + static Scanner in = new Scanner(System.in); + + private static final String LIST_FORM= + "please enter in one of the following form:\n"+ + "todo 'description' \n" + + "deadline 'description' /by 'end time'\n"+ + "event 'description' /from 'start time' /to 'end time'\n"; + public static String AddToList(String description) throws InvalidTimeForm { + + + String[] part = (description.trim()).split(" "); + String suffix = description.replace(part[0],""); + + if (part[0].startsWith("todo")){ + return (AddTodo(suffix)); + } + else if(part[0].startsWith("deadline")){ + return(AddDeadline(suffix)); + } + else if(part[0].startsWith("event") ){ + return(AddEvent(suffix)); + } + else { + return ""; + } + + } + + private static String AddTodo(String description) { + Todo todo= new Todo(false , description); + todolist.add(todo); + return "Todo added\n" ; + } + private static String AddDeadline(String description) throws InvalidTimeForm { + String[] part = (description.trim()).split("/by"); + + if (part.length > 2){ + throw new InvalidTimeForm();// two or more "/by" + } + + Deadline deadline = new Deadline(false, part[0].trim(),part[1].trim()); + todolist.add(deadline) ; + return "deadline added\n" ; + + } + + private static String AddEvent(String description) throws InvalidTimeForm { + String[] part = (description.trim()).split("/from"); + + if (part.length > 2){ + throw new InvalidTimeForm(); + } + + String EventDescription = part[0].trim(); + + part = (part[1].trim()).split("/to"); // reuse of part + + if (part.length > 2){ + throw new InvalidTimeForm(); + } + + String end = part[1].trim(); + String start = part[0].trim(); + + Event event = new Event(false, EventDescription,end,start); + todolist.add(event) ; + return "event added\n" ; + + } + + + + + + static void HandleList() { + PrintList(); + String command =""; + + while(!command.equals("quit")){ + command = in.nextLine(); + switch (command.trim()){ + case"add": + System.out.println(LIST_FORM); + String description = in.nextLine(); + try { + System.out.println(AddToList(description)); + } catch (InvalidTimeForm e) { + System.out.println("wrong time form, please add again"); + } + PrintList(); + break; + case"quit": + System.out.println("Task change complete\n"); + break; + case"help": + System.out.print("supported commands: add , quit , help , mark, unmark ,clear, list, delete \n"); + break; + case"clear": + ClearList(); + System.out.print("list cleared\n"); + break; + case"mark": + SetDone(); + break; + case"unmark": + SetUndone(); + break; + case"list": + PrintList(); + break; + case"": + break; + case"delete": + Deletelist(); + break ; + case"save": + try { + SaveList(); + } catch (IOException e) { + throw new RuntimeException(e); + } + break; + default: + System.out.println("Sorry, I can not understand this command, enter \"help\" for help\n"); + break; + } + + } + + } + + private static void SaveList() throws IOException { + File file = new File("list.txt"); + + if (file.exists()) { + System.out.println("file exists, overwriting file"); + } + else { + file.createNewFile() ; + } + + FileWriter fw = new FileWriter("list.txt"); + for (Todo t :todolist ){ + if(t == null){ + continue; + } + fw.write( (todolist.indexOf(t)+1) + t.toString() +"\n"); + + } + fw.close(); + + + + } + + private static void Deletelist() { + + if(todolist.isEmpty()){ + System.out.println("no available tasks\n"); + return; + } + int number = in.nextInt(); + + while(number> todolist.size()){ + System.out.println("index out of bound, please retype\n"); + number = in.nextInt(); + } + todolist.remove(number-1); + + System.out.println("task deleted\n"); + PrintList(); + } + + + public static void PrintList(){ + int i=1; + System.out.print("---------------------------------------------\n"); + System.out.println("Here are your current tasks in your list:"); + for (Todo t :todolist ){ + if(t == null){ + continue; + } + System.out.printf("%d. " + t.toString() +"\n",i); + i++; + } + System.out.print("---------------------------------------------\n"); + } + + static void ClearList(){ + todolist.clear(); + } + + + + + private static void SetDone() { + if(todolist.isEmpty()){ + System.out.println("No available task! \n"); + return; + } + + System.out.println("please type the task number you want to set as done \n"); + PrintList(); + int number= in.nextInt(); + + while(number> todolist.size()){ + System.out.println("task do not exist, pleas enter a valid task number "); + number= in.nextInt(); + } + + Todo task= todolist.get(number-1); + + task.SetisDone(true); + + System.out.print("I've marked this task as done:"); + System.out.println(task.toString()); + + } + + + + + static void SetUndone(){ + if(todolist.isEmpty()){ + System.out.println("No available task! \n"); + return; + } + + System.out.println("please type the task number you want to set as not done \n"); + PrintList(); + int number= in.nextInt(); + + + + while(number>todolist.size()){ + System.out.println("task do not exist, pleas enter a valid task number "); + number= in.nextInt(); + } + + Todo task= todolist.get(number-1); + + task.SetisDone(false); + + System.out.print("I've marked this task as not done:"); + System.out.println(task.toString()); + + + } + + +} + + + diff --git a/src/main/java/Listmanager.java b/src/main/java/Listmanager.java deleted file mode 100644 index f883131b7..000000000 --- a/src/main/java/Listmanager.java +++ /dev/null @@ -1,133 +0,0 @@ -import java.util.Scanner; - -public class Todolist { - - String Icon = "T"; - private static final int MAX_LIST_LENGTH = 100; - static String[] todolist = new String[MAX_LIST_LENGTH]; - static boolean[] isDoneList = new boolean[MAX_LIST_LENGTH]; - - static int ListCount= 0; - static Scanner in = new Scanner(System.in); - - public static void AddToList(){ - String Task= in.nextLine(); - todolist[ListCount] = Task; - isDoneList[ListCount]= false; - ListCount++; - return; - } - - - - static void HandleList(){ - PrintList(); - String command =""; - - while(!command.equals("quit")){ - command = in.nextLine(); - switch (command){ - case"add": - AddToList(); - System.out.println("Task added"); - PrintList(); - break; - case"quit": - System.out.println("Task change complete"); - break; - case"help": - System.out.print("supported commands: add , quit , help , mark,unmark ,clear, list\n"); - break; - case "clear": - ClearList(); - ClearisDoneList(); - System.out.print("list cleared\n"); - break; - case"mark": - SetDone(); - break; - case"unmark": - SetUndone(); - break; - case"list": - PrintList(); - break; - case"": - break; - default: - System.out.println("Sorry, I can not understand this command, enter \"help\" for help\n"); - break; - } - - } - - } - - public static void PrintList(){ - int i=1; - System.out.print("---------------------------------------------\n"); - System.out.println("Here are your current tasks in your list:"); - for (String s :todolist ){ - if(s == null){ - continue; - } - System.out.printf("%d."+ GetIcon(i)+s+"\n",i); - i++; - } - System.out.print("---------------------------------------------\n"); - } - static void ClearList(){ - int i; - for (i=0;iListCount){ - System.out.println("task do not exist, pleas enter a valid task number "); - number= in.nextInt(); - } - - isDoneList[number-1]=true; - System.out.print("I've marked this task as done:"); - System.out.printf(GetIcon(number)+todolist[number-1]+"\n"); - } - - static void SetUndone(){ - System.out.println("please type the task number you want to set as not done \n"); - PrintList(); - int number= in.nextInt(); - - while(number>ListCount){ - System.out.println("task do not exist, pleas enter a valid task number "); - number= in.nextInt(); - } - - isDoneList[number-1]=false; - System.out.print("I've marked this task as not done:"); - System.out.printf(GetIcon(number)+todolist[number-1]+"\n"); - - } - - -} - - diff --git a/src/main/java/Qchat.java b/src/main/java/Qchat.java index e60b0bad5..dbd476872 100644 --- a/src/main/java/Qchat.java +++ b/src/main/java/Qchat.java @@ -26,7 +26,8 @@ static String CommandReader(){ System.out.print(GOODBYE_GREETING); break; case "list": - Todolist.HandleList(); + ListManager Listmanager = null; + ListManager.HandleList(); break; diff --git a/src/main/java/Todo.java b/src/main/java/Todo.java index e5659e7fc..cc9ffb7a4 100644 --- a/src/main/java/Todo.java +++ b/src/main/java/Todo.java @@ -1,2 +1,20 @@ public class Todo { + + Boolean isDone; + String description; + String Icon="T"; + public Todo(boolean isDone, String description) { + this.isDone = isDone; + this.description = description; + } + + public void SetisDone(boolean isDone) { + this.isDone = isDone; + } + + @Override + public String toString(){ + String DoneIcon = isDone? "x":" "; + return "["+Icon+"]"+"["+DoneIcon+"]"+ description; + } } From e8763fb7482eb8bdef0e204067b990f017e968a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=99=A8=E7=8F=96=20=E5=A7=9A?= <1014717807@QQ.com> Date: Wed, 28 Feb 2024 17:54:50 +0800 Subject: [PATCH 08/17] added the ability to read from saved files --- list.txt | 4 +- src/main/java/Deadline.java | 2 +- src/main/java/Event.java | 5 +- src/main/java/ListManager.java | 87 +++++++++++++++++++++++++++++++--- src/main/java/Todo.java | 10 ++-- 5 files changed, 95 insertions(+), 13 deletions(-) diff --git a/list.txt b/list.txt index b48d5d9fa..db645ea5f 100644 --- a/list.txt +++ b/list.txt @@ -1 +1,3 @@ -1[T][ ] stellaris +1|D|| |slay the spire(by:1) +2|T|| | stellaris +3|E|| | hades(from: 1):(by: 2) diff --git a/src/main/java/Deadline.java b/src/main/java/Deadline.java index 718a72639..553ef2cf6 100644 --- a/src/main/java/Deadline.java +++ b/src/main/java/Deadline.java @@ -10,7 +10,7 @@ public Deadline(boolean isDone, String description, String endtime) { @Override public String toString(){ String DoneIcon = isDone? "x":" "; - return "["+Icon+"]"+"["+DoneIcon+"]"+ description + "(by:"+ endtime+")"; + return "["+Icon+"]"+"["+DoneIcon+"] "+ description + "(by:"+ endtime+")"; } } diff --git a/src/main/java/Event.java b/src/main/java/Event.java index b7c9724f7..bfef6acd5 100644 --- a/src/main/java/Event.java +++ b/src/main/java/Event.java @@ -1,6 +1,7 @@ public class Event extends Deadline{ String starttime; String Icon="E"; + public Event(boolean isDone, String description, String endtime, String starttime) { super(isDone, description, endtime); this.starttime = starttime; @@ -8,7 +9,7 @@ public Event(boolean isDone, String description, String endtime, String starttim @Override public String toString(){ - String DoneIcon = isDone? "x":" "; - return "["+Icon+"]"+"["+DoneIcon+"]"+ " "+ description + "(from: "+starttime+ "):(by: "+endtime+")" ; + String DoneIcon = this.isDone? "x":" "; + return "["+Icon+"]"+"["+DoneIcon+"]"+ " "+ this.description + "(from: "+starttime+ ") (by: "+this.endtime+")" ; } } diff --git a/src/main/java/ListManager.java b/src/main/java/ListManager.java index b30e3bc0a..c5af6760f 100644 --- a/src/main/java/ListManager.java +++ b/src/main/java/ListManager.java @@ -1,6 +1,4 @@ -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; +import java.io.*; import java.util.ArrayList; import java.util.Scanner; @@ -84,8 +82,14 @@ private static String AddEvent(String description) throws InvalidTimeForm { static void HandleList() { - PrintList(); + String command =""; + try { + ReadFile(); + } catch (FileNotFoundException e) { + throw new RuntimeException(e); + } + PrintList(); while(!command.equals("quit")){ command = in.nextLine(); @@ -140,6 +144,26 @@ static void HandleList() { } + private static void ReadFile() throws FileNotFoundException { + File file = new File("list.txt"); + if (!file.exists()) { + return; + } + else { + FileReader fr = new FileReader(file); + BufferedReader reader = new BufferedReader(fr); + try { + String line; + while ((line = reader.readLine()) != null) {// process every line + ProcessSavedLine(line); + } + } catch (IOException e) { + System.out.println(e.getMessage()); + } + + } + } + private static void SaveList() throws IOException { File file = new File("list.txt"); @@ -155,8 +179,8 @@ private static void SaveList() throws IOException { if(t == null){ continue; } - fw.write( (todolist.indexOf(t)+1) + t.toString() +"\n"); - + String content =(todolist.indexOf(t)+1) + t.toString() +"\n"; + fw.write(content.replace("[","|").replace("]","|") ); } fw.close(); @@ -259,6 +283,57 @@ static void SetUndone(){ } + + + private static void ProcessSavedLine(String line) { + + String Done = "|"+"([x ])"+"|"; + + Boolean isDone ; + if(line.contains("| |")){ + isDone = false; + }else if(line.contains("|x|")){ + + isDone = true; + }else{ + System.out.println("unexpected format"); + return; + } + String description; + String starttime; + String endtime; + + if(line.contains("|T|")){ + String parts = line.substring(7); + description = parts; + Todo task = new Todo(isDone,description.trim()); + todolist.add(task); + }else if(line.contains("|D|")){ + + //String[] parts = line.split(Done,2); + String parts = line.substring(7); + String[] contents = parts.split("" + + "by:",2); + description = contents[0].replace("(",""); + endtime = contents[1].replace(")",""); + Deadline task= new Deadline(isDone,description.trim(),endtime.trim()); + todolist.add(task); + + }else if(line.contains("|E|")){ + String parts = line.substring(7); + String[] contents = parts.split( "from:",2); + description = contents[0].replace("(",""); + String[] time= contents[1].split("by:",2 ); + starttime = time[0].replace("(","").replace(")",""); + endtime = time[1].replace("(","").replace(")",""); + Event task = new Event(isDone,description.trim(),endtime.trim(),starttime.trim()); + todolist.add(task); + }else{ + System.out.println("unexpected format"); + return; + } + + } } diff --git a/src/main/java/Todo.java b/src/main/java/Todo.java index cc9ffb7a4..9283499cc 100644 --- a/src/main/java/Todo.java +++ b/src/main/java/Todo.java @@ -1,7 +1,7 @@ public class Todo { - Boolean isDone; - String description; + public Boolean isDone; + public String description; String Icon="T"; public Todo(boolean isDone, String description) { this.isDone = isDone; @@ -12,9 +12,13 @@ public void SetisDone(boolean isDone) { this.isDone = isDone; } + public void SetDescription(String description){ + this.description = description; + } + @Override public String toString(){ String DoneIcon = isDone? "x":" "; - return "["+Icon+"]"+"["+DoneIcon+"]"+ description; + return "["+Icon+"]"+"["+DoneIcon+"] "+ description; } } From 39f4bc66d530491aa79e69cd8e43cbe359500c2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=99=A8=E7=8F=96=20=E5=A7=9A?= <1014717807@QQ.com> Date: Fri, 1 Mar 2024 23:37:37 +0800 Subject: [PATCH 09/17] more OOP --- src/main/java/ListManager.java | 269 +++++++-------------------------- src/main/java/Parser.java | 95 ++++++++++++ src/main/java/Qchat.java | 19 +-- src/main/java/Storage.java | 49 ++++++ src/main/java/UI.java | 42 +++++ 5 files changed, 248 insertions(+), 226 deletions(-) create mode 100644 src/main/java/Parser.java create mode 100644 src/main/java/Storage.java create mode 100644 src/main/java/UI.java diff --git a/src/main/java/ListManager.java b/src/main/java/ListManager.java index c5af6760f..0af600afc 100644 --- a/src/main/java/ListManager.java +++ b/src/main/java/ListManager.java @@ -3,134 +3,87 @@ import java.util.Scanner; public class ListManager { + static UI ui = new UI(); + static Parser parser = new Parser(); + static Storage storage = new Storage(); static ArrayList todolist = new ArrayList<>(); //static boolean[] isDoneList = new boolean[MAX_LIST_LENGTH]; static Scanner in = new Scanner(System.in); - private static final String LIST_FORM= - "please enter in one of the following form:\n"+ - "todo 'description' \n" + - "deadline 'description' /by 'end time'\n"+ - "event 'description' /from 'start time' /to 'end time'\n"; - public static String AddToList(String description) throws InvalidTimeForm { + public static String AddToList(String description) throws InvalidTimeForm { String[] part = (description.trim()).split(" "); - String suffix = description.replace(part[0],""); - - if (part[0].startsWith("todo")){ - return (AddTodo(suffix)); - } - else if(part[0].startsWith("deadline")){ - return(AddDeadline(suffix)); - } - else if(part[0].startsWith("event") ){ - return(AddEvent(suffix)); - } - else { + String suffix = description.replace(part[0], ""); + + if (part[0].startsWith("todo")) { + return (Parser.AddTodo(suffix)); + } else if (part[0].startsWith("deadline")) { + return (Parser.AddDeadline(suffix)); + } else if (part[0].startsWith("event")) { + return (Parser.AddEvent(suffix)); + } else { return ""; } } - private static String AddTodo(String description) { - Todo todo= new Todo(false , description); - todolist.add(todo); - return "Todo added\n" ; - } - private static String AddDeadline(String description) throws InvalidTimeForm { - String[] part = (description.trim()).split("/by"); - - if (part.length > 2){ - throw new InvalidTimeForm();// two or more "/by" - } - - Deadline deadline = new Deadline(false, part[0].trim(),part[1].trim()); - todolist.add(deadline) ; - return "deadline added\n" ; - - } - - private static String AddEvent(String description) throws InvalidTimeForm { - String[] part = (description.trim()).split("/from"); - - if (part.length > 2){ - throw new InvalidTimeForm(); - } - - String EventDescription = part[0].trim(); - - part = (part[1].trim()).split("/to"); // reuse of part - - if (part.length > 2){ - throw new InvalidTimeForm(); - } - - String end = part[1].trim(); - String start = part[0].trim(); - - Event event = new Event(false, EventDescription,end,start); - todolist.add(event) ; - return "event added\n" ; - - } - - - + static void HandleList() { - static void HandleList() { - - String command =""; + String command = ""; try { - ReadFile(); + todolist = storage.ReadFile(); } catch (FileNotFoundException e) { throw new RuntimeException(e); } - PrintList(); + UI.PrintList(todolist); + ; - while(!command.equals("quit")){ + while (!command.equals("quit")) { command = in.nextLine(); - switch (command.trim()){ - case"add": - System.out.println(LIST_FORM); + switch (command.trim()) { + case "add": + ui.PrintListForm(); String description = in.nextLine(); try { System.out.println(AddToList(description)); } catch (InvalidTimeForm e) { System.out.println("wrong time form, please add again"); } - PrintList(); + UI.PrintList(todolist); + ; break; - case"quit": + case "quit": System.out.println("Task change complete\n"); break; - case"help": + case "help": System.out.print("supported commands: add , quit , help , mark, unmark ,clear, list, delete \n"); break; - case"clear": + case "clear": ClearList(); System.out.print("list cleared\n"); break; - case"mark": + case "mark": SetDone(); break; - case"unmark": + case "unmark": SetUndone(); break; - case"list": - PrintList(); + case "list": + UI.PrintList(todolist); + break; - case"": + case "": break; - case"delete": + case "delete": Deletelist(); - break ; - case"save": + break; + case "save": try { - SaveList(); + storage.SaveList(todolist); } catch (IOException e) { throw new RuntimeException(e); } @@ -144,106 +97,51 @@ static void HandleList() { } - private static void ReadFile() throws FileNotFoundException { - File file = new File("list.txt"); - if (!file.exists()) { - return; - } - else { - FileReader fr = new FileReader(file); - BufferedReader reader = new BufferedReader(fr); - try { - String line; - while ((line = reader.readLine()) != null) {// process every line - ProcessSavedLine(line); - } - } catch (IOException e) { - System.out.println(e.getMessage()); - } - - } - } - - private static void SaveList() throws IOException { - File file = new File("list.txt"); - if (file.exists()) { - System.out.println("file exists, overwriting file"); - } - else { - file.createNewFile() ; - } - FileWriter fw = new FileWriter("list.txt"); - for (Todo t :todolist ){ - if(t == null){ - continue; - } - String content =(todolist.indexOf(t)+1) + t.toString() +"\n"; - fw.write(content.replace("[","|").replace("]","|") ); - } - fw.close(); - - } - private static void Deletelist() { - if(todolist.isEmpty()){ + if (todolist.isEmpty()) { System.out.println("no available tasks\n"); return; } int number = in.nextInt(); - while(number> todolist.size()){ + while (number > todolist.size()) { System.out.println("index out of bound, please retype\n"); number = in.nextInt(); } - todolist.remove(number-1); + todolist.remove(number - 1); System.out.println("task deleted\n"); - PrintList(); + UI.PrintList(todolist); + ; } - public static void PrintList(){ - int i=1; - System.out.print("---------------------------------------------\n"); - System.out.println("Here are your current tasks in your list:"); - for (Todo t :todolist ){ - if(t == null){ - continue; - } - System.out.printf("%d. " + t.toString() +"\n",i); - i++; - } - System.out.print("---------------------------------------------\n"); - } - - static void ClearList(){ + static void ClearList() { todolist.clear(); } - - private static void SetDone() { - if(todolist.isEmpty()){ + if (todolist.isEmpty()) { System.out.println("No available task! \n"); return; } System.out.println("please type the task number you want to set as done \n"); - PrintList(); - int number= in.nextInt(); + UI.PrintList(todolist); + int number = in.nextInt(); - while(number> todolist.size()){ + while (number > todolist.size()) { System.out.println("task do not exist, pleas enter a valid task number "); - number= in.nextInt(); + number = in.nextInt(); } - Todo task= todolist.get(number-1); + Todo task = todolist.get(number - 1); task.SetisDone(true); @@ -253,26 +151,24 @@ private static void SetDone() { } - - - static void SetUndone(){ - if(todolist.isEmpty()){ + static void SetUndone() { + if (todolist.isEmpty()) { System.out.println("No available task! \n"); return; } System.out.println("please type the task number you want to set as not done \n"); - PrintList(); - int number= in.nextInt(); - + UI.PrintList(todolist); + ; + int number = in.nextInt(); - while(number>todolist.size()){ + while (number > todolist.size()) { System.out.println("task do not exist, pleas enter a valid task number "); - number= in.nextInt(); + number = in.nextInt(); } - Todo task= todolist.get(number-1); + Todo task = todolist.get(number - 1); task.SetisDone(false); @@ -281,60 +177,11 @@ static void SetUndone(){ } +} - private static void ProcessSavedLine(String line) { - - String Done = "|"+"([x ])"+"|"; - - Boolean isDone ; - if(line.contains("| |")){ - isDone = false; - }else if(line.contains("|x|")){ - - isDone = true; - }else{ - System.out.println("unexpected format"); - return; - } - String description; - String starttime; - String endtime; - - if(line.contains("|T|")){ - String parts = line.substring(7); - description = parts; - Todo task = new Todo(isDone,description.trim()); - todolist.add(task); - }else if(line.contains("|D|")){ - - //String[] parts = line.split(Done,2); - String parts = line.substring(7); - String[] contents = parts.split("" + - "by:",2); - description = contents[0].replace("(",""); - endtime = contents[1].replace(")",""); - Deadline task= new Deadline(isDone,description.trim(),endtime.trim()); - todolist.add(task); - - }else if(line.contains("|E|")){ - String parts = line.substring(7); - String[] contents = parts.split( "from:",2); - description = contents[0].replace("(",""); - String[] time= contents[1].split("by:",2 ); - starttime = time[0].replace("(","").replace(")",""); - endtime = time[1].replace("(","").replace(")",""); - Event task = new Event(isDone,description.trim(),endtime.trim(),starttime.trim()); - todolist.add(task); - }else{ - System.out.println("unexpected format"); - return; - } - - } -} diff --git a/src/main/java/Parser.java b/src/main/java/Parser.java new file mode 100644 index 000000000..a7c7836d1 --- /dev/null +++ b/src/main/java/Parser.java @@ -0,0 +1,95 @@ +import java.util.ArrayList; + +public class Parser { + + public static void ProcessSavedLine(String line, ArrayList todolist) { + String Done = "|"+"([x ])"+"|"; + + Boolean isDone ; + if(line.contains("| |")){ + isDone = false; + }else if(line.contains("|x|")){ + + isDone = true; + }else{ + System.out.println("unexpected format"); + return; + } + String description; + String starttime; + String endtime; + + if(line.contains("|T|")){ + String parts = line.substring(7); + description = parts; + Todo task = new Todo(isDone,description.trim()); + todolist.add(task); + }else if(line.contains("|D|")){ + + //String[] parts = line.split(Done,2); + String parts = line.substring(7); + String[] contents = parts.split("" + + "by:",2); + description = contents[0].replace("(",""); + endtime = contents[1].replace(")",""); + Deadline task= new Deadline(isDone,description.trim(),endtime.trim()); + todolist.add(task); + + }else if(line.contains("|E|")){ + String parts = line.substring(7); + String[] contents = parts.split( "from:",2); + description = contents[0].replace("(",""); + String[] time= contents[1].split("by:",2 ); + starttime = time[0].replace("(","").replace(")",""); + endtime = time[1].replace("(","").replace(")",""); + Event task = new Event(isDone,description.trim(),endtime.trim(),starttime.trim()); + todolist.add(task); + }else{ + System.out.println("unexpected format,skipping"); + return; + } + + } + + + static String AddTodo(String description) { + Todo todo = new Todo(false, description); + ListManager.todolist.add(todo); + return "Todo added\n"; + } + + static String AddDeadline(String description) throws InvalidTimeForm { + String[] part = (description.trim()).split("/by"); + + if (part.length > 2) { + throw new InvalidTimeForm();// two or more "/by" + } + + Deadline deadline = new Deadline(false, part[0].trim(), part[1].trim()); + ListManager.todolist.add(deadline); + return "deadline added\n"; + + } + + static String AddEvent(String description) throws InvalidTimeForm { + + String[] part = (description.trim()).split("/from"); + if (part.length > 2) { + throw new InvalidTimeForm(); + } + String EventDescription = part[0].trim(); + String[] content = (part[1].trim()).split("/to"); + + if (content.length > 2) { + throw new InvalidTimeForm(); + } + String end = content[1].trim(); + String start = content[0].trim(); + + Event event = new Event(false, EventDescription, end, start); + ListManager.todolist.add(event); + return "event added\n"; + + } +} + diff --git a/src/main/java/Qchat.java b/src/main/java/Qchat.java index dbd476872..eb6d1ca61 100644 --- a/src/main/java/Qchat.java +++ b/src/main/java/Qchat.java @@ -2,19 +2,7 @@ import java.util.Scanner; public class Qchat { - - static final String WELCOME_GREETING = new String( - "Qchat ,A truly humanized intelligent voice assisstant \n" - +"knows better about life and better about you\n" - +"What can I do for you?\n" - +"----------------------------------------------------------------\n") ; - static final String GOODBYE_GREETING = new String( - "--------------------------------------------------------\n" + - "goodbye\n"+ "Qchat, your life-long trusted companion\n"); - - - - + static UI ui = new UI(); static String CommandReader(){ Scanner in = new Scanner(System.in); @@ -23,7 +11,7 @@ static String CommandReader(){ switch (command){ case "Bye": - System.out.print(GOODBYE_GREETING); + ui.Goodbye(); break; case "list": ListManager Listmanager = null; @@ -50,7 +38,8 @@ private static void echo(String command) { public static void main(String[] args) { - System.out.print(WELCOME_GREETING); + + ui.Greeting(); String command = "" ; while(!command.equals("Bye")){ diff --git a/src/main/java/Storage.java b/src/main/java/Storage.java new file mode 100644 index 000000000..cc3b0db29 --- /dev/null +++ b/src/main/java/Storage.java @@ -0,0 +1,49 @@ +import com.sun.jdi.ArrayReference; + +import java.io.*; +import java.util.ArrayList; + +public class Storage { + static ArrayList todolist = new ArrayList<>(); + static ArrayList ReadFile() throws FileNotFoundException { + File file = new File("list.txt"); + if (!file.exists()) { + return todolist; + } else { + FileReader fr = new FileReader(file); + BufferedReader reader = new BufferedReader(fr); + try { + String line; + while ((line = reader.readLine()) != null) {// process every line + Parser.ProcessSavedLine(line, ListManager.todolist); + } + } catch (IOException e) { + System.out.println(e.getMessage()); + } + return todolist; + + } + } + + static void SaveList(ArrayList todolist) throws IOException { + File file = new File("list.txt"); + + if (file.exists()) { + System.out.println("file exists, overwriting file"); + } else { + file.createNewFile(); + } + + FileWriter fw = new FileWriter("list.txt"); + for (Object t : todolist) { + if (t == null) { + continue; + } + String content = (todolist.indexOf(t) + 1) + t.toString() + "\n"; + fw.write(content.replace("[", "|").replace("]", "|")); + } + fw.close(); + + + } +} diff --git a/src/main/java/UI.java b/src/main/java/UI.java new file mode 100644 index 000000000..248708064 --- /dev/null +++ b/src/main/java/UI.java @@ -0,0 +1,42 @@ +import java.util.ArrayList; + +public class UI { + static final String WELCOME_GREETING = new String( + "Qchat ,A truly humanized intelligent voice assisstant \n" + +"knows better about life and better about you\n" + +"What can I do for you?\n" + +"----------------------------------------------------------------\n") ; + static final String GOODBYE_GREETING = new String( + "--------------------------------------------------------\n" + + "goodbye\n"+ "Qchat, your life-long trusted companion\n"); + private static final String LIST_FORM= + "please enter in one of the following form:\n"+ + "todo 'description' \n" + + "deadline 'description' /by 'end time'\n"+ + "event 'description' /from 'start time' /to 'end time'\n"; + + public void Greeting(){ + System.out.print(WELCOME_GREETING); + } + + public void Goodbye(){ + System.out.print(GOODBYE_GREETING); + } + public void PrintListForm(){ + System.out.println(LIST_FORM); + } + public static void PrintList(ArrayList todolist){ + int i=1; + System.out.print("---------------------------------------------\n"); + System.out.println("Here are your current tasks in your list:"); + for (Object t :todolist ){ + if(t == null){ + continue; + } + System.out.printf("%d. " + t.toString() +"\n",i); + i++; + } + System.out.print("---------------------------------------------\n"); + } + +} From 1404793d74b736d2c51cc5c4c8ce38c026dc2ec6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=99=A8=E7=8F=96=20=E5=A7=9A?= <1014717807@QQ.com> Date: Fri, 8 Mar 2024 10:00:32 +0800 Subject: [PATCH 10/17] added the function of find matching todos --- src/main/java/ListManager.java | 37 +++++++++++++++++++++++++--------- src/main/java/UI.java | 4 ++-- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/main/java/ListManager.java b/src/main/java/ListManager.java index 0af600afc..7f5501ff9 100644 --- a/src/main/java/ListManager.java +++ b/src/main/java/ListManager.java @@ -6,10 +6,10 @@ public class ListManager { static UI ui = new UI(); static Parser parser = new Parser(); static Storage storage = new Storage(); - static ArrayList todolist = new ArrayList<>(); //static boolean[] isDoneList = new boolean[MAX_LIST_LENGTH]; - + static final String ALL_TASKS = "Here are your current tasks in your list:" ; + static final String MATCHED_TASKS = "Here are the matching tasks in your list:" ; static Scanner in = new Scanner(System.in); @@ -39,7 +39,7 @@ static void HandleList() { } catch (FileNotFoundException e) { throw new RuntimeException(e); } - UI.PrintList(todolist); + UI.PrintList(todolist,ALL_TASKS); ; while (!command.equals("quit")) { @@ -53,7 +53,7 @@ static void HandleList() { } catch (InvalidTimeForm e) { System.out.println("wrong time form, please add again"); } - UI.PrintList(todolist); + UI.PrintList(todolist,ALL_TASKS); ; break; case "quit": @@ -73,11 +73,13 @@ static void HandleList() { SetUndone(); break; case "list": - UI.PrintList(todolist); - + UI.PrintList(todolist,ALL_TASKS); break; case "": break; + case "find": + SearchList(); + break; case "delete": Deletelist(); break; @@ -97,8 +99,25 @@ static void HandleList() { } + private static void SearchList() { + System.out.print("please type the key words you want to find\n"); + String description = in.nextLine(); + ArrayList temp_todolist = new ArrayList<>(); + for(Todo t:todolist){ + if(t.description.contains(description)){ + temp_todolist.add(t); + } + } + if(temp_todolist.isEmpty()){ + System.out.print("no matched task found!\n"); + } + else{ + UI.PrintList(temp_todolist,MATCHED_TASKS); + temp_todolist.clear(); + } + } private static void Deletelist() { @@ -116,7 +135,7 @@ private static void Deletelist() { todolist.remove(number - 1); System.out.println("task deleted\n"); - UI.PrintList(todolist); + UI.PrintList(todolist,ALL_TASKS); ; } @@ -133,7 +152,7 @@ private static void SetDone() { } System.out.println("please type the task number you want to set as done \n"); - UI.PrintList(todolist); + UI.PrintList(todolist,ALL_TASKS); int number = in.nextInt(); while (number > todolist.size()) { @@ -158,7 +177,7 @@ static void SetUndone() { } System.out.println("please type the task number you want to set as not done \n"); - UI.PrintList(todolist); + UI.PrintList(todolist,ALL_TASKS); ; int number = in.nextInt(); diff --git a/src/main/java/UI.java b/src/main/java/UI.java index 248708064..0ea98bdb8 100644 --- a/src/main/java/UI.java +++ b/src/main/java/UI.java @@ -25,10 +25,10 @@ public void Goodbye(){ public void PrintListForm(){ System.out.println(LIST_FORM); } - public static void PrintList(ArrayList todolist){ + public static void PrintList(ArrayList todolist, String description ){ int i=1; System.out.print("---------------------------------------------\n"); - System.out.println("Here are your current tasks in your list:"); + System.out.println(description); for (Object t :todolist ){ if(t == null){ continue; From 0fe72dc2e55c82e2ad6fa714d9c22cbed9b694de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=99=A8=E7=8F=96=20=E5=A7=9A?= <1014717807@QQ.com> Date: Fri, 8 Mar 2024 11:23:03 +0800 Subject: [PATCH 11/17] added javadoc for three classes --- src/main/java/Deadline.java | 20 ++++++++++++--- src/main/java/Event.java | 21 +++++++++++++--- src/main/java/Todo.java | 49 ++++++++++++++++++++++++++++++++----- 3 files changed, 78 insertions(+), 12 deletions(-) diff --git a/src/main/java/Deadline.java b/src/main/java/Deadline.java index 553ef2cf6..076c10c19 100644 --- a/src/main/java/Deadline.java +++ b/src/main/java/Deadline.java @@ -1,16 +1,30 @@ +/** + * The {@code Deadline} class represents a deadline item. + * comparing with todo , it has a end time + * + */ public class Deadline extends Todo{ String endtime; String Icon="D"; - + /** + * Constructs a new deadline item. + * + * @param isDone Indicates whether the deadline item is done + * @param description The description of the deadline item + * @param endtime A String indicating the end time of this deadline + */ public Deadline(boolean isDone, String description, String endtime) { super(isDone, description); this.endtime = endtime; } - + /** + * similar to the one in Todo class + * @return The string representation of the to-do item + */ @Override public String toString(){ String DoneIcon = isDone? "x":" "; return "["+Icon+"]"+"["+DoneIcon+"] "+ description + "(by:"+ endtime+")"; } -} +} \ No newline at end of file diff --git a/src/main/java/Event.java b/src/main/java/Event.java index bfef6acd5..a881c55ea 100644 --- a/src/main/java/Event.java +++ b/src/main/java/Event.java @@ -1,15 +1,30 @@ +/** + * The {@code Event} class represents a event item. + * it has a start time and an end time + * + */ public class Event extends Deadline{ String starttime; String Icon="E"; - + /** + * Constructs a new event item. + * + * @param isDone Indicates whether the deadline item is done + * @param description The description of the deadline item + * @param endtime A String indicating the end time of this event + * @param starttime A String indicating the start time of this event + */ public Event(boolean isDone, String description, String endtime, String starttime) { super(isDone, description, endtime); this.starttime = starttime; } - + /** + * similar to the one in Todo class + * @return The string representation of the event item + */ @Override public String toString(){ String DoneIcon = this.isDone? "x":" "; return "["+Icon+"]"+"["+DoneIcon+"]"+ " "+ this.description + "(from: "+starttime+ ") (by: "+this.endtime+")" ; } -} +} \ No newline at end of file diff --git a/src/main/java/Todo.java b/src/main/java/Todo.java index 9283499cc..2c8df8c50 100644 --- a/src/main/java/Todo.java +++ b/src/main/java/Todo.java @@ -1,24 +1,61 @@ +/** + * The {@code Todo} class represents a to-do item. + * the super class of all types of tasks + */ public class Todo { + /** + * Indicates whether the to-do item is done or not. + */ public Boolean isDone; + + /** + * The description of the to-do item. + */ public String description; - String Icon="T"; + + /** + * The icon representing the to-do item, defaulting to "T". + */ + String Icon = "T"; + + /** + * Constructs a new to-do item. + * + * @param isDone Indicates whether the todo item is done + * @param description The description of the todo item + */ public Todo(boolean isDone, String description) { this.isDone = isDone; this.description = description; } + /** + * Sets the completion status of the to-do item. + * + * @param isDone Indicates whether the to-do item is done + */ public void SetisDone(boolean isDone) { this.isDone = isDone; } - public void SetDescription(String description){ + /** + * Sets the description of the to-do item. + * + * @param description The description of the to-do item + */ + public void SetDescription(String description) { this.description = description; } + /**this toString method add prefix with brackets to indicate the type and status of the tasks + * Returns the string representation of the to-do item. + * + * @return The string representation of the to-do item + */ @Override - public String toString(){ - String DoneIcon = isDone? "x":" "; - return "["+Icon+"]"+"["+DoneIcon+"] "+ description; + public String toString() { + String DoneIcon = isDone ? "x" : " "; + return "[" + Icon + "]" + "[" + DoneIcon + "] " + description; } -} +} \ No newline at end of file From 9c842cbee85b6fe8ef0a9e12e6c95b1ef4453c4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=99=A8=E7=8F=96=20=E5=A7=9A?= <1014717807@QQ.com> Date: Fri, 8 Mar 2024 13:48:20 +0800 Subject: [PATCH 12/17] add more java doc --- src/main/java/ListManager.java | 2 +- src/main/java/Parser.java | 101 ++++++++++++++++++++------------- src/main/java/Storage.java | 30 +++++++--- src/main/java/UI.java | 71 ++++++++++++++++------- 4 files changed, 138 insertions(+), 66 deletions(-) diff --git a/src/main/java/ListManager.java b/src/main/java/ListManager.java index 7f5501ff9..4244ca3e4 100644 --- a/src/main/java/ListManager.java +++ b/src/main/java/ListManager.java @@ -60,7 +60,7 @@ static void HandleList() { System.out.println("Task change complete\n"); break; case "help": - System.out.print("supported commands: add , quit , help , mark, unmark ,clear, list, delete \n"); + System.out.print("supported commands: add , quit , help , mark, unmark ,clear, list, delete, find ,save \n"); break; case "clear": ClearList(); diff --git a/src/main/java/Parser.java b/src/main/java/Parser.java index a7c7836d1..c05d55069 100644 --- a/src/main/java/Parser.java +++ b/src/main/java/Parser.java @@ -1,76 +1,101 @@ import java.util.ArrayList; +/** + * The {@code Parser} class handles the parsing of input lines and creating corresponding to-do items. + */ public class Parser { + public static final int BEGIN_INDEX = 7; + + /** + * Processes a saved line from the file and creates a corresponding to-do item. + * deals with 3 types and store them in todolist + * first the function decide the type ,the it extracts description , start time and end time according to the + * format + * + * @param line The saved line to be processed + * @param todolist The list of to-do items to which the created item will be added + */ public static void ProcessSavedLine(String line, ArrayList todolist) { - String Done = "|"+"([x ])"+"|"; + String Done = "|" + "([x ])" + "|"; - Boolean isDone ; - if(line.contains("| |")){ + Boolean isDone; + if (line.contains("| |")) { isDone = false; - }else if(line.contains("|x|")){ - + } else if (line.contains("|x|")) { isDone = true; - }else{ - System.out.println("unexpected format"); + } else { + System.out.println("Unexpected format"); return; } String description; String starttime; String endtime; - if(line.contains("|T|")){ - String parts = line.substring(7); + if (line.contains("|T|")) { + String parts = line.substring(BEGIN_INDEX); description = parts; - Todo task = new Todo(isDone,description.trim()); + Todo task = new Todo(isDone, description.trim()); todolist.add(task); - }else if(line.contains("|D|")){ - - //String[] parts = line.split(Done,2); - String parts = line.substring(7); - String[] contents = parts.split("" + - "by:",2); - description = contents[0].replace("(",""); - endtime = contents[1].replace(")",""); - Deadline task= new Deadline(isDone,description.trim(),endtime.trim()); + } else if (line.contains("|D|")) { + String parts = line.substring(BEGIN_INDEX); + String[] contents = parts.split("by:", 2); + description = contents[0].replace("(", ""); + endtime = contents[1].replace(")", ""); + Deadline task = new Deadline(isDone, description.trim(), endtime.trim()); todolist.add(task); - - }else if(line.contains("|E|")){ - String parts = line.substring(7); - String[] contents = parts.split( "from:",2); - description = contents[0].replace("(",""); - String[] time= contents[1].split("by:",2 ); - starttime = time[0].replace("(","").replace(")",""); - endtime = time[1].replace("(","").replace(")",""); - Event task = new Event(isDone,description.trim(),endtime.trim(),starttime.trim()); + } else if (line.contains("|E|")) { + String parts = line.substring(BEGIN_INDEX); + String[] contents = parts.split("from:", 2); + description = contents[0].replace("(", ""); + String[] time = contents[1].split("by:", 2); + starttime = time[0].replace("(", "").replace(")", ""); + endtime = time[1].replace("(", "").replace(")", ""); + Event task = new Event(isDone, description.trim(), endtime.trim(), starttime.trim()); todolist.add(task); - }else{ - System.out.println("unexpected format,skipping"); - return; + } else { + System.out.println("Unexpected format, skipping"); } - } - + /** + * Adds a to-do item to the list with the given description. + * + * @param description The description of the to-do item to be added + * @return A message indicating that the to-do item has been added + */ static String AddTodo(String description) { Todo todo = new Todo(false, description); ListManager.todolist.add(todo); return "Todo added\n"; } + /** + * Adds a deadline item to the list with the given description and end time. + * + * @param description The description of the deadline item to be added + * @return A message indicating that the deadline item has been added + * @throws InvalidTimeForm If the time format is invalid + */ static String AddDeadline(String description) throws InvalidTimeForm { String[] part = (description.trim()).split("/by"); if (part.length > 2) { - throw new InvalidTimeForm();// two or more "/by" + throw new InvalidTimeForm(); // two or more "/by" } Deadline deadline = new Deadline(false, part[0].trim(), part[1].trim()); ListManager.todolist.add(deadline); - return "deadline added\n"; - + return "Deadline added\n"; } + /** + * Adds an event item to the list with the given description, start time, and end time. + * + * @param description The description of the event item to be added + * @return A message indicating that the event item has been added + * @throws InvalidTimeForm If the time format is invalid + */ static String AddEvent(String description) throws InvalidTimeForm { String[] part = (description.trim()).split("/from"); @@ -88,8 +113,6 @@ static String AddEvent(String description) throws InvalidTimeForm { Event event = new Event(false, EventDescription, end, start); ListManager.todolist.add(event); - return "event added\n"; - + return "Event added\n"; } } - diff --git a/src/main/java/Storage.java b/src/main/java/Storage.java index cc3b0db29..0be82952b 100644 --- a/src/main/java/Storage.java +++ b/src/main/java/Storage.java @@ -1,10 +1,23 @@ -import com.sun.jdi.ArrayReference; - import java.io.*; import java.util.ArrayList; +/** + * The {@code Storage} class handles the reading and writing of to-do lists from and to a file. + */ public class Storage { + + /** + * The list of to-do items. + */ static ArrayList todolist = new ArrayList<>(); + + /** + * Reads the to-do list from the file "list.txt". + * will create a file if it does not exist + * it read evey line and use parser to handle it + * @return The list of to-do items read from the file + * @throws FileNotFoundException If the file "list.txt" does not exist + */ static ArrayList ReadFile() throws FileNotFoundException { File file = new File("list.txt"); if (!file.exists()) { @@ -14,22 +27,27 @@ static ArrayList ReadFile() throws FileNotFoundException { BufferedReader reader = new BufferedReader(fr); try { String line; - while ((line = reader.readLine()) != null) {// process every line + while ((line = reader.readLine()) != null) { // Process every line Parser.ProcessSavedLine(line, ListManager.todolist); } } catch (IOException e) { System.out.println(e.getMessage()); } return todolist; - } } + /** + * Saves the list of to-do items to the file "list.txt". + * will overwrite existing file + * @param todolist The list of to-do items to be saved + * @throws IOException If an I/O error occurs while writing to the file + */ static void SaveList(ArrayList todolist) throws IOException { File file = new File("list.txt"); if (file.exists()) { - System.out.println("file exists, overwriting file"); + System.out.println("File exists, overwriting file"); } else { file.createNewFile(); } @@ -43,7 +61,5 @@ static void SaveList(ArrayList todolist) throws IOException { fw.write(content.replace("[", "|").replace("]", "|")); } fw.close(); - - } } diff --git a/src/main/java/UI.java b/src/main/java/UI.java index 0ea98bdb8..95448ee0b 100644 --- a/src/main/java/UI.java +++ b/src/main/java/UI.java @@ -1,42 +1,75 @@ import java.util.ArrayList; +/** + * The {@code UI} class handles user interface interactions and displays messages. + */ public class UI { - static final String WELCOME_GREETING = new String( - "Qchat ,A truly humanized intelligent voice assisstant \n" - +"knows better about life and better about you\n" - +"What can I do for you?\n" - +"----------------------------------------------------------------\n") ; + + /** + * A welcome greeting message displayed when the program starts. + */ + static final String WELCOME_GREETING = new String( + "Qchat, A truly humanized intelligent voice assistant\n" + + "knows better about life and better about you\n" + + "What can I do for you?\n" + + "----------------------------------------------------------------\n"); + + /** + * A goodbye message displayed when the program ends. + */ static final String GOODBYE_GREETING = new String( "--------------------------------------------------------\n" + - "goodbye\n"+ "Qchat, your life-long trusted companion\n"); - private static final String LIST_FORM= - "please enter in one of the following form:\n"+ - "todo 'description' \n" + - "deadline 'description' /by 'end time'\n"+ + "goodbye\n" + "Qchat, your life-long trusted companion\n"); + + /** + * The format of the list command. + */ + private static final String LIST_FORM = + "please enter in one of the following forms:\n" + + "todo 'description'\n" + + "deadline 'description' /by 'end time'\n" + "event 'description' /from 'start time' /to 'end time'\n"; - public void Greeting(){ + /** + * Displays the welcome greeting message. + */ + public void Greeting() { System.out.print(WELCOME_GREETING); } - public void Goodbye(){ + /** + * Displays the goodbye message. + */ + public void Goodbye() { System.out.print(GOODBYE_GREETING); } - public void PrintListForm(){ + + /** + * Displays the list command format. + */ + public void PrintListForm() { System.out.println(LIST_FORM); } - public static void PrintList(ArrayList todolist, String description ){ - int i=1; + + /** + * Prints the list of items along with their sequence number and description of printed items + * if used for print every to-do in the list, description would be "Here are your current tasks in your list:" + * if used for print matching tasks ,description would be "Here are the matching tasks in your list:" + * + * @param todolist The list of items to print + * @param description The description of the list + */ + public static void PrintList(ArrayList todolist, String description) { + int i = 1; System.out.print("---------------------------------------------\n"); System.out.println(description); - for (Object t :todolist ){ - if(t == null){ + for (Object t : todolist) { + if (t == null) { continue; } - System.out.printf("%d. " + t.toString() +"\n",i); + System.out.printf("%d. " + t.toString() + "\n", i); i++; } System.out.print("---------------------------------------------\n"); } - } From b96d7f5f77d592c71a9b607fa8a252c270f6d56f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=99=A8=E7=8F=96=20=E5=A7=9A?= <1014717807@QQ.com> Date: Fri, 8 Mar 2024 14:48:09 +0800 Subject: [PATCH 13/17] added user guide --- docs/README.md | 162 ++++++++++++++++++++++++++++++++++++++++++++++--- list.txt | 3 - 2 files changed, 152 insertions(+), 13 deletions(-) diff --git a/docs/README.md b/docs/README.md index 8077118eb..42b5492ca 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2,28 +2,170 @@ ## Features -### Feature-ABC +### Feature- add task -Description of the feature. +Qchat can add 3 different types of tasks into the list -### Feature-XYZ +### Feature- save + +Qchat can save your current tasks and read it next time user uses + +### Feature- find + +Qchat find your task that contains a given keyword + +### Feature- mark as done + +Qchat can mark users task as done or not done -Description of the feature. ## Usage -### `Keyword` - Describe action -Describe the action and its outcome. -Example of usage: -`keyword (optional arguments)` +## Commands + +### `list` - enter the list mode +Example of usage: + +``` +list +``` + +Expected outcome: +``` +--------------------------------------------- +Here are your current tasks in your list: + +--------------------------------------------- +``` +### `Bye` - Quit the Qchat bot + +### list mode commads : + +### `add` - Add a task + +Adds a new task to the to-do list. + +Example of usage: + +``` +add +todo go to class +``` +Expected outcome: +``` +--------------------------------------------- +Here are your current tasks in your list: +1. [T][ ] go to class +--------------------------------------------- +``` + + +### `clear` - Clear all tasks + +Example of usage: + +``` +clear +``` +Expected outcome: +``` +list cleared +``` + +### `list` - list all current tasks + +Example of usage: + +``` +list +``` +Expected outcome: +``` +--------------------------------------------- +Here are your current tasks in your list: +--------------------------------------------- +``` +### `save` - save current tasks into a file + +Example of usage: + +``` +save +``` +Expected outcome: +``` +File exists, overwriting file +``` + + +### `mark & unmark` - set a task as done or not done + +Example of usage: + +``` +mark +1 +``` +Expected outcome: +``` +I've marked this task as done:[T][x] go to class +``` + +### `quit` - quit list mode + +Example of usage: + +``` +quit +``` +Expected outcome: +``` +Task change complete +``` +### `help` - get help of other commands + +Example of usage: + +``` +help +``` +Expected outcome: +``` +supported commands: add , quit , help , mark, unmark ,clear, list, delete, find ,save +``` + +### `find` - find task which contains a given keyword + +Example of usage: +``` +find +class +``` Expected outcome: +``` +--------------------------------------------- +Here are the matching tasks in your list: +1. [T][x] go to class +--------------------------------------------- +``` + +### `delete` - delete a task in the list -Description of the outcome. +Example of usage: ``` -expected output +delete +1 ``` +Expected outcome: +``` +--------------------------------------------- +Here are your current tasks in your list: +--------------------------------------------- + +``` + diff --git a/list.txt b/list.txt index db645ea5f..e69de29bb 100644 --- a/list.txt +++ b/list.txt @@ -1,3 +0,0 @@ -1|D|| |slay the spire(by:1) -2|T|| | stellaris -3|E|| | hades(from: 1):(by: 2) From 6f1bd63a24ba9dafcd6f799d9cef2cb9700826f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=99=A8=E7=8F=96=20=E5=A7=9A?= <1014717807@QQ.com> Date: Fri, 8 Mar 2024 15:06:25 +0800 Subject: [PATCH 14/17] improved feature list --- docs/README.md | 51 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/docs/README.md b/docs/README.md index 42b5492ca..87c218a1c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,25 +1,36 @@ # User Guide -## Features - -### Feature- add task - -Qchat can add 3 different types of tasks into the list - -### Feature- save - -Qchat can save your current tasks and read it next time user uses - -### Feature- find - -Qchat find your task that contains a given keyword - -### Feature- mark as done - -Qchat can mark users task as done or not done - - -## Usage +## Feature List +1. Add Tasks + Users can add various types of tasks such as to-do, deadline, and event tasks to the task list. + Command: `add` +2. View Task List + Users can view all tasks currently in the task list. + Command: `list` +3. Mark Task as Done + Users can mark a task as done. + Command: `mark` +4. Mark Task as Undone + Users can mark a completed task as not done. + Command: `unmark` +5. Delete Task + Users can delete a task from the task list. + Command: `delete` +6. Clear Task List + Users can clear all tasks from the task list. + Command: `clear` +7. Search Tasks + Users can search for tasks containing specific keywords. + Command: `find` +8. Save Task List + Users can save the current task list to a file. + Command: `save` +9. Help + Users can view a list of supported commands for using the task manager. + Command: `help` +10. Quit Task Manager + Users can exit the task manager application. + Command: `quit` From 405db82fef63b24288297a08b033365f4798df8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=99=A8=E7=8F=96=20=E5=A7=9A?= <1014717807@QQ.com> Date: Fri, 8 Mar 2024 15:23:17 +0800 Subject: [PATCH 15/17] releas ip.jar --- ip.jar | Bin 0 -> 13980 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 ip.jar diff --git a/ip.jar b/ip.jar new file mode 100644 index 0000000000000000000000000000000000000000..a11075c118fcb2f69fba646db52f9d9ac8e98840 GIT binary patch literal 13980 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 TKL`l&+t23P0V-hm_1FIc_4Brk literal 0 HcmV?d00001 From 651295ef13a73bfff18a03fe88e17f5307443a22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=99=A8=E7=8F=96=20=E5=A7=9A?= <1014717807@QQ.com> Date: Sun, 31 Mar 2024 18:49:29 +0800 Subject: [PATCH 16/17] final commit , fixed bugs so that now save ,load , add event can function normally , and changed time form so that the start time and end time are stored as Localdates , accept input as yyyy-MM-dd and output as MMM dd yyyy --- list.txt | 2 ++ src/main/java/Deadline.java | 17 ++++++++++++--- src/main/java/Event.java | 8 ++++--- src/main/java/ListManager.java | 26 +++++++++++++--------- src/main/java/Parser.java | 40 ++++++++++++++++++++++++++++------ src/main/java/Qchat.java | 12 ++++------ src/main/java/Storage.java | 17 +++++++++++++-- src/main/java/UI.java | 5 +++-- 8 files changed, 92 insertions(+), 35 deletions(-) diff --git a/list.txt b/list.txt index e69de29bb..8a9a0cd20 100644 --- a/list.txt +++ b/list.txt @@ -0,0 +1,2 @@ +1|D|| | stellaris(by:Mar 01 2024) + diff --git a/src/main/java/Deadline.java b/src/main/java/Deadline.java index 076c10c19..08d1269d1 100644 --- a/src/main/java/Deadline.java +++ b/src/main/java/Deadline.java @@ -3,8 +3,12 @@ * comparing with todo , it has a end time * */ +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.Locale; + public class Deadline extends Todo{ - String endtime; + LocalDate endtime; String Icon="D"; /** * Constructs a new deadline item. @@ -13,10 +17,11 @@ public class Deadline extends Todo{ * @param description The description of the deadline item * @param endtime A String indicating the end time of this deadline */ - public Deadline(boolean isDone, String description, String endtime) { + public Deadline(boolean isDone, String description, LocalDate endtime) { super(isDone, description); this.endtime = endtime; } + /** * similar to the one in Todo class * @return The string representation of the to-do item @@ -24,7 +29,13 @@ public Deadline(boolean isDone, String description, String endtime) { @Override public String toString(){ String DoneIcon = isDone? "x":" "; - return "["+Icon+"]"+"["+DoneIcon+"] "+ description + "(by:"+ endtime+")"; + return "["+Icon+"]"+"["+DoneIcon+"] "+ description + "(by:"+ formatDate(endtime)+")"; + } + + public static String formatDate(LocalDate date) { + + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM dd yyyy", Locale.ENGLISH); + return date.format(formatter); } } \ No newline at end of file diff --git a/src/main/java/Event.java b/src/main/java/Event.java index a881c55ea..1c6c3e0d9 100644 --- a/src/main/java/Event.java +++ b/src/main/java/Event.java @@ -3,8 +3,9 @@ * it has a start time and an end time * */ +import java.time.LocalDate; public class Event extends Deadline{ - String starttime; + LocalDate starttime; String Icon="E"; /** * Constructs a new event item. @@ -14,7 +15,8 @@ public class Event extends Deadline{ * @param endtime A String indicating the end time of this event * @param starttime A String indicating the start time of this event */ - public Event(boolean isDone, String description, String endtime, String starttime) { + public Event(boolean isDone, String description, LocalDate endtime, LocalDate starttime) { + super(isDone, description, endtime); this.starttime = starttime; } @@ -25,6 +27,6 @@ public Event(boolean isDone, String description, String endtime, String starttim @Override public String toString(){ String DoneIcon = this.isDone? "x":" "; - return "["+Icon+"]"+"["+DoneIcon+"]"+ " "+ this.description + "(from: "+starttime+ ") (by: "+this.endtime+")" ; + return "["+Icon+"]"+"["+DoneIcon+"]"+ " "+ this.description + "(from: "+formatDate(starttime)+ ") (to: "+formatDate(this.endtime)+")" ; } } \ No newline at end of file diff --git a/src/main/java/ListManager.java b/src/main/java/ListManager.java index 4244ca3e4..c394f6955 100644 --- a/src/main/java/ListManager.java +++ b/src/main/java/ListManager.java @@ -1,7 +1,8 @@ import java.io.*; +import java.time.DateTimeException; import java.util.ArrayList; import java.util.Scanner; - +import java.time.LocalDate; public class ListManager { static UI ui = new UI(); static Parser parser = new Parser(); @@ -17,14 +18,19 @@ public static String AddToList(String description) throws InvalidTimeForm { String[] part = (description.trim()).split(" "); String suffix = description.replace(part[0], ""); - - if (part[0].startsWith("todo")) { - return (Parser.AddTodo(suffix)); - } else if (part[0].startsWith("deadline")) { - return (Parser.AddDeadline(suffix)); - } else if (part[0].startsWith("event")) { - return (Parser.AddEvent(suffix)); - } else { + try{ + if (part[0].startsWith("todo")) { + return (Parser.AddTodo(suffix)); + } else if (part[0].startsWith("deadline")) { + return (Parser.AddDeadline(suffix)); + } else if (part[0].startsWith("event")) { + return (Parser.AddEvent(suffix)); + } else { + System.out.println("unexpected task from , please add again"); + return ""; + } + }catch (DateTimeException e){ + System.out.println("unexpected date form , please type the date as yyyy-mm-dd format"); return ""; } @@ -178,7 +184,7 @@ static void SetUndone() { System.out.println("please type the task number you want to set as not done \n"); UI.PrintList(todolist,ALL_TASKS); - ; + int number = in.nextInt(); diff --git a/src/main/java/Parser.java b/src/main/java/Parser.java index c05d55069..5f62348b8 100644 --- a/src/main/java/Parser.java +++ b/src/main/java/Parser.java @@ -1,4 +1,7 @@ +import java.time.format.DateTimeFormatter; import java.util.ArrayList; +import java.time.LocalDate; +import java.util.Locale; /** * The {@code Parser} class handles the parsing of input lines and creating corresponding to-do items. @@ -25,7 +28,7 @@ public static void ProcessSavedLine(String line, ArrayList todolist) { } else if (line.contains("|x|")) { isDone = true; } else { - System.out.println("Unexpected format"); + System.out.println("Unexpected format , skipping"); return; } String description; @@ -42,16 +45,18 @@ public static void ProcessSavedLine(String line, ArrayList todolist) { String[] contents = parts.split("by:", 2); description = contents[0].replace("(", ""); endtime = contents[1].replace(")", ""); - Deadline task = new Deadline(isDone, description.trim(), endtime.trim()); + LocalDate endDate = parseDateFile(endtime); + + Deadline task = new Deadline(isDone, description.trim(), endDate); todolist.add(task); } else if (line.contains("|E|")) { String parts = line.substring(BEGIN_INDEX); String[] contents = parts.split("from:", 2); description = contents[0].replace("(", ""); - String[] time = contents[1].split("by:", 2); + String[] time = contents[1].split("to:", 2); starttime = time[0].replace("(", "").replace(")", ""); endtime = time[1].replace("(", "").replace(")", ""); - Event task = new Event(isDone, description.trim(), endtime.trim(), starttime.trim()); + Event task = new Event(isDone, description.trim(), parseDateFile(endtime.trim()), parseDateFile(starttime.trim()) ); todolist.add(task); } else { System.out.println("Unexpected format, skipping"); @@ -78,13 +83,17 @@ static String AddTodo(String description) { * @throws InvalidTimeForm If the time format is invalid */ static String AddDeadline(String description) throws InvalidTimeForm { + if(!description.contains("/by")){ + throw new InvalidTimeForm(); + } String[] part = (description.trim()).split("/by"); if (part.length > 2) { throw new InvalidTimeForm(); // two or more "/by" } + LocalDate endtime = parseDateInput(part[1].trim()); - Deadline deadline = new Deadline(false, part[0].trim(), part[1].trim()); + Deadline deadline = new Deadline(false, part[0].trim(), endtime); ListManager.todolist.add(deadline); return "Deadline added\n"; } @@ -98,6 +107,13 @@ static String AddDeadline(String description) throws InvalidTimeForm { */ static String AddEvent(String description) throws InvalidTimeForm { + if(!description.contains("/from")||!description.contains("/to")){ + throw new InvalidTimeForm(); + } + if(description.indexOf("/from")>description.indexOf("/to")){ + throw new InvalidTimeForm(); + } + String[] part = (description.trim()).split("/from"); if (part.length > 2) { throw new InvalidTimeForm(); @@ -110,9 +126,19 @@ static String AddEvent(String description) throws InvalidTimeForm { } String end = content[1].trim(); String start = content[0].trim(); - - Event event = new Event(false, EventDescription, end, start); + Event event = new Event(false, EventDescription,parseDateInput(end), parseDateInput(start)); ListManager.todolist.add(event); return "Event added\n"; } + + public static LocalDate parseDateFile(String timeString) { + + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM dd yyyy",Locale.ENGLISH); + return LocalDate.parse(timeString, formatter); + } + public static LocalDate parseDateInput(String timeString) { + + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd", Locale.ENGLISH); + return LocalDate.parse(timeString, formatter); + } } diff --git a/src/main/java/Qchat.java b/src/main/java/Qchat.java index eb6d1ca61..cbcb85765 100644 --- a/src/main/java/Qchat.java +++ b/src/main/java/Qchat.java @@ -38,14 +38,10 @@ private static void echo(String command) { public static void main(String[] args) { - - ui.Greeting(); - String command = "" ; - while(!command.equals("Bye")){ - - command = CommandReader(); - - } + ui.Greeting(); + ListManager Listmanager = null; + ListManager.HandleList(); + ui.Goodbye(); } diff --git a/src/main/java/Storage.java b/src/main/java/Storage.java index 0be82952b..080aebd62 100644 --- a/src/main/java/Storage.java +++ b/src/main/java/Storage.java @@ -1,4 +1,5 @@ import java.io.*; +import java.time.DateTimeException; import java.util.ArrayList; /** @@ -17,18 +18,30 @@ public class Storage { * it read evey line and use parser to handle it * @return The list of to-do items read from the file * @throws FileNotFoundException If the file "list.txt" does not exist + * @throws IndexOutOfBoundsException If the file "list.txt" is broken or not readable */ - static ArrayList ReadFile() throws FileNotFoundException { + static ArrayList ReadFile() throws FileNotFoundException { File file = new File("list.txt"); if (!file.exists()) { return todolist; } else { FileReader fr = new FileReader(file); BufferedReader reader = new BufferedReader(fr); + System.out.println("loading saved list from saved file"); try { String line; while ((line = reader.readLine()) != null) { // Process every line - Parser.ProcessSavedLine(line, ListManager.todolist); + + try{ + Parser.ProcessSavedLine(line, todolist); + } + catch (IndexOutOfBoundsException e){ + System.out.println(e.getMessage()); + System.out.println("unexpected format , skipping"); + }catch (DateTimeException e){ + System.out.println("unexpected format , skipping"); + } + } } catch (IOException e) { System.out.println(e.getMessage()); diff --git a/src/main/java/UI.java b/src/main/java/UI.java index 95448ee0b..52b959cd4 100644 --- a/src/main/java/UI.java +++ b/src/main/java/UI.java @@ -12,6 +12,7 @@ public class UI { "Qchat, A truly humanized intelligent voice assistant\n" + "knows better about life and better about you\n" + "What can I do for you?\n" + + "you can enter 'help' for help\n"+ "----------------------------------------------------------------\n"); /** @@ -27,8 +28,8 @@ public class UI { private static final String LIST_FORM = "please enter in one of the following forms:\n" + "todo 'description'\n" + - "deadline 'description' /by 'end time'\n" + - "event 'description' /from 'start time' /to 'end time'\n"; + "deadline 'description' /by \"yyyy-MM-dd\" \n" + + "event 'description' /from \"yyyy-MM-dd\" /to \"yyyy-MM-dd\" \n"; /** * Displays the welcome greeting message. From c00f1e81caec81b87e8edcc91def95dca3a31844 Mon Sep 17 00:00:00 2001 From: classskipper351 <126574608+classskipper351@users.noreply.github.com> Date: Sun, 31 Mar 2024 18:53:05 +0800 Subject: [PATCH 17/17] realease ip of final version --- ip.jar | Bin 13980 -> 14935 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/ip.jar b/ip.jar index a11075c118fcb2f69fba646db52f9d9ac8e98840..e2d9ff2e65b91e8d4c55b70856d89144d3463736 100644 GIT binary patch delta 11912 zcmY+Kb8u%(x3)9MB$;qx+qOBG*tRCN%{{R(`OU<(ZQHhO+xX^rPkrZo&ibosS2b#P z_3G94eWltgI3p-XLwrU9`|{-r*ylgMF9ZjOZ*jmcKSJP-s*M|}D4K6R%-UErxwCXc z`1f86PHLnLp>GN(&;BX?6c{!_X~qT4N2Zi!ZrxQMB7mR%6zSkrfM6%#-qpD6PcXQ7 z{v>Xvi?joQhw(PnrHcU9y ziDEp#{u7X)*%&H~Auxam#ei$hghg_#I*AEivyShZuu!M)U>p-7Ti)vtylp8j1}|rd z=;7S5uI7NWMzOLRLoun%%s^4x) z!ywGnflBVJA>R>D=g|l*PRS5SU&+q+E`_ZZmT2G$pH_5&vq9`}bj9#p%Z5AB%aD5V zNRD6brnY}Mu?JnM#$pG_)P^gu>Ix$so^C~>izdl8Td~SPCI!>pe{0i(S~c5Hz#OKI z{td|G3oD^$uieTL9hkGMqiNS)%A4p+jf0|tLo!KPSryHC2pA4XtY}sC&rZUge|%m>z(S3y-qyTDU$SVv#&TEGZX5W1csyJdb+`UhXmca zybbaDf`5qJNP}oHj5(NPU3Q{U#B4KLY8>`=TR+{lX}IBH=fffyp_v4SqyQkjGXs25 zkcR&9_48}HF9aAEFEkj~e-En;2+#ogSHS&ki@KWFIx`qq8#p=TsjSJN3ZcCRW4LN! zQ04s${h>Np|2hkxDfof=W3>JJ0e)p@4z00x&ej6)i*t(dQVmtHC+O>@F!sbL2XZb7 z3Xn3Mlyvjpb8tHP`s(ru(a9B0Uu!VfJ7!wD9gl%cUyb32#ldW7sB$qthvL!JoR-`8 z0!4u3J~)X-bxymd@>y8jA%XC+b$vIYx_6Dcyq8SayNHZG*x1;$sUb~Yv3Ua4&fBUo3G%1|6nK^Yt<}R=5p80X`<*;H@ejGAqunL8C1&K0c7>%v2Vry-~XbEwy zp97SY==lqI)uuVD+86$O(Bfe)segLIlwWR?E19)UzYzo~2L-cez8l*#N4fb8D!^Aa z74uoxP)!P*DnmUXX!+M(W*f|ejLb@67oD)tmn=;fJy(2Py=}W`_#RB#_H(BL82#^V zkPn6D(X3KXUaVSW4sIE-MoDya^UHC*L9}Vn#3@Bzo#LZ|!1u8{ITy8`3p7nf68?m- zjpVaR9VcZKbU%m)d6Ji}b6JL{IRiZWqWViCuO;mt3$t66KlC1eFoVmOu`9&g^ui_) zI!t#-$&blSX&zru>WBN1*;?`mRNt;WA)?Ud7tpK~ceZ@nU|Th9c->Ikp3W!VMlnWdTz)zPw!>5558#j_5QoP> z;@4?*S_~JCh1}k=m{^D3UL1mW=$_|}cqo9_)*?wU6yg2jTZe`&+C~(?o3&_FW8gXx zv8Z}!49f}nS_u+=-UYhhmK19k$OlZ_>M@+fyu$k&4yPmg2x2t%3OP!$Mk0BUDa;h- z>Y~!zGV2J7<1*~KAu&5Gyx;|8rC+R)+wXEQYRPyuNil>^Q+DPV%=T&D?E>o%44GxR zDt}_S%MrVo+fBbSM0s`m=dei9irk)qgMrP}C_v$Tg0PAPKz7g+0N$L-dqwRsewlcD zYaF>?C&36}d|ezQ2Vz$oLVtDDrIst*lVlh6MRXo>$&!ideEb(Owr|NCUx~;SAS8uh z6@OA(1q_0RfZ0e51>{(?hqMp!&BLBW9rb`wl_b*D83> z_F}ygxbDlHnDBf?o0jzF~=ZkAL(MzB1y zL+B^mGw$9Yc)aDczDu<}nZj?dTrNPhi`)Z5=;OT-8eAn9KC3ggW-BN32z- zP4Y+g!3vExK;s1+tLQK86(aAlG?i+9LEFzqToFHwHrzDj<#=r8kK1NaEq+=3G=Uf{ zP@tzFS3o-_Pnvcj>LyI%k_iZJ%nJmG6sFX*`9%Zmoo;QPXlAWPJ%T##{nuRUB?8!2 zIBxA$tBbr0m4Z&FXXUl?7;U`Lp^(lT`8hQz6qc$DIkRj>P0TYn_B`e691b&g9#)`h zqDxbxSC-c5FT!5oT@l@a5#$*sODcFu*Wr7@nirXNn_hbH-6%#?FG_*FHwVyi2uHz7QfJ)@fZ zD+MS0(@j~#S_dRP(PstFJ)&qC=2$;GvA6)?CkSQg87|QAuU2Kpw}sm2Gvl;Q81$U< zXr!^b*xM*g2BhSeJ8mJj@fqZ5I8KRr?k)z#oRG+J=X$gocm49i0{lP)GYH`vL%AAhiEz(&M7p(y=P$rV%oF;L~bwI z-!3h}QAKT_ddlj~1dV|sf}8ywAH;$i2Q!m!^Y)9QWWW%zwpHgFBTF=69|(KMl4HvwrH_fbeU6TS z6ApdZBU>gtLx+=#bbcx|gBp-vD$A)49!-X$ccR`lqwE zWizQ*lb-#GEvF*Bs1H_FFWMRMsA~wH6sCzxfWM{}rff%Qci0#s9r^g!B7D42vxp*# zpvWh}l4VXbPH*gX5xd^8uX7l`8gZBhH1&Y*Cw;e9EJ_pajuI^OjRUw%xAO?=+hRXp z%_|5JwSrQIq>NpozLVT9LmWGB_D(fO!(3LOrl`*YxdwA9mnqQaTdGRNU#9Pg(j;4Ea<|>k0Wr!2wPqD!x5;D*2^DVrC8-X_I?h+uh*!>H%w2;tUrH8;>TZrc+6r zn>6ovxtYE5BPR~TW#0@Zqp7QDxdYs&1Q+7*wSDLyep{wNEv508HyzatVixXs<@;u7 zGq@ORsgzygB*{SuzYr=~GLYM|L2JN0xR#4Gckamuyi;DQ1fY3=;JuYMxHz=eBV29a zKewQJxG$TrDtLGhJ#0F8Q*!6IHMP2|oupc{-5=E9JK>B|AQyWQJn7dYDk_Wk+ z1#{XBcsgNV4RDEoDjBj)Z;dkyO?n#EMc}}rWN$}OU3dY%7tQruLVih<20E3f^}I1? z8lljnqaSsb!gZ{+B{_jnE^pv7?tza+6|VFn(iX8IjhL4E6@7GeA9MMn zNA`1doL zKcCrRyEgVUAlG}YxId;J~gtYvkWf&sV-bwU0xQ6r63RW4c8Qt9X}PrPg1 z0kiolVYkrR08IUA-`;!0z>b5gU_!$bu>r<(;}?3J*EFZMr&^H?WPWqPwayWqUxy6y@G60Iu@qKU-MiF`IvOpNZ-b9Bhkq=0 zXHZ*`FjsO+$G}K_XCxylIU!Z6SP_tXHd^;b<{%=ex#X9zWkoj*d*sM$%O!^kG%#Px zTNNG8Gsl0Z^wqG<6HC2VQ72CzBI=loqo|-#lRt|7So5|J(?04MR_WMkF~8mK>^NmH zt34|1xaClJV}RjK_*9Y6pyCyD*dy`nom1e)fjn@aDmB8kqT#1ZpBvF6`P z0wL_%rmu)-{7j2pge12mns!CQut3O4<_G*Z5Ij}~3MsJW^I zdpJnd9H8bYWzHkoi@RG0n~}O+y~E#~PfuADy`r#Ks?YwZRG(O_OLbjPbJusshSudc z(|%)!D!zUZ+xd()%7wb$0{*0-jz5eRE!qHvSDl700-^0pev^h`vfrps4ycdG@|rko zy090w3TPMZA^)sQbjyS;Z!S=Nq?6fU?StjCCoN@%@Mdtk8uMf! zM8+CyuB!40!v*ewhT^PnpciqC)BuVBC>ly0j++#(&e~WmhYTpyv z`pf@-B-row2_!!S$@q&`p~kSn2t+~9X)pwk<+4rRpf4(rm{7`Bc}b=vi^=EYAGCka zF0XwM*8U-{^;$hesZMEw~F6$2dzQ*m0`gI;#XJGxVKtX?bgU?}Nv$GxKK47s}P-#x% zhO=kCk54Oif^Z8Ud(n%Ks(vf~{_w&0k96=;tm`aoaM z$RJ8U0EiKd08oGNLQ}`~rSwW#TJj5&1!wrw^24u*=7PIM5<|m$sAn|w z!h6GQ{o-xi$@G5tL$3w)2kCp>jxQP;8vAc&_?^J$Hh{{i@bl&mnV!bz0p=_Nr9MgK z4;Xai?mZah$J}U9cclSkcdZ_3go!UZ1#I40J!ZW-76=o^U$(i?Gv=!BGG;D45GJhL zh590R&bu(#yqSM8ZjmFHv3YCusXLbn3HAD_er_+_LPw~uVa+L?@P_gWVXR9eXp8AF5xqd-nD?qi_l~hw2rr7F2`vbS8U1tCjB*WFI@Fp zZIVra!L&@uWD>8zktEFDoy}(ykCXStbW7qOQyHj-6K~cXNi;g(ZHOP)H(oC1S~K+N z&^@9LFWgVgwCOWkXMvNspiMF$S5n*z_qD3LwdknbVgEqoCtX6? zu`!?*m&x7x+w9NHk{xw=y6sj36h5mLpHV#70L^&G<0p{a*q(?c?EHKdt6B!)5ux!e zo;41nUm&PNOGN?8b3k=yA|p4RN)~Iz6Ycq9m2jW!)ME zY}gw1+1V{@#ECHCSIm)|{2dJw$cOpQjr)KcGE48(JvU=NW4b=CDpeG6q<{toVU=JiD?LAs)Sll0% zQk`B%B#Ri8=#@N_s^UiTO%#TROyd0O7C7ujZeO8p(FOQdlo=>fd(qNYTJ#F+#6F-x zRHQ<~+nB{-le2Ny2S*hQqGG4PI~tn{-Z5+JPG00gPUMbx*sW0qPu6i4&EsxJ4<>{Y zt#&QA0pt8{VFw>zEb=WPu_^V>Oj5p+aU8CoDi-IBt8KLQr<1Qx(QsH%PE7ko-f7?g zp)MLbDUUhe!rO@tUrbq&Bp5K0b_D@+faTKcRkV*C0_fXNd0p!iyp-pVl5sO;!RMAL zwh&@!5s$74O_6bW)^J?8Qdry0r&n23D``p3G4+__VKzmtR&%o!ROMrk>s$*#r;9p| znd7&xOh_%|iZ86@s;~4pGduwM#no$+lml;GZnQ5&&OD5&W7U?%M28qr^$U=yE1Wkk zK3C%q)6u!!j2FN2t?C%zP&W^oM=&tBTd*p3dS=R_F6@BGk#64|QK#Os@f1CojSZg@ zlpRr{wlfW@e~2z?G>SMTmzkw4JeMRXUcF9lyGSIVN*qdryb0wBn4h!Ke;YpgKAw!U zUA%HVn_6!Sw;Q*;H?`0~ng-yka(`HsB$r9Mad}9vWp_Aj!!I3k zp>o{lLtls9$m?*M(EBj?srtIyl%Y=r+xbB|{{ywxf(HK*j6-@QU~wCY^EJd*sJx1HHa0ATZ|1VyKNC2B^?p03Vj;M0 zfvT`#Vh~2KnE9d;9^%Xm3gs-CVT!ZVko7dHGS?qq!w6}cF;5jzR+0`pYBRp@(1{88 z&ho>Ym}vGiMNC==&MLiJ!OHxIEuOs1U~C25GlTas;VfnSDvB1KvpHADf@mJ7D{$dVsN?GH$`YdZu%Ctj`w0;{D_ms2q`{!oLj+gzcaqqFhJJyUZB zEb1TNIX3BBbvC0+U?U2${U{$8@RvgaG|MHLg;M>u z;MZXnR+jTQr=0+j4T45RY2kd8cy;Oew}|kqeB4Qu)3r;)`?i1?8cg5MFU7oj2L9HY zZK_mrJ!jLu+au>-raC8~8OASC`;Y|Tm3kZCh}CGhbdI50A*XeY?&+@)z(QnmuRO43u2lZ}*H$UUyGtr?9x zWaW!}9{gqG7n?EZV1PCKR&p=V6u<SFA6yaMbfdx4@=x+ zclt^%(epM`@@XCVtjd>E+06OxxL#Oc+YaN%qTuSPZQp^N==N7(CwbP`dnQ% z>1VzGy+$h~NDpk*XW*X-qzZ60mH1n7up|B3yvUCFw|N2L#zh6R)p1qP-sMnOdYI6X z6||^l)y&6&P|C{Y{0l|07A5UI(e$ktaK-rz$s}_ZZ3m2GWHI{ebtPad_?NrV13$mM z6Y9_UjEl@j9Zzcxoz^@oCD;LG6Hj{&l!6eAkR@VEb}giL%^}TTV}_3J^Nx+gSWtM3NDJC`E>k+&Cjy!*a)*vU5GQ|LLlm{<4GC0F)82ez zuJzkqrQShTzfBjX2*`jc!L9z$NAKFBQnPqCAJaNcI|JAejeC8}cRY6ctre!aEbIPB zm?PRsa)MD+m*BJKi2cqhtb9W2o9fWo8LXYTH&i*Q$kzP#V56p<_vQ^A^|@dtE5^lx zG1+6L6_b>%REIYXFEw^+c3tKRYArh1f#2bkS14jw(FB(Lod~$7jYW92ON~*i9K{;h zPKhhX9PvO__)Bj@)DD-y4x$*mx3v*EDF-aoa$^L0aM52iy9(aha7P&p8|t82L9BWR z7oFH@ON=eH-;6?_;R^E0UGw)e4L#$-sWF9bAwO|Xw7Y%Q(VVVZEhyu%*YDO$+M>K7)>>n-GEXTaLt?T4Fs96S6*o4Dh!6=Qyy;|# zLS!C9Fsn_rH}fvR7|Guyv~ZEay`EVpd2IFU1y?a_E*dBK+)Nf%nJZ;=xC|QCESVM~ zEc1b3ffy2@xelP-lULk(lo@(T1dq!HYbpXf!4)Sv;zcWgl`A!S)TiTElG&!yjO!(% zk~#I+O)xc!)-I8On?%uvwDvfQ-N)`$KvFA=OnJWh(;}%B8I#mSEk{0+m>sWcCv~gL zbgzX}aeyX@WHrPFzo?kFw(m~Dis zWa}4*3kYltCjG+n(~Ao>48A>^_8pgGTf4i$lULRuuGt52XV!*L%Xux8{DlaID+Ew4 zvW%_;F}-(+=E9S~?;eT&crHVpd5!9(cbTbODlO)aj6U0vF#SOoKn5pY$gy2l@1ilT zAgf>lD*mdtr&zpZ;4MQ6<{1`oa|TXJhE9t;CKAlu`&~wg@}yD##OI=#IVyT=8HXfu zG}`09W_% zkd6Np4veKY*j24&WgVI(WPZ}hmC6cx7H^x&2p8<~!6KhMEN;ZXb zq)4t^=1*J+Rc!RUyyd8n&5)mr`i^(wpu@x*8pMTB*SX{A{(UohKNr|QeQft@ysp+8 zhxzSSHiYf9e$GHex!|+-aMnjQ#1CaTGydDE1n_4>I4$g-Nx{pBOBcBA_rzaN^nv22 zbxUPI!oIBjz5Lr*Cy8b>4fLMq!yqn2a%6J4O1mP#+TNI$^k(>KHQf{CP#<1mfI=FVd!kOijl}+6o0M>KM zb2y_sPki*ai|_1^W|>)1l2uYJt!0jW?@+pB>#etpNS64au1nn|?)NzM;YF2~IC>42 z!BCg7ttMMGI@Ooa_l`~-2SwkWTzy4~Ef{gF!?z9`Uc0*)uW0k%;5#BPe4{q(9p<}R zaN-`E>v4+F5NPv%t6R3$Ys~)&2iAIGY1(8xEG3LIksS@khM7pKiqh~Ge0>Oy9iz~* zU@DSkpz3QY?C{5?E5&Hplk?Sh>anP}#nJVIRPXO$v=nQ}&zjQ1UsYnUz4a~}oq5Y& zc(MNq&FWqbZ)M251}}c?pExou+alq?*J8;M7l~03`s*cR0S4sC*WZgm zQd!Jb=GS1 zxg03yvVm^EU0*I-x;}H+sObS|>C%nyN)U}2i`;-CpewAuq0WO+;-vs@hRkhl_E&LO2f;6kz`T(%^b(`~g ztaH5Lpr_2c(fLxeEBAyq$qCbqeKF+ALhCs9x=?sJ!uZtq2$KLjpxNHXjDfP#2+C14 z?$mAM&0P!dsuF_3#pD*3)YcIi6EW;D5g|C$5xd0?jX`?(0cq&3wKIf1D|gxk@3c#5 zEu%3~c%mitCUQ*J=tTG=(3PJz_kkaIS;<`;Nzb?74KprX@&R*{H`bA$kg@H$!BQWr zQ}y+*(}ye2x4q>S@Ww%iG>2vN_OST^!99fj=+810N#BUAJ>{Ra=*JPgCUPWjn!l=N zx!5DFj+E#2Ff<&I^W6+C>@#;D$UIGVt3O4N7RN!m5RK zaOb{*Uohj3J2CbkS&dJxUB5aC?ZoKY2- z)W+rn2G_Q7XD?_g2s+;hG3lWY#ga)sM650DI?{Ofc}Zf9EDp>XA-S;5ETbv3P#YL_ z>U+!WwffKVfVmFVu7(psn*B|^S%*`TQJ>K+V$)5gUxZ}U;*B`lABxTVqw04KsRIED z5{92hiO1b)I>%W;2Er_Uuex3G4NYQcXe>~XTG%IKtAvA@%QTRBLed8^U6UU}CVv*I zIIP-ng4OFQ|CN|V#o5CUe%uj7yU6N*Z9_0C(FUvdR zT&Ym5+KcR`ml=gg^F`ELS{vK~?$%VOPttK2K5aCNm9p>gG-gsf!yRgYCR|$I7$;L_wy@VS2Dr}sEdXa07AxvGnqZ?6u<9VAN z1}CXAd$UExpy^JS0Px24qpwApmrOB`$RsA#+9P0>xv%v`kyT?fGyUnU^=pgRS*l7Z zy7B@w3=ABw%z&Vps~^_bInP?Uq&(Gv^eP>Hd4gD3)x{I)Px7jhmYTd!SsM!APq9Hl zxvSsk8+}Ew%n9$o<=gBs>l*C3z8T73P@Ro>`X!eCb|gu40-V|>y@py(7#p(+4qObr zqql|Xx(f89fk0VE;d)q1lzDW!#VSiqAm5@=%pw@<_`{L?)o*|u{m=00*INm!W>xx* zMqZk;q%0hW^r1COkGuxeYN9u+%OA>o5crVDd%_i^eAq}sJA%RsrhiiO(;P<}*eFax z*;5}*yftd70hIl|zygTBj%5JOaz8DX<#v9QcB9P>5@JeX9dn2WuDJc;w-G+S4u+TR zs6bM1^6vw1c-UXW8F-7SQcaFtu0I8AQ_+cH(w()<)Qoizln||guOUSlQl^#g43v07 z<>y1e2JJ+X&o}nTmF+3S zIcf63RSx3|0%?Z7&n`vF#}Vmr?>4pG%*voyfB8!j3RM}jxo$%Fw*6sjK8|GFF09;E zPczKhg<3zz{>Jm?(#K9zyq%)0)qa)gdYjg!4C-2FcQ`KDg89?pE5n;L<6HE%Y+!>hYOx0|f~U5b=gcpBMj79Br|jQtpeo9;|jP)|45OI&Y`f3~n$LWx{ci zU06sm!B;nJQPmAFJ!9sa#j>rQT3f5SW9P?4E#Vo<^+VOh(5s|S7sW5ZSPe{}OjAY8 z02~iWf0z8J{=|#=nFQ}9>AOEN(6si8M~ptFf;q?=IjsPqygV> z^zKb_9SKTOO8%X410L_ijlXqV-H~#mp^R>+bQ2GMsxRejEaj0Y!Y*g(BALc_3%Q z@Zyx`p5AxLkk9-625L3uF|t-Y;P8i6P=>5boS7@?hD%-7;J`X0!q;)jH@FaZ)FVNMUXcUBNUktWPD$Ks z#^77QFydd7S>wO>BnXm~f#@G@@_!+*zg_>~ zCjT1@pFzs3oZza^AUh~bx_=M(mn75p|8~khZVK{$JN<1Le*sOf5<>iAtX#3;g8QL^ z5ZN%b{`xB#{}w?0Cj5UzA^P7%8#p?dIQ|c^`S02O5lH_1%K5*mq#*zSY}nd=A3Pdg z|8uM*}mH|Bep}_P@8y|Di|!Z&yWX&a z0tXbsP6aMb1Nvac1WmHjgJ018Z3^?8(}RJj*csdXcZ&bN2mk!AfA7y<5$Iom!VL1} Mz=8U~@z1ya2MFbj=>Px# delta 10937 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