The Schwarzenegger - Developer Guide

By: CS2113T-F11-1 Since: 2020

Supported Java versions ![Supported OS](https://img.shields.io/badge/Supported%20OS-Windows MacOS Linux-yellow.svg) Java CI

Table of Contents

  1. Introduction

    1.1. Background

    1.2. Purpose

    1.3. Scope

  2. Setting Up

    2.1. Prerequisites

    2.2. Setting up the Project in Your Computer

  3. Design

    3.1. Architecture

    3.2. Ui Component

    3.3. Logic Component

    3.4. Model Component

    3.5. Storage Component

        3.5.1. Storage for Profile

        3.5.2. Storage for Diet

        3.5.3. Storage for Workout

  4. Implementation

    4.1. Main Menu-related Features

    4.2. Profile-related Features

        4.2.1. Adding a Profile

        4.2.2. Viewing a Profile

        4.2.3. Editing a Profile

        4.2.4. Deleting a Profile

    4.3. Diet-related Features

        4.3.1. List Out All Commands

        4.3.2. Start Recording Diet Data

            4.3.2.1. Showing Help Message

            4.3.2.2. Adding Food Items for the Current Diet

            4.3.2.3. Listing Data for the Current Diet

            4.3.2.4. Deleting Data from the Current Diet

            4.3.2.5. Clearing Data from the Current Diet

            4.3.2.6. Stopping the Recording of Diet Data

        4.3.3. List All Past Diet Sessions

        4.3.4. Edit a Past Diet Session

        4.3.5. Delete a Past Diet Session

        4.3.6. Clear all Past Diet Sessions

        4.3.7. Search for Past Diet Sessions

        4.3.8. Exit the Diet Manager

    4.4. Workout-related Features

        4.4.1. Creating a New Workout Session

            4.4.1.1. Adding an Exercise

            4.4.1.2. Deleting an Exercise

            4.4.1.3. Listing All Exercises in This Session

            4.4.1.4. Searching for Related Exercises

        4.4.2. Listing Past Workout Sessions

        4.4.3. Editing Workout Session

        4.4.4. Deleting a Workout Session

        4.4.5. Searching Based on Conditions

    4.5. Logging

  5. Testing

    5.1. Running Tests

    5.2. Types of Tests

  6. Dev Ops

    6.1. Build Automation

    6.2. Continuous Integration

    6.3. Coverage Report

    6.4. Making a Release

    6.5. Managing Dependencies

  7. Appendices

1. Introduction

1.1. Background

The Schwarzenegger is a desktop command line interface-based app for managing all your needs regarding fitness. With the built-in personal assistant, you are able to track your daily workout and diet sessions based on your profile. If you can type fast, The Schwarzenegger can help you maximise your efficiency for maintaining fitness.

1.2. Purpose

This document contains the specified architecture and software design specifications for the application, The Schwarzenegger.

1.3. Scope

This document describes the software architecture and software design requirements for The Schwarzenegger. This guide is mainly for developers, designers and software engineers that are or going to work on The Schwarzenegger.

Return to Top

2. Setting Up

2.1. Prerequisites

  1. JDK 11.
  2. IntelliJ IDEA IDE.

2.2. Setting up the Project in Your Computer

  1. Fork this repository, and clone the fork to your computer.
  2. Open IntelliJ (if you are not in the welcome screen, click File > Close Project to close the existing project dialog first).
  3. Set up the correct JDK version for Gradle
    1. Click Configure > Structure for New Projects and then Project Settings > Project > Project SDK.
    2. If JDK 11 is listed in the drop down, select it. Otherwise, click New… and select the directory where you installed JDK 11.
    3. Click OK.
  4. Click Import Project.
  5. Locate the build.gradle file and select it. Click OK.
  6. Click Open as Project.
  7. Click OK to accept the default settings if prompted.

Return to Top

3. Design

This section provides a high level overview of our application, The Schwarzenegger.

3.1. Architecture

Architecture

The image above explains the design of the application, The Schwarzenegger.

The main driver of the application is Main: Duke. It is responsible for mainly two phases:

In addition to that, the architecture of The Schwarzenegger is broken down into several packages, mainly the following:

Return to Top

3.2. Ui Component

Ui Component

The Ui package is a combination class where the interactions with the user are formatted in a consistent way.

The Ui component,

Return to Top

3.3. Logic Component

Logic Component

  1. The Schwarzenegger uses Parser classes to parse the user command.
  2. This splits the user input into interpretable portions by other functions.
  3. All commands inherits from base class Command with an execute() method. They are stored in a hashmap CommandLib and retrieved using user’s input as key.
  4. Command interacts with parsers, models and storage to carry out the user’s command.
  5. The result of the command execution is encapsulated as a CommandResult object which is passed back to CommonUi to display the message.

Return to Top

3.4. Model Component

Model Component

The Model component contains Profile, DietManager, PastRecord and WorkoutSession classes.

Return to Top

3.5. Storage Component

Storage in the application refers to storing files of user profile and workout, diet sessions into respective local subdirectories sorted based on time in a local directory called /saves which is in the same directory as the project root.

3.5.1. Storage for Profile

Storage for profile saves user profile created as profile.json in the /saves/profile directory. Profile data file is created as follows:

Implementation Profile workoutSessionStorage handles reading of file data by calling loadData() and overwriting of file data by calling saveData().

Return to Top

3.5.2. Storage for Diet

Storage for diet saves diet sessions created as individual files sorted based on the time created in the /saves/diet directory. Each diet session file is created as follows:

Implementation Storage handles reading of file data by calling readDietSession() and overwriting of file data by calling writeToStorageDietSession().

Return to Top

3.5.3. Storage for Workout

Storage for workout saves workout sessions created as individual files named based on the time created in /saves/workout directory. The metainformation of the files such as createion date and last edit date is saved in /saves/workout/history.json.

Only history.json file is load when initilizing the application. The rest of Session files are load on request, e.g. edit. When a new workout session is created, a new file will be stored and its meta information will be appended to history.json. When a workout session is deleted, the file will be removed and its record will be removed from history.json.

Return to Top

4. Implementation

This section describes some details on how the features are being implemented. All profile/ diet/ workout-related features.

All profile/ diet/ workout-related features can be broken down into 4 distinct functionality, addition, viewing/ listing, deletion and editing. For diet and workout-related features, there is an additional functionality of searching.

This feature allows user to access the different menu for workout, diet and profile. The failure to do so will trigger an exception where the user will be notified of the reason, e.g. invalid command. The action will be aborted, and the program will advise the user to type “help” for command syntax reference.

If the command is successful,the user will be put into the respective menu and a starting message on the entered menu will be displayed to the user.

Implementation

When the user attempts to access different menu for workout, diet and profile menu, the Duke, CommonUi, CommonParser and CommandLib classes will be accessed, and the following sequence of actions is called to prompt execution result to user:

  1. User executes a command
    1. Duke calls CommonUi.getCommand() to receive user input.
    2. Duke calls CommonParser.parseCommand() to parse user input into a string array.
  2. Duke calls CommandLib.getCommand with the string arry containing the inputs.
  3. Depending on the input,Duke creates ProfileSession or DietManager or WorkoutManager object.
  4. After entering the ProfileSession or DietManager or WorkoutManager objects, the menus will have their own separate tasks.

The sequence diagram below summarizes how Main Menu works:

Load Data Sequence Diagram

Return to Top

4.2.1. Adding a Profile

This feature allows user to add a new profile. The failure to do so will trigger an exception where the user will be notified of the reason, e.g. invalid command format. The action will be aborted, and the program will advise the user to type “help” for command syntax reference.

If the creation is successful, a confirmation message on the newly created profile will be displayed to the user.

Implementation

When the user attempts to add a new profile, the ProfileSession, CommonUi, ProfileParser, Command, CommandLib, ProfileStorage, Profile and CommandResult classes will be accessed, and the following sequence of actions is called to prompt execution result to user:

  1. User executes add /n Schwarzenegger /h 188 /w 113 /e 100 /c 2500
    1. ProfileSession calls CommonUi.getCommand() to receive user input.
    2. ProfileSession calls ProfileParser.parseCommand() to parse user input into a string array.
  2. Creating ProfileAdd object.
    1. Based on the parsed input, ProfileSession calls CommandLib to return the correct Command Object ProfileAdd.
  3. Executing command.
    1. ProfileSession calls ProfileAdd.execute() with the rest of parsed input.
    2. ProfileAdd calls ProfileStorage.loadData() to load existing profile in the system. If there is an existing profile, ProfileAdd returns a failure result to ProfileSession. Otherwise, the process continues with step 3.
    3. ProfileAdd calls ProfileParser.extractCommandTagAndInfo() to parse user input into specific tags and information.
    4. Based on the parsed information from ProfileParser.extractCommandTagAndInfo(), ProfileAdd creates a new Profile.
    5. ProfileAdd calls ProfileStorage.saveData() to save the Profile object.
    6. ProfileAdd returns a successful result to ProfileSession.
  4. Prompting result to user.
    1. ProfileSession calls CommandResult.getFeedbackMessage() to get the execution feedback message.
    2. ProfileSession calls CommonUi.showToUser() to show result to the user.

All descriptions, warnings and responses will be handled by CommonUi to ensure consistence across the app.

The sequence diagram below summarizes how creating a new profile works:

Load Data Sequence Diagram

Below are the sub-diagrams:

Figure 4.2.1
Figure 4.2.1. Sub-diagram for Parsing Input in ProfileSession

Figure 4.2.2. Sub-diagram for Showing Message to User in ProfileSession

Design considerations

Parsing of the user’s input command:

Return to Top

4.2.2. Viewing a Profile

This feature allows user to view added profile with calculated BMI based on height and weight. The failure to do so will trigger an exception where the user will be notified of the reason, e.g. redundant parameters. The action will be aborted, and the program will advise the user to type “help” for command syntax reference.

If the data loading is successful, a message on the added profile will be displayed to the user.

Implementation

When the user attempts to view an added profile, the ProfileSession, CommonUi, ProfileParser, Command, CommandLib, ProfileStorage, Profile, DietManager and CommandResult classes will be accessed. The following sequence of steps will then occur:

  1. User executes view
    1. ProfileSession calls CommonUi.getUserCommand() to receive user input.
    2. ProfileSessioncallsProfileParser.parseCommand()` to parse user input into a string array.
  2. Creating ProfileView object.
    1. Based on the parsed input, ProfileSession calls CommandLib to return the correct Command Object ProfileView.
  3. Executing command.
    1. ProfileSession calls ProfileView.execute() with the rest of parsed input.
    2. ProfileView calls ProfileStorage.loadData() to load existing profile in the system. If there is no existing profile, ProfileView returns a failure result to ProfileSession. Otherwise, the process continues with step 3.
    3. ProfileView calls DietManager.getTodayTotalCalories() to get user’s calories intake today.
    4. Based on user’s calories intake today and string representation of Profile, ProfileView returns a result to ProfileSession.
  4. Prompting result to user.
    1. ProfileSession calls CommandResult.getCommandResult() to get the CommandResult object.
    2. ProfileSession calls CommonUi.showToUser() to show result to the user.

All descriptions, warnings and responses will be handled by CommonUi to ensure consistence across the app.

The sequence diagram below summarizes how viewing an added profile works:

Load Data Sequence Diagram

You can refer to Figure 4.2.1. Sub-diagram for Parsing Input in ProfileSession and Figure 4.2.2. Sub-diagram for Showing Message to User in ProfileSession for the corresponding sub-diagrams.

Design considerations

Aspects: Loading of stored data

Return to Top

4.2.3. Editing a Profile

This feature allows user to anytime go back to edit a profile created in the past such as editing physique data and expected daily calories intake. The failure to do so will trigger an exception where the user will be notified of the reason, e.g. invalid command format. The action will be aborted, and the program will advise the user to type “help” for command syntax reference.

If the editing is successful, a confirmation message on the edited profile will be displayed to the user.

Implementation

When the user attempts to edit a profile, the ProfileSession, CommonUi, ProfileParser, Command, CommandLib, ProfileStorage, Profile and CommandResult classes will be accessed, and the following sequence of actions is called to prompt execution result to user:

  1. User executes edit /w 60
    1. ProfileSession calls CommonUi.getCommand() to receive user input.
    2. ProfileSession calls ProfileParser.parseCommand() to parse user input into a string array.
  2. Creating ProfileEdit object.
    1. Based on the parsed input, ProfileSession calls CommandLib to return the correct Command Object ProfileEdit.
  3. Executing command.
    1. ProfileSession calls ProfileEdit.execute() with the rest of parsed input.
    2. ProfileEdit calls ProfileStorage.loadData() to load existing profile in the system. If there is no existing profile, ProfileAdd returns a failure result to ProfileSession. Otherwise, the process continues with step 3.
    3. ProfileEdit calls ProfileParser.extractCommandTagAndInfo() to parse user input into specific tags and information.
    4. Based on the parsed information from ProfileParser.extractCommandTagAndInfo(), ProfileEdit creates a new Profile.
    5. ProfileEdit calls Profile.equals() to compare the newly created and existing profile. If there are no changes, ProfileEdit returns a failure result to ProfileSession. Otherwise, the process continues with step 6.
    6. ProfileEdit calls ProfileStorage.saveData() to save the newly created Profile object.
    7. ProfileAdd returns a successful result to ProfileSession.
  4. Prompting result to user.
    1. ProfileSession calls CommandResult.getFeedbackMessage() to get the execution feedback message.
    2. ProfileSession calls CommonUi.showToUser() to show result to the user.

All descriptions, warnings and responses will be handled by CommonUi to ensure consistence across the app.

The sequence diagram below summarizes how creating a new profile works:

Load Data Sequence Diagram

You can refer to Figure 4.2.1. Sub-diagram for Parsing Input in ProfileSession and Figure 4.2.2. Sub-diagram for Showing Message to User in ProfileSession for the corresponding sub-diagrams.

Design considerations

Parsing of the user’s input command:

Return to Top

4.2.4. Deleting a Profile

This feature allows user to delete a profile created in the past. The failure to do so will trigger an exception where the user will be notified of the reason, e.g. redundant parameters. The action will be aborted, and the program will advise the user to type “help” for command syntax reference.

If the deletion is successful, a confirmation message on the profile deletion will be displayed to the user.

Implementation

When the user attempts to delete an added profile, the ProfileSession, CommonUi, ProfileParser, Command, CommandLib, ProfileStorage, Profile and CommandResult classes will be accessed. The following sequence of steps will then occur:

  1. User executes delete
    1. ProfileSession calls CommonUi.getUserCommand() to receive user input.
    2. ProfileSessioncallsProfileParser.parseCommand()` to parse user input into a string array.
  2. Creating ProfileDelete object.
    1. Based on the parsed input, ProfileSession calls CommandLib to return the correct Command Object ProfileDelete.
  3. Executing command.
    1. ProfileSession calls ProfileDelete.execute() with the rest of parsed input.
    2. ProfileDelete calls ProfileStorage.loadData() to load existing profile in the system. If there is no existing profile, ProfileDelete returns a failure result to ProfileSession. Otherwise, the process continues with step 3.
    3. ProfileDelete calls CommonUi.CheckConfirmation() to get user’s confirmation on the deletion since this action is irrevocable. If user fails to confirm, ProfileDelete returns an abort result to ProfileSession. Otherwise, the process continues with step 4.
    4. ProfileDelete calls ProfileStorage.saveData() to save a null object which represents a deleted profile.
    5. ProfileDelete returns a result to ProfileSession.
  4. Prompting result to user.
    1. ProfileSession calls CommandResult.getFeedbackMessage() to get the execution feedback message.
    2. ProfileSession calls CommonUi.showToUser() to show result to the user.

All descriptions, warnings and responses will be handled by CommonUi to ensure consistence across the app.

The sequence diagram below summarizes how deleting an added profile works:

Load Data Sequence Diagram

You can refer to Figure 4.2.1. Sub-diagram for Parsing Input in ProfileSession and Figure 4.2.2. Sub-diagram for Showing Message to User in ProfileSession for the corresponding sub-diagrams.

Design considerations

Aspects: Loading of stored data

Return to Top

4.3.1. Listing out all commands: help

This command lists out all help commands in a typed list that indicates to the user all the commands available and how to use them.

Implementation
When the user types help in a Diet Manager instance, the following sequence occurs.

  1. User executes help
    1. DietManager calls dietManagerUi.getCommand() to receive user input.
    2. DietManager calls DietManagerParser.parseCommand() to parse user input into a string array.
  2. Creating DietSessionHelp object.
    1. Based on the parsed input, DietManager calls CommandLib to return the correct Command Object DietSessionHelp.
  3. Executing command.
    1. DietManager calls DietSessionHelp.execute() with the rest of parsed input.
    2. DietSessionHelp appends onto a string builder a list of typed help commands.
    3. DietSessionHelp returns a CommandResult object with the help message.
  4. Prompting result to user.
    1. DietManager calls CommandResult.getFeedbackMessage() to get the execution feedback message.
    2. CommandResult calls Ui.showToUser() to show result to the user.

Return to Top

4.3.2. Start recording diet data: new

The feature allows users to start recording diet data.

Implementation
When the user types new </d [DATE]> </t [TAG]> the following sequence occurs.

  1. User executes new /d 2020-05-04 /t breakfast
    1. DietManager calls dietManagerUi.getCommand() to receive user input.
    2. DietManager calls DietManagerParser.parseCommand() to parse user input into a string array.
  2. Creating DietSessionHelp object.
    1. Based on the parsed input, DietManager calls CommandLib to return the correct Command Object DietSessionCreate.
  3. Executing command.
    1. DietManager calls DietSessionCreate.execute() with the rest of parsed input.
    2. DietSessionCreate calls the start() method within an instantiated DietSession created with the parsed input.
    3. DietSession then proceeds to completion until the user types “end”, saving after every command with DietStorage.
    4. DietSessionHelp returns a CommandResult object with the help message of the diet manager.
  4. Prompting result to user.
    1. DietManager calls CommandResult.getFeedbackMessage() to get the execution feedback message.
    2. CommandResult calls Ui.showToUser() to show result to the user.

The sequence diagram below summarizes how creating new diet session works:

Load Data Sequence Diagram

Figure 4.3.2.1. CreateDietSession-diagram for Parsing Input in DietManager

Return to Top

4.3.2.1. Showing help message: help

This command lists out all help commands in a typed list that indicates to the user all the commands available and how to use them.

Implementation
When the user types help the following sequence occurs. 1. The user keys in help. 1. DietSession calls dietSessionUi.getCommand() to receive user input. 1. DietSession calls DietSessionParser.parseCommand() to parse user input into a string array. 1. Creating FoodItemHelp object. 1. Based on the parsed input, DietSession calls CommandLib to return the correct Command Object FoodItemHelp. 1. Executing command. 1. DietSession calls FoodItemHelp.execute(). 1. FoodItemHelp appends onto a string builder a list of typed help commands. 1. FoodItemHelp returns a CommandResult object with the help message. 1. Prompting result to user. 1. DietSession calls CommandResult.getFeedbackMessage() to get the execution feedback message. 1. CommandResult calls Ui.showToUser() to show result to the user.

Return to Top

4.3.2.2. Adding food items for the current diet: add

The feature allows users to add food items into the current diet session.

Implementation
When the user types add [FOOD_NAME] /c [CALORIES] the following sequence occurs. 1. The user keys in add bologna /c 123. 1. DietSession calls dietSessionUi.getCommand() to receive user input. 1. DietSession calls DietSessionParser.parseCommand() to parse user input into a string array. 1. Creating FoodItemAdd object. 1. Based on the parsed input, DietSession calls CommandLib to return the correct Command Object FoodItemAdd. 1. Executing command. 1. DietSession calls FoodItemAdd.execute(). 1. A Food object is instantiated with the rest of the parameters, bologna and 123. 1. The instantiated Food object is added to an ArrayList of Food objects in DietSession 1. FoodItemHelp returns a CommandResult object with the add food item message. 1. Prompting result to user. 1. DietSession calls CommandResult.getFeedbackMessage() to get the execution feedback message. 1. CommandResult calls Ui.showToUser() to show result to the user.

The sequence diagram below summarizes how adding a new food to the diet session works:

Load Data Sequence Diagram

Below is the sub-diagram:

Load Data Sequence Diagram

Figure 4.3.2.2.1. Sub-diagram for Parsing Input in DietSession

Return to Top

4.3.2.3. Listing data for the current diet: list

This command allows users to view all food items in the current diet session.

Implementation
When the user types list the following sequence occurs. 1. The user keys in list. 1. DietSession calls dietSessionUi.getCommand() to receive user input. 1. DietSession calls DietSessionParser.parseCommand() to parse user input into a string array. 1. Creating FoodItemList object. 1. Based on the parsed input, DietSession calls CommandLib to return the correct Command Object FoodItemList. 1. Executing command. 1. DietSession calls FoodItemList.execute(). 1. The ArrayList of Food objects is iterated through and stored in a String. 1. FoodItemList returns a CommandResult object with the list of food items. 1. Prompting result to user. 1. DietSession calls CommandResult.getFeedbackMessage() to get the execution feedback message. 1. CommandResult calls Ui.showToUser() to show result to the user.

Load Data Sequence Diagram

Design considerations

Aspects: Displaying of listed data

Return to Top

4.3.2.4. Deleting data from the current diet session: delete

The feature allows users to remove food items into the current diet session.

Implementation
When the user types delete [INDEX_OF_FOOD] the following sequence occurs. 1. The user keys in delete 1. 1. DietSession calls dietSessionUi.getCommand() to receive user input. 1. DietSession calls DietSessionParser.parseCommand() to parse user input into a string array. 1. Creating FoodItemDelete object. 1. Based on the parsed input, DietSession calls CommandLib to return the correct Command Object FoodItemDelete. 1. Executing command. 1. DietSession calls FoodItemDelete.execute(). 1. The index-1 of the ArrayList for the food is removed. 1. FoodItemDelete returns a CommandResult object with the delete success message. 1. Prompting result to user. 1. DietSession calls CommandResult.getFeedbackMessage() to get the execution feedback message. 1. CommandResult calls Ui.showToUser() to show result to the user.

Load Data Sequence Diagram

Return to Top

4.3.2.5. Clearing all data from the current diet session clear

The feature allows users to remove food items into the current diet session.

Implementation
When the user types clear the following sequence occurs. 1. The user keys in clear. 1. DietSession calls dietSessionUi.getCommand() to receive user input. 1. DietSession calls DietSessionParser.parseCommand() to parse user input into a string array. 1. Creating FoodItemClear object. 1. Based on the parsed input, DietSession calls CommandLib to return the correct Command Object FoodItemClear. 1. Executing command. 1. DietSession calls FoodItemClear.execute(). 1. A new ArrayList of Food is assigned to the original, leaving it with no data inside. 1. FoodItemClear returns a CommandResult object with the clear success message. 1. Prompting result to user. 1. DietSession calls CommandResult.getFeedbackMessage() to get the execution feedback message. 1. CommandResult calls Ui.showToUser() to show result to the user.

Load Data Sequence Diagram

Design considerations

Aspects: Ram usage

Return to Top

4.3.2.6. Stopping the recording of diet session data: end

The feature allows users to end the current diet session and return back to the diet manager.

Implementation
When the user types end the following sequence occurs. 1. The user keys in end.

  1. A DietSessionUi component will call dietSessionUI.getInput().
  2. Input will be parsed in processCommand().
  3. Exiting of inputLoop()

    The inputLoop() exits when userInput.equals(“end”).

Return to Top

4.3.3. List all past diet sessions: list

The feature allows users to view all past created diet sessions.

Implementation
When the user types list in a diet manager instance the following sequence occurs. 1. The user keys in list. 1. DietManager calls dietManagerUi.getCommand() to receive user input. 1. DietManager calls DietManagerParser.parseCommand() to parse user input into a string array. 1. Creating DietSessionList object. 1. Based on the parsed input, DietManager calls CommandLib to return the correct Command Object DietSessionList. 1. Executing command. 1. DietManager calls DietSessionList.execute() with the rest of parsed input. 1. The execute method opens a directed save folder on the drive then assigns it to a File array. 1. DietSessionList then calls the formatList() method which takes the File Array and converts it into an ArrayList. 1. DietSessionList then calls the formatRow() method from within formatList() which converts the files into a formatted table output. 1. DietSessionList returns a CommandResult object with the entire table message of the diet sessions. 1. Prompting result to user. 1. DietManager calls CommandResult.getFeedbackMessage() to get the execution feedback message. 1. CommandResult calls Ui.showToUser() to show result to the user.

The sequence diagram below summarizes how listing past Diet sessions work:

Load Data Sequence Diagram

Return to Top

4.3.4. Edit a past diet session: edit

The feature allows users to edit previously created diet sessions.

Implementation
When the user types edit [INDEX_OF_SESSION] the following sequence occurs. 1. The user keys in edit 1. 1. DietManager calls dietManagerUi.getCommand() to receive user input. 1. DietManager calls DietManagerParser.parseCommand() to parse user input into a string array. 1. Creating DietSessionEdit object. 1. Based on the parsed input, DietManager calls CommandLib to return the correct Command Object DietSessionEdit. 1. Executing command. 1. DietManager calls DietSessionEdit.execute() with the rest of parsed input. 1. The execute method then calls readDietSession() from DietStorage which returns a dietSession instance. 1. DietSessionEdit then calls the start() method within an instantiated DietSession created with the parsed input. 1. DietSession then proceeds to completion until the user types “end”, saving after every command with DietStorage. 1. DietSessionHelp returns a CommandResult object with the help message of the diet manager. 1. Prompting result to user. 1. DietManager calls CommandResult.getFeedbackMessage() to get the execution feedback message. 1. CommandResult calls Ui.showToUser() to show result to the user.

The sequence diagram below summarizes how editing Diet session works:

Load Data Sequence Diagram

Design considerations Saving of the user’s Diet sessions:

Return to Top

4.3.5. Delete a previously created diet session: delete

The feature allows users to delete previously created diet sessions.

Implementation
When the user types delete [INDEX_OF_SESSION] from a Diet manager instance the following sequence occurs. 1. The user keys in delete 1. 1. DietManager calls dietManagerUi.getCommand() to receive user input. 1. DietManager calls DietManagerParser.parseCommand() to parse user input into a string array. 1. Creating DietSessionDelete object. 1. Based on the parsed input, DietManager calls CommandLib to return the correct Command Object DietSessionDelete. 1. Executing command. 1. DietManager calls DietSessionDelete.execute() with the rest of parsed input. 1. The execute method then deletes the file at the indicated index 1 if a file was present there. 1. DietSessionDelete returns a CommandResult object with the delete confirmation message from DietmanagerUi. 1. Prompting result to user. 1. DietManager calls CommandResult.getFeedbackMessage() to get the execution feedback message. 1. CommandResult calls Ui.showToUser() to show result to the user.

The sequence diagram below summarizes how Diet sessions are deleted:

Delete_Diet_Session_Sequence_Diagram

Return to Top

4.3.6. Clear all past diet session: clear

The feature allows users to clear all previously created diet sessions at once.

Implementation
When the user types clear the following sequence occurs. 1. The user keys in clear. 1. DietManager calls dietManagerUi.getCommand() to receive user input. 1. DietManager calls DietManagerParser.parseCommand() to parse user input into a string array. 1. Creating DietSessionClear object. 1. Based on the parsed input, DietManager calls CommandLib to return the correct Command Object DietSessionClear. 1. Executing command. 1. DietManager calls DietSessionDelete.execute() with the rest of parsed input. 1. The execute method then deletes the file at the indicated index 1 if a file was present there. 1. DietSessionDelete returns a CommandResult object with the delete confirmation message from DietmanagerUi. 1. Prompting result to user. 1. DietManager calls CommandResult.getFeedbackMessage() to get the execution feedback message. 1. CommandResult calls Ui.showToUser() to show result to the user.

The sequence diagram below summarizes how Diet sessions are all cleared:

Delete_Diet_Session_Sequence_Diagram

Return to Top

4.3.7. Search for Past Diet Sessions: search

The feature allows users to search for previously created diet sessions within a date range or with a specified tag.

Implementation
When the user types search /s 2020-11-01 /e 2020-11-03 /t breakfast the following sequence occurs. 1. The user keys in search /s 2020-11-01 /e 2020-11-03 /t breakfast. 1. DietManager calls dietManagerUi.getCommand() to receive user input. 1. DietManager calls DietManagerParser.parseCommand() to parse user input into a string array. 1. Creating DietSessionSearch object. 1. Based on the parsed input, DietManager calls CommandLib to return the correct Command Object DietSessionSearch. 1. Executing command. 1. DietManager calls DietSessionSearch.execute() with the rest of parsed input. 1. The execute method then iterates through the entire folder and looks for empty tags and folders with the methods checkEmptyTag() and checkEmptyFolder. 1. DietSessionSearch calls the addToSearchResult() method which from within calls the addRow() method that converts the file output into a table format. 1. DietSessionSearch returns a CommandResult object with the search results. 1. If the starting search date is after the ending search date, the method will return with an exception which is then returned with the CommandResult message. 1. Prompting result to user. 1. DietManager calls CommandResult.getFeedbackMessage() to get the execution feedback message. 1. CommandResult calls Ui.showToUser() to show result to the user.

The sequence diagram below summarizes how Diet sessions is searched:

Search_Diet_Session_Sequence_Diagram

Return to Top

4.3.8. Exit the Diet manager: end

The function returns the user back to the main menu of The Schwarzenegger.

Implementation
When the user types end the following sequence occurs. 1. The user keys in end.

  1. A DietSessionUi component will call dietSessionUI.getInput().
  2. Input will be parsed in processCommand().
  3. Exiting of inputLoop()

    The inputLoop() exits when userInput.equals(“end”), returning to the Start() method, then ending the DietManager instance.

Return to Top

4.4.1. Creating a New Workout Session

Users can create a new workout session. The failure to do so will trigger an exception where the user will be notified of the reason, e.g. invalid command or IO related errors. The action will be aborted. If the creation is successful, the user will go into the new workout session to edit the exercises in that session.

The user can specify tags for the session. Creation time, last edit time and saving file name will be auto generated by the application and saved.

Implementation

When the user attempts to create a new workout session, the Ui, WorkoutManagerParser and CommandLib class will be accessed and the following sequence of actions are called to return a command object NewWs.

  1. User executes new /t leg chest
    1. WorkoutManager calls Ui.getUserCommand() to receive user input.
    2. WorkoutManager calls WorkoutManagerParser.parse into a string array
  2. Creation of command object.
    1. Based on the parsed input, WorkoutManager calls CommandLib to return the correct Command Object NewWs.
  3. Executing Command
    1. WorkoutManager calls NewWS.execute() with the rest of parsed input.
    2. NewWS parse the arguments to identify the tags
    3. NewWS calls PastRecordList.add() to create a new file to store information in this session.

      If the creation fails, the action is aborted. Else, this record will be stored and the file path will

      be returned.

    4. NewWS creates a new WorkoutSession Object with the file path.
    5. NewWS calls workoutSession. workoutSessionStart() so that user can add information into this session.
    6. After user exits this workout, WorkoutManager returns a CommandResult.
  4. Based on CommandResult, correct response will be printed to user.

All description, warnings and response will be handled by Ui to ensure consistence across the app. The following sequence diagram shows how the new command works

The sequence diagram below summarizes how creating new workout session works: Load Data Sequence Diagram Design considerations Parsing of the user’s input command:

Return to Top

4.4.1.1. Adding an Exercise

Users can add a new exercise. The failure to do so will trigger an exception where the user will be notified of the reason, e.g. invalid command or IO related errors. The action will be aborted. If the addition is successful, a new exercise will be added to the exerciselist.

Implementation

When the user attempts to add a new exercise, the CommonUi, WorkoutSession, WorkoutSessionParser , CommandLib, WorkoutSessionAdd and WorkoutSessionStorage class will be accessed and the following sequence of actions are called to return a CommandResult object containing a message to show to user.

  1. User executes add benchpress /n 6 /w 120
    1. WorkoutSession calls CommonUi.getUserCommand() to receive user input.
    2. WorkoutSession calls WorkoutSessionParser.workoutSessionParser to convert the input to a string array.
  2. Creation of command object.
    1. Based on the parsed input, WorkoutSession calls CommandLib to return the correct Command Object WorkoutSessionAdd.
  3. Executing Command
    1. WorkoutSession calls WorkoutSessionAdd.execute() with the rest of parsed input.
    2. WorkoutSessionAdd parse the arguments to identify the repetitions and weight for the exercise.
    3. WorkoutSessionAdd calls WorkOutSession.Storage.writeToFile() to store information of all exercises recorded.
    4. WorkoutSessionAdd returns a CommandResult to WorkoutSession`.
  4. Based on CommandResult, correct response will be printed to user.

All description, warnings and response will be handled by CommonUi to ensure consistence across the app.

The sequence diagram below summarizes how the add command works: Load Data Sequence Diagram

Below are the sub-diagrams:

Load Data Sequence Diagram

Figure 4.4.1.1.1. Sub-diagram for Parsing Input in WorkoutSession

Figure 4.4.1.1.2. Sub-diagram for Showing Message to User

Design considerations Aspects: Making add and its parameters as seperate or a single input

Return to Top

4.4.1.2. Deleting an Exercise

Users can delete an exercise from a pre-existing list of exercise. The failure to do so will trigger an exception where the user will be notified of the reason, e.g. invalid command or IO related errors. The action will be aborted. If the deletion is successful, a new exercise will be added to the exerciselist.

Implementation

When the user attempts to delete an exercise, the CommonUi, WorkoutSession, WorkoutSessionParser , CommandLib, WorkoutSessionDelete and WorkoutSessionStorage class will be accessed and the following sequence of actions are called to return a CommandResult object containing a message to show to user.

  1. User executes delete 1
    1. WorkoutSession calls CommonUi.getUserCommand() to receive user input.
    2. WorkoutSession calls WorkoutSessionParser.workoutSessionParser to convert the input to a string array.
  2. Creation of command object.
    1. Based on the parsed input, WorkoutSession calls CommandLib to return the correct Command Object WorkoutSessionDelete.
  3. Executing Command
    1. WorkoutSession calls WorkoutSessionDelete.execute() with the rest of parsed input.
    2. WorkoutSessionDelete parse the arguments to identify the index of the exercise to be deleted.
    3. WorkoutSessionDelete calls exerciseList.remove() to delete the respective exercise.
    4. WorkoutSessionDelete calls WorkOutSession.Storage.writeToFile() to store information of all exercises recorded.
    5. WorkoutSessionDelete returns a CommandResult to WorkoutSession`.
  4. Based on CommandResult, correct response will be printed to user.

All description, warnings and response will be handled by CommonUi to ensure consistence across the app.

The sequence diagram below summarizes how the delete command works: Load Data Sequence Diagram

You can refer to Figure 4.4.1.1.1. Sub-diagram for Parsing Input in WorkoutSession and Figure 4.4.1.1.2. Sub-diagram for Showing Message to User for the corresponding sub-diagrams.

Design considerations Aspects: Making delete and index to delete as separate or a single input

Return to Top

4.4.1.3. Listing All Exercises in This Session

Users can list all exercise from a pre-existing list of exercise. The failure to do so will trigger an exception where the user will be notified of the reason, e.g. invalid command or IO related errors. The action will be aborted. If the listing is successful, the user will be able to see the full list of exercises.

Implementation

When the user attempts to list all exercises, the CommonUi, WorkoutSession, WorkoutSessionParser , CommandLib, WorkoutSessionList and WorkoutSessionStorage class will be accessed and the following sequence of actions are called to return a CommandResult object containing a message to show to user.

  1. User executes list
    1. WorkoutSession calls CommonUi.getUserCommand() to receive user input.
    2. WorkoutSession calls WorkoutSessionParser.workoutSessionParser to convert the input to a string array.
  2. Creation of command object.
    1. Based on the parsed input, WorkoutSession calls CommandLib to return the correct Command Object WorkoutSessionList.
  3. Executing Command
    1. WorkoutSession calls WorkoutSessionList.execute() with the rest of parsed input.
    2. WorkoutSessionList calls WorkoutSessionList.printList() to check if the list is empty.
    3. WorkoutSessionList.printList() calls WorkoutSessionList.formatList() to arrange the list in a readable and dynamic format for the user.
    4. WorkoutSessionList.formatList() returns a String of formatted output to WorkoutSessionList.printList() then to WorkoutSessionList.
    5. WorkoutSessionList returns a CommandResult to WorkoutSession.
  4. Based on CommandResult, correct response will be printed to user.

All description, warnings and response will be handled by CommonUi to ensure consistence across the app.

The sequence diagram below summarizes how the list command works: Load Data Sequence Diagram

Design considerations Aspects: Length of results

Return to Top

Users can search for an exercise from a pre-existing list of exercise. The failure to do so will trigger an exception where the user will be notified of the reason, e.g. invalid command or IO related errors. The action will be aborted. If the searching is successful, the user will be able to see the list of exercises that match.

Implementation

When the user attempts to search for an exercise from all exercises, the CommonUi, WorkoutSession, WorkoutSessionParser , CommandLib, WorkoutSessionSearch and WorkoutSessionStorage class will be accessed and the following sequence of actions are called to return a CommandResult object containing a message to show to user.

  1. User executes search bench
    1. WorkoutSession calls CommonUi.getUserCommand() to receive user input.
    2. WorkoutSession calls WorkoutSessionParser.workoutSessionParser to convert the input to a string array.
  2. Creation of command object.
    1. Based on the parsed input, WorkoutSession calls CommandLib to return the correct Command Object WorkoutSessionSearch.
  3. Executing Command
    1. WorkoutSession calls WorkoutSessionSearch.execute() with the rest of parsed input.
    2. WorkoutSessionSearch checks if the search term is empty. If it is empty, WorkoutSessionSearch returns a failure result to WorkoutSession. Otherwise, the process continues with step 3
    3. WorkoutSessionSearch calls WorkoutSessionSearch.formatList() to search the search term with the exerciseList. If it is empty, WorkoutSessionSearch.formatList() returns a failure result to WorkoutSession. Otherwise, the process continues with step 4
    4. WorkoutSessionSearch returns a CommandResult to WorkoutSession.
  4. Based on CommandResult, correct response will be printed to user.

All description, warnings and response will be handled by CommonUi to ensure consistence across the app.

The sequence diagram below summarizes how the search command works: Load Data Sequence Diagram

Design considerations Aspects: Length of results

Return to Top

4.4.2. Listing Past Workout Sessions

The feature to list workoutSessions allows the user to view a summary of all the history workout sessions, including their index, creation date and tags.

Implementation When the user attempts to list workoutSessions, the WorkoutManger, WorkoutManagerParse, ListWS and WorkoutManagerStorage class will be called upon. The following sequence of steps will then occur:

  1. User executes list /s 20201010 /e 20201025
    1. WorkoutManager calls Ui.getUserCommand() to receive user input.
    2. WorkoutManager calls WorkoutManagerParser.parse into a string array
  2. Creation of command object.
    1. Based on the parsed input, WorkoutManager calls CommandLib to return the correct Command Object ListWS.
  3. Executing Command
    1. WorkoutManager calls ListWS.execute() to execute the command
    2. ListWS calls PastRecordList.list()
    3. PastRecordList will return formatted list.
    4. WorkoutManager returns a CommandResult which contains the formatted list and execution result.
  4. Based on CommandResult, correct response will be printed to user.

Load Data Sequence Diagram

Design considerations Aspects: Security of stored data

Return to Top

4.4.3. Editing Workout Session

User can anytime go back to edit a workout session created in the past such as adding or removing exercies in that session.

Each past workout session is stored in a different file name following its creation time. The meta information of these past records such as file name, creation time are stored in another file which will be loaded as the program initlises. The actual workout session record will only be loaded if needed e.g. when editting is called.

Implementation When the user attempts to edit a past workout session, the Ui, WorkoutManagerParser, CommandLib and WorkoutStorage class will be accessed and the following sequence of actions are called.

  1. User executes edit 1
    1. WorkoutManager calls Ui.getUserCommand() to receive user input.
    2. WorkoutManager calls WorkoutManagerParser.parse into a string array
  2. Creation of command object.
    1. Based on the parsed input, WorkoutManager calls CommandLib to return the correct Command Object EditWS.
  3. Executing Command
    1. WorkoutManager calls EditWS.execute() with the rest of parsed input.
    2. EditWS calls PastRecordList.edit() to locate the file. If the does not exist, the action is aborted. Else, PastRecordList updates the meta information of the file and write to local workoutSessionStorage. The file path will be returned.
    3. EditWS creates a new WorkoutSession Object with the file path. WorkoutSession is initilised by loading the data in the file.
    4. EditWS calls workoutSession.workoutSessionStart() so that user start editing this session.
    5. After user exits this workout, WorkoutManager returns a CommandResult.
  4. Based on CommandResult, correct response will be printed to user.

All description, warnings and response will be handled by Ui to ensure consistence across the app. The following sequence diagram shows how the new command works

The sequence diagram below summarizes how editting past record works: Load Data Sequence Diagram Design considerations Past record workoutSessionStorage and model design:

Return to Top

4.4.4. Deleting a workout Session

User can delete a workout session created in the past by giving its index.

Each past workout session is stored in a different file name following its creation time. The meta information of these past records such as file name, creation time are stored in another file which will be loaded as the program initlises. When the user tries to delete a file, the application refers to the meta information of the file to locate the file and delete it. Then the meta information of the record will be deleted.

User can clear all data by iteratively delete the record until the meta data file is empty. To simplify that, user can use clear command to achieve that.

Implementation

When the user attempts to delete a past workout session, the Ui, WorkoutManagerParser, CommandLib and WorkoutStorage class will be accessed and the following sequence of actions are called.

  1. User executes delete 1 or clear
    1. WorkoutManager calls Ui.getUserCommand() to receive user input.
    2. WorkoutManager calls WorkoutManagerParser.parse into a string array
  2. Creation of command object.
    1. Based on the parsed input, WorkoutManager calls CommandLib to return the correct Command Object DeleteWS

      or clearWS.

  3. Executing Command
    1. WorkoutManager calls DeleteWS.execute() with the rest of parsed input.
    2. DeleteWS calls PastRecorList.delete() to locate the file. If the does not exist, the action is aborted. Else, PastRecorList remove the meta information of the file and delete the local workoutSessionStorage file.
    3. After user exits this workout, WorkoutManager returns a CommandResult.
  4. Based on CommandResult, correct response will be printed to user.

All description, warnings and response will be handled by Ui to ensure consistence across the app.

The sequence diagram below summarizes how deleting past record works: Load Data Sequence Diagram

Design considerations

Return to Top

4.4.5. Searching Based on Conditions

The feature search allows the user to view a summary of all the history workout sessions which satisfies certain conditions.

The user can search by the date of creation, or the tags that the session has. User can put in 0 or 1 or 2 criteria during search.

The user can attach variable number of tags after /t and one date after /d. The date must be specified in certain formats for it to be recognisable. Else, it will be treated as there is no date criteria given. See here for all supported formats.

The tag criterion selects sessions which contains all the tags that the user specified in the search. The date criterion selects the sessions which is created on that date. Only sessions that satisfies all conditions will be selected and displayed.

The result is displayed in a table with the index of the selected records so that users can easily do further operations on them, e.g. delete or edit.

Implementation

When the user attempts to list workoutSessions, the WorkoutManger, DeleteWS, WorkoutManagerStorage and WorkoutManagerParse class will be called upon. The following sequence of steps will then occur:

  1. User executes search /t leg /d 20201017
    1. WorkoutManager calls Ui.getUserCommand() to receive user input.
    2. WorkoutManager calls WorkoutManagerParser.parse into a string array
  2. Creation of command object.
    1. Based on the parsed input, WorkoutManager calls CommandLib to return the correct Command Object SearchWS.
  3. Executing Command
    1. WorkoutManager calls SearchWS.execute() to execute the command
    2. SearchWS calls PastRecorList.search()
    3. PastRecordList will call WorkoutManagerParser.parse to parse the arguments into an array of predicates
    4. PastRecordList filters the pastRecord arraylist and return a string representation of the filtered records to WorkoutManager
    5. WorkoutManager returns a CommandResult.
  4. Based on CommandResult, correct response will be printed to user.

The sequence diagram below summarizes how searching record works: Load Data Sequence Diagram Design considerations Aspects: indexing the selected results

The index of a record is not stored in the schema because it easily varies with addition and deletion. Thus given a record, searching for its index will have higher time complexity.

Return to Top

4.5. Logging

Logging in the application refers to storing exceptions, warnings and messages that occur during the execution of Kitchen Helper. It was included to help developers to identify bugs and to simplify their debugging process.

The java.util.logging package in Java is used for logging. The logging mechanism can be managed from the SchwarzeneggerLogger class through the logger attribute.

All controls of the logger for the application can be viewed/ altered in the class construction. The current settings for the logger are as follow:

Logging Levels:

SchwarzeneggerLogger follows singleton design pattern. Thus, other classes can access the logger by calling SchwarzeneggerLogger.getInstanceLogger(), and logging can be done by invoking the function log(). This will ensure that all loggings will be made to the same file across the various classes.

An example is shown below:

private static Logger logger = SchwarzeneggerLogger.getInstanceLogger();
logger.log(Level.WARNING, DESCRIPTION_OF_WARNING, e.toString());

Return to Top

5. Testing

5.1. Running Tests

There are two ways to run tests for The Schwarzenegger.

Method 1: Using IntelliJ JUnit test runner

Method 2: Using Gradle

Return to Top

5.2. Types of Tests

We have use types of tests:

  1. Unit tests targeting the lowest level methods/classes. e.g. profile.UtilsTest
  2. Integration tests that are checking the integration of multiple code units (those code units are assumed to be working). e.g. logic.commands.workout.workoutsession.WorkoutSessionAddTest
  3. Hybrids of unit and integration tests. These test are checking multiple code units as well as how they are connected together. e.g. profile.ProfileSessionTest

Return to Top

6. Dev Ops

6.1. Build Automation

We use Gradle for tasks related to build automation, such as running tests, and checking code for style compliance.

To run all build-related tasks:

  1. Open a terminal in the project’s root directory.
  2. Run the command:
    • Windows: gradlew build
    • MacOS/Linux: ./gradlew build
  3. A message stating BUILD SUCCESSFUL will be shown in the terminal if all tasks run successfully.

    Otherwise, use the error report provided to resolve the issue before trying again.

Return to Top

6.2. Continuous Integration

We use Github Actions for continuous integration. No setup will be required for users who fork from the main The Schwarzenegger repository.

Whenever you create a pull request to the main repository for The Schwarzenegger:

Return to Top

6.3. Coverage Report

We use the IntelliJ IDEA’s coverage analysis tool for coverage reporting. A tutorial on how to install and use this tool can be found here.

Return to Top

6.4. Making a Release

You can follow the steps below to make a new release: 1. Generate the JAR file using Gradle by opening a terminal in the project’s root directory, and run the command:

Return to Top

6.5. Managing Dependencies

Currently, the Gson library is being used for JSON parsing, and the Apache Commons Lang for being used for string processing in The Schwarzenegger. Below are 2 ways to manage these dependencies.

Return to Top

Appendices

Appendix A: Product Scope

Target user profile:

Value Proposition:

Return to Top

Appendix B: User Stories

Priority Version As a … I want to … So that I can …
HIGH v1.0 New user View the available commands easily Learn more about the product before I use it
HIGH v1.0 New user Create a user profile Add a new profile to store my data
HIGH v1.0 User View my profile in the database Reference my added data and know my fitness classification
HIGH v1.0 User Save my profile into the database Retrieve it in subsequent launches of the app
HIGH v1.0 User Load my profile from the database at the start of the app view my added user profile
HIGH v1.0 User Delete my profile from the database Correct accidental typos
HIGH v1.0 User Create a new workout session Start a recorded workout session
HIGH v1.0 User Add moves into a workout session Personalise and record moves in each workout session
HIGH v1.0 User Delete workout session record Correct accidental typos
HIGH v1.0 User End my current workout session Be sure that my workout has ended
HIGH v1.0 User Check my current workout session record Do my workout and keep track of everything easily
HIGH v1.0 User List out all my past diet session records Check what I have eaten in the past
HIGH v1.0 User Create a diet session with date and tags Identify when I ate which meal
HIGH v1.0 User Add different kinds of food into my diet Keep track fo what I eat
HIGH v1.0 User Save my diet records View it next time
MEDIUM v1.0 User Edit user profile Change my data if something changes
MEDIUM v2.0 User Clear all my diet sessions Clear memory space on my storage to store new things
MEDIUM v2.0 User Clear all my workout session records Clear all past redundant data
LOW v2.0 User Search for past workout sessions Easily filter through the data that I don’t need
LOW v2.0 User Search for my past diet sessions See whether I have been eating properly lately
LOW v2.1 User View how much more I need to eat in a day plan my later meals easier
LOW v2.1 User Get recommendation on my weight expectation Adjust accordingly to achieve the Normal Weight BMI classification

Return to Top

Appendix C: Non-Functional Requirements

Below are the non-functional requirements of The Schwarzenegger: 1. Should work on any mainstream OS as long as it has Java 11 or above installed. 2. A user with above average typing speed for regular English text (i.e. not code, not system admin commands) should be able to accomplish most of the tasks faster using commands than a program that uses the mouse. 3. Should not require user to install program file. 4. Should work for single user. 5. Should be able to run without internet connection.

Return to Top

Appendix D: Glossary

Return to Top

Appendix E: Supported Formats of Date Input

Here shows all 12 valid formats.

`yyyyMMdd HH:mm`
`yyyy-MM-dd HH:mm`
`yyyy MM dd HH:mm`

`yyyyMMdd HHmm`
`yyyy-MM-dd HHmm`
`yyyy MM dd HHmm`

`yyyyMMdd`
`yyyy-MM-dd`
`yyyy MM dd`

`dd MM yyyy`
`ddMMyyyy`
`dd-MM-yyyy`

Return to Top