diff --git a/.gitignore b/.gitignore
index f69985ef1f..3a15cdf59e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,17 +1,17 @@
-# IDEA files
-/.idea/
-/out/
-/*.iml
-
-# Gradle build files
-/.gradle/
-/build/
-src/main/resources/docs/
-
-# MacOS custom attributes files created by Finder
-.DS_Store
-*.iml
-bin/
-
-/text-ui-test/ACTUAL.txt
-text-ui-test/EXPECTED-UNIX.TXT
+# IDEA files
+/.idea/
+/out/
+/*.iml
+
+# Gradle build files
+/.gradle/
+/build/
+src/main/resources/docs/
+
+# MacOS custom attributes files created by Finder
+.DS_Store
+*.iml
+bin/
+
+/text-ui-test/ACTUAL.txt
+text-ui-test/EXPECTED-UNIX.TXT
diff --git a/.project b/.project
new file mode 100644
index 0000000000..3aaffc18f5
--- /dev/null
+++ b/.project
@@ -0,0 +1,34 @@
+z
+
+ ip
+ Project ip created by Buildship.
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.buildship.core.gradleprojectbuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+ org.eclipse.buildship.core.gradleprojectnature
+
+
+
+ 1632124959946
+
+ 30
+
+ org.eclipse.core.resources.regexFilterMatcher
+ node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__
+
+
+
+
diff --git a/.settings/org.eclipse.buildship.core.prefs b/.settings/org.eclipse.buildship.core.prefs
new file mode 100644
index 0000000000..ac31e3c7b5
--- /dev/null
+++ b/.settings/org.eclipse.buildship.core.prefs
@@ -0,0 +1,13 @@
+arguments=
+auto.sync=false
+build.scans.enabled=false
+connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER)
+connection.project.dir=
+eclipse.preferences.version=1
+gradle.user.home=
+java.home=C\:/Program Files/Java/jdk-11.0.9
+jvm.arguments=
+offline.mode=false
+override.workspace.settings=true
+show.console.view=true
+show.executions.view=true
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index 8e359a0145..419450f2f6 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -1,9 +1,9 @@
-# Contributors
-
-Display | Name | Github Profile | Homepage
----|:---:|:---:|:---:
-![](https://avatars0.githubusercontent.com/u/22460123?s=100) | Jeffry Lum | [Github](https://github.com/j-lum/) | [Homepage](https://se.kasugano.moe)
-![](https://avatars0.githubusercontent.com/u/1673303?s=100) | Damith C. Rajapakse | [Github](https://github.com/damithc/) | [Homepage](https://www.comp.nus.edu.sg/~damithch/)
-# I would like to join this list. How can I help the project
-
-For more information, please refer to our [contributor's guide](https://oss-generic.github.io/process/).
+# Contributors
+
+Display | Name | Github Profile | Homepage
+---|:---:|:---:|:---:
+![](https://avatars0.githubusercontent.com/u/22460123?s=100) | Jeffry Lum | [Github](https://github.com/j-lum/) | [Homepage](https://se.kasugano.moe)
+![](https://avatars0.githubusercontent.com/u/1673303?s=100) | Damith C. Rajapakse | [Github](https://github.com/damithc/) | [Homepage](https://www.comp.nus.edu.sg/~damithch/)
+# I would like to join this list. How can I help the project
+
+For more information, please refer to our [contributor's guide](https://oss-generic.github.io/process/).
diff --git a/README.md b/README.md
index 8715d4d915..9db1777ba0 100644
--- a/README.md
+++ b/README.md
@@ -1,24 +1,24 @@
-# Duke project template
-
-This is a project template for a greenfield Java project. It's named after the Java mascot _Duke_. Given below are instructions on how to use it.
-
-## Setting up in Intellij
-
-Prerequisites: JDK 11, update Intellij to the most recent version.
-
-1. Open Intellij (if you are not in the welcome screen, click `File` > `Close Project` to close the existing project first)
-1. Open the project into Intellij as follows:
- 1. Click `Open`.
- 1. Select the project directory, and click `OK`.
- 1. If there are any further prompts, accept the defaults.
-1. Configure the project to use **JDK 11** (not other versions) as explained in [here](https://www.jetbrains.com/help/idea/sdk.html#set-up-jdk).
- In the same dialog, set the **Project language level** field to the `SDK default` option.
-3. After that, locate the `src/main/java/Duke.java` file, right-click it, and choose `Run Duke.main()` (if the code editor is showing compile errors, try restarting the IDE). If the setup is correct, you should see something like the below as the output:
- ```
- Hello from
- ____ _
- | _ \ _ _| | _____
- | | | | | | | |/ / _ \
- | |_| | |_| | < __/
- |____/ \__,_|_|\_\___|
- ```
+# Duke project template
+
+This is a project template for a greenfield Java project. It's named after the Java mascot _Duke_. Given below are instructions on how to use it.
+
+## Setting up in Intellij
+
+Prerequisites: JDK 11, update Intellij to the most recent version.
+
+1. Open Intellij (if you are not in the welcome screen, click `File` > `Close Project` to close the existing project first)
+1. Open the project into Intellij as follows:
+ 1. Click `Open`.
+ 1. Select the project directory, and click `OK`.
+ 1. If there are any further prompts, accept the defaults.
+1. Configure the project to use **JDK 11** (not other versions) as explained in [here](https://www.jetbrains.com/help/idea/sdk.html#set-up-jdk).
+ In the same dialog, set the **Project language level** field to the `SDK default` option.
+3. After that, locate the `src/main/java/Duke.java` file, right-click it, and choose `Run Duke.main()` (if the code editor is showing compile errors, try restarting the IDE). If the setup is correct, you should see something like the below as the output:
+ ```
+ Hello from
+ ____ _
+ | _ \ _ _| | _____
+ | | | | | | | |/ / _ \
+ | |_| | |_| | < __/
+ |____/ \__,_|_|\_\___|
+ ```
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000000..6209a3a9d1
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,64 @@
+plugins {
+ id 'java'
+ id 'application'
+ id 'checkstyle'
+ id 'com.github.johnrengelman.shadow' version '5.1.0'
+ id "org.openjfx.javafxplugin" version "0.0.10"
+}
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ implementation 'org.junit.jupiter:junit-jupiter:5.4.2'
+ testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.5.0'
+ testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.5.0'
+
+ String javaFxVersion = '11'
+
+ implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'win'
+ implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'mac'
+ implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'linux'
+ implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'win'
+ implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'mac'
+ implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'linux'
+ implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'win'
+ implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'mac'
+ implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'linux'
+ implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'win'
+ implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'mac'
+ implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'linux'
+}
+
+test {
+ useJUnitPlatform()
+
+ testLogging {
+ events "passed", "skipped", "failed"
+
+ showExceptions true
+ exceptionFormat "full"
+ showCauses true
+ showStackTraces true
+ showStandardStreams = false
+ }
+}
+
+application {
+ mainClassName = "luke.Launcher"
+}
+
+shadowJar {
+ archiveBaseName = "luke"
+ archiveClassifier = null
+}
+
+checkstyle {
+ toolVersion = '8.29'
+}
+
+run{
+ standardInput = System.in
+ enableAssertions = true
+}
diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml
new file mode 100644
index 0000000000..6d69fcf10b
--- /dev/null
+++ b/config/checkstyle/checkstyle.xml
@@ -0,0 +1,398 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/config/checkstyle/suppressions.xml b/config/checkstyle/suppressions.xml
new file mode 100644
index 0000000000..42f14212c1
--- /dev/null
+++ b/config/checkstyle/suppressions.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/data/luke.txt b/data/luke.txt
new file mode 100644
index 0000000000..a94d9cc3d0
--- /dev/null
+++ b/data/luke.txt
@@ -0,0 +1 @@
+T,0,study
diff --git a/docs/README.md b/docs/README.md
index 8077118ebe..14c6b468fc 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,29 +1,73 @@
-# User Guide
-
-## Features
-
-### Feature-ABC
-
-Description of the feature.
-
-### Feature-XYZ
-
-Description of the feature.
-
-## Usage
-
-### `Keyword` - Describe action
-
-Describe the action and its outcome.
-
-Example of usage:
-
-`keyword (optional arguments)`
-
-Expected outcome:
-
-Description of the outcome.
-
-```
-expected output
-```
+# User Guide
+
+## Features
+
+### Add Tasks
+
+Add tasks that needs to be done in no set time.
+
+### Add Deadlines
+
+Add deadlines that need to be completed by a certain date.
+
+### Add Events
+
+Add events that will take place at a certain date.
+
+## Usage
+
+### `help` - Get Help
+
+Returns a list of command keywords.
+
+### `list` - List Entries
+
+Returns the list of entries.
+
+### `todo` - Add Tasks
+
+Adds a task entry.
+
+Example of usage:
+
+`todo Service the car`
+
+`todo Take the snake for a walk`
+
+### `deadline` - Add Deadlines
+
+Adds a deadline entry.
+
+Example of usage:
+
+`deadline Get an internship / 2022-02-21`
+
+`deadline Get a job / 2023-03-14`
+
+### `done` - Finish Tasks/Deadlines/Events
+
+Marks an entry as done.
+
+Example of usage:
+
+`done 3`
+
+Marks the third entry as done.
+
+### `delete` - Delete Entry
+
+Deletes an entry.
+
+Example of usage:
+
+`done 2`
+
+Removes the second entry in the entry list.
+
+### `bye` - Say Bye to Luke
+
+Closes the application.
+
+###Credits
+
+Photos by Generated Photos
diff --git a/docs/Ui.png b/docs/Ui.png
new file mode 100644
index 0000000000..cd6421fde3
Binary files /dev/null and b/docs/Ui.png differ
diff --git a/docs/_config.yml b/docs/_config.yml
new file mode 100644
index 0000000000..cc35c1df2c
--- /dev/null
+++ b/docs/_config.yml
@@ -0,0 +1 @@
+theme: jekyll-theme-modernist
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000000..f3d88b1c2f
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000000..b7c8c5dbf5
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.2-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
new file mode 100755
index 0000000000..2fe81a7d95
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,183 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000000..62bd9b9cce
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,103 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java
deleted file mode 100644
index 5d313334cc..0000000000
--- 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/luke/Deadline.java b/src/main/java/luke/Deadline.java
new file mode 100644
index 0000000000..2217c1d892
--- /dev/null
+++ b/src/main/java/luke/Deadline.java
@@ -0,0 +1,71 @@
+package luke;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+
+/**
+ * Class that inherits from Entry to encapsulate Deadlines.
+ */
+public class Deadline extends Entry {
+
+ private LocalDate deadline;
+
+ /**
+ * Constructor for Deadline.
+ */
+ public Deadline() {
+ super();
+ this.deadline = LocalDate.now();
+ }
+
+ /**
+ * Constructor for Deadline.
+ *
+ * @param task Entry to be saved.
+ * @param deadline Deadline of entry.
+ * @throws LukeException Error thrown if deadline is in wrong format.
+ */
+ public Deadline(String task, String deadline) throws LukeException {
+ super(task);
+ try {
+ this.deadline = LocalDate.parse(deadline);
+ } catch (DateTimeParseException e) {
+ this.deadline = LocalDate.now();
+ throw LukeException.INVALID_DATE_FORMAT_EXCEPTION;
+ }
+ }
+
+ /**
+ * Overrides Entry's saveString method.
+ * Returns string to be saved representing the Deadline.
+ *
+ * @return String to be saved representing the Deadline.
+ */
+ @Override
+ public String saveString() {
+ return "D" + super.saveString() + "," + this.deadline;
+ }
+
+ /**
+ * Overrides Entry's toString method.
+ * Returns String description of deadline.
+ *
+ * @return String representing Deadline.
+ */
+ @Override
+ public String toString() {
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM dd yyyy");
+ return "[D]" + super.toString() + "(by: " + this.deadline.format(formatter) + ")";
+ }
+
+ /**
+ * Returns true if Deadline is Empty.
+ *
+ * @return Boolean corresponding to Deadline's length.
+ */
+ @Override
+ public boolean isEmpty() {
+ return super.isEmpty() && !deadline.isAfter(LocalDate.now());
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/luke/DeadlineTest.java b/src/main/java/luke/DeadlineTest.java
new file mode 100644
index 0000000000..d87f6f7ccf
--- /dev/null
+++ b/src/main/java/luke/DeadlineTest.java
@@ -0,0 +1,27 @@
+package luke;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class DeadlineTest {
+ @Test
+ public void deadlineToStringTest() {
+ try {
+ Deadline deadline = new Deadline("testing-deadline", "2021-08-20");
+ assertEquals("[D][ ] testing-deadline(by: Aug 20 2021)", deadline.toString());
+ } catch (LukeException e) {
+ assertEquals(LukeException.INVALID_DATE_FORMAT_EXCEPTION.getMessage(), e.getMessage());
+ }
+ }
+
+ @Test
+ public void deadlineSaveStringTest() {
+ try {
+ Deadline deadline = new Deadline("testing-deadline", "2021-08-20");
+ assertEquals("D,0,testing-deadline,2021-08-20", deadline.saveString());
+ } catch (LukeException e) {
+ assertEquals(LukeException.INVALID_DATE_FORMAT_EXCEPTION.getMessage(), e.getMessage());
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/luke/DialogBox.java b/src/main/java/luke/DialogBox.java
new file mode 100644
index 0000000000..241bb09f0a
--- /dev/null
+++ b/src/main/java/luke/DialogBox.java
@@ -0,0 +1,52 @@
+package luke;
+
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import javafx.geometry.Pos;
+import javafx.scene.Node;
+import javafx.scene.control.Label;
+import javafx.scene.image.ImageView;
+import javafx.scene.layout.HBox;
+
+public class DialogBox extends HBox {
+
+ private Label text;
+ private final ImageView DISPLAY_PICTURE;
+
+ public DialogBox(Label l, ImageView iv) {
+ text = l;
+ DISPLAY_PICTURE = iv;
+
+ text.setWrapText(true);
+ DISPLAY_PICTURE.setFitWidth(100.0);
+ DISPLAY_PICTURE.setFitHeight(100.0);
+
+ this.setAlignment(Pos.TOP_RIGHT);
+ this.getChildren().addAll(text, DISPLAY_PICTURE);
+ }
+
+ /**
+ * Flips the dialog box such that the ImageView is on the left and text on the right.
+ */
+ private void flip() {
+ this.setAlignment(Pos.TOP_LEFT);
+ ObservableList tmp = FXCollections.observableArrayList(this.getChildren());
+ FXCollections.reverse(tmp);
+ this.getChildren().setAll(tmp);
+ }
+
+ public static DialogBox getUserDialog(Label l, ImageView iv) {
+ return new DialogBox(l, iv);
+ }
+
+ public static DialogBox getLukeDialog(Label l, ImageView iv) {
+ var db = new DialogBox(l, iv);
+ db.flip();
+ return db;
+ }
+
+ public DialogBox padDialog(int padding) {
+ text.setAlignment(Pos.BASELINE_RIGHT);
+ return this;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/luke/Entry.java b/src/main/java/luke/Entry.java
new file mode 100644
index 0000000000..72352a207f
--- /dev/null
+++ b/src/main/java/luke/Entry.java
@@ -0,0 +1,79 @@
+package luke;
+
+/**
+ * Abstract class that defines entry.
+ */
+public abstract class Entry {
+ private final String ENTRY;
+
+ private boolean isDone;
+
+ /**
+ * Constructor for Entry.
+ */
+ Entry() {
+ this.ENTRY = "";
+ this.isDone = false;
+ }
+
+ /**
+ * Constructor for Entry with a value.
+ *
+ * @param value Entry value.
+ */
+ Entry(String value) {
+ this.ENTRY = value;
+ this.isDone = false;
+ }
+
+ /**
+ * Method to set the isDone status to true of an Entry.
+ *
+ * @return Boolean if successful operation.
+ */
+ public boolean setDone() {
+ if (this.isDone) {
+ return false;
+ } else {
+ this.isDone = true;
+ return true;
+ }
+ }
+
+ /**
+ * Returns true if Entry is Empty.
+ *
+ * @return Boolean corresponding to Entry's length.
+ */
+ public boolean isEmpty() {
+ return this.ENTRY.isEmpty() || this.ENTRY.isBlank();
+ }
+
+ /**
+ * Returns the string to be saved representing the Entry.
+ *
+ * @return String to represent entry in memory.
+ */
+ public String saveString() {
+ String isDoneString = "0";
+ if (this.isDone) {
+ isDoneString = "1";
+ }
+ return "," + isDoneString + "," + this.ENTRY;
+ }
+
+ public boolean contains(String keyword) {
+ return this.ENTRY.contains(keyword);
+ }
+
+ /**
+ * Overrides Object's toString method to return a description of Entry.
+ *
+ * @return String to represent Entry.
+ */
+ @Override
+ public String toString() {
+ char isDoneDisplay = this.isDone ? 'X' : ' ';
+ return ("[" + isDoneDisplay + "] " + this.ENTRY);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/luke/EntryList.java b/src/main/java/luke/EntryList.java
new file mode 100644
index 0000000000..f202a12765
--- /dev/null
+++ b/src/main/java/luke/EntryList.java
@@ -0,0 +1,129 @@
+package luke;
+
+import java.util.ArrayList;
+
+/**
+ * Class that implements methods to store an Arraylist of Entries
+ */
+public class EntryList extends ArrayList {
+
+ private int numberOfEntries;
+
+ /**
+ * Constructor for EntryList.
+ */
+ EntryList() {
+ super();
+ this.numberOfEntries = super.size();
+ }
+
+ /**
+ * Prints all the Entries stored currently.
+ *
+ * @throws LukeException Exception if no entries are to be displayed.
+ */
+ public String getEntries() throws LukeException {
+ StringBuilder entryList = new StringBuilder();
+ if (numberOfEntries > 0) {
+ for (int i = 0; i < numberOfEntries; i++) {
+ entryList.append(super.get(i)).append("\n");
+ }
+ return entryList.toString();
+ } else {
+ throw new LukeException("No entries to display!");
+ }
+ }
+
+ /**
+ * Finds entries with given keyword.
+ * Searches for partial entries as well.
+ *
+ * @param keyword to search for.
+ * @param ui Ui to return info string.
+ * @return String of found entries.
+ */
+ public String getFindEntry(String keyword, Ui ui) {
+ int len = super.size();
+ int count = 1;
+ StringBuilder output = new StringBuilder(ui.getListMatches());
+ for (int i = 0; i < len; i++) {
+ Entry currentEntry = super.get(i);
+ if (currentEntry.contains(keyword)) {
+ if (count == 1) {
+ output.append(ui.getFoundMatches());
+ }
+ output.append(ui.getPrintEntry(currentEntry, count++));
+ }
+ }
+ return output.toString();
+ }
+
+ /**
+ * Marks a given entry number as done.
+ *
+ * @param entryNumber The number of the entry to be marked.
+ * @return String for marked entry.
+ * @throws LukeException Error thrown when no entry exists for the given entryNumber.
+ */
+ public String getEntryAsDone(int entryNumber) throws LukeException {
+ StringBuilder output = new StringBuilder();
+ if (entryNumber > 0 && entryNumber <= numberOfEntries) {
+ if (super.get(entryNumber - 1).setDone()) {
+ output.append("Nice! I've marked this entry as done:");
+ output.append("\t").append(super.get(entryNumber - 1));
+ } else {
+ output.append("Entry is already marked as done!");
+ }
+ return output.toString();
+ } else {
+ throw new LukeException("There's no Entry corresponding to that Number!");
+ }
+ }
+
+ /**
+ * Adds given Entry to the List when adding from memory.
+ *
+ * @param entry Entry to be added.
+ */
+ public void addEntry(Entry entry) {
+ super.add(numberOfEntries++, entry);
+ }
+
+ /**
+ * Adds given Entry to the List.
+ * Prints Success Message if Successful.
+ *
+ * @param entry The Entry to be added.
+ * @param command The command corresponding to the Entry.
+ * @return String to show added Entry.
+ * @throws LukeException Error thrown if Entry is empty.
+ */
+ public String getAddEntry(Entry entry, String command, Ui ui) throws LukeException {
+ StringBuilder output = new StringBuilder();
+ if (!entry.isEmpty()){
+ super.add(numberOfEntries++, entry);
+ output.append(ui.getAddEntry(entry, numberOfEntries));
+ } else {
+ throw new LukeException("The " + command + " description can't be empty!");
+ }
+ return output.toString();
+ }
+
+ /**
+ * Deletes entry by index.
+ *
+ * @param index Index of Entry to be deleted.
+ * @param ui UI Object to print deleted Entry message.
+ * @return String to show deleted entry.
+ * @throws LukeException Error thrown if no Entry corresponds to the index.
+ */
+ public String getDeleteEntry(int index, Ui ui) throws LukeException {
+ if (super.isEmpty() || index < 1 || index > numberOfEntries) {
+ throw new LukeException("Duke can't find anything to delete!");
+ } else {
+ Entry deletedEntry = super.remove(index - 1);
+ numberOfEntries--;
+ return ui.getDeletedEntry(deletedEntry);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/luke/Event.java b/src/main/java/luke/Event.java
new file mode 100644
index 0000000000..2255a4b1c2
--- /dev/null
+++ b/src/main/java/luke/Event.java
@@ -0,0 +1,70 @@
+package luke;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+
+/**
+ * Class that inherits from Entry to encapsulate Events.
+ */
+public class Event extends Entry{
+
+ private LocalDate event;
+
+ /**
+ * Constructor for Event.
+ */
+ Event() {
+ super();
+ this.event = LocalDate.now();
+ }
+
+ /**
+ * Constructor for Event.
+ *
+ * @param task Entry Task to be saved.
+ * @param event Event details.
+ * @throws LukeException Error thrown if event format is incorrect.
+ */
+ Event(String task, String event) throws LukeException {
+ super(task);
+ try {
+ this.event = LocalDate.parse(event);
+ } catch (DateTimeParseException e) {
+ this.event = LocalDate.now();
+ throw LukeException.INVALID_DATE_FORMAT_EXCEPTION;
+ }
+ }
+
+ /**
+ * Overrides Object's toString method.
+ *
+ * @return String representing Event.
+ */
+ @Override
+ public String toString() {
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM dd yyyy");
+ return "[E]" + super.toString() + "(at: " + this.event.format(formatter) + ")";
+ }
+
+ /**
+ * Overrides Entry's saveString method.
+ * Returns string to be saved representing the Event.
+ *
+ * @return String to be saved representing the Event.
+ */
+ @Override
+ public String saveString() {
+ return "E" + super.saveString() + "," + this.event;
+ }
+
+ /**
+ * Returns true if Event is Empty.
+ *
+ * @return Boolean corresponding to Event's length.
+ */
+ @Override
+ public boolean isEmpty() {
+ return super.isEmpty() || !event.isAfter(LocalDate.now());
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/luke/EventTest.java b/src/main/java/luke/EventTest.java
new file mode 100644
index 0000000000..1eb2a7bc8f
--- /dev/null
+++ b/src/main/java/luke/EventTest.java
@@ -0,0 +1,27 @@
+package luke;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class EventTest {
+ @Test
+ public void eventToStringTest() {
+ try {
+ Event event = new Event("testing-event", "2021-08-20");
+ assertEquals("[E][ ] testing-event(at: Aug 20 2021)", event.toString());
+ } catch (LukeException e) {
+ assertEquals(LukeException.INVALID_DATE_FORMAT_EXCEPTION.getMessage(), e.getMessage());
+ }
+ }
+
+ @Test
+ public void eventSaveStringTest() {
+ try {
+ Event event = new Event("testing-event", "2021-08-20");
+ assertEquals("E,0,testing-event,2021-08-20", event.saveString());
+ } catch (LukeException e) {
+ assertEquals(LukeException.INVALID_DATE_FORMAT_EXCEPTION.getMessage(), e.getMessage());
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/luke/Launcher.java b/src/main/java/luke/Launcher.java
new file mode 100644
index 0000000000..af1af67312
--- /dev/null
+++ b/src/main/java/luke/Launcher.java
@@ -0,0 +1,9 @@
+package luke;
+
+import javafx.application.Application;
+
+public class Launcher {
+ public static void main(String[] args) {
+ Application.launch(Luke.class, args);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/luke/Luke.java b/src/main/java/luke/Luke.java
new file mode 100644
index 0000000000..c1329e4bf1
--- /dev/null
+++ b/src/main/java/luke/Luke.java
@@ -0,0 +1,271 @@
+package luke;
+
+import java.util.ArrayList;
+import java.util.Objects;
+import java.util.List;
+
+import javafx.application.Application;
+import javafx.scene.Scene;
+import javafx.scene.control.Button;
+import javafx.scene.control.Label;
+import javafx.scene.control.ScrollPane;
+import javafx.scene.control.TextField;
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
+import javafx.scene.layout.AnchorPane;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Region;
+import javafx.scene.layout.VBox;
+import javafx.scene.paint.Color;
+import javafx.scene.text.Font;
+import javafx.stage.Stage;
+
+/**
+ * Class to encapsulate Luke Chatbot.
+ */
+public class Luke extends Application {
+
+ private final Ui lukeUi;
+ private final Parser lukeParser;
+ private final Storage lukeStorage;
+ private EntryList entries;
+
+ private final Image USER = new Image(Objects.requireNonNull(this.getClass().getResourceAsStream("/images/UserImage.jpg")));
+ private final Image LUKE = new Image(Objects.requireNonNull(this.getClass().getResourceAsStream("/images/LukeImage.jpg")));
+
+ public static final String TERMINATION_COMMAND = "bye";
+ public static final String LIST_ENTRIES_COMMAND = "list";
+ public static final String MARK_ENTRY_DONE_COMMAND = "done";
+ public static final String DELETE_ENTRY_COMMAND = "delete";
+ public static final String TODO_COMMAND = "todo";
+ public static final String EVENT_COMMAND = "event";
+ public static final String DEADLINE_COMMAND = "deadline";
+ public static final String FIND_COMMAND = "find";
+ public static final String HELP_COMMAND = "help";
+ public static final List commands =
+ List.of(TERMINATION_COMMAND, LIST_ENTRIES_COMMAND,
+ MARK_ENTRY_DONE_COMMAND, DELETE_ENTRY_COMMAND,
+ TODO_COMMAND, EVENT_COMMAND, DEADLINE_COMMAND,
+ FIND_COMMAND, HELP_COMMAND);
+
+ /**
+ * Constructor for Luke Chatbot.
+ */
+
+ public Luke() {
+ this.lukeUi = new Ui();
+ this.lukeParser = new Parser();
+ this.lukeStorage = new Storage();
+ try {
+ this.entries = this.lukeStorage.readData();
+ } catch (LukeException e) {
+ this.lukeUi.handleLoadingError(e);
+ this.entries = new EntryList();
+ }
+ }
+
+ @Override
+ public void start(Stage stage) {
+ VBox lukeContainer = new VBox();
+ TextField lukeInput = new TextField();
+ ScrollPane scrollPane = configureScrollPane(lukeContainer);
+ Button sendButton = configureSendButton(lukeContainer, lukeInput, stage);
+ VBox sideLabel = configureSideLabel();
+ HBox topRow = configureTopRow(scrollPane, sideLabel);
+ AnchorPane container = configureAnchorPane(scrollPane, sendButton, lukeInput, topRow);
+ Scene scene = new Scene(container);
+ configureLukeContainerAndLukeInput(lukeContainer, lukeInput, scrollPane, stage);
+ configureStage(scene, stage);
+ stage.show();
+ }
+
+ private void configureStage(Scene scene, Stage stage) {
+ stage.setTitle("Luke");
+ stage.setResizable(false);
+ stage.setMinHeight(500.0);
+ stage.setMinWidth(700.0);
+ stage.setScene(scene);
+ }
+
+ private Button configureSendButton(VBox lukeContainer, TextField lukeInput, Stage stage) {
+ Button sendButton = new Button();
+ sendButton.setPrefWidth(200.0);
+ sendButton.setOnMouseClicked((event) -> {
+ handleUserInput(lukeContainer, lukeInput, stage);
+ });
+ return sendButton;
+ }
+
+ private AnchorPane configureAnchorPane(ScrollPane scrollPane, Button sendButton, TextField lukeInput, HBox topRow) {
+ AnchorPane anchor = new AnchorPane();
+ AnchorPane.setTopAnchor(scrollPane, 1.0);
+ AnchorPane.setBottomAnchor(sendButton, 1.0);
+ AnchorPane.setRightAnchor(sendButton, 1.0);
+ AnchorPane.setLeftAnchor(lukeInput , 1.0);
+ AnchorPane.setBottomAnchor(lukeInput, 1.0);
+ anchor.getChildren().addAll(topRow, lukeInput, sendButton);
+ anchor.setPrefSize(700.0, 500.0);
+ anchor.setStyle("-fx-background-color: #13223b");
+ return anchor;
+ }
+
+ private void configureLukeContainerAndLukeInput(
+ VBox lukeContainer, TextField lukeInput, ScrollPane scrollPane, Stage stage) {
+ lukeContainer.setPrefHeight(Region.USE_COMPUTED_SIZE);
+ lukeContainer.heightProperty().addListener((observable -> scrollPane.setVvalue(1.0)));
+
+ lukeInput.setPrefWidth(496.0);
+ lukeInput.setOnAction((event) -> {
+ handleUserInput(lukeContainer, lukeInput, stage);
+ });
+ }
+
+ /**
+ * Iteration 2:
+ * Creates two dialog boxes, one echoing USER input and the other containing Luke's reply and then appends them to
+ * the dialog container. Clears the USER input after processing.
+ */
+ private void handleUserInput(VBox dialogContainer, TextField userInput, Stage stage) {
+ Label userText = new Label(userInput.getText());
+ Label lukeText = new Label(getResponse(userInput.getText(), stage));
+ dialogContainer.getChildren().addAll(
+ DialogBox.getUserDialog(userText, new ImageView(USER)).padDialog(10),
+ DialogBox.getLukeDialog(lukeText, new ImageView(LUKE)).padDialog(10)
+ );
+ userInput.clear();
+ }
+
+ /**
+ * Function to get response from Luke.
+ */
+ private String getResponse(String input, Stage stage) {
+ if (input.equals(TERMINATION_COMMAND)) {
+ stage.close();
+ return "";
+ } else {
+ return run(input);
+ }
+ }
+
+ private HBox configureTopRow(ScrollPane scrollPane, VBox sideLabel) {
+ HBox topRow = new HBox();
+ topRow.getChildren().addAll(scrollPane, sideLabel);
+ return topRow;
+ }
+
+ private ScrollPane configureScrollPane(VBox lukeContainer) {
+ ScrollPane scrollPane = new ScrollPane();
+ scrollPane.setContent(lukeContainer);
+ scrollPane.setPrefSize(500.0, 473.3);
+ scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
+ scrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.ALWAYS);
+ scrollPane.setVvalue(1.0);
+ scrollPane.setFitToWidth(true);
+ return scrollPane;
+ }
+
+ private VBox configureSideLabel() {
+ Label title = new Label(" LUKE ");
+ title.setTextFill(Color.color(1,1,1));
+ title.setFont(new Font("Georgia", 45));
+ title.setStyle("-fx-start-margin: 100");
+
+ Label description = new Label(this.toString());
+ description.setTextFill(Color.color(1,1,1));
+ description.setFont(new Font("Georgia", 24));
+ description.setStyle("-fx-start-margin: 100");
+
+ VBox sideLabel = new VBox();
+ sideLabel.getChildren().addAll(title, description);
+ return sideLabel;
+ }
+
+ /**
+ * Method containing Logic for processed Input.
+ *
+ * @param parsedTerms ArrayList containing the command, entry and timing (in that order).
+ * @throws LukeException If ProcessedInput is invalid/incoherent.
+ */
+ private String processInput(ArrayList parsedTerms) throws LukeException {
+ if (parsedTerms.size() < 3) {
+ throw new LukeException("Luke cannot understand your entry :/\nType 'help' for assistance");
+ }
+ String command = parsedTerms.get(0);
+ String entry = parsedTerms.get(1);
+ String timing = parsedTerms.get(2);
+ String output = "";
+
+ //Process Command
+ switch(command) {
+ case LIST_ENTRIES_COMMAND:
+ output = entries.getEntries();
+ break;
+
+ case MARK_ENTRY_DONE_COMMAND:
+ output = entries.getEntryAsDone(Integer.parseInt(entry));
+ break;
+
+ case TODO_COMMAND:
+ output = entries.getAddEntry(new Todo(entry), command, this.lukeUi);
+ break;
+
+ case EVENT_COMMAND:
+ output = entries.getAddEntry(new Event(entry, timing), command, this.lukeUi);
+ break;
+
+ case DEADLINE_COMMAND:
+ output = entries.getAddEntry(new Deadline(entry, timing), command, this.lukeUi);
+ break;
+
+ case DELETE_ENTRY_COMMAND:
+ output = entries.getDeleteEntry(Integer.parseInt(entry), this.lukeUi);
+ break;
+
+ case FIND_COMMAND:
+ output = entries.getFindEntry(entry, this.lukeUi);
+ break;
+
+ case HELP_COMMAND:
+ output = this.lukeUi.getCommands();
+ break;
+
+ default:
+ throw new LukeException("Sorry! Luke can't understand that\nType 'help' for assistance");
+ }
+ return output;
+ }
+
+
+ public String run(String input) {
+ String output = "";
+ if (input.equals("bye")) {
+ return this.lukeUi.getGoodByeUser();
+ }
+ try {
+ ArrayList parsedTerms = this.lukeParser.parseInput(input);
+ output = this.processInput(parsedTerms);
+ this.lukeStorage.saveEntries(this.entries);
+ } catch (LukeException e) {
+ output = this.lukeUi.getParsingError(e);
+ } catch (AssertionError e) {
+ output = this.lukeUi.getAssertingError(e);
+ }
+ return output;
+ }
+
+ /**
+ * Overrides the Object's toString method.
+ *
+ * @return String description of Luke.
+ */
+ @Override
+ public String toString() {
+ return " Hello! I'm Luke, \n"
+ + " your slightly useful \n"
+ + " personal assistant! \n"
+ + " I can help you remember \n"
+ + " tasks and other things :D ";
+ }
+}
+
+
diff --git a/src/main/java/luke/LukeException.java b/src/main/java/luke/LukeException.java
new file mode 100644
index 0000000000..71f9884d51
--- /dev/null
+++ b/src/main/java/luke/LukeException.java
@@ -0,0 +1,31 @@
+package luke;
+
+public class LukeException extends Exception {
+
+ public static final LukeException INVALID_DATE_FORMAT_EXCEPTION =
+ new LukeException("Sorry I can't read that! Enter dates in YYYY-MM-DD format");
+
+ /**
+ * Constructor for LukeException.
+ */
+ LukeException() {
+ super();
+ }
+
+ /**
+ * Constructor for LukeException.
+ */
+ LukeException(String argument) {
+ super(argument);
+ }
+
+ /**
+ * Overrides Object's toString method.
+ *
+ * @return String representing Exception.
+ */
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/luke/LukeTest.java b/src/main/java/luke/LukeTest.java
new file mode 100644
index 0000000000..73e5e63a48
--- /dev/null
+++ b/src/main/java/luke/LukeTest.java
@@ -0,0 +1,14 @@
+package luke;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class LukeTest {
+ @Test
+ public void lukeTest() {
+ Luke luke = new Luke();
+ assertEquals("Hello! I'm Luke, your slightly useful personal assistant!\n"
+ + "I can help you remember tasks and other things :D", luke.toString());
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/luke/Parser.java b/src/main/java/luke/Parser.java
new file mode 100644
index 0000000000..0d38f629b8
--- /dev/null
+++ b/src/main/java/luke/Parser.java
@@ -0,0 +1,105 @@
+package luke;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * Class that implements method to parse user inputs.
+ */
+public class Parser {
+
+ /**
+ * Constructor for Parser.
+ */
+ Parser() {}
+
+ /**
+ * Returns parsed input in an Arraylist.
+ *
+ * @param input String input from user.
+ * @return ArrayList of command, entry, timing (if present).
+ * @throws LukeException Error is thrown if Command is invalid.
+ */
+ public ArrayList parseInput(String input) throws LukeException, AssertionError {
+ ArrayList terms = new ArrayList<>();
+ this.parseString(input, terms);
+ String command = "";
+ if (terms.isEmpty()) {
+ throw new LukeException("Luke can't find any commands :((");
+ } else {
+ command = terms.remove(0);
+ }
+ assert isValidCommand(command) : "Invalid Command! Luke can't understand what you mean :((";
+ this.parseEntry(terms);
+ String entry = terms.isEmpty() ? "" : terms.remove(0);
+ String timing = terms.isEmpty() ? "" : this.parseTiming(terms);
+ return new ArrayList<>(Arrays.asList(command, entry, timing));
+ }
+
+ private boolean isValidCommand(String command) {
+ boolean isValid = false;
+ for (String knownCommand : Luke.commands) {
+ if (knownCommand.equals(command)) {
+ isValid = true;
+ break;
+ }
+ }
+ return isValid;
+ }
+
+ private void parseString(String input, ArrayList terms) throws AssertionError {
+ // Function to store all terms in input as separate Strings (separated by space in the input)
+ int length = input.length();
+ assert length >= 1 : "Invalid String Input";
+ StringBuilder currentWord = new StringBuilder();
+ for (int i = 0; i < length; i++) {
+ char currentChar = input.charAt(i);
+ if (currentChar == ' ') {
+ terms.add(currentWord.toString());
+ currentWord.setLength(0);
+ } else {
+ currentWord.append(currentChar);
+ }
+ }
+ terms.add(currentWord.toString());
+ }
+
+ private String parseTiming(ArrayList terms) {
+ if (terms.get(0).startsWith("/")) {
+ terms.remove(0);
+ StringBuilder timing = new StringBuilder();
+ int len = terms.size();
+ for (int i = 0; i < len; i++) {
+ if (i != len - 1){
+ timing.append(terms.get(i)).append(" ");
+ } else {
+ timing.append(terms.get(i));
+ }
+ }
+ return timing.toString();
+ } else {
+ return "";
+ }
+ }
+
+ private void parseEntry(ArrayList terms) {
+ boolean isTermsNotEmpty = !terms.isEmpty();
+ if (isTermsNotEmpty) {
+ StringBuilder entry = new StringBuilder();
+ // Combine All Strings Until End of List or '/' character is found
+ ArrayList termsCopy = new ArrayList<>(terms);
+ for (String term : termsCopy) {
+ if (term.startsWith("/")) {
+ String entryDesc = entry.toString();
+ terms.add(0, entryDesc.substring(0, entryDesc.length()-1));
+ return;
+ } else {
+ entry.append(term).append(' ');
+ terms.remove(0);
+ }
+ }
+ String entryDesc = entry.toString();
+ terms.add(0, entryDesc.substring(0, entryDesc.length()-1));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/luke/Storage.java b/src/main/java/luke/Storage.java
new file mode 100644
index 0000000000..f75f9cedf1
--- /dev/null
+++ b/src/main/java/luke/Storage.java
@@ -0,0 +1,110 @@
+package luke;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Scanner;
+
+/**
+ * Class that implements methods to store Entries.
+ */
+public class Storage {
+
+ private final String PROJECT_ROOT = System.getProperty("user.dir");
+ private final Path DATA_DIRECTORY_PATH = Paths.get(PROJECT_ROOT, "data");
+
+ private Path dataPath;
+ private File lukeData;
+
+ /**
+ * Constructor for Storage.
+ */
+ Storage() {
+ this.dataPath = DATA_DIRECTORY_PATH.resolve("luke.txt");
+ this.lukeData = new File(dataPath.toString());
+ }
+
+ /**
+ * Saves all Entries from entries into memory.
+ *
+ * @param entries EntryList of all entries to be saved.
+ * @throws LukeException Error thrown if data file is corrupted/missing.
+ */
+ public void saveEntries(EntryList entries) throws LukeException {
+ Path dataPath = DATA_DIRECTORY_PATH.resolve("luke.txt");
+ File lukeData = new File(dataPath.toString());
+ try {
+ FileWriter fw = new FileWriter(lukeData);
+ BufferedWriter lukeWriter = new BufferedWriter(fw);
+ for (Entry entry : entries){
+ String nextEntry = entry.saveString();
+ lukeWriter.write(nextEntry);
+ lukeWriter.write("\n");
+ }
+ lukeWriter.close();
+ fw.close();
+ } catch (IOException e) {
+ throw new LukeException("Luke's data file is corrupted/missing! Can't be saved");
+ }
+ }
+
+ /**
+ * Returns EntryList with data from memory.
+ *
+ * @return EntryList containing all data from memory.
+ * @throws LukeException Error thrown if file is missing/corrupted.
+ */
+ public EntryList readData() throws LukeException {
+ EntryList entries = new EntryList();
+ try {
+ return addEntriesFromFile(entries);
+ } catch (FileNotFoundException e) {
+ try {
+ if (!(lukeData.getParentFile().mkdir()) && !(lukeData.createNewFile())) {
+ throw new LukeException("Uh-Oh! Your data can't be stored (I can't create a directory) :/");
+ } else {
+ return new EntryList();
+ }
+ } catch (IOException err) {
+ throw new LukeException("Uh-Oh! Your data can't be stored (IO Error) :/");
+ }
+ }
+ }
+
+ private EntryList addEntriesFromFile(EntryList entries) throws LukeException, FileNotFoundException {
+ Scanner fileScanner = new Scanner(lukeData).useDelimiter("[,\n]");
+ while (fileScanner.hasNext()) {
+ String entryType = fileScanner.next();
+ boolean isDone = Integer.parseInt(fileScanner.next()) == 1;
+ String entryData = fileScanner.next();
+ Entry nextEntry = new Todo("");
+ boolean hasNextEntry = true;
+ switch (entryType) {
+ case "T":
+ nextEntry = new Todo(entryData);
+ break;
+ case "D":
+ nextEntry = new Deadline(entryData, fileScanner.next()); //fileScanner.next() will contain timing
+ break;
+ case "E":
+ nextEntry = new Event(entryData, fileScanner.next()); //fileScanner.next() will contain timing
+ break;
+ default:
+ //Corrupted Entry Case
+ hasNextEntry = false;
+ break;
+ }
+ if (hasNextEntry) {
+ if (isDone) {
+ nextEntry.setDone();
+ }
+ entries.addEntry(nextEntry);
+ }
+ }
+ return entries;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/luke/Todo.java b/src/main/java/luke/Todo.java
new file mode 100644
index 0000000000..14128e1d08
--- /dev/null
+++ b/src/main/java/luke/Todo.java
@@ -0,0 +1,44 @@
+package luke;
+
+/**
+ * Class that inherits from Entry to encapsulate Todos.
+ */
+public class Todo extends Entry {
+
+ /**
+ * Constructor for Todo.
+ */
+ Todo() {
+ super();
+ }
+
+ /**
+ * Constructor for Todo.
+ *
+ * @param task The String that will be stored as a Todo.
+ */
+ Todo(String task) {
+ super(task);
+ }
+
+ /**
+ * Overrides Entry's toString method.
+ *
+ * @return String representation of Todo.
+ */
+ @Override
+ public String toString() {
+ return "[T]" + super.toString();
+ }
+
+ /**
+ * Overrides Entry's saveString method.
+ * Returns string to be saved representing the Todo.
+ *
+ * @return String to be saved representing the Todo.
+ */
+ @Override
+ public String saveString() {
+ return "T" + super.saveString();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/luke/Ui.java b/src/main/java/luke/Ui.java
new file mode 100644
index 0000000000..d95a8237ef
--- /dev/null
+++ b/src/main/java/luke/Ui.java
@@ -0,0 +1,150 @@
+package luke;
+
+import java.util.Objects;
+
+import javafx.scene.control.Button;
+import javafx.scene.control.Label;
+import javafx.scene.control.ScrollPane;
+import javafx.scene.control.TextField;
+import javafx.scene.image.Image;
+import javafx.scene.layout.AnchorPane;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.VBox;
+import javafx.scene.Scene;
+import javafx.stage.Stage;
+
+/**
+ * Class that implements methods to present Luke.
+ */
+public class Ui {
+
+ private final Image USER =
+ new Image(Objects.requireNonNull(this.getClass().getResourceAsStream("/images/UserImage.jpg")));
+ private final Image LUKE =
+ new Image(Objects.requireNonNull(this.getClass().getResourceAsStream("/images/LukeImage.jpg")));
+
+ /**
+ * Constructor to create a UI object.
+ */
+ Ui() {
+ }
+
+ private final static String LOGO = " _ _ \n"
+ + "| | _ _| | _____ \n"
+ + "| | | | | | |/ / _ \\\n"
+ + "| |___| |_| | < __/\n"
+ + "|____/ \\__,_|_|\\_\\___|\n";
+
+ private final static String HORIZONTAL_DIVIDE =
+ "___________________________________________________________________";
+
+ /**
+ * Prints out a welcome message.
+ */
+ public void welcomeUser() {
+ System.out.println("Hello from\n" + LOGO);
+ System.out.println("I'm Luke, your slightly useful personal assistant!"
+ + "What can Luke do for you today?");
+ System.out.println(HORIZONTAL_DIVIDE);
+ }
+
+ /**
+ * Prints out the added entry.
+ *
+ * @param entry The newly-added entry.
+ * @param id The #id of the newly-added entry.
+ */
+ public String getAddEntry(Entry entry, int id) {
+ return "I've added this entry to your list!" +
+ this.getPrintEntry(entry, id);
+ }
+
+ public String getListMatches() {
+ return "Looking for matching tasks in your list...";
+ }
+
+ public String getFoundMatches() {
+ return "Here are the matching tasks in your list: ";
+ }
+
+ /**
+ * Prints out given entry.
+ *
+ * @param entry Entry to be printed.
+ * @param id ID of entry to be printed.
+ */
+ public void printEntry(Entry entry, int id) {
+ System.out.println("\t" + id + "." + entry);
+ }
+
+ /**
+ * Returns given entry.
+ *
+ * @param entry Entry to be printed.
+ * @param id ID of entry to be printed.
+ * @return String for given entry.
+ */
+ public String getPrintEntry(Entry entry, int id) {
+ return "\t" + id + "." + entry;
+ }
+
+ /**
+ * Prints out farewell message.
+ *
+ * @return String to say farewell to USER.
+ */
+ public String getGoodByeUser() {
+ return "Bye! Hope to see you again soon :D";
+ }
+
+ /**
+ * Prints out the Error Message received when Parsing.
+ *
+ * @param parsingError Error encountered while parsing input.
+ */
+ public String getParsingError(LukeException parsingError) {
+ return parsingError.getMessage();
+ }
+
+ /**
+ * Prints out the Error Message received in Assertions when Parsing.
+ *
+ * @param assertError Error encountered while parsing input.
+ */
+ public String getAssertingError(AssertionError assertError) {
+ return assertError.getMessage();
+ }
+
+ /**
+ * Returns all the commands in one large String.
+ *
+ * @return String containing all commands Duke uses.
+ */
+ public String getCommands() {
+ StringBuilder helpPage = new StringBuilder("These are the available commands:\n");
+ for (String command : Luke.commands) {
+ helpPage.append(command).append("\n");
+ }
+ return helpPage.toString();
+ }
+
+
+ /**
+ * Prints out the Error Message received when loading data from memory.
+ *
+ * @param loadingError Error encountered while loading data from memory.
+ */
+ public void handleLoadingError(LukeException loadingError) {
+ System.out.println(loadingError.getMessage());
+ System.out.println(HORIZONTAL_DIVIDE);
+ }
+
+ /**
+ * Prints out entry just after deletion.
+ *
+ * @param deletedEntry Entry that has just been deleted.
+ */
+ public String getDeletedEntry(Entry deletedEntry) {
+ return "Removed entry\n" + deletedEntry;
+ }
+}
\ No newline at end of file
diff --git a/src/main/resources/images/LukeImage.jpg b/src/main/resources/images/LukeImage.jpg
new file mode 100644
index 0000000000..18b37c0b2b
Binary files /dev/null and b/src/main/resources/images/LukeImage.jpg differ
diff --git a/src/main/resources/images/UserImage.jpg b/src/main/resources/images/UserImage.jpg
new file mode 100644
index 0000000000..1d5c15ada7
Binary files /dev/null and b/src/main/resources/images/UserImage.jpg differ
diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT
index 657e74f6e7..7a4cb583fc 100644
--- a/text-ui-test/EXPECTED.TXT
+++ b/text-ui-test/EXPECTED.TXT
@@ -1,7 +1,55 @@
-Hello from
- ____ _
-| _ \ _ _| | _____
-| | | | | | | |/ / _ \
-| |_| | |_| | < __/
-|____/ \__,_|_|\_\___|
-
+Hello from
+ _ _
+| | _ _| | _____
+| | | | | | |/ / _ \
+| |___| |_| | < __/
+|____/ \__,_|_|\_\___|
+
+ ____________________________________________________________
+ Hello! I'm Luke, your slightly useful personal assistant!
+ What can I do for you, my liege?
+ Type 'list' to show previous inputs
+ Type 'todo TASK' to indicate that TASK has to be done
+ Type 'deadline TASK /by DATE/TIME' to indicate that TASK has to be done by DATE/TIME
+ Type 'event TASK /at DATE/TIME PERIOD' to indicate that TASK occurs at DATE/TIME PERIOD
+ Type 'done #' to indicate that task # has been done
+ Type 'bye' to end
+ ____________________________________________________________
+ ____________________________________________________________
+ Got it. I've added this task:
+ [T][ ] borrow book
+ Now you have 1 tasks in the list.
+ ____________________________________________________________
+ ____________________________________________________________
+ Got it. I've added this task:
+ [D][ ] return book (by: Sunday)
+ Now you have 2 tasks in the list.
+ ____________________________________________________________
+ ____________________________________________________________
+ Got it. I've added this task:
+ [E][ ] project meeting (at: Mon 2-4pm)
+ Now you have 3 tasks in the list.
+ ____________________________________________________________
+ ____________________________________________________________
+ Here are the tasks in your list:
+ 1.[T][ ] borrow book
+ 2.[D][ ] return book (by: Sunday)
+ 3.[E][ ] project meeting (at: Mon 2-4pm)
+ ____________________________________________________________
+ ____________________________________________________________
+ Nice! I've marked this task as done:
+ [D][X] return book (by: Sunday)
+ ____________________________________________________________
+ ____________________________________________________________
+ Nice! I've marked this task as done:
+ [E][X] project meeting (at: Mon 2-4pm)
+ ____________________________________________________________
+ ____________________________________________________________
+ Here are the tasks in your list:
+ 1.[T][ ] borrow book
+ 2.[D][X] return book (by: Sunday)
+ 3.[E][X] project meeting (at: Mon 2-4pm)
+ ____________________________________________________________
+ ____________________________________________________________
+ Bye! Talk again sometime!
+ ____________________________________________________________
\ No newline at end of file
diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt
index e69de29bb2..361a93c834 100644
--- a/text-ui-test/input.txt
+++ b/text-ui-test/input.txt
@@ -0,0 +1,8 @@
+todo borrow book
+deadline return book /by Sunday
+event project meeting /at Mon 2-4pm
+list
+done 2
+done 3
+list
+bye
diff --git a/text-ui-test/runtest.bat b/text-ui-test/runtest.bat
index 0873744649..918e1513c3 100644
--- a/text-ui-test/runtest.bat
+++ b/text-ui-test/runtest.bat
@@ -1,21 +1,21 @@
-@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
-
-REM compile the code into the bin folder
-javac -cp ..\src\main\java -Xlint:none -d ..\bin ..\src\main\java\*.java
-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 Duke < input.txt > ACTUAL.TXT
-
-REM compare the output to the expected output
-FC ACTUAL.TXT EXPECTED.TXT
+@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
+
+REM compile the code into the bin folder
+javac -cp ..\src\main\java -Xlint:none -d ..\bin ..\src\main\java\Duke.java
+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 Duke < 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
old mode 100644
new mode 100755
index c9ec870033..cf8a36c1c2
--- a/text-ui-test/runtest.sh
+++ b/text-ui-test/runtest.sh
@@ -1,38 +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
+#!/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