diff --git a/README.md b/README.md
index 8715d4d91..07ce6d819 100644
--- a/README.md
+++ b/README.md
@@ -13,12 +13,38 @@ Prerequisites: JDK 11, update Intellij to the most recent version.
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
- ____ _
- | _ \ _ _| | _____
- | | | | | | | |/ / _ \
- | |_| | |_| | < __/
- |____/ \__,_|_|\_\___|
- ```
+ 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:
+
+ ```
+ Kowalski
+ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣠⣤⣴⠶⠶⣦⣤⣤⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
+ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⡾⠟⠋⠉⠀⠀⠀⠀⠀⠀⠈⠉⠛⠿⣶⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
+ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣾⠟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⢿⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀
+ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣴⠟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣧⠀⠀⠀⠀⠀⠀⠀⠀
+ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⠋⠀⠀⠀⠀⠀⠀⠀⢀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠹⣷⡀⠀⠀⠀⠀⠀⠀
+ ⠀⠀⠀⠀⠀⠀⠀⠀⢸⡏⠀⠀⠀⠀⠀⣠⣾⠟⠛⠛⠛⠻⢶⣄⠀⠀⠀⠀⠀⠀⣴⡾⠛⠛⢿⣧⠀⠀⠀⠀⠀⠀
+ ⠀⠀⠀⠀⠀⠀⠀⠀⣾⠁⠀⠀⠀⢀⣾⠏⠀⠀⠀⠀⠀⠀⠀⠙⣷⡀⠀⠀⠀⢸⡟⠀⠀⠀⠈⣿⡆⠀⠀⠀⠀⠀
+ ⠀⠀⠀⠀⠀⠀⠀⠀⣿⠀⠀⠀⠀⣼⠏⠀⠀⠀⠀⠀⣠⣤⡀⠀⠘⣷⣤⣶⢶⣿⣇⠀⣖⣶⡆⠘⣿⡀⠀⠀⠀⠀
+ ⠀⠀⠀⠀⠀⠀⠀⠀⣿⠀⠀⠀⢠⣿⠀⠀⠀⠀⠀⠸⣧⣿⣿⠀⣼⠏⠁⠀⠀⠀⠹⣧⠙⠛⠁⠀⣿⣧⠀⠀⠀⠀
+ ⠀⠀⠀⠀⠀⠀⠀⠀⣿⠀⠀⠀⠈⣿⠀⠀⠀⠀⠀⠀⠈⠉⠀⠀⢻⣿⣶⠶⣶⣶⣿⠏⠀⠀⠀⣰⣿⡏⠀⠀⠀⠀
+ ⠀⠀⠀⠀⠀⠀⠀⢰⡟⠀⠀⠀⠀⠹⣇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠛⠋⠉⠀⠀⠀⣠⣾⠋⢹⡆⠀⠀⠀⠀
+ ⠀⠀⠀⠀⠀⠀⢀⣿⠃⠀⠀⠀⠀⠀⠙⢷⣤⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⠟⠻⢷⣄⢻⣦⠀⠀⠀
+ ⠀⠀⠀⠀⠀⢠⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⣻⣶⠆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠻⣷⡙⢷⣄⠀
+ ⠀⠀⠀⠀⢠⡿⠁⠀⠀⠀⠀⠀⠀⠀⠀⢀⣤⣴⠟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⠃⠈⢻⣆
+ ⠀⠀⠀⢠⡿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠻⣦⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⠏⠀⠀⠀⣿
+ ⠀⠀⠀⣿⠇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⡟⠀⠀⠀⢠⣿
+ ⠀⠀⢰⡟⠀⠀⠀⠀⠀⠀⠠⣤⣄⠀⠀⠀⠀⠀⠀⠀⠀⠹⣷⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⡇⠀⠀⠀⣾⠃
+ ⠀⠀⢸⣷⠀⠀⠀⠀⠀⠀⠀⠈⠙⢿⣦⣀⠀⠀⠀⠀⠀⠀⢹⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⡇⠀⣠⣾⠏⠀
+ ⢀⣴⡿⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⢠⡿⠻⢷⣄⡀⠀⠀⠀⢸⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⠿⠿⣿⠃⠀⠀
+ ⣿⡏⠀⢹⣧⠀⠀⠀⠀⠀⠀⠀⠀⢸⡇⠀⠀⠙⠿⣦⣤⣤⡿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⢿⣦⠀⠀
+ ⠙⢿⣦⣀⠻⣧⡀⠀⠀⠀⠀⠀⢠⣼⣷⣄⠀⣀⣀⡀⠈⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣼⠏⢰⡿⢶⡆
+ ⠀⠀⠉⠙⠛⠿⠿⣦⣀⢠⣶⣶⡿⠁⠀⠹⣿⠋⠉⢿⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⡿⠃⠀⠀⣠⡾⠃
+ ⠀⠀⠀⠀⠀⠀⠀⠈⠻⢿⣿⡦⠀⠀⠀⠀⠀⠀⠀⢸⡟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⣿⣋⣀⣤⣴⠟⠋⠀⠀
+ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣦⣀⠀⠀⠀⠀⣰⡿⠁⠀⠀⠀⠀⠀⢀⣀⣠⣴⠿⠛⠉⠙⠛⠉⠉⠀⠀⠀⠀⠀
+ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⠻⠶⠶⠟⠛⠛⠛⠛⠛⠛⠛⠛⠋⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
+ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
+ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡀⠀⠀⠀
+ ⠀⠀⠀⠀⠀⠀⠀⠘⠦⣠⠀⠀⠠⠀⡀⠀⠀⣘⢦⠀⢤⡄⠀⠈⠡⡄⡀⠀⡀⣄⠈⠀⠀⠐⠀⠀⠀⠈⠀⠀⠀⠀
+ ⠀⠀⠀⠀⠐⠶⠠⠄⠠⠀⠀⠤⠀⠤⠄⠀⡰⡉⠈⠱⠘⠀⡄⣀⠀⠀⠀⠠⠀⠭⠰⠶⠤⠆⠰⡶⠘⢤⠄⠀⢀⠀
+ KOWALSKI ANALYSIS!
+ ```
\ No newline at end of file
diff --git a/data/Kowalski.txt b/data/Kowalski.txt
new file mode 100644
index 000000000..59b16c06a
--- /dev/null
+++ b/data/Kowalski.txt
@@ -0,0 +1,3 @@
+T | X | Code for CS1010 Assignment
+D | 0 | Write up your analysis report for Skipper | Friday 2359
+E | 0 | Attend Snowball Olympics | Tomorrow 9am - Friday 6pm
diff --git a/docs/README.md b/docs/README.md
index 8077118eb..49e528eff 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,29 +1,271 @@
-# User Guide
+# Kowalski Bot
+If you've watched **[Penguins of Madagascar](https://youtu.be/Z-5SrndEVrI?si=_ivcZTA_PTUoJhI8)**, you'll know **_[Kowalski](https://youtu.be/f3CVuo_HFLM?si=v1hv_y0UU4YP8HYb)_**.
-## Features
+He is often referred to as Skipper's Lieutenant, the second-in-command.
-### Feature-ABC
+If you're someone who needs a Kowalski by your side at all times, this bot is for you!
-Description of the feature.
-### Feature-XYZ
+## Overview
-Description of the feature.
+Kowalski is a bot for you to keep track of your everyday tasks.
+Be it keeping track of your homework assignments,
+your daily chores, Kowalski's got your back!
+
+Kowalski has got 3 types of tasks - ToDo task, Deadline task, and Event task.
+
+### Task types
+- ToDo: Task with ```Name```
+- Deadline: Task with ```Name``` and ```Deadline```
+- Event: Task with ```Name```, ```From``` and ```To```
+
+
+### Kowalski.txt
+
+Kowalski is able to save the tasks which you add by storing them in a text file called **Kowalski.txt**.
+
+If you are using this bot for the **_first time_**, this bot will
+automatically create a directory called **data** which will then store your **Kowalski.txt** inside of it.
+
+E.g. ```C:\Users\Skipper\Desktop\Kowalski_Bot\data\Kowalski.txt```
+assuming you are storing the jar file in ```C:\Users\Skipper\Desktop\Kowalski_Bot```
+
+## Running Kowalski Bot
+#### Prerequisites:
+- Java _(version >= 11)_ installed
+- Having the latest JAR file release of Kowalski
+- ~~[Kowalski's energy](https://youtu.be/xv9ek6RP4r8?si=AhwSaukCiyUihn-X)~~
+
+#### Steps:
+1. Open terminal and change directory to the directory in which you've stored the JAR file.
+2. Run `java -jar ./Kowalski.jar`
+
+To exit the application, type the keyword `bye`.
+To restart the application, repeat steps 1 & 2.
+
+## Features
+
+### 1. List all tasks ```list```
+
+Lists all tasks which the user has input.
+
+### 2. Find matching tasks ```find```
+
+Finds and filters tasks containing a keyword, and prints them out in a list.
+
+### 3. Remove a task ```delete```
+
+Removes a task from the list of tasks.
+
+### 4. Mark a task ```mark```
+
+Marks a task as complete.
+
+### 5. Unmark a task ```unmark```
+
+Marks a task as **_incomplete_**.
+
+### 5. Add a ToDo task ```todo```
+
+Adds in a task for the user, containing only the name.
+
+### 6. Add a Deadline task ```deadline```
+
+Adds in a deadline for the user, containing a name and deadline of the task.
+
+### 7. Add an Event task ```event```
+
+Adds in an event for the user, containing a name, start date/time and end date/time.
## Usage
-### `Keyword` - Describe action
+### Adding a task
+
+The format for adding specific tasks are as follows. The command keyword is not case sensitive, but the /*vars* are.
+
+
+**Formats**:
+- Todo: ```todo NAME```
+- Deadline: ```deadline NAME /by STRING```
+- Event: ```event NAME /from STRING /to STRING```
+
+
+***Example usage***:
+
+- ```todo Code for CS1010 Assignment```
+- ```deadline Write up your analysis report for Skipper /by Friday 2359```
+- ```event Attend Snowball Olympics /from Tomorrow 9am /to Friday 6pm```
+
+
+***Expected outcome***:
+
+If the arguments were entered correctly, the task should be added successfully.
+
+***Example output***:
+
+_For Todo Tasks:_
+```
+Skipper you've got this work to do:
+ [T][ ] Code for CS1010 Assignment
+Now you have 1 task in the list.
+____________________________________________________________
+Kowalski analysing inputs...
+Change recorded in the Text file!
+____________________________________________________________
+```
+_For Deadline Tasks:_
+```
+Skipper, I have recorded this deadline:
+ [D][ ] Write up your analysis report for Skipper (by: Friday 2359)
+Now you have 2 tasks in the list.
+____________________________________________________________
+Kowalski analysing inputs...
+Change recorded in the Text file!
+____________________________________________________________
+```
+_For Event Tasks:_
+```
+Skipper I've noted this event in my calendar:
+ [E][ ] Attend Snowball Olympics (from: Tomorrow 9am to: Friday 6pm)
+Now you have 3 tasks in the list.
+____________________________________________________________
+Kowalski analysing inputs...
+Change recorded in the Text file!
+____________________________________________________________
+```
-Describe the action and its outcome.
-Example of usage:
+### ```mark``` / ```unmark``` : Mark/Unmark tasks
-`keyword (optional arguments)`
+**Format**: ```mark/unmark NUMBER```
-Expected outcome:
+Firstly, the task number must be retrieved. This can be done easily using the command ```list```.
-Description of the outcome.
+Next, use ```mark x``` or ```unmark x``` to set the state of the task to the desired state.
+***Example usage***:
+
+- ```mark 1```
+- ```unmark 3```
+
+***Expected outcome***:
+
+If a valid number is entered, a response marking the task will be shown.
+
+***Example output***:
+
+_After marking task:_
+```
+Way to go Skipper! I've marked this task as done:
+ [T][X] Code for CS1010 Assignment
+____________________________________________________________
+Kowalski analysing inputs...
+Change recorded in the Text file!
+____________________________________________________________
```
-expected output
+_After unmarking task:_
+
```
+C'mon Skipper, you're much better than that! I've marked this task as undone:
+ [E][ ] Attend Snowball Olympics (from: Tomorrow 9am to: Friday 6pm)
+____________________________________________________________
+Kowalski analysing inputs...
+Change recorded in the Text file!
+____________________________________________________________
+```
+
+
+### List: ```list```: Listing all tasks
+
+**Format**: ```list```
+
+By typing list, the user can print out all existing tasks into the command line.
+
+***Example usage***:
+
+- ```list```
+
+*Expected outcome*:
+
+All tasks will be printed out in the console.
+
+*Example output*:
+
+```
+1.[T][X] Code for CS1010 Assignment
+2.[D][ ] Write up your analysis report for Skipper (by: Friday 2359)
+3.[E][ ] Attend Snowball Olympics (from: Tomorrow 9am to: Friday 6pm)
+____________________________________________________________
+```
+
+
+### Find: ```find``` : Finding keywords
+
+**Format**: ```find STRING```
+
+The command looks through all existing tasks, and prints them out if their name contains the string query.
+
+*Example usage*:
+
+- ```find lecture```
+- ```find homework```
+
+*Expected outcome*:
+
+All tasks containing the keywords in their name will be printed out.
+
+*Example output*:
+
+__Input:__``` find report```
+
+```
+Skipper here are the matching tasks:
+1.[D][ ] Write up your analysis report for Skipper (by: Friday 2359)
+____________________________________________________________
+```
+
+### Delete: ```delete``` : Deleting a task
+
+**Format**: ```delete NUMBER```
+
+As with *mark/unmark*, the number of the task to be deleted must be obtained.
+
+Next, typing the command in the given format will delete said task from the list.
+
+Once deleted, said task **CANNOT** be retrieved.
+
+***Example usage***:
+
+- ```delete 4```
+
+***Expected outcome***:
+
+Task of the given number (in the list) will be deleted.
+
+***Example output***:
+
+```
+Damn Skipper, you've got some courage removing this task:
+ [T][ ] Admire favourite snack
+Now you have 3 tasks in the list.
+____________________________________________________________
+Kowalski analysing inputs...
+Change recorded in the Text file!
+____________________________________________________________
+```
+
+### Bye: ```bye``` : Exit the program
+
+**Format**: ```bye```
+
+***Expected outcome***:
+
+Exits the program and updates the stored tasks in **_Kowalski.txt_** file.
+
+***Expected output***:
+```
+Bye Skipper! Hope to serve you again for your next mission!
+____________________________________________________________
+```
+
+
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/Kowalski/Kowalski.java b/src/main/java/Kowalski/Kowalski.java
new file mode 100644
index 000000000..2ebe8d342
--- /dev/null
+++ b/src/main/java/Kowalski/Kowalski.java
@@ -0,0 +1,30 @@
+package Kowalski;
+
+import Kowalski.UI.Ui;
+import Kowalski.commands.Parser;
+import Kowalski.commands.Storage;
+import Kowalski.commands.TaskList;
+
+import java.io.IOException;
+import java.util.Scanner;
+
+/**
+ * Kowalski is a bot for users to keep track of your everyday tasks.
+ * It is able to store and retrieve tasks which you need to do, tasks with deadlines and events important to users.
+ * It allows you to easily add, remove tasks, or even mark and unmark tasks.
+ * It also allows users to find previous tasks based on their inputs.
+ */
+public class Kowalski {
+ public static Scanner in = new Scanner (System.in);
+
+ public static void main(String[] args) throws IOException {
+ Ui.printIntro();
+ Storage.readTextFile(TaskList.currentTask);
+ String userCommand = TaskList.processInput(in.next());
+ while (!(userCommand.equals("bye"))){
+ Parser.parseUserCommand(TaskList.processInput(userCommand), TaskList.currentTask, in);
+ userCommand = in.next();
+ }
+ Ui.printEndConversation();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/Kowalski/UI/Ui.java b/src/main/java/Kowalski/UI/Ui.java
new file mode 100644
index 000000000..6092acfc5
--- /dev/null
+++ b/src/main/java/Kowalski/UI/Ui.java
@@ -0,0 +1,81 @@
+package Kowalski.UI;
+
+public class Ui {
+ private static final String DIVIDING_LINE = "____________________________________________________________";
+ private static final String KOWALSKI_INTRODUCTION = "Welcome Skipper! I'm Kowalski, reporting for Duty!";
+ private static final String KOWALSKI_STARTING_QN = "What can I do for you today?";
+ private static final String KOWALSKI_ECHO = "Enter commands, and I will echo them back to you, " +
+ "as well as add them to your list.";
+ private static final String KOWALSKI_LIST_COMMAND = "Type 'list' to see your to-do list.";
+ private static final String KOWALSKI_MARK_COMMAND = "Type 'mark' to mark a task as done.";
+ private static final String KOWALSKI_UNMARK_COMMAND = "Type 'unmark' to mark a task as not done.";
+ private static final String KOWALSKI_TODO_TASK_COMMAND = "Type 'todo ' to add a task to the list.";
+ private static final String KOWALSKI_DEADLINE_TASK_COMMAND = "Type 'deadline /by ' to add a task " +
+ "with a deadline to the list.";
+ private static final String KOWALSKI_EVENT_TASK_COMMAND = "Type 'event /from /to ' to add an " +
+ "event to the list.";
+ private static final String KOWALSKI_DELETE_TASK_COMMAND = "Type 'delete ' to delete a task from your list.";
+ private static final String KOWALSKI_BYE_COMMAND = "Type 'bye' to end the conversation.";
+ private static final String ZERO_TASK_MESSAGE = "Now you have 0 tasks in the list.";
+ private static final String ONE_TASK_MESSAGE = "Now you have 1 task in the list.";
+ private static final String KOWALSKI_BYE_MESSAGE = "Bye Skipper! Hope to serve you again for your next mission!";
+ private static final String NOW_YOU_HAVE = "Now you have ";
+ private static final String TASKS_IN_THE_LIST = " tasks in the list.";
+ /**
+ * Prints out the message introducing the functionalities of Kowalski Bot
+ */
+ public static void printIntro(){
+ System.out.println(DIVIDING_LINE);
+ System.out.println(KOWALSKI_INTRODUCTION + System.lineSeparator());
+ printHelpCommands();
+ System.out.println(System.lineSeparator() + KOWALSKI_STARTING_QN );
+ printDivider();
+ }
+
+ /**
+ * Prints out a list of commands to guide the user to accurately use the Kowalski Bot
+ */
+ public static void printHelpCommands(){
+ System.out.println(KOWALSKI_ECHO);
+ System.out.println(KOWALSKI_LIST_COMMAND);
+ System.out.println(KOWALSKI_MARK_COMMAND);
+ System.out.println(KOWALSKI_UNMARK_COMMAND);
+ System.out.println(KOWALSKI_TODO_TASK_COMMAND);
+ System.out.println(KOWALSKI_DEADLINE_TASK_COMMAND);
+ System.out.println(KOWALSKI_EVENT_TASK_COMMAND);
+ System.out.println(KOWALSKI_DELETE_TASK_COMMAND);
+ System.out.println(KOWALSKI_BYE_COMMAND);
+ }
+
+ /**
+ * Prints a dividing line between statements for added clarity
+ */
+ public static void printDivider(){
+ System.out.println(DIVIDING_LINE);
+ }
+
+ /**
+ * Prints out an accurate message for the number of tasks in the list.
+ * @param numberOfTasks : represents the total current task count
+ */
+ public static void printCurrentTaskMessage(int numberOfTasks){
+ switch (numberOfTasks){
+ case 0:
+ System.out.println(ZERO_TASK_MESSAGE);
+ break;
+ case 1:
+ System.out.println(ONE_TASK_MESSAGE);
+ break;
+ default:
+ System.out.println(NOW_YOU_HAVE + numberOfTasks + TASKS_IN_THE_LIST);
+ }
+ }
+
+ /**
+ * Prints out the message to end conversation with the user
+ */
+ public static void printEndConversation(){
+ System.out.println(KOWALSKI_BYE_MESSAGE);
+ printDivider();
+ }
+}
diff --git a/src/main/java/Kowalski/commands/KowalskiException.java b/src/main/java/Kowalski/commands/KowalskiException.java
new file mode 100644
index 000000000..17ee5f1f5
--- /dev/null
+++ b/src/main/java/Kowalski/commands/KowalskiException.java
@@ -0,0 +1,4 @@
+package Kowalski.commands;
+
+public class KowalskiException extends Exception{
+}
diff --git a/src/main/java/Kowalski/commands/Parser.java b/src/main/java/Kowalski/commands/Parser.java
new file mode 100644
index 000000000..b9deca213
--- /dev/null
+++ b/src/main/java/Kowalski/commands/Parser.java
@@ -0,0 +1,252 @@
+package Kowalski.commands;
+
+import Kowalski.UI.Ui;
+import Kowalski.tasks.Deadline;
+import Kowalski.tasks.Event;
+import Kowalski.tasks.Task;
+import Kowalski.tasks.Todo;
+
+import java.util.InputMismatchException;
+import java.util.List;
+import java.util.Scanner;
+
+public class Parser {
+ private static final String BYE = "bye";
+ private static final String LIST = "list";
+ private static final String FIND = "find";
+ private static final String DELETE = "delete";
+ private static final String UNMARK = "unmark";
+ private static final String MARK = "mark";
+ private static final String TODO = "todo";
+ private static final String DEADLINE = "deadline";
+ private static final String EVENT = "event";
+ private static final String BY = "/by";
+ private static final String FROM = "/from";
+ private static final String TO = "/to";
+ private static final String INPUT_MISMATCH_EXCEPTION_MESSAGE = "Skipper input a god damn number!";
+ private static final String INDEX_OUT_OF_BOUNDS_EXCEPTION_MESSAGE = "Invalid Task Number! Skipper stop acting like Private!";
+ private static final String KOWALSKI_EXCEPTION_MESSAGE = "Skipper your inputs are wrong! Try again!";
+ private static final String DEFAULT_ERROR_MESSAGE = "Skipper pull up your socks!";
+ private static final String TASK_DELETE_MESSAGE = "Damn Skipper, you've got some courage removing this task:";
+ private static final String MARK_AS_DONE_MESSAGE = "Way to go Skipper! I've marked this task as done:";
+ private static final String MARK_AS_NOT_DONE_MESSAGE = "C'mon Skipper, you're much better than that! I've marked this task as undone:";
+ private static final String TODO_MESSAGE = "Skipper you've got this work to do:";
+ private static final String DEADLINE_MESSAGE = "Skipper, I have recorded this deadline:";
+ private static final String EVENT_MESSAGE = "Skipper I've noted this event in my calendar:";
+ private static final String TWO_SPACE_GAP = " ";
+
+ /**
+ * Used to check if the user has accurately input the deadline by stating the "/by"
+ * @param deadlineDetails : Contains the details of the deadline task
+ * @throws KowalskiException In the event that the input has no "/by"
+ */
+ public static void checkDeadlineInput(String deadlineDetails) throws KowalskiException{
+ if (!(deadlineDetails.contains(BY))) {
+ throw new KowalskiException();
+ }
+ }
+
+ /**
+ * Used to check if the user has accurately input the deadline by stating the "/from" and "/to"
+ * @param eventDetails : Contains the details of the event task
+ * @throws KowalskiException In the event that the input has no "/from" or "/to" or both
+ */
+ public static void checkEventInput(String eventDetails) throws KowalskiException{
+ if (!((eventDetails.contains(FROM)) && (eventDetails.contains(TO)))) {
+ throw new KowalskiException();
+ }
+ }
+
+ /**
+ * Cleans up the user input and forms new Deadline Task
+ * @param deadlineDetails : User input for details of the deadline task
+ * @return new deadline task created
+ */
+ private static Task getNewDeadlineTask(String deadlineDetails) {
+ String[] deadlineArray = deadlineDetails.split(BY);
+ for (int i = 0; i < deadlineArray.length; i++) {
+ deadlineArray[i] = deadlineArray[i].trim();
+ }
+ return new Deadline(deadlineArray[0], deadlineArray[1]);
+ }
+
+ /**
+ * Cleans up the user input and forms new event Task
+ * @param eventDetails : User input for details of the event task
+ * @return new event task created
+ */
+ private static Task getNewEventTask(String eventDetails) {
+ String[] eventArray = eventDetails.split(FROM);
+ String eventInformation = eventArray[0].trim();
+ String [] fromAndTo = eventArray[1].split(TO);
+ String eventFrom = fromAndTo[0].trim();
+ String eventTo = fromAndTo[1].trim();
+
+ return new Event(eventInformation, eventFrom, eventTo);
+ }
+
+ /**
+ * Parses user command and initiates actions according to the first word input by the user.
+ * Able to initiate actions for commands - bye, list, find, delete, unmark, mark, todo, deadline, event
+ * @param UserCommand first word input by the user
+ * @param currentTask is an ArrayList storing the current tasks
+ * @param in is of scanner class to enable usage of the scanning library's functions
+ */
+ public static void parseUserCommand(String UserCommand, List currentTask, Scanner in) {
+
+ int taskNumber;
+ int lastTaskIndex;
+
+ switch (UserCommand){
+ case BYE:
+ break;
+
+ case LIST:
+ TaskList.printCurrentTaskItems();
+ Ui.printDivider();
+ break;
+
+ case FIND:
+ String wordToMatch = in.nextLine();
+ if (!wordToMatch.isEmpty()) {
+ TaskList.findMatch(wordToMatch.trim().toLowerCase());
+ } else {
+ System.out.println(KOWALSKI_EXCEPTION_MESSAGE);
+ }
+ Ui.printDivider();
+ break;
+
+ case DELETE:
+ try {
+ taskNumber = in.nextInt();
+ } catch (InputMismatchException e) {
+ System.out.println(INPUT_MISMATCH_EXCEPTION_MESSAGE);
+ break;
+ }
+
+ try {
+ System.out.println(TASK_DELETE_MESSAGE);
+ System.out.println(TWO_SPACE_GAP + currentTask.get(taskNumber - 1));
+ Ui.printCurrentTaskMessage(currentTask.size()-1);
+ TaskList.removeTask(taskNumber-1);
+ Storage.writeText(currentTask);
+ } catch (IndexOutOfBoundsException e){
+ System.out.println(INDEX_OUT_OF_BOUNDS_EXCEPTION_MESSAGE);
+ }
+ Ui.printDivider();
+ break;
+
+ case UNMARK:
+ try {
+ taskNumber = in.nextInt();
+ } catch (InputMismatchException e) {
+ System.out.println(INPUT_MISMATCH_EXCEPTION_MESSAGE);
+ Ui.printDivider();
+ break;
+ }
+
+ try{
+ currentTask.get(taskNumber - 1).markAsNotDone();
+ System.out.println(MARK_AS_NOT_DONE_MESSAGE);
+ System.out.println(TWO_SPACE_GAP + currentTask.get(taskNumber - 1));
+ Storage.writeText(currentTask);
+ } catch (IndexOutOfBoundsException e) {
+ System.out.println(INDEX_OUT_OF_BOUNDS_EXCEPTION_MESSAGE);
+ Ui.printDivider();
+ break;
+ }
+ Ui.printDivider();
+ break;
+
+ case MARK:
+ try {
+ taskNumber = in.nextInt();
+ } catch (InputMismatchException e) {
+ System.out.println(INPUT_MISMATCH_EXCEPTION_MESSAGE);
+ Ui.printDivider();
+ break;
+ }
+
+ try{
+ currentTask.get(taskNumber - 1).markAsDone();
+ System.out.println(MARK_AS_DONE_MESSAGE);
+ System.out.println(TWO_SPACE_GAP + currentTask.get(taskNumber - 1));
+ Storage.writeText(currentTask);
+ } catch (IndexOutOfBoundsException e) {
+ System.out.println(INDEX_OUT_OF_BOUNDS_EXCEPTION_MESSAGE);
+ Ui.printDivider();
+ break;
+ }
+ Ui.printDivider();
+ break;
+
+ case TODO:
+ String toDoDetails = in.nextLine();
+
+ Task newToDoTask = new Todo(toDoDetails.trim());
+ TaskList.addTask(newToDoTask);
+ lastTaskIndex = currentTask.size() - 1;
+
+ System.out.println(TODO_MESSAGE);
+ System.out.println(TWO_SPACE_GAP + currentTask.get(lastTaskIndex));
+ Ui.printCurrentTaskMessage(currentTask.size());
+ Storage.writeText(currentTask);
+ Ui.printDivider();
+ break;
+
+ case DEADLINE:
+ String deadlineDetails = in.nextLine();
+
+ try{
+ checkDeadlineInput(deadlineDetails);
+
+ //Adding the new deadline task into currentTask List after processing and cleaning inputs
+ Task newDeadlineTask = getNewDeadlineTask(deadlineDetails);
+ TaskList.addTask(newDeadlineTask);
+ lastTaskIndex = currentTask.size() - 1;
+
+ //Printing the appropriate information for the User
+ System.out.println(DEADLINE_MESSAGE);
+ System.out.println(TWO_SPACE_GAP + currentTask.get( lastTaskIndex));
+ Ui.printCurrentTaskMessage(currentTask.size());
+ Storage.writeText(currentTask);
+ Ui.printDivider();
+ } catch (KowalskiException e){
+ System.out.println(KOWALSKI_EXCEPTION_MESSAGE);
+ Ui.printDivider();
+ }
+ break;
+
+ case EVENT:
+ String eventDetails = in.nextLine();
+
+ try{
+ checkEventInput(eventDetails);
+
+ //Adding the new event task into currentTask List after processing and cleaning inputs
+ Task newEventTask = getNewEventTask(eventDetails);
+ TaskList.addTask(newEventTask);
+ lastTaskIndex = currentTask.size() - 1;
+
+ //Printing the appropriate information for the User
+ System.out.println(EVENT_MESSAGE);
+ System.out.println(TWO_SPACE_GAP + currentTask.get(lastTaskIndex));
+ Ui.printCurrentTaskMessage(currentTask.size());
+ Storage.writeText(currentTask);
+ Ui.printDivider();
+ } catch (KowalskiException e) {
+ System.out.println(KOWALSKI_EXCEPTION_MESSAGE);
+ Ui.printDivider();
+ }
+ break;
+
+
+ default:
+ System.out.println(DEFAULT_ERROR_MESSAGE+ System.lineSeparator());
+ Ui.printHelpCommands();
+ Ui.printDivider();
+ break;
+ }
+ }
+
+}
diff --git a/src/main/java/Kowalski/commands/Storage.java b/src/main/java/Kowalski/commands/Storage.java
new file mode 100644
index 000000000..af6ff85b0
--- /dev/null
+++ b/src/main/java/Kowalski/commands/Storage.java
@@ -0,0 +1,161 @@
+package Kowalski.commands;
+
+import Kowalski.UI.Ui;
+import Kowalski.tasks.Deadline;
+import Kowalski.tasks.Event;
+import Kowalski.tasks.Task;
+import Kowalski.tasks.Todo;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.nio.file.FileAlreadyExistsException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+
+public class Storage {
+ private static final String TEXT_FILE_FOLDER = "data";
+ private static final String FULL_FILE_PATH = "data/Kowalski.txt";
+ private static final String TODO = "T";
+ private static final String DEADLINE = "D";
+ private static final String EVENT = "E";
+ private static final String COMPLETED_TASK_CROSS = "X";
+ private static final String FROM_AND_TO_SEPARATOR = " - ";
+ private static final String TEXT_FILE_CORRUPTED_ERROR = "Kowalski Analysis Error: Text File Corrupted!";
+ private static final String CREATE_NEW_TEXT_FILE = "Creating new Kowalski.txt file";
+ private static final String RETRIEVING_PREVIOUS_DATA_MESSAGE = "Kowalski retrieving previous data...";
+ private static final String DATA_RETRIEVAL_SUCCESS_MESSAGE = "Kowalski Data Retrieval Success!";
+ private static final String DATA_RETRIEVAL_FAIL_MESSAGE = "Kowalski Data Retrieval Failed!";
+ private static final String ANALYSING_INPUT_MESSAGE = "Kowalski analysing inputs..." ;
+ private static final String CHANGE_RECORDED_IN_TEXT_FILE = "Change recorded in the Text file!";
+ private static final String ISSUE_WITH_DIRECTORY_OR_TEXT_FILE = "Kowalski Analysis failed - Issue with directory/text file!";
+ private static final String FAILURE_TO_CREATE_DIRECTORY = "Skipper, I am unable to create the data directory for you!" ;
+ private static final String NEWLINE = "\n" ;
+
+ /**
+ * This function takes in the lines of code from the Kowalski.txt and processes them to
+ * list out all the previous tasks which we had saved.
+ * @param fileInput: String containing each line of input from Kowalski.txt
+ * @param currentTask ArrayList containing the current tasks
+ */
+ public static void restoreTaskList(String fileInput, List currentTask){
+ String [] inputArray = fileInput.split("\\s*\\|\\s*");
+ switch (inputArray[0].trim()){
+ case TODO:
+ Task newToDoTask = new Todo(inputArray[2].trim());
+ if (inputArray[1].trim().equals(COMPLETED_TASK_CROSS)) {
+ newToDoTask.markAsDone();
+ } else {
+ newToDoTask.markAsNotDone();
+ }
+ currentTask.add(newToDoTask);
+ break;
+
+ case DEADLINE:
+ Task newDeadlineTask = new Deadline(inputArray[2].trim(), inputArray[3].trim());
+ if (inputArray[1].trim().equals(COMPLETED_TASK_CROSS)) {
+ newDeadlineTask.markAsDone();
+ } else {
+ newDeadlineTask.markAsNotDone();
+ }
+ currentTask.add(newDeadlineTask);
+ break;
+ case EVENT:
+ String [] fromAndTo = inputArray[3].trim().split(FROM_AND_TO_SEPARATOR);
+ Task newEventTask = new Event(inputArray[2].trim(), fromAndTo[0].trim(), fromAndTo[1].trim());
+ if (inputArray[1].trim().equals(COMPLETED_TASK_CROSS)) {
+ newEventTask.markAsDone();
+ } else {
+ newEventTask.markAsNotDone();
+ }
+ currentTask.add(newEventTask);
+ break;
+ default:
+ System.out.println(TEXT_FILE_CORRUPTED_ERROR);
+ break;
+ }
+ }
+
+ /**
+ * Read text file accesses Kowalski.txt and calls the restoreTaskList function
+ * @param currentTask ArrayList containing the current tasks
+ * @throws IOException when unable to get the Kowalski file or has any input errors
+ */
+ public static void readTextFile(List currentTask) throws IOException{
+ try {
+ createTextFileFolder(Paths.get(TEXT_FILE_FOLDER));
+ Path filePath = Paths.get(FULL_FILE_PATH);
+ if (!Files.exists(filePath)){
+ System.out.println(CREATE_NEW_TEXT_FILE);
+ Files.createFile(filePath);
+ }
+ FileReader fileReader = new FileReader(FULL_FILE_PATH);
+ BufferedReader line = new BufferedReader(fileReader);
+ System.out.println(RETRIEVING_PREVIOUS_DATA_MESSAGE);
+ while (line.ready()) {
+ restoreTaskList(line.readLine(), currentTask);
+ }
+ System.out.println(DATA_RETRIEVAL_SUCCESS_MESSAGE);
+ Ui.printDivider();
+ } catch (IOException e){
+ System.out.println(DATA_RETRIEVAL_FAIL_MESSAGE);
+ throw e;
+ }
+ }
+
+ /**
+ * Function which is called to generate an arrayList "lines" which updates according to the users' inputs.
+ * Calls the writeTextFile function to update Kowalski.txt
+ * @param currentTask ArrayList containing the current tasks
+ */
+ public static void writeText(List currentTask){
+ List lines = new ArrayList<>();
+ for (Task task:currentTask){
+ lines.add(task.textFileInputString());
+ }
+ Ui.printDivider();
+ System.out.println(ANALYSING_INPUT_MESSAGE);
+ writeTextFile(lines);
+ }
+
+ /**
+ * Accesses the Kowalski.txt and updates it in the correct format.
+ * @param lines: Arraylist containing the processed current tasks in the CurrentTask
+ */
+ public static void writeTextFile(List lines) {
+ try {
+ Path parentPath = Paths.get(TEXT_FILE_FOLDER);
+ createTextFileFolder(parentPath);
+
+ FileWriter writer = new FileWriter(FULL_FILE_PATH);
+ for (String line : lines) {
+ writer.write(line + NEWLINE);
+
+ }
+ System.out.println(CHANGE_RECORDED_IN_TEXT_FILE);
+ writer.close();
+ } catch (IOException e){
+ System.out.println(ISSUE_WITH_DIRECTORY_OR_TEXT_FILE);
+ }
+ }
+
+ /**
+ * Used to create the data folder to store the Kowalski.txt file
+ * @param parentPath: Path file containing the path we intend to make Kowalski.txt in
+ * @throws IOException whenever the input for the path or creation of the directory is improper
+ */
+ public static void createTextFileFolder(Path parentPath ) throws IOException{
+ try {
+ Files.createDirectories(parentPath);
+ } catch (FileAlreadyExistsException ignored){
+ //Ignore this error if file exists
+ } catch (IOException e){
+ System.out.println(FAILURE_TO_CREATE_DIRECTORY);
+ throw e;
+ }
+ }
+}
diff --git a/src/main/java/Kowalski/commands/TaskList.java b/src/main/java/Kowalski/commands/TaskList.java
new file mode 100644
index 000000000..c316a3f8c
--- /dev/null
+++ b/src/main/java/Kowalski/commands/TaskList.java
@@ -0,0 +1,75 @@
+package Kowalski.commands;
+
+import Kowalski.tasks.Task;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class TaskList {
+ public static List currentTask = new ArrayList<>();
+ public static final String DOT = ".";
+ public static final String NO_MATCHES_MESSAGE = "My analysis shows no matches Skipper!";
+ public static final String MATCHES_FOUND_MESSAGE = "Skipper here are the matching tasks:";
+
+ /**
+ * Used to process the different variations of the users inputs
+ * @param userInput : String which the user inputs
+ * @return String which is in lowercase and clear of any unnecessary whitespace
+ */
+ public static String processInput(String userInput){
+ return (userInput.trim()).toLowerCase();
+ }
+
+ /**
+ * Used in the "list" command to print all the Current Tasks in the proper format
+ */
+ public static void printCurrentTaskItems(){
+ for (int i = 1; i <= currentTask.size(); i++){
+ System.out.println(i + DOT + currentTask.get(i-1));
+ }
+ }
+
+ /**
+ * Used in the "find" command to print all the matching Tasks in the proper format
+ * @param matchList ArrayList containing the matching tasks
+ */
+ public static void printMatchingTasks(List matchList){
+ for (int i = 1; i <= matchList.size(); i++){
+ System.out.println(i + DOT + matchList.get(i-1));
+ }
+ }
+
+ /**
+ * Method to add tasks in the ArrayList currentTask
+ * @param task an instance of the task which needs to be added
+ */
+ public static void addTask(Task task) {
+ currentTask.add(task);;
+ }
+
+ /**
+ * Method to remove tasks in the ArrayList currentTask
+ * @param index index of the task to be removed from currentTask
+ */
+ public static void removeTask(int index){
+ currentTask.remove(index);
+ }
+
+ /**
+ * Method to return the task with descriptions matching the user's input word
+ * @param input user's input word
+ */
+ public static void findMatch(String input){
+ ListmatchList = currentTask.stream()
+ .filter(task -> task.getDescription().toLowerCase().contains(input))
+ .collect(Collectors.toList());
+
+ if (matchList.isEmpty()){
+ System.out.println(NO_MATCHES_MESSAGE);
+ } else {
+ System.out.println(MATCHES_FOUND_MESSAGE);
+ printMatchingTasks(matchList);
+ }
+ }
+}
diff --git a/src/main/java/Kowalski/tasks/Deadline.java b/src/main/java/Kowalski/tasks/Deadline.java
new file mode 100644
index 000000000..597925af8
--- /dev/null
+++ b/src/main/java/Kowalski/tasks/Deadline.java
@@ -0,0 +1,32 @@
+package Kowalski.tasks;
+
+public class Deadline extends Task {
+
+ protected String deadline;
+
+ public Deadline(String description, String by) {
+ super(description);
+ this.deadline = by;
+ }
+
+ /**
+ * This function returns the deadline of the "deadline" event
+ * @return String of the Deadline
+ */
+ public String getDeadline() {
+ return deadline;
+ }
+
+ @Override
+ public String textFileInputString(){
+ return String.format("D | %s | %s | %s",
+ isDone? "X" : "0",
+ getDescription().trim(),
+ getDeadline());
+ }
+
+ @Override
+ public String toString() {
+ return "[D]" + super.toString() + " (by: " + deadline + ")";
+ }
+}
diff --git a/src/main/java/Kowalski/tasks/Event.java b/src/main/java/Kowalski/tasks/Event.java
new file mode 100644
index 000000000..e4aa458c8
--- /dev/null
+++ b/src/main/java/Kowalski/tasks/Event.java
@@ -0,0 +1,42 @@
+package Kowalski.tasks;
+
+public class Event extends Task {
+ protected String startDayAndTime;
+ protected String endDayAndTime;
+
+ public Event (String description, String startDayAndTime, String endDayAndTime) {
+ super(description);
+ this.startDayAndTime = startDayAndTime;
+ this.endDayAndTime = endDayAndTime;
+ }
+
+ /**
+ * Method obtains the start date and time of the event
+ * @return String of the start date and time
+ */
+ public String getStartDayAndTime() {
+ return startDayAndTime;
+ }
+
+ /**
+ * Method obtains the end date and time of the event
+ * @return String of the end date and time
+ */
+ public String getEndDayAndTime() {
+ return endDayAndTime;
+ }
+
+ @Override
+ public String textFileInputString(){
+ return String.format("E | %s | %s | %s - %s",
+ isDone? "X" : "0",
+ getDescription().trim(),
+ getStartDayAndTime(),
+ getEndDayAndTime());
+ }
+
+ @Override
+ public String toString() {
+ return "[E]" + super.toString() + " (from: " + startDayAndTime + " to: " + endDayAndTime + ")";
+ }
+}
diff --git a/src/main/java/Kowalski/tasks/Task.java b/src/main/java/Kowalski/tasks/Task.java
new file mode 100644
index 000000000..72004cc99
--- /dev/null
+++ b/src/main/java/Kowalski/tasks/Task.java
@@ -0,0 +1,59 @@
+package Kowalski.tasks;
+
+public class Task {
+ protected String description;
+ protected boolean isDone;
+
+ public Task(String description) {
+ this.description = description;
+ this.isDone = false;
+ }
+
+ /**
+ * This method provides the description of a certain task
+ * @return details of task
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * This method returns the symbol to store the status of a task in the text file
+ * @return "X" or " " depending on whether the task is done
+ */
+ public String getStatusIcon() {
+
+ return (isDone ? "X" : " "); // mark done task with X
+ }
+
+ /**
+ * Marks a task as incomplete
+ */
+ public void markAsNotDone(){
+
+ this.isDone = false;
+ }
+
+ /**
+ * Marks a task as complete
+ */
+ public void markAsDone(){
+
+ this.isDone = true;
+ }
+
+ /**
+ * Returns the information of the task in a proper format to be stored in the text file
+ * @return various information regarding a task in the proper format
+ */
+ public String textFileInputString() {
+ return String.format("%s | %s",
+ isDone? "X" : "0",
+ getDescription().trim());
+ }
+
+ @Override
+ public String toString() {
+ return "[" + getStatusIcon() + "] " + getDescription();
+ }
+}
diff --git a/src/main/java/Kowalski/tasks/Todo.java b/src/main/java/Kowalski/tasks/Todo.java
new file mode 100644
index 000000000..3d4519840
--- /dev/null
+++ b/src/main/java/Kowalski/tasks/Todo.java
@@ -0,0 +1,21 @@
+package Kowalski.tasks;
+
+public class Todo extends Task {
+
+ public Todo(String description){
+ super(description);
+ }
+
+
+ @Override
+ public String textFileInputString(){
+ return String.format("T | %s | %s",
+ isDone? "X" : "0",
+ getDescription().trim());
+ }
+
+ @Override
+ public String toString() {
+ return "[T]" + super.toString();
+ }
+}
diff --git a/src/main/java/META-INF/MANIFEST.MF b/src/main/java/META-INF/MANIFEST.MF
new file mode 100644
index 000000000..6d10568b7
--- /dev/null
+++ b/src/main/java/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Main-Class: Kowalski.Kowalski
+