diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
new file mode 100644
index 00000000000..0cd51c5fb97
--- /dev/null
+++ b/.github/workflows/docs.yml
@@ -0,0 +1,25 @@
+name: MarkBind Action
+
+on:
+ push:
+ branches:
+ - master
+
+jobs:
+ build_and_deploy:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Install Graphviz
+ run: sudo apt-get install graphviz
+ - name: Install Java
+ uses: actions/setup-java@v3
+ with:
+ java-version: '11'
+ distribution: 'temurin'
+ - name: Build & Deploy MarkBind site
+ uses: MarkBind/markbind-action@v2
+ with:
+ token: ${{ secrets.GITHUB_TOKEN }}
+ rootDirectory: './docs'
+ baseUrl: '/tp' # assuming your repo name is tp
+ version: '^5.2.0'
diff --git a/.gitignore b/.gitignore
index 284c4ca7cd9..eab4c7db6a5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,3 +21,4 @@ src/test/data/sandbox/
# MacOS custom attributes files created by Finder
.DS_Store
docs/_site/
+docs/_markbind/logs/
diff --git a/README.md b/README.md
index 13f5c77403f..e51ac5dcf4c 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,7 @@
-[![CI Status](https://github.com/se-edu/addressbook-level3/workflows/Java%20CI/badge.svg)](https://github.com/se-edu/addressbook-level3/actions)
+[![CI Status](https://github.com/AY2324S2-CS2103T-T14-2/tp/workflows/Java%20CI/badge.svg)](https://github.com/AY2324S2-CS2103T-T14-2/tp/actions)
![Ui](docs/images/Ui.png)
-* This is **a sample project for Software Engineering (SE) students**.
- Example usages:
- * as a starting point of a course project (as opposed to writing everything from scratch)
- * as a case study
-* The project simulates an ongoing software project for a desktop application (called _AddressBook_) used for managing contact details.
- * It is **written in OOP fashion**. It provides a **reasonably well-written** code base **bigger** (around 6 KLoC) than what students usually write in beginner-level SE modules, without being overwhelmingly big.
- * It comes with a **reasonable level of user and developer documentation**.
-* It is named `AddressBook Level 3` (`AB3` for short) because it was initially created as a part of a series of `AddressBook` projects (`Level 1`, `Level 2`, `Level 3` ...).
-* For the detailed documentation of this project, see the **[Address Book Product Website](https://se-education.org/addressbook-level3)**.
-* This project is a **part of the se-education.org** initiative. If you would like to contribute code to this project, see [se-education.org](https://se-education.org#https://se-education.org/#contributing) for more info.
+**MediTrack is a desktop application for managing your patient details.** While it has a GUI, most of the user interactions happen using a CLI (Command Line Interface).
+
+This project is based on the AddressBook-Level3 project created by the [SE-EDU initiative](https://se-education.org).
diff --git a/build.gradle b/build.gradle
index a2951cc709e..5dff42d87c6 100644
--- a/build.gradle
+++ b/build.gradle
@@ -20,6 +20,10 @@ checkstyle {
toolVersion = '10.2'
}
+run {
+ enableAssertions = true
+}
+
test {
useJUnitPlatform()
finalizedBy jacocoTestReport
@@ -66,7 +70,11 @@ dependencies {
}
shadowJar {
- archiveFileName = 'addressbook.jar'
+ archiveFileName = 'MediTrack.jar'
+}
+
+run {
+ enableAssertions = true
}
defaultTasks 'clean', 'test'
diff --git a/docs/.gitignore b/docs/.gitignore
new file mode 100644
index 00000000000..1748e487fbd
--- /dev/null
+++ b/docs/.gitignore
@@ -0,0 +1,23 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+lerna-debug.log*
+_markbind/logs/
+
+# Dependency directories
+node_modules/
+
+# Production build files (change if you output the build to a different directory)
+_site/
+
+# Env
+.env
+.env.local
+
+# IDE configs
+.vscode/
+.idea/*
+*.iml
diff --git a/docs/AboutUs.md b/docs/AboutUs.md
index 1c9514e966a..29bd4170aa4 100644
--- a/docs/AboutUs.md
+++ b/docs/AboutUs.md
@@ -1,59 +1,50 @@
---
-layout: page
-title: About Us
+ layout: default.md
+ title: "About Us"
---
+# About Us
+
We are a team based in the [School of Computing, National University of Singapore](http://www.comp.nus.edu.sg).
You can reach us at the email `seer[at]comp.nus.edu.sg`
## Project team
-### John Doe
-
-
+### Sivakumar Aishvarya
-[[homepage](http://www.comp.nus.edu.sg/~damithch)]
-[[github](https://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+
-* Role: Project Advisor
-### Jane Doe
+[[github](https://github.com/S-Aishvarya)]
-
-[[github](http://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
-
-* Role: Team Lead
-* Responsibilities: UI
+* Role: Developer
+* Responsibilities: Scheduling and tracking + Documentation + Commons
-### Johnny Doe
+### Eugene Hirose
-
+
-[[github](http://github.com/johndoe)] [[portfolio](team/johndoe.md)]
+[[github](http://github.com/Vision-2000)]
* Role: Developer
-* Responsibilities: Data
+* Responsibilities: Testing + UI + Logic
-### Jean Doe
+### Jeong Jaeho
-
+
-[[github](http://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](http://github.com/jeong-jaeho)]
* Role: Developer
-* Responsibilities: Dev Ops + Threading
+* Responsibilities: Team lead + Integration + Storage
-### James Doe
+### Kim Junseo
-
+
-[[github](http://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](https://github.com/jskimdev)]
* Role: Developer
-* Responsibilities: UI
+* Responsibilities: Code Quality + Model + JavaFX visuals
diff --git a/docs/Configuration.md b/docs/Configuration.md
index 13cf0faea16..32f6255f3b9 100644
--- a/docs/Configuration.md
+++ b/docs/Configuration.md
@@ -1,6 +1,8 @@
---
-layout: page
-title: Configuration guide
+ layout: default.md
+ title: "Configuration guide"
---
+# Configuration guide
+
Certain properties of the application can be controlled (e.g user preferences file location, logging level) through the configuration file (default: `config.json`).
diff --git a/docs/DevOps.md b/docs/DevOps.md
index d2fd91a6001..8228c845e86 100644
--- a/docs/DevOps.md
+++ b/docs/DevOps.md
@@ -1,12 +1,15 @@
---
-layout: page
-title: DevOps guide
+ layout: default.md
+ title: "DevOps guide"
+ pageNav: 3
---
-* Table of Contents
-{:toc}
+# DevOps guide
---------------------------------------------------------------------------------------------------------------------
+
+
+
+
## Build automation
diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md
index 1b56bb5d31b..5c8d1c9a57a 100644
--- a/docs/DeveloperGuide.md
+++ b/docs/DeveloperGuide.md
@@ -1,15 +1,23 @@
---
-layout: page
-title: Developer Guide
+ layout: default.md
+ title: "Developer Guide"
+ pageNav: 3
---
-* Table of Contents
-{:toc}
+
+# MediTrack Developer Guide
+
+
+
+
+
--------------------------------------------------------------------------------------------------------------------
## **Acknowledgements**
-* {list here sources of all reused/adapted ideas, code, documentation, and third-party libraries -- include links to the original source as well}
+- [Regular-Expressions.info](https://www.regular-expressions.info/tutorial.html) was our source for learning regex.
+
+- The format of User Guide and Developer Guide was taken from [AddressBook Level-3](https://se-education.org/addressbook-level3/) with some modifications.
--------------------------------------------------------------------------------------------------------------------
@@ -21,14 +29,9 @@ Refer to the guide [_Setting up and getting started_](SettingUp.md).
## **Design**
-
-
-:bulb: **Tip:** The `.puml` files used to create diagrams in this document `docs/diagrams` folder. Refer to the [_PlantUML Tutorial_ at se-edu/guides](https://se-education.org/guides/tutorials/plantUml.html) to learn how to create and edit diagrams.
-
-
### Architecture
-
+
The ***Architecture Diagram*** given above explains the high-level design of the App.
@@ -36,7 +39,8 @@ Given below is a quick overview of main components and how they interact with ea
**Main components of the architecture**
-**`Main`** (consisting of classes [`Main`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/Main.java) and [`MainApp`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/MainApp.java)) is in charge of the app launch and shut down.
+**`Main`** (consisting of classes [`Main`](https://github.com/AY2324S2-CS2103T-T14-2/tp/blob/master/src/main/java/seedu/address/Main.java) and [`MainApp`](https://github.com/AY2324S2-CS2103T-T14-2/tp/blob/master/src/main/java/seedu/address/MainApp.java)) is in charge of the app launch and shut down.
+
* At app launch, it initializes the other components in the correct sequence, and connects them up with each other.
* At shut down, it shuts down the other components and invokes cleanup methods where necessary.
@@ -53,7 +57,7 @@ The bulk of the app's work is done by the following four components:
The *Sequence Diagram* below shows how the components interact with each other for the scenario where the user issues the command `delete 1`.
-
+
Each of the four main components (also shown in the diagram above),
@@ -62,92 +66,102 @@ Each of the four main components (also shown in the diagram above),
For example, the `Logic` component defines its API in the `Logic.java` interface and implements its functionality using the `LogicManager.java` class which follows the `Logic` interface. Other components interact with a given component through its interface rather than the concrete class (reason: to prevent outside component's being coupled to the implementation of a component), as illustrated in the (partial) class diagram below.
-
+
The sections below give more details of each component.
+
+
### UI component
-The **API** of this component is specified in [`Ui.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/ui/Ui.java)
+The **API** of this component is specified in [`Ui.java`](https://github.com/AY2324S2-CS2103T-T14-2/tp/blob/master/src/main/java/seedu/address/ui/Ui.java)
-![Structure of the UI Component](images/UiClassDiagram.png)
+
-The UI consists of a `MainWindow` that is made up of parts e.g.`CommandBox`, `ResultDisplay`, `PersonListPanel`, `StatusBarFooter` etc. All these, including the `MainWindow`, inherit from the abstract `UiPart` class which captures the commonalities between classes that represent parts of the visible GUI.
+The UI consists of a `MainWindow` that is made up of parts e.g.`CommandBox`, `ResultDisplay`, `PatientListPanel`, `StatusBarFooter` etc. All these, including the `MainWindow`, inherit from the abstract `UiPart` class which captures the commonalities between classes that represent parts of the visible GUI.
-The `UI` component uses the JavaFx UI framework. The layout of these UI parts are defined in matching `.fxml` files that are in the `src/main/resources/view` folder. For example, the layout of the [`MainWindow`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/ui/MainWindow.java) is specified in [`MainWindow.fxml`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/resources/view/MainWindow.fxml)
+The `UI` component uses the JavaFx UI framework. The layout of these UI parts are defined in matching `.fxml` files that are in the `src/main/resources/view` folder. For example, the layout of the [`MainWindow`](https://github.com/AY2324S2-CS2103T-T14-2/tp/blob/master/src/main/java/seedu/address/ui/MainWindow.java) is specified in [`MainWindow.fxml`](https://github.com/AY2324S2-CS2103T-T14-2/tp/blob/master/src/main/resources/view/MainWindow.fxml)
The `UI` component,
* executes user commands using the `Logic` component.
* listens for changes to `Model` data so that the UI can be updated with the modified data.
* keeps a reference to the `Logic` component, because the `UI` relies on the `Logic` to execute commands.
-* depends on some classes in the `Model` component, as it displays `Person` object residing in the `Model`.
+* depends on some classes in the `Model` component, as it displays `Patient` object residing in the `Model`.
+
+
### Logic component
-**API** : [`Logic.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/logic/Logic.java)
+**API** : [`Logic.java`](https://github.com/AY2324S2-CS2103T-T14-2/tp/blob/master/src/main/java/seedu/address/logic/Logic.java)
Here's a (partial) class diagram of the `Logic` component:
-
+
-The sequence diagram below illustrates the interactions within the `Logic` component, taking `execute("delete 1")` API call as an example.
+The sequence diagram below illustrates the interactions within the `Logic` component, taking `execute("find n/Bob")` API call as an example.
-![Interactions Inside the Logic Component for the `delete 1` Command](images/DeleteSequenceDiagram.png)
+
-:information_source: **Note:** The lifeline for `DeleteCommandParser` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline continues till the end of diagram.
-
+
+
+**Note:** The lifeline for `FindCommandParser` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline continues till the end of diagram.
+
How the `Logic` component works:
-1. When `Logic` is called upon to execute a command, it is passed to an `AddressBookParser` object which in turn creates a parser that matches the command (e.g., `DeleteCommandParser`) and uses it to parse the command.
-1. This results in a `Command` object (more precisely, an object of one of its subclasses e.g., `DeleteCommand`) which is executed by the `LogicManager`.
-1. The command can communicate with the `Model` when it is executed (e.g. to delete a person).
+1. When `Logic` is called upon to execute a command, it is passed to an `InputParser` object which in turn creates a parser that matches the command (e.g., `FindCommandParser`) and uses it to parse the command.
+1. This results in a `Command` object (more precisely, an object of one of its subclasses e.g., `FindCommand`) which is executed by the `LogicManager`.
+1. The command can communicate with the `Model` when it is executed (e.g. to delete a patient).
Note that although this is shown as a single step in the diagram above (for simplicity), in the code it can take several interactions (between the command object and the `Model`) to achieve.
1. The result of the command execution is encapsulated as a `CommandResult` object which is returned back from `Logic`.
Here are the other classes in `Logic` (omitted from the class diagram above) that are used for parsing a user command:
-
+
How the parsing works:
-* When called upon to parse a user command, the `AddressBookParser` class creates an `XYZCommandParser` (`XYZ` is a placeholder for the specific command name e.g., `AddCommandParser`) which uses the other classes shown above to parse the user command and create a `XYZCommand` object (e.g., `AddCommand`) which the `AddressBookParser` returns back as a `Command` object.
-* All `XYZCommandParser` classes (e.g., `AddCommandParser`, `DeleteCommandParser`, ...) inherit from the `Parser` interface so that they can be treated similarly where possible e.g, during testing.
+* When called upon to parse a user command, the `InputParser` class creates an `XYZCommandParser` (`XYZ` is a placeholder for the specific command name e.g., `AddCommandParser`) which uses the other classes shown above to parse the user command and create a `XYZCommand` object (e.g., `AddCommand`) which the `InputParser` returns back as a `Command` object.
+* All `XYZCommandParser` classes (e.g., `AddCommandParser`, `DeleteByIndexCommandParser`, ...) inherit from the `Parser` interface so that they can be treated similarly where possible e.g, during testing.
-### Model component
-**API** : [`Model.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/model/Model.java)
+
-
+### Model component
+**API** : [`Model.java`](https://github.com/AY2324S2-CS2103T-T14-2/tp/blob/master/src/main/java/seedu/address/model/Model.java)
+
-The `Model` component,
+
-* stores the address book data i.e., all `Person` objects (which are contained in a `UniquePersonList` object).
-* stores the currently 'selected' `Person` objects (e.g., results of a search query) as a separate _filtered_ list which is exposed to outsiders as an unmodifiable `ObservableList` that can be 'observed' e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change.
-* stores a `UserPref` object that represents the user’s preferences. This is exposed to the outside as a `ReadOnlyUserPref` objects.
-* does not depend on any of the other three components (as the `Model` represents data entities of the domain, they should make sense on their own without depending on other components)
+**Note:** The diagram omits details of `UniqueVisitList` as that will be shown in [**Visit feature**](#visit-feature).
-:information_source: **Note:** An alternative (arguably, a more OOP) model is given below. It has a `Tag` list in the `AddressBook`, which `Person` references. This allows `AddressBook` to only require one `Tag` object per unique tag, instead of each `Person` needing their own `Tag` objects.
+
-
+The `Model` component,
-
+* stores the patient list data i.e., all `Patient` objects (which are contained in a `UniquePatientList` object).
+* stores the currently 'selected' `Patient` objects (e.g., results of a search query) as a separate _filtered_ list which is exposed to outsiders as an unmodifiable `ObservableList` that can be 'observed' e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change.
+* stores a `UserPref` object that represents the user’s preferences. This is exposed to the outside as a `ReadOnlyUserPref` objects.
+* does not depend on any of the other three components (as the `Model` represents data entities of the domain, they should make sense on their own without depending on other components).
+
### Storage component
-**API** : [`Storage.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/storage/Storage.java)
+**API** : [`Storage.java`](https://github.com/AY2324S2-CS2103T-T14-2/tp/blob/master/src/main/java/seedu/address/storage/Storage.java)
-
+
The `Storage` component,
-* can save both address book data and user preference data in JSON format, and read them back into corresponding objects.
-* inherits from both `AddressBookStorage` and `UserPrefStorage`, which means it can be treated as either one (if only the functionality of only one is needed).
-* depends on some classes in the `Model` component (because the `Storage` component's job is to save/retrieve objects that belong to the `Model`)
+* can save both patient list data and user preference data in JSON format, and read them back into corresponding objects.
+* inherits from both `PatientListStorage` and `UserPrefStorage`, which means it can be treated as either one (if only the functionality of only one is needed).
+* depends on some classes in the `Model` component (because the `Storage` component's job is to save/retrieve objects that belong to the `Model`).
### Common classes
-Classes used by multiple components are in the `seedu.addressbook.commons` package.
+Classes used by multiple components are in the `seedu.address.commons` package.
+
+
--------------------------------------------------------------------------------------------------------------------
@@ -155,93 +169,120 @@ Classes used by multiple components are in the `seedu.addressbook.commons` packa
This section describes some noteworthy details on how certain features are implemented.
-### \[Proposed\] Undo/redo feature
+### Find feature
+
+#### Implementation
+
+The `find` feature is implemented by using the `ArgumentTokenizer`, `ArgumentMultimap` and `Prefix` classes. `Prefix`
+represents argument prefixes such as `n/` for names. In combination with the below methods, the parser can access different parts
+of the argument based on the prefixes:
+
+* `ArgumentTokenizer#tokenize(String argsString, Prefix... prefixes)` — Generates an `ArgumentMultimap` object which contains
+information on string argument mapped to each prefix.
+* `ArgumentMultimap#getPreamble()` — Returns the part of the argument before any prefixes.
+* `ArgumentMultimap#getValue(Prefix prefix)` — Returns the part of the argument belonging to the given prefix.
+
+The following activity diagram describes the operation of `FindCommandParser`:
-#### Proposed Implementation
+
-The proposed undo/redo mechanism is facilitated by `VersionedAddressBook`. It extends `AddressBook` with an undo/redo history, stored internally as an `addressBookStateList` and `currentStatePointer`. Additionally, it implements the following operations:
+Each valid prefix is checked, and if found, the value proceeding it in the argument string is saved in the form of a subclass
+of `Predicate`. Otherwise, a `Predicate` that always returns true is used instead. When `FindCommand` is created, both of the
+`Predicate` are passed into it, which will be chained into a singular `Predicate` such that the `Model` component can use to update
+the `PatientList`.
-* `VersionedAddressBook#commit()` — Saves the current address book state in its history.
-* `VersionedAddressBook#undo()` — Restores the previous address book state from its history.
-* `VersionedAddressBook#redo()` — Restores a previously undone address book state from its history.
+The operation returns an error if:
+* There is redundant argument before valid prefixes.
+* None of the valid prefixes are provided.
+* There are duplicate prefixes.
+* The arguments provided have invalid format with respect to their prefixes, e.g. argument for `p/` prefix contains letters.
-These operations are exposed in the `Model` interface as `Model#commitAddressBook()`, `Model#undoAddressBook()` and `Model#redoAddressBook()` respectively.
-Given below is an example usage scenario and how the undo/redo mechanism behaves at each step.
-Step 1. The user launches the application for the first time. The `VersionedAddressBook` will be initialized with the initial address book state, and the `currentStatePointer` pointing to that single address book state.
-![UndoRedoState0](images/UndoRedoState0.png)
+#### Design considerations
-Step 2. The user executes `delete 5` command to delete the 5th person in the address book. The `delete` command calls `Model#commitAddressBook()`, causing the modified state of the address book after the `delete 5` command executes to be saved in the `addressBookStateList`, and the `currentStatePointer` is shifted to the newly inserted address book state.
+The current design was chosen to allow for addition of more `find` conditions in later iterations. With the current implementation, only
+the `FindCommandParser` class needs to be changed, as well as the creation of a new `Predicate` subclass.
-![UndoRedoState1](images/UndoRedoState1.png)
+An alternative was to use a flag to denote the condition to filter the list by. For example, if a user wishes to find a patient with
+the name `Bob`, the command would be `find-n Bob`. This was rejected as it only allows for finding with a single condition, leading
+to a less flexible feature.
-Step 3. The user executes `add n/David …` to add a new person. The `add` command also calls `Model#commitAddressBook()`, causing another modified address book state to be saved into the `addressBookStateList`.
-![UndoRedoState2](images/UndoRedoState2.png)
+#### Planned enhancements
-:information_source: **Note:** If a command fails its execution, it will not call `Model#commitAddressBook()`, so the address book state will not be saved into the `addressBookStateList`.
+In later iterations, we plan to add appointment date and the 3 visit fields as optional conditions. The implementation will be identical to the above, as we can exploit the chaining of multiple `Predicate` objects in Java.
-
+More complex enhancements can be made using the `Flag` subclass of `Prefix`, which is integrated into `ArgumentMultimap` as a zero-argument `Prefix`. This allows us to reuse the same command word `find`, but implement a different set of behaviour that is triggered when one or more optional `Flag` is detected. For example, the command `find-d n/Bob` could be implemented to find and delete all patients with the keyword `Bob` in their name.
-Step 4. The user now decides that adding the person was a mistake, and decides to undo that action by executing the `undo` command. The `undo` command will call `Model#undoAddressBook()`, which will shift the `currentStatePointer` once to the left, pointing it to the previous address book state, and restores the address book to that state.
-![UndoRedoState3](images/UndoRedoState3.png)
+### List in alphabetical order feature
-:information_source: **Note:** If the `currentStatePointer` is at index 0, pointing to the initial AddressBook state, then there are no previous AddressBook states to restore. The `undo` command uses `Model#canUndoAddressBook()` to check if this is the case. If so, it will return an error to the user rather
-than attempting to perform the undo.
+#### Implementation
-
+The list in alphabetical order feature is implemented by using the `ArrayList` and `Comparator` classes. `ArrayList` is used to manage the list of `Patients` while `Comparator` is used to compare the `fullName` of each `Patient`.
-The following sequence diagram shows how an undo operation goes through the `Logic` component:
+The implementation of the `list` command works as follows.
-![UndoSequenceDiagram](images/UndoSequenceDiagram-Logic.png)
+Upon the user's entering the `list` command, after checking that the list of patients is not empty, a list of all `Patients` is retrieved from the `Model` object and added to a separate `ArrayList`. From there, a `Comparator` is created that sorts the list of `Patients` using their `fullName`. Then, each element from the `ArrayList` is removed then added in the correct alphabetical order. Once this is completed, the `CommandResult` returns successfully and displays the correct output, a list of all patients in alphabetical order.
-:information_source: **Note:** The lifeline for `UndoCommand` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
+The following sequence diagram shows the sequence of events when the `list` command is typed by a user.
-
+
-Similarly, how an undo operation goes through the `Model` component is shown below:
+#### Design considerations
-![UndoSequenceDiagram](images/UndoSequenceDiagram-Model.png)
+The current design was chosen as the existing list of `Patients` in the `Model` object, `getFilteredPatientList()`, is an immutable object that necessitated the creation of an `ArrayList` object, though it may be inefficient.
-The `redo` command does the opposite — it calls `Model#redoAddressBook()`, which shifts the `currentStatePointer` once to the right, pointing to the previously undone state, and restores the address book to that state.
-:information_source: **Note:** If the `currentStatePointer` is at index `addressBookStateList.size() - 1`, pointing to the latest address book state, then there are no undone AddressBook states to restore. The `redo` command uses `Model#canRedoAddressBook()` to check if this is the case. If so, it will return an error to the user rather than attempting to perform the redo.
+### Delete All feature
-
+#### Implementation
-Step 5. The user then decides to execute the command `list`. Commands that do not modify the address book, such as `list`, will usually not call `Model#commitAddressBook()`, `Model#undoAddressBook()` or `Model#redoAddressBook()`. Thus, the `addressBookStateList` remains unchanged.
+The feature of deleting all entries is implemented via two separate commands (DeleteAllCommand and ForceDeleteAllCommand).
+When the user enters 'delete-all' command, InputParser updates its isPreviousCommandDeleteAll variable as true
+and parses the command into a DeleteAllCommand.
+The LogicManager then executes the DeleteAllCommand. This would return a CommandResult with a confirmation message,
+which asks if the user wants to truly delete all entries and prompts the user to give either a 'yes' or 'no' command.
+If the user enters 'yes', the InputParser checks that the previous command was a DeleteAllCommand and parses the 'yes'
+command into a YesCommand that is set to delete all entries when its execute method is called.
+The LogicManager executes the YesCommand to delete all entries.
+If the user enters 'no' instead of 'yes', this would parse the 'no' command into a NoCommand that does not make any
+changes to the entries.
+The LogicManager executes the NoCommand, leading to no effective change.
-![UndoRedoState4](images/UndoRedoState4.png)
+When the 'delete-all-f' command is entered instead of 'delete-all', InputParser would parse the command into a ForceDeleteAllCommand.
+The LogicManager would execute the ForceDeleteAllCommand. This would set the current model of the patient list to clear
+out all existing entries by calling setPatientList method with an empty PatientList object used as its argument.
+A CommandResult object would be returned with a success message that states that all data has been successfully deleted.
-Step 6. The user executes `clear`, which calls `Model#commitAddressBook()`. Since the `currentStatePointer` is not pointing at the end of the `addressBookStateList`, all address book states after the `currentStatePointer` will be purged. Reason: It no longer makes sense to redo the `add n/David …` command. This is the behavior that most modern desktop applications follow.
+The following sequence diagram describes the sequence of logic when the user inputs 'delete-all-f' command:
-![UndoRedoState5](images/UndoRedoState5.png)
+
-The following activity diagram summarizes what happens when a user executes a new command:
+#### Design considerations
-
+The current design was chosen so that there is a safety check mechanism that asks for confirmation from the user if the
+user truly wants to delete all entries when the 'delete-all' command is given.
+If the user wishes to bypass the safety check and is certain of the intent to delete all entries, the user can enter
+'delete-all-f' command to forcefully delete all entries.
-#### Design considerations:
+
-**Aspect: How undo & redo executes:**
+### Visit feature
-* **Alternative 1 (current choice):** Saves the entire address book.
- * Pros: Easy to implement.
- * Cons: May have performance issues in terms of memory usage.
+#### Implementation
-* **Alternative 2:** Individual command knows how to undo/redo by
- itself.
- * Pros: Will use less memory (e.g. for `delete`, just save the person being deleted).
- * Cons: We must ensure that the implementation of each individual command are correct.
+
-_{more aspects and alternatives to be added}_
+The `Visit` - `Patient` relationship in the `Logic` component is identical to that of `Patient` - `PatientList` relationship. In our implementation, the `Patient` class has the added responsibility of acting as a container for all `Visit` objects associated with it. This is achieved by the `UniqueVisitList` created upon construction of a `Patient` instance.
-### \[Proposed\] Data archiving
+#### Design Considerations
-_{Explain here how the data archiving feature will be implemented}_
+The current design is convenient as all methods relating to the `Visit` object will be going through the `Patient` object, which means the `Visit` does not need to hold a reference to the `Patient` it belongs to. Furthermore, `Command` instances that uses `Visit` will not need a reference to it, ensuring immutability.
+
+The initial design was to have the 3 `Visit` fields be part of the `Patient` object to keep track of the latest instance of visit. This was primarily for ease of implementation, as fewer new classes would need to be created. However, this design fell apart as we needed to keep track of past patient visits as well.
--------------------------------------------------------------------------------------------------------------------
@@ -254,6 +295,8 @@ _{Explain here how the data archiving feature will be implemented}_
* [Configuration guide](Configuration.md)
* [DevOps guide](DevOps.md)
+
+
--------------------------------------------------------------------------------------------------------------------
## **Appendix: Requirements**
@@ -262,42 +305,62 @@ _{Explain here how the data archiving feature will be implemented}_
**Target user profile**:
-* has a need to manage a significant number of contacts
+* has a need to manage a significant number of patient details
* prefer desktop apps over other types
* can type fast
* prefers typing to mouse interactions
* is reasonably comfortable using CLI apps
-**Value proposition**: manage contacts faster than a typical mouse/GUI driven app
+**Value proposition**: MediTrack can manage patient details faster than a typical mouse/GUI driven app.
+
### User stories
Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unlikely to have) - `*`
-| Priority | As a … | I want to … | So that I can… |
-| -------- | ------------------------------------------ | ------------------------------ | ---------------------------------------------------------------------- |
-| `* * *` | new user | see usage instructions | refer to instructions when I forget how to use the App |
-| `* * *` | user | add a new person | |
-| `* * *` | user | delete a person | remove entries that I no longer need |
-| `* * *` | user | find a person by name | locate details of persons without having to go through the entire list |
-| `* *` | user | hide private contact details | minimize chance of someone else seeing them by accident |
-| `*` | user with many persons in the address book | sort persons by name | locate a person easily |
+| Priority | As a … | I want to … | So that I can… |
+|----------|--------------|----------------------------------|--------------------------------------------------------------------------|
+| `* * *` | receptionist | see usage instructions | refer to instructions when I forget how to use the App |
+| `* * *` | receptionist | see the list of patients | check the index of all patients |
+| `* * *` | receptionist | add a new patient | |
+| `* * *` | receptionist | add a new visit | specify a patient and record their visit |
+| `* * *` | receptionist | delete a patient | remove entries that are outdated |
+| `* * *` | receptionist | delete a visit | remove details of a patient's latest visit |
+| `* * *` | receptionist | find a patient by name | locate details of a patient without having to go through the entire list |
+| `* *` | receptionist | find a patient by contact number | look for a specific patient without worrying about duplicate names |
+| `* *` | receptionist | delete all patients | easily reset the list to a blank state |
+| `* *` | receptionist | exit with a command | close the application with keyboard inputs only |
-*{More to be added}*
+
+
### Use cases
-(For all use cases below, the **System** is the `AddressBook` and the **Actor** is the `user`, unless specified otherwise)
+(For all use cases below, the **System** is the `MediTrack` and the **Actor** is the `receptionist`, unless specified otherwise)
+
+**Use case: UC01 - Add a patient**
-**Use case: Delete a person**
+**MSS**
+1. Receptionist requests to add a patient’s data in the list.
+2. MediTrack adds the patient’s data into the list.
+
+ Use case ends.
+
+**Extensions**
+
+* 1a. There is already a patient with the same phone number.
+
+ Use case ends.
+
+**Use case: UC02 - Delete a patient**
**MSS**
-1. User requests to list persons
-2. AddressBook shows a list of persons
-3. User requests to delete a specific person in the list
-4. AddressBook deletes the person
+1. Receptionist requests to list patients.
+2. MediTrack shows a list of patients.
+3. Receptionist requests to delete a specific patient in the list.
+4. MediTrack deletes the patient.
Use case ends.
@@ -309,24 +372,82 @@ Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unli
* 3a. The given index is invalid.
- * 3a1. AddressBook shows an error message.
+ * 3a1. MediTrack shows an error message.
Use case resumes at step 2.
+**Use case: UC03 - Find a patient**
+
+**MSS**
+
+1. Receptionist requests for a patient's information.
+2. MediTrack returns the patient's information.
+
+ Use case ends.
+
+**Extensions**
+
+* 1a. The patient's information is not found in the list.
+
+ Use case ends.
+
+**Use case: UC04 - Exit**
+
+**MSS**
+
+1. Receptionist requests to exit the program.
+
+ Use case ends.
+
+**Use case: UC05 - Delete all patients**
+
+**MSS**
+
+1. Receptionist requests to delete all patients.
+2. MediTrack asks for confirmation.
+3. Receptionist confirms.
+4. MediTrack deletes all patient information.
+
+ Use case ends.
+
+**Extensions**
+
+* 1a. There are no patient information.
+
+ Use case ends.
+
+* 3a. Receptionist cancels.
+
+ Use case ends.
+
+**Use case: UC06 - Start the system**
+
+**MSS**
+
+1. Receptionist starts the program
+2. MediTrack shows a list of patients
+
+ Use case ends.
+
*{More to be added}*
### Non-Functional Requirements
1. Should work on any _mainstream OS_ as long as it has Java `11` or above installed.
-2. Should be able to hold up to 1000 persons without a noticeable sluggishness in performance for typical usage.
+2. Should be able to hold up to 100 patients without a noticeable lag in performance for typical usage.
3. 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 using the mouse.
-
-*{More to be added}*
+4. Should work without internet connection.
+5. Can only be used by a registered receptionist.
+6. Each command should take no more than 1 second until a response is displayed.
### Glossary
-* **Mainstream OS**: Windows, Linux, Unix, MacOS
-* **Private contact detail**: A contact detail that is not meant to be shared with others
+* **Mainstream OS**: Windows, Linux, MacOS
+* **Patient**: A patient who has visited the clinic at least once due to an illness
+* **Receptionist**: The user operating MediTrack
+* **Patient information**: Name, contact number, address, email, date of birth, sex, appointment
+* **Visit**: An instance of a particular patient coming to the clinic for a medical reason
+* **Visit information**: Condition, severity, date of visit
--------------------------------------------------------------------------------------------------------------------
@@ -334,10 +455,13 @@ Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unli
Given below are instructions to test the app manually.
-:information_source: **Note:** These instructions only provide a starting point for testers to work on;
+
+
+**Note:** These instructions only provide a starting point for testers to work on;
testers are expected to do more *exploratory* testing.
-
+
+
### Launch and shutdown
@@ -345,7 +469,7 @@ testers are expected to do more *exploratory* testing.
1. Download the jar file and copy into an empty folder
- 1. Double-click the jar file Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum.
+ 1. Double-click the jar file Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum.
1. Saving window preferences
@@ -354,29 +478,33 @@ testers are expected to do more *exploratory* testing.
1. Re-launch the app by double-clicking the jar file.
Expected: The most recent window size and location is retained.
-1. _{ more test cases … }_
+1. Shutting down
+
+ 1. Test case: `exit`
+ Expected: Confirmation message prompting a yes or no.
+ 2. Test case: `yes`
+ Expected: Window closes.
+
+### Adding a patient
+
+1. Adding a patient when no patients exist
+ 1. Prerequisites: Ensure that the list is empty by using the command `delete-all-f`.
+ 1. Test case: `add n/John Doe p/98765432 e/johnd@example.com a/311, Clementi Ave 2, #02-25 b/25/2/2024 s/Male`
+ Expected: Patient added to the list. Details of the patient shown in the status message.
+ 1. Incorrect add commands to try: the above, but with some arguments missing
+ Expected: No patient added. Error details shown in status message.
-### Deleting a person
+### Deleting a patient
-1. Deleting a person while all persons are being shown
+1. Deleting a patient while all patients are being shown
- 1. Prerequisites: List all persons using the `list` command. Multiple persons in the list.
+ 1. Prerequisites: List all patients using the `list` command. Multiple patients in the list.
1. Test case: `delete 1`
- Expected: First contact is deleted from the list. Details of the deleted contact shown in the status message. Timestamp in the status bar is updated.
+ Expected: First patient is deleted from the list. Details of the deleted patient shown in the status message.
1. Test case: `delete 0`
- Expected: No person is deleted. Error details shown in the status message. Status bar remains the same.
+ Expected: No patient is deleted. Error details shown in the status message.
1. Other incorrect delete commands to try: `delete`, `delete x`, `...` (where x is larger than the list size)
Expected: Similar to previous.
-
-1. _{ more test cases … }_
-
-### Saving data
-
-1. Dealing with missing/corrupted data files
-
- 1. _{explain how to simulate a missing/corrupted file, and the expected behavior}_
-
-1. _{ more test cases … }_
diff --git a/docs/Documentation.md b/docs/Documentation.md
index 3e68ea364e7..082e652d947 100644
--- a/docs/Documentation.md
+++ b/docs/Documentation.md
@@ -1,29 +1,21 @@
---
-layout: page
-title: Documentation guide
+ layout: default.md
+ title: "Documentation guide"
+ pageNav: 3
---
-**Setting up and maintaining the project website:**
-
-* We use [**Jekyll**](https://jekyllrb.com/) to manage documentation.
-* The `docs/` folder is used for documentation.
-* To learn how set it up and maintain the project website, follow the guide [_[se-edu/guides] **Using Jekyll for project documentation**_](https://se-education.org/guides/tutorials/jekyll.html).
-* Note these points when adapting the documentation to a different project/product:
- * The 'Site-wide settings' section of the page linked above has information on how to update site-wide elements such as the top navigation bar.
- * :bulb: In addition to updating content files, you might have to update the config files `docs\_config.yml` and `docs\_sass\minima\_base.scss` (which contains a reference to `AB-3` that comes into play when converting documentation pages to PDF format).
-* If you are using Intellij for editing documentation files, you can consider enabling 'soft wrapping' for `*.md` files, as explained in [_[se-edu/guides] **Intellij IDEA: Useful settings**_](https://se-education.org/guides/tutorials/intellijUsefulSettings.html#enabling-soft-wrapping)
+# Documentation Guide
+* We use [**MarkBind**](https://markbind.org/) to manage documentation.
+* The `docs/` folder contains the source files for the documentation website.
+* To learn how set it up and maintain the project website, follow the guide [[se-edu/guides] Working with Forked MarkBind sites](https://se-education.org/guides/tutorials/markbind-forked-sites.html) for project documentation.
**Style guidance:**
* Follow the [**_Google developer documentation style guide_**](https://developers.google.com/style).
+* Also relevant is the [_se-edu/guides **Markdown coding standard**_](https://se-education.org/guides/conventions/markdown.html).
-* Also relevant is the [_[se-edu/guides] **Markdown coding standard**_](https://se-education.org/guides/conventions/markdown.html)
-
-**Diagrams:**
-
-* See the [_[se-edu/guides] **Using PlantUML**_](https://se-education.org/guides/tutorials/plantUml.html)
-**Converting a document to the PDF format:**
+**Converting to PDF**
-* See the guide [_[se-edu/guides] **Saving web documents as PDF files**_](https://se-education.org/guides/tutorials/savingPdf.html)
+* See the guide [_se-edu/guides **Saving web documents as PDF files**_](https://se-education.org/guides/tutorials/savingPdf.html).
diff --git a/docs/Gemfile b/docs/Gemfile
deleted file mode 100644
index c8385d85874..00000000000
--- a/docs/Gemfile
+++ /dev/null
@@ -1,10 +0,0 @@
-# frozen_string_literal: true
-
-source "https://rubygems.org"
-
-git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
-
-gem 'jekyll'
-gem 'github-pages', group: :jekyll_plugins
-gem 'wdm', '~> 0.1.0' if Gem.win_platform?
-gem 'webrick'
diff --git a/docs/Logging.md b/docs/Logging.md
index 5e4fb9bc217..589644ad5c6 100644
--- a/docs/Logging.md
+++ b/docs/Logging.md
@@ -1,8 +1,10 @@
---
-layout: page
-title: Logging guide
+ layout: default.md
+ title: "Logging guide"
---
+# Logging guide
+
* We are using `java.util.logging` package for logging.
* The `LogsCenter` class is used to manage the logging levels and logging destinations.
* The `Logger` for a class can be obtained using `LogsCenter.getLogger(Class)` which will log messages according to the specified logging level.
diff --git a/docs/SettingUp.md b/docs/SettingUp.md
index 275445bd551..03df0295bd2 100644
--- a/docs/SettingUp.md
+++ b/docs/SettingUp.md
@@ -1,27 +1,32 @@
---
-layout: page
-title: Setting up and getting started
+ layout: default.md
+ title: "Setting up and getting started"
+ pageNav: 3
---
-* Table of Contents
-{:toc}
+# Setting up and getting started
+
+
--------------------------------------------------------------------------------------------------------------------
## Setting up the project in your computer
-:exclamation: **Caution:**
+
+**Caution:**
Follow the steps in the following guide precisely. Things will not work out if you deviate in some steps.
-
+
First, **fork** this repo, and **clone** the fork into your computer.
If you plan to use Intellij IDEA (highly recommended):
1. **Configure the JDK**: Follow the guide [_[se-edu/guides] IDEA: Configuring the JDK_](https://se-education.org/guides/tutorials/intellijJdk.html) to to ensure Intellij is configured to use **JDK 11**.
-1. **Import the project as a Gradle project**: Follow the guide [_[se-edu/guides] IDEA: Importing a Gradle project_](https://se-education.org/guides/tutorials/intellijImportGradleProject.html) to import the project into IDEA.
- :exclamation: Note: Importing a Gradle project is slightly different from importing a normal Java project.
+1. **Import the project as a Gradle project**: Follow the guide [_[se-edu/guides] IDEA: Importing a Gradle project_](https://se-education.org/guides/tutorials/intellijImportGradleProject.html) to import the project into IDEA.
+
+ Note: Importing a Gradle project is slightly different from importing a normal Java project.
+
1. **Verify the setup**:
1. Run the `seedu.address.Main` and try a few commands.
1. [Run the tests](Testing.md) to ensure they all pass.
@@ -34,10 +39,11 @@ If you plan to use Intellij IDEA (highly recommended):
If using IDEA, follow the guide [_[se-edu/guides] IDEA: Configuring the code style_](https://se-education.org/guides/tutorials/intellijCodeStyle.html) to set up IDEA's coding style to match ours.
- :bulb: **Tip:**
+
+ **Tip:**
Optionally, you can follow the guide [_[se-edu/guides] Using Checkstyle_](https://se-education.org/guides/tutorials/checkstyle.html) to find how to use the CheckStyle within IDEA e.g., to report problems _as_ you write code.
-
+
1. **Set up CI**
diff --git a/docs/Testing.md b/docs/Testing.md
index 8a99e82438a..78ddc57e670 100644
--- a/docs/Testing.md
+++ b/docs/Testing.md
@@ -1,12 +1,15 @@
---
-layout: page
-title: Testing guide
+ layout: default.md
+ title: "Testing guide"
+ pageNav: 3
---
-* Table of Contents
-{:toc}
+# Testing guide
---------------------------------------------------------------------------------------------------------------------
+
+
+
+
## Running tests
@@ -19,8 +22,10 @@ There are two ways to run tests.
* **Method 2: Using Gradle**
* Open a console and run the command `gradlew clean test` (Mac/Linux: `./gradlew clean test`)
-:link: **Link**: Read [this Gradle Tutorial from the se-edu/guides](https://se-education.org/guides/tutorials/gradle.html) to learn more about using Gradle.
-
+
+
+**Link**: Read [this Gradle Tutorial from the se-edu/guides](https://se-education.org/guides/tutorials/gradle.html) to learn more about using Gradle.
+
--------------------------------------------------------------------------------------------------------------------
diff --git a/docs/UserGuide.md b/docs/UserGuide.md
index 7abd1984218..87f79d79bad 100644
--- a/docs/UserGuide.md
+++ b/docs/UserGuide.md
@@ -1,12 +1,24 @@
---
-layout: page
-title: User Guide
+ layout: default.md
+ title: "User Guide"
+ pageNav: 3
---
-AddressBook Level 3 (AB3) is a **desktop app for managing contacts, optimized for use via a Command Line Interface** (CLI) while still having the benefits of a Graphical User Interface (GUI). If you can type fast, AB3 can get your contact management tasks done faster than traditional GUI apps.
+# MediTrack User Guide
-* Table of Contents
-{:toc}
+## Introduction
+
+Welcome to the MediTrack User Guide, your comprehensive companion in navigating the MediTrack application. This guide is designed to empower users-healthcare professionals and receptionists-by providing in-depth knowledge and practical tips on utilizing MediTrack effectively for patient data management. The user guide is written in a way that is easy to comprehend to even those with no prior technical knowledge or experience with a similar task management application.
+
+MediTrack stands at the forefront of healthcare technology, offering an intuitive platform for recording and managing patient data. Our application is built with the dual purpose of enhancing patient care and streamlining administrative tasks, thereby facilitating a more efficient and productive healthcare environment. Using a Command Line Interface (CLI) while still having the benefits of a Graphical User Interface (GUI), MediTrack will allow for greater efficiency in typing commands to carry out all necessary functions in managing patient particulars.
+
+The purpose of this User Guide is multifaceted. Primarily, it serves as an educational tool, introducing you to the myriad features and functionalities of MediTrack. Whether you are a first-time user or looking to deepen your understanding of more advanced features, this guide is tailored to meet your needs. It provides step-by-step instructions, best practices, and troubleshooting advice to ensure that you can navigate the application with ease and confidence.
+
+
+
+
+
+
--------------------------------------------------------------------------------------------------------------------
@@ -14,24 +26,22 @@ AddressBook Level 3 (AB3) is a **desktop app for managing contacts, optimized fo
1. Ensure you have Java `11` or above installed in your Computer.
-1. Download the latest `addressbook.jar` from [here](https://github.com/se-edu/addressbook-level3/releases).
+1. Download the latest `MediTrack.jar` from [here](https://github.com/AY2324S2-CS2103T-T14-2/tp/releases).
-1. Copy the file to the folder you want to use as the _home folder_ for your AddressBook.
+1. Copy the file to the folder you want to use as the _home folder_ for MediTrack.
-1. Open a command terminal, `cd` into the folder you put the jar file in, and use the `java -jar addressbook.jar` command to run the application.
+1. Open a command terminal, `cd` into the folder you put the jar file in, and use the `java -jar MediTrack.jar` command to run the application.
A GUI similar to the below should appear in a few seconds. Note how the app contains some sample data.
![Ui](images/Ui.png)
1. Type the command in the command box and press Enter to execute it. e.g. typing **`help`** and pressing Enter will open the help window.
Some example commands you can try:
- * `list` : Lists all contacts.
-
- * `add n/John Doe p/98765432 e/johnd@example.com a/John street, block 123, #01-01` : Adds a contact named `John Doe` to the Address Book.
+ * `list` : Lists all patients.
- * `delete 3` : Deletes the 3rd contact shown in the current list.
+ * `add n/John Doe p/98765432 e/johnd@example.com a/311, Clementi Ave 2, #02-25 b/25/2/2024 s/Male` : Adds a patient named `John Doe` to the patient list.
- * `clear` : Deletes all contacts.
+ * `delete 3` : Deletes the 3rd patient shown in the current list.
* `exit` : Exits the app.
@@ -39,160 +49,325 @@ AddressBook Level 3 (AB3) is a **desktop app for managing contacts, optimized fo
--------------------------------------------------------------------------------------------------------------------
+
+
## Features
-
+
-**:information_source: Notes about the command format:**
+**Notes about the command format:**
* Words in `UPPER_CASE` are the parameters to be supplied by the user.
e.g. in `add n/NAME`, `NAME` is a parameter which can be used as `add n/John Doe`.
-* Items in square brackets are optional.
- e.g `n/NAME [t/TAG]` can be used as `n/John Doe t/friend` or as `n/John Doe`.
-
-* Items with `…` after them can be used multiple times including zero times.
- e.g. `[t/TAG]…` can be used as ` ` (i.e. 0 times), `t/friend`, `t/friend t/family` etc.
+* Items in square brackets are optional.
+ e.g. `n/NAME [o/APPOINTMENT]` can be used as `n/John Doe o/2024-4-1` or as `n/John Doe`.
* Parameters can be in any order.
e.g. if the command specifies `n/NAME p/PHONE_NUMBER`, `p/PHONE_NUMBER n/NAME` is also acceptable.
-* Extraneous parameters for commands that do not take in parameters (such as `help`, `list`, `exit` and `clear`) will be ignored.
+* Extraneous parameters for commands that do not take in parameters (such as `help`, `list` and `exit`) will be ignored.
e.g. if the command specifies `help 123`, it will be interpreted as `help`.
+* For any parameters using date format, strictly need to follow "yyyy-MM-dd" and "dd/MM/yyyy". If the date exceeds the maximum date of that month, then will take the maximum date of that month.
+
+* Duplicate patients are not allowed (Patients are considered the same patients if they have the same name and phone number).
+
+* Name should only consist of letters, or a single special character surrounded by letters, the special characters allowed being spaces, `\`, `/` and `-`. For example, `s/o` is allowed, but `s / o` is not since `/` is between 2 spaces.
+
+* Phone can have from 3 to 8 digits.
+
+* There is no restriction in Date of Birth and Appointment. Appointment can be before Date of Birth.
+
+* Sex field only accepts specific "Male" and "Female" as an input (eg. "MALE" or "FEMALE" is not accepted).
+
+* “Appointment” refers to a scheduled future date when a patient plans to visit the clinic. Conversely, “Visit” refers to a recorded instance of a patient’s past attendance at the clinic.
+
+* Severity field only accepts specific label as "Low" or "High" as an input (eg. "LOW" or "HIGH" is not accepted).
+
* If you are using a PDF version of this document, be careful when copying and pasting commands that span multiple lines as space characters surrounding line-breaks may be omitted when copied over to the application.
-
+
+
+--------------------------------------------------------------------------------------------------------------------
+
+## Command summary
+
+
+| Action | Format, Example |
+|----------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| **Add Patient** | `add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS b/DATE_OF_BIRTH s/SEX` e.g., `add n/John Doe p/98765432 e/johnd@example.com a/311, Clementi Ave 2, #02-25 b/25/2/2024 s/Male` |
+| **Add Visit** | `addv INDEX d/DATE_OF_VISIT c/CONDITION v/SEVERITY` or `addv n/NAME p/PHONE_NUMBER d/DATE_OF_VISIT c/CONDITION v/SEVERITY` e.g., `addv 1 d/25/2/2024 c/Mild Fever v/Low` |
+| **Delete by index** | `delete INDEX` e.g., `delete 3` |
+| **Delete by name and phone** | `delete-p n/NAME p/PHONE_NUMBER` e.g. `delete-p n/Jaeho p/22224444` |
+| **Delete all** | `delete-all` |
+| **Force delete all** | `delete-all-f` |
+| **Delete Visit** | `deletev INDEX` or `deletev n/NAME p/PHONE_NUMBER` e.g., `deletev 3` |
+| **Edit Patient** | `edit INDEX [n/NAME] [p/PHONE_NUMBER] [e/EMAIL] [a/ADDRESS] [b/DATE_OF_BIRTH] [s/SEX] [o/APPOINTMENT]` or `edit n/NAME p/PHONE_NUMBER [n/NAME] [p/PHONE] [e/EMAIL] [a/ADDRESS] [b/DATEOFBIRTH] [s/SEX] [o/APPOINTMENT]` e.g.,`edit 2 n/James Lee e/jameslee@example.com` |
+| **Edit Visit** | `editv INDEX [d/DATE_OF_VISIT] [c/CONDITION] [v/SEVERITY`] or `editv n/NAME p/PHONE_NUMBER [d/DATE_OF_VISIT] [c/CONDITION] [v/SEVERITY]` e.g.,`editv n/Alex Yeoh p/87438807 c/Sore throat v/Low` |
+| **Find** | `find [n/KEYWORDS] [p/PHONE_NUMBER]` e.g., `find n/John p/98765432` |
+| **List** | `list` |
+| **List in alphabetical order** | `list-a` |
+| **List in order of appointment date** | `list-by-date` |
+| **List all appointments on/before a certain date** | `list-until-date o/dd/mm/yyyy` e.g. , `list-until-date o/12/01/2024` |
+| **Help** | `help` |
+| **Exit** | `exit` |
+| **Force exit** | `exit-f` |
+
+--------------------------------------------------------------------------------------------------------------------
-### Viewing help : `help`
+### Viewing help, accessing user guide : `help`
-Shows a message explaning how to access the help page.
+Shows a message that provides the link to the user guide.
![help message](images/helpMessage.png)
Format: `help`
-### Adding a person: `add`
+### Adding a patient: `add`
+
+Adds a patient to the patient list.
+
+Format: `add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS b/DATE_OF_BIRTH s/Sex`
+
+
+
+**Note:** Appointment field can only be edited after adding the patient into the patient list
+
+
+Example:
+* `add n/John Doe p/98765432 e/johnd@example.com a/John street, block 123, #01-01 b/2001-1-1 s/Male`
-Adds a person to the address book.
+
-Format: `add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]…`
-:bulb: **Tip:**
-A person can have any number of tags (including 0)
-
+### Adding a visit to a patient: `addv`
-Examples:
-* `add n/John Doe p/98765432 e/johnd@example.com a/John street, block 123, #01-01`
-* `add n/Betsy Crowe t/friend e/betsycrowe@example.com a/Newgate Prison p/1234567 t/criminal`
+Adds a visit to a patient.
-### Listing all persons : `list`
+Format: `addv INDEX d/DATE_OF_VISIT c/CONDITION v/SEVERITY` or `addv n/NAME p/PHONE_NUMBER d/DATE_OF_VISIT c/CONDITION v/SEVERITY`
-Shows a list of all persons in the address book.
+* Adds a new visit to the patient at the specified `INDEX`. The index refers to the index number shown in the displayed patient list. The index **must be a positive integer** 1, 2, 3, …
+* Alternatively provide the desired patient's name and phone number instead of the index.
+* If both an index and one of name or phone number is provided, the index will be prioritised and latter will be ignored.
+* The new visit will be the one shown in the UI.
+* The specified patient will move to the bottom of the patient list.
+
+Example:
+* `addv 1 d/25/2/2024 c/Mild Fever v/Low`
+* `addv n/Alex Yeoh p/87438807 d/25/2/2024 c/High Fever v/High`
+
+### Listing all patients : `list`
+
+Shows a list of all patients in the patient list.
Format: `list`
-### Editing a person : `edit`
+### Listing all patients in alphabetical order : `list-a`
+
+Shows a list of all patients in the patient list in alphabetical order.
+
+Format: `list-a`
+
+**Note:** Currently, list-a can only support names where the first letters are in uppercase. Names that are in lowercase will not be listed in the correct order.
+
+### Listing all patients in order of appointment date : `list-by-date`
+
+Shows a list of all patients in the patient list in order of appointment.
+
+Format: `list-by-date`
+
+
-Edits an existing person in the address book.
-Format: `edit INDEX [n/NAME] [p/PHONE] [e/EMAIL] [a/ADDRESS] [t/TAG]…`
+### Listing all patients whose appointments fall or on before a certain date : `list-until-date`
-* Edits the person at the specified `INDEX`. The index refers to the index number shown in the displayed person list. The index **must be a positive integer** 1, 2, 3, …
+Shows a list of all patients in the patient list whose appointments fall on or before the given date.
+
+Format: `list-until-date o/dd/mm/yyyy`
+
+Example:
+* `list-until-date o/13/01/2024` Displays all patients with appointments on or before 13 January 2024.
+
+### Editing a patient : `edit`
+
+Edits an existing patient in the patient list.
+
+Format: `edit INDEX [n/NAME] [p/PHONE] [e/EMAIL] [a/ADDRESS] [b/DATEOFBIRTH] [s/SEX] [o/APPOINTMENT]` or `edit n/NAME p/PHONE_NUMBER [n/NAME] [p/PHONE] [e/EMAIL] [a/ADDRESS] [b/DATEOFBIRTH] [s/SEX] [o/APPOINTMENT]`
+
+* Edits the patient at the specified `INDEX`. The index refers to the index number shown in the displayed patient list. The index **must be a positive integer** 1, 2, 3, …
* At least one of the optional fields must be provided.
* Existing values will be updated to the input values.
-* When editing tags, the existing tags of the person will be removed i.e adding of tags is not cumulative.
-* You can remove all the person’s tags by typing `t/` without
- specifying any tags after it.
-Examples:
-* `edit 1 p/91234567 e/johndoe@example.com` Edits the phone number and email address of the 1st person to be `91234567` and `johndoe@example.com` respectively.
-* `edit 2 n/Betsy Crower t/` Edits the name of the 2nd person to be `Betsy Crower` and clears all existing tags.
+Example:
+* `edit 1 p/91234567 e/johndoe@example.com` Edits the phone number and email address of the 1st patient to be `91234567` and `johndoe@example.com` respectively.
+* `edit 2 n/Betsy Crower` Edits the name of the 2nd patient to be `Betsy Crower`.
+* `edit n/Alex Yeoh p/88472848 n/Eugene` Edits the name of patient from `Alex Yeoh` to `Eugene`.
+
+
+
+### Editing the latest visit of a patient: `editv`
+
+Edits the displayed visit of a patient.
+
+Format: `editv INDEX [d/DATE_OF_VISIT] [c/CONDITION] [v/SEVERITY]` or `editv n/NAME p/PHONE_NUMBER [d/DATE_OF_VISIT] [c/CONDITION] [v/SEVERITY]`
-### Locating persons by name: `find`
+* Edits the latest visit of the patient at the specified `INDEX`. The index refers to the index number shown in the displayed patient list. The index **must be a positive integer** 1, 2, 3, …
+* At least one of the optional fields must be provided.
+* Alternatively provide the desired patient's name and phone number instead of the index.
+* If both an index and one of name or phone number is provided, the index will be prioritised and latter will be ignored.
+* The edited visit will be the one shown in the UI.
+* The specified patient will move to the bottom of the patient list.
+
+Example:
+* `editv 1 d/25/2/2024` Edits the visit date of the 1st patient to `25/2/2024`
+* `editv n/Alex Yeoh p/87438807 c/Sore throat v/Low` Edits the condition and severity of `Alex Yeoh` with `87438807` to `Sore throat` and `Low`.
-Finds persons whose names contain any of the given keywords.
+### Locating patients by name: `find`
-Format: `find KEYWORD [MORE_KEYWORDS]`
+Finds patients whose name contains the given keyword and/or whose phone number matches the given one.
-* The search is case-insensitive. e.g `hans` will match `Hans`
-* The order of the keywords does not matter. e.g. `Hans Bo` will match `Bo Hans`
-* Only the name is searched.
-* Only full words will be matched e.g. `Han` will not match `Hans`
-* Persons matching at least one keyword will be returned (i.e. `OR` search).
- e.g. `Hans Bo` will return `Hans Gruber`, `Bo Yang`
+Format: `find [n/KEYWORDS] [p/PHONE_NUMBER]`
-Examples:
-* `find John` returns `john` and `John Doe`
-* `find alex david` returns `Alex Yeoh`, `David Li`
- ![result for 'find alex david'](images/findAlexDavidResult.png)
+* At least one of the optional fields must be provided.
+* If both fields are provided, patient must meet both conditions to be listed.
+* The search for name is case-insensitive. e.g. `hans` will match `Hans`.
+* The order of the keywords does not matter. e.g. `Hans Bo` will match `Bo Hans`.
+* Keywords must be separated by a space to be recognised as distinct.
+* Only full words will be matched. e.g. `Han` will not match `Hans`.
+* Patients matching at least one keyword will be returned (i.e. `OR` search).
+ e.g. `Hans Bo` will return `Hans Gruber`, `Bo Yang`.
+* Unlike keywords, only 1 phone number can be provided. e.g. `p/98765432 97538642` is invalid.
-### Deleting a person : `delete`
+Example:
+* `find n/John` Displays all patients with name containing `John`.
+* `find n/John p/98765432` Displays all patients with name containing `john` and phone number `98765432`.
+* `find n/alex roy` returns `Alex Yeoh`, `Roy Balakrishnan`. The output is shown below.
+ ![result for 'find n/alex roy'](images/findAlexRoyResult.png)
-Deletes the specified person from the address book.
+### Deleting a patient using index number within the patient list : `delete`
+
+Deletes the patient at the specified index within the patient list.
Format: `delete INDEX`
-* Deletes the person at the specified `INDEX`.
-* The index refers to the index number shown in the displayed person list.
-* The index **must be a positive integer** 1, 2, 3, …
+* Deletes the patient at the specified `INDEX`. The index refers to the index number shown in the displayed patient list. The index **must be a positive integer** 1, 2, 3, …
+* If the specified index goes over the number of indices available in the patient list, the program will return an error
+ message that states that the patient index provided is invalid.
+
+Example:
+* `delete 1` Deletes the first patient in the displayed list.
+
+### Deleting a specific patient using name and phone number : `delete-p`
+
+Deletes the patient with the specified name and phone number within the patient list.
+
+Format: `delete-p n/NAME p/PHONE_NUMBER`
+
+* Refer to the respective rules under the 'add' command for acceptable inputs to 'delete-p' command.
+* If at least one of the name and phone number doesn't match, it will return an error message that states that there is no patient with the specified name and phone number.
+
+Example:
+* `delete n/Eugene Hirose p/90807561` Deletes the patient with name exactly the same as "Eugene Hirose" and phone number exactly the same as "90807561".
-Examples:
-* `list` followed by `delete 2` deletes the 2nd person in the address book.
-* `find Betsy` followed by `delete 1` deletes the 1st person in the results of the `find` command.
+
-### Clearing all entries : `clear`
+### Deleting all entries : `delete-all`
-Clears all entries from the address book.
+Deletes all patients' information in the patientlist.json.
-Format: `clear`
+Format: `delete-all`
+
+Example:
+* 'delete-all' followed by 'yes' Deletes all patients' information in the patientlist.json and displays an empty list.
+* 'delete-all' followed by 'no' Causes no changes to the patient list.
+* 'delete-all' followed by any other commands other than 'yes' and 'no' returns an error message that prompts the user to give either 'yes' or 'no' instead after 'delete-all' command.
+
+### Forcefully deleting all entries : `delete-all-f`
+
+Forcefully deletes all entries from the patient list.
+
+Format: `delete-all-f`
+
+Example:
+* `delete-all-f` Deletes all patients' information in the patientlist.json and displays an empty list.
+
+### Deleting the latest visit of a patient: `deletev`
+
+Deletes the displayed visit of a patient.
+
+Format: `deletev INDEX` or `deletev n/NAME p/PHONE_NUMBER`
+
+* Deletes the latest visit of the patient at the specified `INDEX`. The index refers to the index number shown in the displayed patient list. The index **must be a positive integer** 1, 2, 3, …
+* Alternatively provide the desired patient's name and phone number instead of the index.
+* If both an index and one of name or phone number is provided, the index will be prioritised and latter will be ignored.
+* The new visit displayed will be the one added before the deleted visit, if there is one.
+* The specified patient will move to the bottom of the patient list.
+
+Example:
+* `deletev 1`
+* `deletev n/Alex Yeoh p/87438807`
+
+
### Exiting the program : `exit`
-Exits the program.
+Lets the system know the user wants to exit the program.
Format: `exit`
-### Saving the data
+Example:
+* 'exit' followed by 'yes' exits the application.
+* 'exit' followed by 'no' causes no changes to the application and cancel exit command.
+
+### Forcefully exiting the program : `exit-f`
+
+Forcefully exits the program.
-AddressBook data are saved in the hard disk automatically after any command that changes the data. There is no need to save manually.
+Format: `exit-f`
+
+Example:
+* 'exit-f' exits the application.
### Editing the data file
-AddressBook data are saved automatically as a JSON file `[JAR file location]/data/addressbook.json`. Advanced users are welcome to update data directly by editing that data file.
+MediTrack data are saved automatically as a JSON file `[JAR file location]/data/patientlist.json`. Advanced users are welcome to update data directly by editing that data file.
-:exclamation: **Caution:**
-If your changes to the data file makes its format invalid, AddressBook will discard all data and start with an empty data file at the next run. Hence, it is recommended to take a backup of the file before editing it.
-Furthermore, certain edits can cause the AddressBook to behave in unexpected ways (e.g., if a value entered is outside of the acceptable range). Therefore, edit the data file only if you are confident that you can update it correctly.
-
+
-### Archiving data files `[coming in v2.0]`
+**Caution:**
+If your changes to the data file makes its format invalid, MediTrack will discard all data and start with an empty data file at the next run. Hence, it is recommended to take a backup of the file before editing it.
+Furthermore, certain edits can cause the MediTrack to behave in unexpected ways (e.g., if a value entered is outside the acceptable range). Therefore, edit the data file only if you are confident that you can update it correctly.
+
-_Details coming soon ..._
+
---------------------------------------------------------------------------------------------------------------------
## FAQ
**Q**: How do I transfer my data to another Computer?
-**A**: Install the app in the other computer and overwrite the empty data file it creates with the file that contains the data of your previous AddressBook home folder.
+**A**: Install the app in the other computer and overwrite the empty data file it creates with the file that contains the data of your previous MediTrack home folder.
+
+**Q**: How can I check where my data file is located?
+**A**: Check your `[JAR file location]/preferences.json`. The location of your data file is listed under `patientListFilePath`. You can also change this if needed.
+
+**Q**: How do I change the default size of the window?
+**A**: In your `[JAR file location]/preferences.json`, you can adjust the initial window dimensions and location.
+
+**Q**: I've used the `find` command to look for a specific patient. How do I go back to the full list?
+**A**: You may use the `list` command or one of its variations.
--------------------------------------------------------------------------------------------------------------------
## Known issues
1. **When using multiple screens**, if you move the application to a secondary screen, and later switch to using only the primary screen, the GUI will open off-screen. The remedy is to delete the `preferences.json` file created by the application before running the application again.
+2. Command prompts in the error messages do not follow the command format given in the [Features](#features) section, specifically regarding the use of square brackets. It is recommended to refer back to this user guide if you encounter any issues with commands.
--------------------------------------------------------------------------------------------------------------------
-## Command summary
+### Glossary
-Action | Format, Examples
---------|------------------
-**Add** | `add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]…` e.g., `add n/James Ho p/22224444 e/jamesho@example.com a/123, Clementi Rd, 1234665 t/friend t/colleague`
-**Clear** | `clear`
-**Delete** | `delete INDEX` e.g., `delete 3`
-**Edit** | `edit INDEX [n/NAME] [p/PHONE_NUMBER] [e/EMAIL] [a/ADDRESS] [t/TAG]…` e.g.,`edit 2 n/James Lee e/jameslee@example.com`
-**Find** | `find KEYWORD [MORE_KEYWORDS]` e.g., `find James Jake`
-**List** | `list`
-**Help** | `help`
+* **CLI**: A method of interacting with a computer where the user issues commands to the system by typing in lines of text.
+* **GUI**: A type of user interface that allows users to interact with electronic devices through graphical icons and visual indicators such as secondary notation, instead of text-based interfaces, typed command labels or text navigation.
+* **JSON (JavaScript Object Notation)**: A lightweight data-interchange format that is easy for humans to read and write and easy for machines to parse and generate.
diff --git a/docs/_config.yml b/docs/_config.yml
deleted file mode 100644
index 6bd245d8f4e..00000000000
--- a/docs/_config.yml
+++ /dev/null
@@ -1,15 +0,0 @@
-title: "AB-3"
-theme: minima
-
-header_pages:
- - UserGuide.md
- - DeveloperGuide.md
- - AboutUs.md
-
-markdown: kramdown
-
-repository: "se-edu/addressbook-level3"
-github_icon: "images/github-icon.png"
-
-plugins:
- - jemoji
diff --git a/docs/_data/projects.yml b/docs/_data/projects.yml
deleted file mode 100644
index 8f3e50cb601..00000000000
--- a/docs/_data/projects.yml
+++ /dev/null
@@ -1,23 +0,0 @@
-- name: "AB-1"
- url: https://se-edu.github.io/addressbook-level1
-
-- name: "AB-2"
- url: https://se-edu.github.io/addressbook-level2
-
-- name: "AB-3"
- url: https://se-edu.github.io/addressbook-level3
-
-- name: "AB-4"
- url: https://se-edu.github.io/addressbook-level4
-
-- name: "Duke"
- url: https://se-edu.github.io/duke
-
-- name: "Collate"
- url: https://se-edu.github.io/collate
-
-- name: "Book"
- url: https://se-edu.github.io/se-book
-
-- name: "Resources"
- url: https://se-edu.github.io/resources
diff --git a/docs/_includes/custom-head.html b/docs/_includes/custom-head.html
deleted file mode 100644
index 8559a67ffad..00000000000
--- a/docs/_includes/custom-head.html
+++ /dev/null
@@ -1,6 +0,0 @@
-{% comment %}
- Placeholder to allow defining custom head, in principle, you can add anything here, e.g. favicons:
-
- 1. Head over to https://realfavicongenerator.net/ to add your own favicons.
- 2. Customize default _includes/custom-head.html in your source directory and insert the given code snippet.
-{% endcomment %}
diff --git a/docs/_includes/head.html b/docs/_includes/head.html
deleted file mode 100644
index 83ac5326933..00000000000
--- a/docs/_includes/head.html
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
- {%- include custom-head.html -%}
-
- {{page.title}}
-
-
diff --git a/docs/_includes/header.html b/docs/_includes/header.html
deleted file mode 100644
index 33badcd4f99..00000000000
--- a/docs/_includes/header.html
+++ /dev/null
@@ -1,36 +0,0 @@
-
diff --git a/docs/_layouts/alt-page.html b/docs/_layouts/alt-page.html
deleted file mode 100644
index 5dbc6ef245f..00000000000
--- a/docs/_layouts/alt-page.html
+++ /dev/null
@@ -1,14 +0,0 @@
----
-layout: default
----
-
-
-
-
-
- {{ content }}
-
-
-
diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html
deleted file mode 100644
index e092cd572e0..00000000000
--- a/docs/_layouts/default.html
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
- {%- include head.html -%}
-
-
-
- {%- include header.html -%}
-
-
-
- {{ content }}
-
-
-
-
-
-
diff --git a/docs/_layouts/page.html b/docs/_layouts/page.html
deleted file mode 100644
index 01e4b2a93b8..00000000000
--- a/docs/_layouts/page.html
+++ /dev/null
@@ -1,14 +0,0 @@
----
-layout: default
----
-
-
-
-
-
- {{ content }}
-
-
-
diff --git a/docs/_markbind/layouts/default.md b/docs/_markbind/layouts/default.md
new file mode 100644
index 00000000000..08b0dda8045
--- /dev/null
+++ b/docs/_markbind/layouts/default.md
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+* [Home]({{ baseUrl }}/index.html)
+* [User Guide]({{ baseUrl }}/UserGuide.html) :expanded:
+ * [Quick Start]({{ baseUrl }}/UserGuide.html#quick-start)
+ * [Features]({{ baseUrl }}/UserGuide.html#features)
+ * [FAQ]({{ baseUrl }}/UserGuide.html#faq)
+ * [Command Summary]({{ baseUrl }}/UserGuide.html#faq)
+* [Developer Guide]({{ baseUrl }}/DeveloperGuide.html) :expanded:
+ * [Acknowledgements]({{ baseUrl }}/DeveloperGuide.html#acknowledgements)
+ * [Setting Up]({{ baseUrl }}/DeveloperGuide.html#setting-up-getting-started)
+ * [Design]({{ baseUrl }}/DeveloperGuide.html#design)
+ * [Implementation]({{ baseUrl }}/DeveloperGuide.html#implementation)
+ * [Documentation, logging, testing, configuration, dev-ops]({{ baseUrl }}/DeveloperGuide.html#documentation-logging-testing-configuration-dev-ops)
+ * [Appendix: Requirements]({{ baseUrl }}/DeveloperGuide.html#appendix-requirements)
+ * [Appendix: Instructions for manual testing]({{ baseUrl }}/DeveloperGuide.html#appendix-instructions-for-manual-testing)
+* Tutorials
+ * [Tracing code]({{ baseUrl }}/tutorials/TracingCode.html)
+ * [Adding a command]({{ baseUrl }}/tutorials/AddRemark.html)
+ * [Removing Fields]({{ baseUrl }}/tutorials/RemovingFields.html)
+* [About Us]({{ baseUrl }}/AboutUs.html)
+
+
+
+
+ {{ content }}
+
+
+
+
+
+
+
+
+
+
+
[**Powered by** {{MarkBind}}, generated on {{timestamp}}]
+
+
diff --git a/docs/_markbind/variables.json b/docs/_markbind/variables.json
new file mode 100644
index 00000000000..9d89eb0358b
--- /dev/null
+++ b/docs/_markbind/variables.json
@@ -0,0 +1,3 @@
+{
+ "jsonVariableExample": "Your variables can be defined here as well"
+}
diff --git a/docs/_markbind/variables.md b/docs/_markbind/variables.md
new file mode 100644
index 00000000000..89ae5318fa4
--- /dev/null
+++ b/docs/_markbind/variables.md
@@ -0,0 +1,4 @@
+
+To inject this HTML segment in your markbind files, use {{ example }} where you want to place it.
+More generally, surround the segment's id with double curly braces.
+
diff --git a/docs/_sass/minima/_base.scss b/docs/_sass/minima/_base.scss
deleted file mode 100644
index 0d3f6e80ced..00000000000
--- a/docs/_sass/minima/_base.scss
+++ /dev/null
@@ -1,295 +0,0 @@
-html {
- font-size: $base-font-size;
-}
-
-/**
- * Reset some basic elements
- */
-body, h1, h2, h3, h4, h5, h6,
-p, blockquote, pre, hr,
-dl, dd, ol, ul, figure {
- margin: 0;
- padding: 0;
-
-}
-
-
-
-/**
- * Basic styling
- */
-body {
- font: $base-font-weight #{$base-font-size}/#{$base-line-height} $base-font-family;
- color: $text-color;
- background-color: $background-color;
- -webkit-text-size-adjust: 100%;
- -webkit-font-feature-settings: "kern" 1;
- -moz-font-feature-settings: "kern" 1;
- -o-font-feature-settings: "kern" 1;
- font-feature-settings: "kern" 1;
- font-kerning: normal;
- display: flex;
- min-height: 100vh;
- flex-direction: column;
- overflow-wrap: break-word;
-}
-
-
-
-/**
- * Set `margin-bottom` to maintain vertical rhythm
- */
-h1, h2, h3, h4, h5, h6,
-p, blockquote, pre,
-ul, ol, dl, figure,
-%vertical-rhythm {
- margin-bottom: $spacing-unit / 2;
-}
-
-hr {
- margin-top: $spacing-unit;
- margin-bottom: $spacing-unit;
-}
-
-/**
- * `main` element
- */
-main {
- display: block; /* Default value of `display` of `main` element is 'inline' in IE 11. */
-}
-
-
-
-/**
- * Images
- */
-img {
- max-width: 100%;
- vertical-align: middle;
-}
-
-
-
-/**
- * Figures
- */
-figure > img {
- display: block;
-}
-
-figcaption {
- font-size: $small-font-size;
-}
-
-
-
-/**
- * Lists
- */
-ul, ol {
- margin-left: $spacing-unit;
-}
-
-li {
- > ul,
- > ol {
- margin-bottom: 0;
- }
-}
-
-
-
-/**
- * Headings
- */
-h1, h2, h3, h4, h5, h6 {
- font-weight: $base-font-weight;
-}
-
-
-
-/**
- * Links
- */
-a {
- color: $link-base-color;
- text-decoration: none;
-
- &:visited {
- color: $link-visited-color;
- }
-
- &:hover {
- color: $text-color;
- text-decoration: underline;
- }
-
- .social-media-list &:hover {
- text-decoration: none;
-
- .username {
- text-decoration: underline;
- }
- }
-}
-
-
-/**
- * Blockquotes
- */
-blockquote {
- color: $brand-color;
- border-left: 4px solid $brand-color-light;
- padding-left: $spacing-unit / 2;
- @include relative-font-size(1.125);
- font-style: italic;
-
- > :last-child {
- margin-bottom: 0;
- }
-
- i, em {
- font-style: normal;
- }
-}
-
-
-
-/**
- * Code formatting
- */
-pre,
-code {
- font-family: $code-font-family;
- font-size: 0.9375em;
- border: 1px solid $brand-color-light;
- border-radius: 3px;
- background-color: $code-background-color;
-}
-
-code {
- padding: 1px 5px;
-}
-
-pre {
- padding: 8px 12px;
- overflow-x: auto;
-
- > code {
- border: 0;
- padding-right: 0;
- padding-left: 0;
- }
-}
-
-.highlight {
- border-radius: 3px;
- background: $code-background-color;
- @extend %vertical-rhythm;
-
- .highlighter-rouge & {
- background: $code-background-color;
- }
-}
-
-
-
-/**
- * Wrapper
- */
-.wrapper {
- max-width: calc(#{$content-width} - (#{$spacing-unit}));
- margin-right: auto;
- margin-left: auto;
- padding-right: $spacing-unit / 2;
- padding-left: $spacing-unit / 2;
- @extend %clearfix;
-
- @media screen and (min-width: $on-large) {
- max-width: calc(#{$content-width} - (#{$spacing-unit} * 2));
- padding-right: $spacing-unit;
- padding-left: $spacing-unit;
- }
-}
-
-
-
-/**
- * Clearfix
- */
-%clearfix:after {
- content: "";
- display: table;
- clear: both;
-}
-
-
-
-/**
- * Icons
- */
-
-.orange {
- color: #f66a0a;
-}
-
-.grey {
- color: #828282;
-}
-
-/**
- * Tables
- */
-table {
- margin-bottom: $spacing-unit;
- width: 100%;
- text-align: $table-text-align;
- color: $table-text-color;
- border-collapse: collapse;
- border: 1px solid $table-border-color;
- tr {
- &:nth-child(even) {
- background-color: $table-zebra-color;
- }
- }
- th, td {
- padding: ($spacing-unit / 3) ($spacing-unit / 2);
- }
- th {
- background-color: $table-header-bg-color;
- border: 1px solid $table-header-border;
- }
- td {
- border: 1px solid $table-border-color;
- }
-
- @include media-query($on-laptop) {
- display: block;
- overflow-x: auto;
- -webkit-overflow-scrolling: touch;
- -ms-overflow-style: -ms-autohiding-scrollbar;
- }
-}
-
-@media print {
- /**
- * Prevents page break from cutting through content when printing
- */
- body {
- display: block;
- }
- /**
- * Replaces the top navigation menu with the project name when printing
- */
- .site-header .wrapper {
- display: none;
- }
- .site-header {
- text-align: center;
- }
- .site-header:before {
- content: "AB-3";
- font-size: 32px;
- }
-}
-
diff --git a/docs/_sass/minima/_layout.scss b/docs/_sass/minima/_layout.scss
deleted file mode 100644
index ca99f981701..00000000000
--- a/docs/_sass/minima/_layout.scss
+++ /dev/null
@@ -1,263 +0,0 @@
-/**
- * Site header
- */
-.site-header {
- border-top: 5px solid $brand-color-dark;
- border-bottom: 1px solid $brand-color-light;
- min-height: $spacing-unit * 1.865;
- line-height: $base-line-height * $base-font-size * 2.25;
-
- // Positioning context for the mobile navigation icon
- position: relative;
-}
-
-.site-title {
- @include relative-font-size(1.625);
- font-weight: 300;
- letter-spacing: -1px;
- margin-bottom: 0;
- float: left;
-
- @include media-query($on-palm) {
- padding-right: 45px;
- }
-
- &,
- &:visited {
- color: $brand-color-dark;
- }
-}
-
-.site-nav {
- position: absolute;
- top: 9px;
- right: $spacing-unit / 2;
- background-color: $background-color;
- border: 1px solid $brand-color-light;
- border-radius: 5px;
- text-align: right;
-
- .nav-trigger {
- display: none;
- }
-
- .menu-icon {
- float: right;
- width: 36px;
- height: 26px;
- line-height: 0;
- padding-top: 10px;
- text-align: center;
-
- > svg path {
- fill: $brand-color-dark;
- }
- }
-
- label[for="nav-trigger"] {
- display: block;
- float: right;
- width: 36px;
- height: 36px;
- z-index: 2;
- cursor: pointer;
- }
-
- input ~ .trigger {
- clear: both;
- display: none;
- }
-
- input:checked ~ .trigger {
- display: block;
- padding-bottom: 5px;
- }
-
- .page-link {
- color: $text-color;
- line-height: $base-line-height;
- display: block;
- padding: 5px 10px;
-
- // Gaps between nav items, but not on the last one
- &:not(:last-child) {
- margin-right: 0;
- }
- margin-left: 20px;
- }
-
- @media screen and (min-width: $on-medium) {
- position: static;
- float: right;
- border: none;
- background-color: inherit;
-
- label[for="nav-trigger"] {
- display: none;
- }
-
- .menu-icon {
- display: none;
- }
-
- input ~ .trigger {
- display: block;
- }
-
- .page-link {
- display: inline;
- padding: 0;
-
- &:not(:last-child) {
- margin-right: 20px;
- }
- margin-left: auto;
- }
- }
-}
-
-
-
-/**
- * Page content
- */
-.page-content {
- padding: $spacing-unit 0;
- flex: 1 0 auto;
-}
-
-.page-heading {
- @include relative-font-size(2);
-}
-
-.post-list-heading {
- @include relative-font-size(1.75);
-}
-
-.post-list {
- margin-left: 0;
- list-style: none;
-
- > li {
- margin-bottom: $spacing-unit;
- }
-}
-
-.post-meta {
- font-size: $small-font-size;
- color: $brand-color;
-}
-
-.post-link {
- display: block;
- @include relative-font-size(1.5);
-}
-
-
-
-/**
- * Posts
- */
-.post-header {
- margin-bottom: $spacing-unit;
-}
-
-.post-title,
-.post-content h1 {
- @include relative-font-size(2.625);
- letter-spacing: -1px;
- line-height: 1.15;
-
- @media screen and (min-width: $on-large) {
- @include relative-font-size(2.625);
- }
-}
-
-.post-content {
- margin-bottom: $spacing-unit;
-
- h1, h2, h3 { margin-top: $spacing-unit * 2 }
- h4, h5, h6 { margin-top: $spacing-unit }
-
- h2 {
- @include relative-font-size(1.75);
-
- @media screen and (min-width: $on-large) {
- @include relative-font-size(2);
- }
- }
-
- h3 {
- @include relative-font-size(1.375);
-
- @media screen and (min-width: $on-large) {
- @include relative-font-size(1.625);
- }
- }
-
- h4 {
- @include relative-font-size(1.25);
- }
-
- h5 {
- @include relative-font-size(1.125);
- }
- h6 {
- @include relative-font-size(1.0625);
- }
-}
-
-
-.social-media-list {
- display: table;
- margin: 0 auto;
- li {
- float: left;
- margin: 5px 10px 5px 0;
- &:last-of-type { margin-right: 0 }
- a {
- display: block;
- padding: $spacing-unit / 4;
- border: 1px solid $brand-color-light;
- &:hover { border-color: darken($brand-color-light, 10%) }
- }
- }
-}
-
-
-
-/**
- * Pagination navbar
- */
-.pagination {
- margin-bottom: $spacing-unit;
- @extend .social-media-list;
- li {
- a, div {
- min-width: 41px;
- text-align: center;
- box-sizing: border-box;
- }
- div {
- display: block;
- padding: $spacing-unit / 4;
- border: 1px solid transparent;
-
- &.pager-edge {
- color: darken($brand-color-light, 5%);
- border: 1px dashed;
- }
- }
- }
-}
-
-
-
-/**
- * Grid helpers
- */
-@media screen and (min-width: $on-large) {
- .one-half {
- width: calc(50% - (#{$spacing-unit} / 2));
- }
-}
diff --git a/docs/_sass/minima/custom-mixins.scss b/docs/_sass/minima/custom-mixins.scss
deleted file mode 100644
index 9d4bedc1c67..00000000000
--- a/docs/_sass/minima/custom-mixins.scss
+++ /dev/null
@@ -1,21 +0,0 @@
-@mixin alert-variant($background, $border, $color) {
- color: $color;
- @include gradient-bg($background);
- border-color: $border;
-
- .alert-link {
- color: darken($color, 10%);
- }
-}
-
-@mixin gradient-bg($color, $foreground: null) {
- @if $enable-gradients {
- @if $foreground {
- background-image: $foreground, linear-gradient(180deg, mix($body-bg, $color, 15%), $color);
- } @else {
- background-image: linear-gradient(180deg, mix($body-bg, $color, 15%), $color);
- }
- } @else {
- background-color: $color;
- }
-}
diff --git a/docs/_sass/minima/custom-styles.scss b/docs/_sass/minima/custom-styles.scss
deleted file mode 100644
index 56b5d56b430..00000000000
--- a/docs/_sass/minima/custom-styles.scss
+++ /dev/null
@@ -1,34 +0,0 @@
-// Placeholder to allow defining custom styles that override everything else.
-// (Use `_sass/minima/custom-variables.scss` to override variable defaults)
-h2, h3, h4, h5, h6 {
- color: #e46c0a;
-}
-
-// Bootstrap style alerts
-.alert {
- position: relative;
- padding: $alert-padding-y $alert-padding-x;
- margin-bottom: $alert-margin-bottom;
- border: $alert-border-width solid transparent;
- border-radius : $alert-border-radius;
-}
-
-// Headings for larger alerts
-.alert-heading {
- // Specified to prevent conflicts of changing $headings-color
- color: inherit;
-}
-
-// Provide class for links that match alerts
-.alert-link {
- font-weight: $alert-link-font-weight;
-}
-
-// Generate contextual modifier classes for colorizing the alert.
-
-@each $color, $value in $theme-colors {
- .alert-#{$color} {
- @include alert-variant(color-level($value, $alert-bg-level), color-level($value, $alert-border-level), color-level($value, $alert-color-level));
- }
-}
-
diff --git a/docs/_sass/minima/custom-variables.scss b/docs/_sass/minima/custom-variables.scss
deleted file mode 100644
index a128970cbe7..00000000000
--- a/docs/_sass/minima/custom-variables.scss
+++ /dev/null
@@ -1,76 +0,0 @@
-// Placeholder to allow overriding predefined variables smoothly.
-
-//Bootstrap's default
-$white: #fff !default;
-$gray-100: #f8f9fa !default;
-$gray-200: #e9ecef !default;
-$gray-300: #dee2e6 !default;
-$gray-400: #ced4da !default;
-$gray-500: #adb5bd !default;
-$gray-600: #6c757d !default;
-$gray-700: #495057 !default;
-$gray-800: #343a40 !default;
-$gray-900: #212529 !default;
-$black: #000 !default;
-$blue: #0d6efd !default;
-$indigo: #6610f2 !default;
-$purple: #6f42c1 !default;
-$pink: #d63384 !default;
-$red: #dc3545 !default;
-$orange: #fd7e14 !default;
-$yellow: #ffc107 !default;
-$green: #28a745 !default;
-$teal: #20c997 !default;
-$cyan: #17a2b8 !default;
-
-$primary: $blue !default;
-$secondary: $gray-600 !default;
-$success: $green !default;
-$info: $cyan !default;
-$warning: $yellow !default;
-$danger: $red !default;
-$light: $gray-100 !default;
-$dark: $gray-800 !default;
-
-$theme-colors: (
- "primary": $primary,
- "secondary": $secondary,
- "success": $success,
- "info": $info,
- "warning": $warning,
- "danger": $danger,
- "light": $light,
- "dark": $dark
-) !default;
-
-$theme-color-interval: 8% !default;
-
-$body-bg: $white !default;
-$body-color: $gray-900 !default;
-$body-text-align: null !default;
-
-$enable-gradients: true;
-
-// Define alert colors, border radius, and padding.
-$border-radius: .25rem !default;
-$border-width: 1px !default;
-$font-weight-bold: 700 !default;
-
-$alert-padding-y: .75rem !default;
-$alert-padding-x: 1.25rem !default;
-$alert-margin-bottom: 1rem !default;
-$alert-border-radius: $border-radius !default;
-$alert-link-font-weight: $font-weight-bold !default;
-$alert-border-width: $border-width !default;
-
-$alert-bg-level: -10 !default;
-$alert-border-level: -9 !default;
-$alert-color-level: 6 !default;
-
-// Request a color level
-// scss-docs-start color-level
-@function color-level($color: $primary, $level: 0) {
- $color-base: if($level > 0, $black, $white);
- $level: abs($level);
- @return mix($color-base, $color, $level * $theme-color-interval);
-}
diff --git a/docs/_sass/minima/initialize.scss b/docs/_sass/minima/initialize.scss
deleted file mode 100644
index 30288811151..00000000000
--- a/docs/_sass/minima/initialize.scss
+++ /dev/null
@@ -1,51 +0,0 @@
-@charset "utf-8";
-
-// Define defaults for each variable.
-
-$base-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Segoe UI Symbol", "Segoe UI Emoji", "Apple Color Emoji", Roboto, Helvetica, Arial, sans-serif !default;
-$code-font-family: "Menlo", "Inconsolata", "Consolas", "Roboto Mono", "Ubuntu Mono", "Liberation Mono", "Courier New", monospace;
-$base-font-size: 16px !default;
-$base-font-weight: 400 !default;
-$small-font-size: $base-font-size * 0.875 !default;
-$base-line-height: 1.5 !default;
-
-$spacing-unit: 30px !default;
-
-$table-text-align: left !default;
-
-// Width of the content area
-$content-width: 800px !default;
-
-$on-palm: 600px !default;
-$on-laptop: 800px !default;
-
-$on-medium: $on-palm !default;
-$on-large: $on-laptop !default;
-
-// Use media queries like this:
-// @include media-query($on-palm) {
-// .wrapper {
-// padding-right: $spacing-unit / 2;
-// padding-left: $spacing-unit / 2;
-// }
-// }
-// Notice the following mixin uses max-width, in a deprecated, desktop-first
-// approach, whereas media queries used elsewhere now use min-width.
-@mixin media-query($device) {
- @media screen and (max-width: $device) {
- @content;
- }
-}
-
-@mixin relative-font-size($ratio) {
- font-size: #{$ratio}rem;
-}
-
-// Import pre-styling-overrides hook and style-partials.
-@import
- "minima/custom-variables", // Hook to override predefined variables.
- "minima/custom-mixins", // Hook to add custom mixins.
- "minima/base", // Defines element resets.
- "minima/layout", // Defines structure and style based on CSS selectors.
- "minima/custom-styles" // Hook to override existing styles.
-;
diff --git a/docs/_sass/minima/skins/classic.scss b/docs/_sass/minima/skins/classic.scss
deleted file mode 100644
index 37ea9c5244c..00000000000
--- a/docs/_sass/minima/skins/classic.scss
+++ /dev/null
@@ -1,84 +0,0 @@
-@charset "utf-8";
-
-$brand-color: #828282 !default;
-$brand-color-light: lighten($brand-color, 40%) !default;
-$brand-color-dark: darken($brand-color, 25%) !default;
-
-$text-color: #111 !default;
-$background-color: #fdfdfd !default;
-$code-background-color: #eef !default;
-
-$link-base-color: #2a7ae2 !default;
-$link-visited-color: darken($link-base-color, 15%) !default;
-
-$table-text-color: lighten($text-color, 18%) !default;
-$table-zebra-color: lighten($brand-color, 46%) !default;
-$table-header-bg-color: lighten($brand-color, 43%) !default;
-$table-header-border: lighten($brand-color, 36%) !default;
-$table-border-color: $brand-color-light !default;
-
-
-// Syntax highlighting styles should be adjusted appropriately for every "skin"
-// ----------------------------------------------------------------------------
-
-.highlight {
- .c { color: #998; font-style: italic } // Comment
- .err { color: #a61717; background-color: #e3d2d2 } // Error
- .k { font-weight: bold } // Keyword
- .o { font-weight: bold } // Operator
- .cm { color: #998; font-style: italic } // Comment.Multiline
- .cp { color: #999; font-weight: bold } // Comment.Preproc
- .c1 { color: #998; font-style: italic } // Comment.Single
- .cs { color: #999; font-weight: bold; font-style: italic } // Comment.Special
- .gd { color: #000; background-color: #fdd } // Generic.Deleted
- .gd .x { color: #000; background-color: #faa } // Generic.Deleted.Specific
- .ge { font-style: italic } // Generic.Emph
- .gr { color: #a00 } // Generic.Error
- .gh { color: #999 } // Generic.Heading
- .gi { color: #000; background-color: #dfd } // Generic.Inserted
- .gi .x { color: #000; background-color: #afa } // Generic.Inserted.Specific
- .go { color: #888 } // Generic.Output
- .gp { color: #555 } // Generic.Prompt
- .gs { font-weight: bold } // Generic.Strong
- .gu { color: #aaa } // Generic.Subheading
- .gt { color: #a00 } // Generic.Traceback
- .kc { font-weight: bold } // Keyword.Constant
- .kd { font-weight: bold } // Keyword.Declaration
- .kp { font-weight: bold } // Keyword.Pseudo
- .kr { font-weight: bold } // Keyword.Reserved
- .kt { color: #458; font-weight: bold } // Keyword.Type
- .m { color: #099 } // Literal.Number
- .s { color: #d14 } // Literal.String
- .na { color: #008080 } // Name.Attribute
- .nb { color: #0086B3 } // Name.Builtin
- .nc { color: #458; font-weight: bold } // Name.Class
- .no { color: #008080 } // Name.Constant
- .ni { color: #800080 } // Name.Entity
- .ne { color: #900; font-weight: bold } // Name.Exception
- .nf { color: #900; font-weight: bold } // Name.Function
- .nn { color: #555 } // Name.Namespace
- .nt { color: #000080 } // Name.Tag
- .nv { color: #008080 } // Name.Variable
- .ow { font-weight: bold } // Operator.Word
- .w { color: #bbb } // Text.Whitespace
- .mf { color: #099 } // Literal.Number.Float
- .mh { color: #099 } // Literal.Number.Hex
- .mi { color: #099 } // Literal.Number.Integer
- .mo { color: #099 } // Literal.Number.Oct
- .sb { color: #d14 } // Literal.String.Backtick
- .sc { color: #d14 } // Literal.String.Char
- .sd { color: #d14 } // Literal.String.Doc
- .s2 { color: #d14 } // Literal.String.Double
- .se { color: #d14 } // Literal.String.Escape
- .sh { color: #d14 } // Literal.String.Heredoc
- .si { color: #d14 } // Literal.String.Interpol
- .sx { color: #d14 } // Literal.String.Other
- .sr { color: #009926 } // Literal.String.Regex
- .s1 { color: #d14 } // Literal.String.Single
- .ss { color: #990073 } // Literal.String.Symbol
- .bp { color: #999 } // Name.Builtin.Pseudo
- .vc { color: #008080 } // Name.Variable.Class
- .vg { color: #008080 } // Name.Variable.Global
- .vi { color: #008080 } // Name.Variable.Instance
- .il { color: #099 } // Literal.Number.Integer.Long
-}
diff --git a/docs/_sass/minima/skins/solarized-dark.scss b/docs/_sass/minima/skins/solarized-dark.scss
deleted file mode 100644
index f3b1f387de0..00000000000
--- a/docs/_sass/minima/skins/solarized-dark.scss
+++ /dev/null
@@ -1,4 +0,0 @@
-@charset "utf-8";
-
-$sol-is-dark: true;
-@import "minima/skins/solarized";
diff --git a/docs/_sass/minima/skins/solarized.scss b/docs/_sass/minima/skins/solarized.scss
deleted file mode 100644
index 982bd7f2990..00000000000
--- a/docs/_sass/minima/skins/solarized.scss
+++ /dev/null
@@ -1,133 +0,0 @@
-@charset "utf-8";
-
-// Solarized skin
-// ==============
-// Created by Sander Voerman using the Solarized
-// color scheme by Ethan Schoonover .
-
-// This style sheet implements two options for the minima.skin setting:
-// "solarized" for light mode and "solarized-dark" for dark mode.
-$sol-is-dark: false !default;
-
-
-// Color scheme
-// ------------
-// The inline comments show the canonical L*a*b values for each color.
-
-$sol-base03: #002b36; // 15 -12 -12
-$sol-base02: #073642; // 20 -12 -12
-$sol-base01: #586e75; // 45 -07 -07
-$sol-base00: #657b83; // 50 -07 -07
-$sol-base0: #839496; // 60 -06 -03
-$sol-base1: #93a1a1; // 65 -05 -02
-$sol-base2: #eee8d5; // 92 -00 10
-$sol-base3: #fdf6e3; // 97 00 10
-$sol-yellow: #b58900; // 60 10 65
-$sol-orange: #cb4b16; // 50 50 55
-$sol-red: #dc322f; // 50 65 45
-$sol-magenta: #d33682; // 50 65 -05
-$sol-violet: #6c71c4; // 50 15 -45
-$sol-blue: #268bd2; // 55 -10 -45
-$sol-cyan: #2aa198; // 60 -35 -05
-$sol-green: #859900; // 60 -20 65
-
-$sol-mono3: $sol-base3;
-$sol-mono2: $sol-base2;
-$sol-mono1: $sol-base1;
-$sol-mono00: $sol-base00;
-$sol-mono01: $sol-base01;
-
-@if $sol-is-dark {
- $sol-mono3: $sol-base03;
- $sol-mono2: $sol-base02;
- $sol-mono1: $sol-base01;
- $sol-mono00: $sol-base0;
- $sol-mono01: $sol-base1;
-}
-
-
-// Minima color variables
-// ----------------------
-
-$brand-color: $sol-mono1 !default;
-$brand-color-light: mix($sol-mono1, $sol-mono3) !default;
-$brand-color-dark: $sol-mono00 !default;
-
-$text-color: $sol-mono01 !default;
-$background-color: $sol-mono3 !default;
-$code-background-color: $sol-mono2 !default;
-
-$link-base-color: $sol-blue !default;
-$link-visited-color: mix($sol-blue, $sol-mono00) !default;
-
-$table-text-color: $sol-mono00 !default;
-$table-zebra-color: mix($sol-mono2, $sol-mono3) !default;
-$table-header-bg-color: $sol-mono2 !default;
-$table-header-border: $sol-mono1 !default;
-$table-border-color: $sol-mono1 !default;
-
-
-// Syntax highlighting styles
-// --------------------------
-
-.highlight {
- .c { color: $sol-mono1; font-style: italic } // Comment
- .err { color: $sol-red } // Error
- .k { color: $sol-mono01; font-weight: bold } // Keyword
- .o { color: $sol-mono01; font-weight: bold } // Operator
- .cm { color: $sol-mono1; font-style: italic } // Comment.Multiline
- .cp { color: $sol-mono1; font-weight: bold } // Comment.Preproc
- .c1 { color: $sol-mono1; font-style: italic } // Comment.Single
- .cs { color: $sol-mono1; font-weight: bold; font-style: italic } // Comment.Special
- .gd { color: $sol-red } // Generic.Deleted
- .gd .x { color: $sol-red } // Generic.Deleted.Specific
- .ge { color: $sol-mono00; font-style: italic } // Generic.Emph
- .gr { color: $sol-red } // Generic.Error
- .gh { color: $sol-mono1 } // Generic.Heading
- .gi { color: $sol-green } // Generic.Inserted
- .gi .x { color: $sol-green } // Generic.Inserted.Specific
- .go { color: $sol-mono00 } // Generic.Output
- .gp { color: $sol-mono00 } // Generic.Prompt
- .gs { color: $sol-mono01; font-weight: bold } // Generic.Strong
- .gu { color: $sol-mono1 } // Generic.Subheading
- .gt { color: $sol-red } // Generic.Traceback
- .kc { color: $sol-mono01; font-weight: bold } // Keyword.Constant
- .kd { color: $sol-mono01; font-weight: bold } // Keyword.Declaration
- .kp { color: $sol-mono01; font-weight: bold } // Keyword.Pseudo
- .kr { color: $sol-mono01; font-weight: bold } // Keyword.Reserved
- .kt { color: $sol-violet; font-weight: bold } // Keyword.Type
- .m { color: $sol-cyan } // Literal.Number
- .s { color: $sol-magenta } // Literal.String
- .na { color: $sol-cyan } // Name.Attribute
- .nb { color: $sol-blue } // Name.Builtin
- .nc { color: $sol-violet; font-weight: bold } // Name.Class
- .no { color: $sol-cyan } // Name.Constant
- .ni { color: $sol-violet } // Name.Entity
- .ne { color: $sol-violet; font-weight: bold } // Name.Exception
- .nf { color: $sol-blue; font-weight: bold } // Name.Function
- .nn { color: $sol-mono00 } // Name.Namespace
- .nt { color: $sol-blue } // Name.Tag
- .nv { color: $sol-cyan } // Name.Variable
- .ow { color: $sol-mono01; font-weight: bold } // Operator.Word
- .w { color: $sol-mono1 } // Text.Whitespace
- .mf { color: $sol-cyan } // Literal.Number.Float
- .mh { color: $sol-cyan } // Literal.Number.Hex
- .mi { color: $sol-cyan } // Literal.Number.Integer
- .mo { color: $sol-cyan } // Literal.Number.Oct
- .sb { color: $sol-magenta } // Literal.String.Backtick
- .sc { color: $sol-magenta } // Literal.String.Char
- .sd { color: $sol-magenta } // Literal.String.Doc
- .s2 { color: $sol-magenta } // Literal.String.Double
- .se { color: $sol-magenta } // Literal.String.Escape
- .sh { color: $sol-magenta } // Literal.String.Heredoc
- .si { color: $sol-magenta } // Literal.String.Interpol
- .sx { color: $sol-magenta } // Literal.String.Other
- .sr { color: $sol-green } // Literal.String.Regex
- .s1 { color: $sol-magenta } // Literal.String.Single
- .ss { color: $sol-magenta } // Literal.String.Symbol
- .bp { color: $sol-mono1 } // Name.Builtin.Pseudo
- .vc { color: $sol-cyan } // Name.Variable.Class
- .vg { color: $sol-cyan } // Name.Variable.Global
- .vi { color: $sol-cyan } // Name.Variable.Instance
- .il { color: $sol-cyan } // Literal.Number.Integer.Long
-}
diff --git a/docs/assets/css/style.scss b/docs/assets/css/style.scss
deleted file mode 100644
index b5ec6976efa..00000000000
--- a/docs/assets/css/style.scss
+++ /dev/null
@@ -1,12 +0,0 @@
----
-# Only the main Sass file needs front matter (the dashes are enough)
----
-
-@import
- "minima/skins/{{ site.minima.skin | default: 'classic' }}",
- "minima/initialize";
-
-.icon {
- height: 21px;
- width: 21px
-}
diff --git a/docs/diagrams/ArchitectureSequenceDiagram.puml b/docs/diagrams/ArchitectureSequenceDiagram.puml
index 48b6cc4333c..bc8392e3cd6 100644
--- a/docs/diagrams/ArchitectureSequenceDiagram.puml
+++ b/docs/diagrams/ArchitectureSequenceDiagram.puml
@@ -14,13 +14,14 @@ activate ui UI_COLOR
ui -[UI_COLOR]> logic : execute("delete 1")
activate logic LOGIC_COLOR
-logic -[LOGIC_COLOR]> model : deletePerson(p)
+logic -[LOGIC_COLOR]> model : deletePatient(p)
activate model MODEL_COLOR
model -[MODEL_COLOR]-> logic
deactivate model
-logic -[LOGIC_COLOR]> storage : saveAddressBook(addressBook)
+logic -[LOGIC_COLOR]> storage : savePatientList(patientList)
+
activate storage STORAGE_COLOR
storage -[STORAGE_COLOR]> storage : Save to file
diff --git a/docs/diagrams/BetterModelClassDiagram.puml b/docs/diagrams/BetterModelClassDiagram.puml
deleted file mode 100644
index 598474a5c82..00000000000
--- a/docs/diagrams/BetterModelClassDiagram.puml
+++ /dev/null
@@ -1,21 +0,0 @@
-@startuml
-!include style.puml
-skinparam arrowThickness 1.1
-skinparam arrowColor MODEL_COLOR
-skinparam classBackgroundColor MODEL_COLOR
-
-AddressBook *-right-> "1" UniquePersonList
-AddressBook *-right-> "1" UniqueTagList
-UniqueTagList -[hidden]down- UniquePersonList
-UniqueTagList -[hidden]down- UniquePersonList
-
-UniqueTagList -right-> "*" Tag
-UniquePersonList -right-> Person
-
-Person -up-> "*" Tag
-
-Person *--> Name
-Person *--> Phone
-Person *--> Email
-Person *--> Address
-@enduml
diff --git a/docs/diagrams/DeleteSequenceDiagram.puml b/docs/diagrams/DeleteSequenceDiagram.puml
deleted file mode 100644
index 5241e79d7da..00000000000
--- a/docs/diagrams/DeleteSequenceDiagram.puml
+++ /dev/null
@@ -1,70 +0,0 @@
-@startuml
-!include style.puml
-skinparam ArrowFontStyle plain
-
-box Logic LOGIC_COLOR_T1
-participant ":LogicManager" as LogicManager LOGIC_COLOR
-participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR
-participant ":DeleteCommandParser" as DeleteCommandParser LOGIC_COLOR
-participant "d:DeleteCommand" as DeleteCommand LOGIC_COLOR
-participant "r:CommandResult" as CommandResult LOGIC_COLOR
-end box
-
-box Model MODEL_COLOR_T1
-participant "m:Model" as Model MODEL_COLOR
-end box
-
-[-> LogicManager : execute("delete 1")
-activate LogicManager
-
-LogicManager -> AddressBookParser : parseCommand("delete 1")
-activate AddressBookParser
-
-create DeleteCommandParser
-AddressBookParser -> DeleteCommandParser
-activate DeleteCommandParser
-
-DeleteCommandParser --> AddressBookParser
-deactivate DeleteCommandParser
-
-AddressBookParser -> DeleteCommandParser : parse("1")
-activate DeleteCommandParser
-
-create DeleteCommand
-DeleteCommandParser -> DeleteCommand
-activate DeleteCommand
-
-DeleteCommand --> DeleteCommandParser :
-deactivate DeleteCommand
-
-DeleteCommandParser --> AddressBookParser : d
-deactivate DeleteCommandParser
-'Hidden arrow to position the destroy marker below the end of the activation bar.
-DeleteCommandParser -[hidden]-> AddressBookParser
-destroy DeleteCommandParser
-
-AddressBookParser --> LogicManager : d
-deactivate AddressBookParser
-
-LogicManager -> DeleteCommand : execute(m)
-activate DeleteCommand
-
-DeleteCommand -> Model : deletePerson(1)
-activate Model
-
-Model --> DeleteCommand
-deactivate Model
-
-create CommandResult
-DeleteCommand -> CommandResult
-activate CommandResult
-
-CommandResult --> DeleteCommand
-deactivate CommandResult
-
-DeleteCommand --> LogicManager : r
-deactivate DeleteCommand
-
-[<--LogicManager
-deactivate LogicManager
-@enduml
diff --git a/docs/diagrams/FindActivityDiagram.puml b/docs/diagrams/FindActivityDiagram.puml
new file mode 100644
index 00000000000..e92f1914515
--- /dev/null
+++ b/docs/diagrams/FindActivityDiagram.puml
@@ -0,0 +1,25 @@
+@startuml
+skin rose
+skinparam ActivityFontSize 15
+skinparam ArrowFontSize 12
+start
+:Execute parse method of FindCommandParser;
+:Generate ArgumentMultimap;
+
+'Since the beta syntax does not support placing the condition outside the
+'diamond we place it as the true branch instead.
+
+if () then ([argument contains "n/"])
+ :Set NameContainsKeywordPredicate;
+else ([else])
+ :Set PREDICATE_SHOW_ALL_PATIENTS;
+endif
+
+if () then ([argument contains "p/"])
+ :Set PhoneMatchesPredicate;
+else ([else])
+ :Set PREDICATE_SHOW_ALL_PATIENTS;
+endif
+:Return FindCommand;
+stop
+@enduml
diff --git a/docs/diagrams/FindSequenceDiagram.puml b/docs/diagrams/FindSequenceDiagram.puml
new file mode 100644
index 00000000000..86d71ecb4b2
--- /dev/null
+++ b/docs/diagrams/FindSequenceDiagram.puml
@@ -0,0 +1,70 @@
+@startuml
+!include style.puml
+skinparam ArrowFontStyle plain
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":InputParser" as InputParser LOGIC_COLOR
+participant ":FindCommandParser" as FindCommandParser LOGIC_COLOR
+participant "f:FindCommand" as FindCommand LOGIC_COLOR
+participant "r:CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant "m:Model" as Model MODEL_COLOR
+end box
+
+[-> LogicManager : execute("find n/Bob")
+activate LogicManager
+
+LogicManager -> InputParser : parseCommand("find n/Bob")
+activate InputParser
+
+create FindCommandParser
+InputParser -> FindCommandParser
+activate FindCommandParser
+
+FindCommandParser --> InputParser
+deactivate FindCommandParser
+
+InputParser -> FindCommandParser : parse("n/Bob")
+activate FindCommandParser
+
+create FindCommand
+FindCommandParser -> FindCommand
+activate FindCommand
+
+FindCommand --> FindCommandParser :
+deactivate FindCommand
+
+FindCommandParser --> InputParser : f
+deactivate FindCommandParser
+'Hidden arrow to position the destroy marker below the end of the activation bar.
+FindCommandParser -[hidden]-> InputParser
+destroy FindCommandParser
+
+InputParser --> LogicManager : f
+deactivate InputParser
+
+LogicManager -> FindCommand : execute(m)
+activate FindCommand
+
+FindCommand -> Model : updateFilteredPatientList(namePredicate)
+activate Model
+
+Model --> FindCommand
+deactivate Model
+
+create CommandResult
+FindCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> FindCommand
+deactivate CommandResult
+
+FindCommand --> LogicManager : r
+deactivate FindCommand
+
+[<--LogicManager : r
+deactivate LogicManager
+@enduml
diff --git a/docs/diagrams/ForceDeleteAllSequenceDiagram-Logic.puml b/docs/diagrams/ForceDeleteAllSequenceDiagram-Logic.puml
new file mode 100644
index 00000000000..a16929d5c04
--- /dev/null
+++ b/docs/diagrams/ForceDeleteAllSequenceDiagram-Logic.puml
@@ -0,0 +1,46 @@
+@startuml
+!include style.puml
+skinparam ArrowFontStyle plain
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":InputParser" as InputParser LOGIC_COLOR
+participant "f:ForceDeleteAllCommand" as ForceDeleteAllCommand LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant ":Model" as Model MODEL_COLOR
+end box
+[-> LogicManager : execute(delete-all-f)
+activate LogicManager
+
+LogicManager -> InputParser : parseCommand(delete-all-f)
+activate InputParser
+
+create ForceDeleteAllCommand
+InputParser -> ForceDeleteAllCommand
+activate ForceDeleteAllCommand
+
+ForceDeleteAllCommand --> InputParser
+deactivate ForceDeleteAllCommand
+
+InputParser --> LogicManager : f
+deactivate InputParser
+
+LogicManager -> ForceDeleteAllCommand : execute()
+activate ForceDeleteAllCommand
+
+ForceDeleteAllCommand -> Model : setPatientList()
+activate Model
+
+Model --> ForceDeleteAllCommand
+deactivate Model
+
+ForceDeleteAllCommand --> LogicManager : result
+deactivate ForceDeleteAllCommand
+ForceDeleteAllCommand -[hidden]-> LogicManager : result
+destroy ForceDeleteAllCommand
+
+[<--LogicManager
+deactivate LogicManager
+@enduml
diff --git a/docs/diagrams/ListAlphabeticalSequenceDiagram.puml b/docs/diagrams/ListAlphabeticalSequenceDiagram.puml
new file mode 100644
index 00000000000..9ece6ab824b
--- /dev/null
+++ b/docs/diagrams/ListAlphabeticalSequenceDiagram.puml
@@ -0,0 +1,47 @@
+@startuml
+!include style.puml
+skinparam ArrowFontStyle plain
+
+box Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":InputParser" as InputParser LOGIC_COLOR
+participant "f:ListAlphabeticalCommand" as ListAlphabeticalCommand LOGIC_COLOR
+participant ":CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant ":Model" as Model MODEL_COLOR
+end box
+
+[-> LogicManager : execute("list-a")
+activate LogicManager
+
+LogicManager -> InputParser : parseCommand("list-a")
+activate InputParser
+
+create ListAlphabeticalCommand
+InputParser -> ListAlphabeticalCommand
+activate ListAlphabeticalCommand
+
+ListAlphabeticalCommand -> Model : updateFilteredPatientList
+
+Model -> ListAlphabeticalCommand : (patient1, patient2)
+ListAlphabeticalCommand --> Model
+Model --> ListAlphabeticalCommand
+ListAlphabeticalCommand -> Model: deletePatient
+Model --> ListAlphabeticalCommand
+ListAlphabeticalCommand -> Model: addPatient
+Model --> ListAlphabeticalCommand
+
+ListAlphabeticalCommand -> CommandResult: CommandResult(MESSAGE_SUCCESS)
+
+CommandResult --> ListAlphabeticalCommand
+deactivate CommandResult
+
+ListAlphabeticalCommand --> LogicManager : r
+deactivate ListAlphabeticalCommand
+
+[<--LogicManager
+deactivate LogicManager
+@enduml
+
diff --git a/docs/diagrams/ModelClassDiagram.puml b/docs/diagrams/ModelClassDiagram.puml
index 0de5673070d..9d7e223f55d 100644
--- a/docs/diagrams/ModelClassDiagram.puml
+++ b/docs/diagrams/ModelClassDiagram.puml
@@ -5,20 +5,25 @@ skinparam arrowColor MODEL_COLOR
skinparam classBackgroundColor MODEL_COLOR
Package Model as ModelPackage <>{
-Class "<>\nReadOnlyAddressBook" as ReadOnlyAddressBook
+Class "<>\nReadOnlyPatientList" as ReadOnlyPatientList
Class "<>\nReadOnlyUserPrefs" as ReadOnlyUserPrefs
Class "<>\nModel" as Model
-Class AddressBook
+Class PatientList
Class ModelManager
Class UserPrefs
-Class UniquePersonList
-Class Person
+Class UniquePatientList
+Class Patient
Class Address
Class Email
Class Name
Class Phone
-Class Tag
+Class DateOfBirth
+Class Sex
+Class Appointment
+Class UniqueVisitList
+Class SexOption
+
Class I #FFFFFF
}
@@ -26,29 +31,39 @@ Class I #FFFFFF
Class HiddenOutside #FFFFFF
HiddenOutside ..> Model
-AddressBook .up.|> ReadOnlyAddressBook
+PatientList .up.|> ReadOnlyPatientList
ModelManager .up.|> Model
Model .right.> ReadOnlyUserPrefs
-Model .left.> ReadOnlyAddressBook
-ModelManager -left-> "1" AddressBook
+Model .left.> ReadOnlyPatientList
+ModelManager -left-> "1" PatientList
ModelManager -right-> "1" UserPrefs
UserPrefs .up.|> ReadOnlyUserPrefs
-AddressBook *--> "1" UniquePersonList
-UniquePersonList --> "~* all" Person
-Person *--> Name
-Person *--> Phone
-Person *--> Email
-Person *--> Address
-Person *--> "*" Tag
+PatientList *--> "1" UniquePatientList
+UniquePatientList --> "~* all" Patient
+Patient *--> Name
+Patient *--> Phone
+Patient *--> Email
+Patient *--> Address
+Patient *--> DateOfBirth
+Patient *--> Sex
+Patient *--> Appointment
+
+Patient *-right-> "1"UniqueVisitList
+Sex *--> SexOption
-Person -[hidden]up--> I
-UniquePersonList -[hidden]right-> I
+Patient -[hidden]up--> I
+UniquePatientList -[hidden]right-> I
Name -[hidden]right-> Phone
-Phone -[hidden]right-> Address
-Address -[hidden]right-> Email
+Phone -[hidden]right-> Email
+Email -[hidden]right-> Address
+Address -[hidden]right-> DateOfBirth
+DateOfBirth -[hidden]right-> Sex
+Sex -[hidden]right-> Appointment
+Appointment -[hidden]up-> UniqueVisitList
+
-ModelManager --> "~* filtered" Person
+ModelManager --> "~* filtered" Patient
@enduml
diff --git a/docs/diagrams/ParserClasses.puml b/docs/diagrams/ParserClasses.puml
index ce4c5ce8c8d..6c17c32ef96 100644
--- a/docs/diagrams/ParserClasses.puml
+++ b/docs/diagrams/ParserClasses.puml
@@ -9,7 +9,7 @@ Class XYZCommand
package "Parser classes"{
Class "<>\nParser" as Parser
-Class AddressBookParser
+Class InputParser
Class XYZCommandParser
Class CliSyntax
Class ParserUtil
@@ -19,12 +19,12 @@ Class Prefix
}
Class HiddenOutside #FFFFFF
-HiddenOutside ..> AddressBookParser
+HiddenOutside ..> InputParser
-AddressBookParser .down.> XYZCommandParser: <>
+InputParser .down.> XYZCommandParser: <>
XYZCommandParser ..> XYZCommand : <>
-AddressBookParser ..> Command : <>
+InputParser ..> Command : <>
XYZCommandParser .up.|> Parser
XYZCommandParser ..> ArgumentMultimap
XYZCommandParser ..> ArgumentTokenizer
diff --git a/docs/diagrams/StorageClassDiagram.puml b/docs/diagrams/StorageClassDiagram.puml
index a821e06458c..1a14916c0eb 100644
--- a/docs/diagrams/StorageClassDiagram.puml
+++ b/docs/diagrams/StorageClassDiagram.puml
@@ -14,12 +14,12 @@ Class JsonUserPrefsStorage
Class "<>\nStorage" as Storage
Class StorageManager
-package "AddressBook Storage" #F4F6F6{
-Class "<>\nAddressBookStorage" as AddressBookStorage
-Class JsonAddressBookStorage
-Class JsonSerializableAddressBook
-Class JsonAdaptedPerson
-Class JsonAdaptedTag
+package "PatientList Storage" #F4F6F6{
+Class "<>\nPatientListStorage" as PatientListStorage
+Class JsonPatientListStorage
+Class JsonSerializablePatientList
+Class JsonAdaptedPatient
+Class JsonAdaptedVisit
}
}
@@ -29,15 +29,17 @@ HiddenOutside ..> Storage
StorageManager .up.|> Storage
StorageManager -up-> "1" UserPrefsStorage
-StorageManager -up-> "1" AddressBookStorage
+
+StorageManager -up-> "1" PatientListStorage
Storage -left-|> UserPrefsStorage
-Storage -right-|> AddressBookStorage
+Storage -right-|> PatientListStorage
JsonUserPrefsStorage .up.|> UserPrefsStorage
-JsonAddressBookStorage .up.|> AddressBookStorage
-JsonAddressBookStorage ..> JsonSerializableAddressBook
-JsonSerializableAddressBook --> "*" JsonAdaptedPerson
-JsonAdaptedPerson --> "*" JsonAdaptedTag
+JsonPatientListStorage .up.|> PatientListStorage
+
+JsonPatientListStorage ..> JsonSerializablePatientList
+JsonSerializablePatientList --> "*" JsonAdaptedPatient
+JsonAdaptedPatient --> "*" JsonAdaptedVisit
@enduml
diff --git a/docs/diagrams/UiClassDiagram.puml b/docs/diagrams/UiClassDiagram.puml
index 95473d5aa19..67b8177c240 100644
--- a/docs/diagrams/UiClassDiagram.puml
+++ b/docs/diagrams/UiClassDiagram.puml
@@ -11,8 +11,8 @@ Class UiManager
Class MainWindow
Class HelpWindow
Class ResultDisplay
-Class PersonListPanel
-Class PersonCard
+Class PatientListPanel
+Class PatientCard
Class StatusBarFooter
Class CommandBox
}
@@ -32,26 +32,26 @@ UiManager .left.|> Ui
UiManager -down-> "1" MainWindow
MainWindow *-down-> "1" CommandBox
MainWindow *-down-> "1" ResultDisplay
-MainWindow *-down-> "1" PersonListPanel
+MainWindow *-down-> "1" PatientListPanel
MainWindow *-down-> "1" StatusBarFooter
MainWindow --> "0..1" HelpWindow
-PersonListPanel -down-> "*" PersonCard
+PatientListPanel -down-> "*" PatientCard
MainWindow -left-|> UiPart
ResultDisplay --|> UiPart
CommandBox --|> UiPart
-PersonListPanel --|> UiPart
-PersonCard --|> UiPart
+PatientListPanel --|> UiPart
+PatientCard --|> UiPart
StatusBarFooter --|> UiPart
HelpWindow --|> UiPart
-PersonCard ..> Model
+PatientCard ..> Model
UiManager -right-> Logic
MainWindow -left-> Logic
-PersonListPanel -[hidden]left- HelpWindow
+PatientListPanel -[hidden]left- HelpWindow
HelpWindow -[hidden]left- CommandBox
CommandBox -[hidden]left- ResultDisplay
ResultDisplay -[hidden]left- StatusBarFooter
diff --git a/docs/diagrams/UndoRedoState0.puml b/docs/diagrams/UndoRedoState0.puml
deleted file mode 100644
index 43a45903ac9..00000000000
--- a/docs/diagrams/UndoRedoState0.puml
+++ /dev/null
@@ -1,21 +0,0 @@
-@startuml
-!include style.puml
-skinparam ClassFontColor #000000
-skinparam ClassBorderColor #000000
-skinparam ClassBackgroundColor #FFFFAA
-
-title Initial state
-
-package States {
- class State1 as "ab0:AddressBook "
- class State2 as "ab1:AddressBook "
- class State3 as "ab2:AddressBook "
-}
-State1 -[hidden]right-> State2
-State2 -[hidden]right-> State3
-hide State2
-hide State3
-
-class Pointer as "Current State" #FFFFFF
-Pointer -up-> State1
-@end
diff --git a/docs/diagrams/UndoRedoState1.puml b/docs/diagrams/UndoRedoState1.puml
deleted file mode 100644
index 5a41e9e1651..00000000000
--- a/docs/diagrams/UndoRedoState1.puml
+++ /dev/null
@@ -1,23 +0,0 @@
-@startuml
-!include style.puml
-skinparam ClassFontColor #000000
-skinparam ClassBorderColor #000000
-skinparam ClassBackgroundColor #FFFFAA
-
-title After command "delete 5"
-
-package States <> {
- class State1 as "ab0:AddressBook "
- class State2 as "ab1:AddressBook "
- class State3 as "ab2:AddressBook "
-}
-
-State1 -[hidden]right-> State2
-State2 -[hidden]right-> State3
-
-hide State3
-
-class Pointer as "Current State" #FFFFFF
-
-Pointer -up-> State2
-@end
diff --git a/docs/diagrams/UndoRedoState2.puml b/docs/diagrams/UndoRedoState2.puml
deleted file mode 100644
index ad32fce1b0b..00000000000
--- a/docs/diagrams/UndoRedoState2.puml
+++ /dev/null
@@ -1,21 +0,0 @@
-@startuml
-!include style.puml
-skinparam ClassFontColor #000000
-skinparam ClassBorderColor #000000
-skinparam ClassBackgroundColor #FFFFAA
-
-title After command "add n/David"
-
-package States <> {
- class State1 as "ab0:AddressBook "
- class State2 as "ab1:AddressBook "
- class State3 as "ab2:AddressBook "
-}
-
-State1 -[hidden]right-> State2
-State2 -[hidden]right-> State3
-
-class Pointer as "Current State" #FFFFFF
-
-Pointer -up-> State3
-@end
diff --git a/docs/diagrams/UndoRedoState3.puml b/docs/diagrams/UndoRedoState3.puml
deleted file mode 100644
index 9187a690036..00000000000
--- a/docs/diagrams/UndoRedoState3.puml
+++ /dev/null
@@ -1,21 +0,0 @@
-@startuml
-!include style.puml
-skinparam ClassFontColor #000000
-skinparam ClassBorderColor #000000
-skinparam ClassBackgroundColor #FFFFAA
-
-title After command "undo"
-
-package States <> {
- class State1 as "ab0:AddressBook "
- class State2 as "ab1:AddressBook "
- class State3 as "ab2:AddressBook "
-}
-
-State1 -[hidden]right-> State2
-State2 -[hidden]right-> State3
-
-class Pointer as "Current State" #FFFFFF
-
-Pointer -up-> State2
-@end
diff --git a/docs/diagrams/UndoRedoState4.puml b/docs/diagrams/UndoRedoState4.puml
deleted file mode 100644
index 2bc631ffcd0..00000000000
--- a/docs/diagrams/UndoRedoState4.puml
+++ /dev/null
@@ -1,21 +0,0 @@
-@startuml
-!include style.puml
-skinparam ClassFontColor #000000
-skinparam ClassBorderColor #000000
-skinparam ClassBackgroundColor #FFFFAA
-
-title After command "list"
-
-package States <> {
- class State1 as "ab0:AddressBook "
- class State2 as "ab1:AddressBook "
- class State3 as "ab2:AddressBook "
-}
-
-State1 -[hidden]right-> State2
-State2 -[hidden]right-> State3
-
-class Pointer as "Current State" #FFFFFF
-
-Pointer -up-> State2
-@end
diff --git a/docs/diagrams/UndoRedoState5.puml b/docs/diagrams/UndoRedoState5.puml
deleted file mode 100644
index e77b04104aa..00000000000
--- a/docs/diagrams/UndoRedoState5.puml
+++ /dev/null
@@ -1,22 +0,0 @@
-@startuml
-!include style.puml
-skinparam ClassFontColor #000000
-skinparam ClassBorderColor #000000
-skinparam ClassBackgroundColor #FFFFAA
-
-title After command "clear"
-
-package States <> {
- class State1 as "ab0:AddressBook "
- class State2 as "ab1:AddressBook "
- class State3 as "ab3:AddressBook "
-}
-
-State1 -[hidden]right-> State2
-State2 -[hidden]right-> State3
-
-class Pointer as "Current State" #FFFFFF
-
-Pointer -up-> State3
-note right on link: State ab2 deleted.
-@end
diff --git a/docs/diagrams/UndoSequenceDiagram-Logic.puml b/docs/diagrams/UndoSequenceDiagram-Logic.puml
deleted file mode 100644
index e57368c5159..00000000000
--- a/docs/diagrams/UndoSequenceDiagram-Logic.puml
+++ /dev/null
@@ -1,46 +0,0 @@
-@startuml
-!include style.puml
-skinparam ArrowFontStyle plain
-
-box Logic LOGIC_COLOR_T1
-participant ":LogicManager" as LogicManager LOGIC_COLOR
-participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR
-participant "u:UndoCommand" as UndoCommand LOGIC_COLOR
-end box
-
-box Model MODEL_COLOR_T1
-participant ":Model" as Model MODEL_COLOR
-end box
-[-> LogicManager : execute(undo)
-activate LogicManager
-
-LogicManager -> AddressBookParser : parseCommand(undo)
-activate AddressBookParser
-
-create UndoCommand
-AddressBookParser -> UndoCommand
-activate UndoCommand
-
-UndoCommand --> AddressBookParser
-deactivate UndoCommand
-
-AddressBookParser --> LogicManager : u
-deactivate AddressBookParser
-
-LogicManager -> UndoCommand : execute()
-activate UndoCommand
-
-UndoCommand -> Model : undoAddressBook()
-activate Model
-
-Model --> UndoCommand
-deactivate Model
-
-UndoCommand --> LogicManager : result
-deactivate UndoCommand
-UndoCommand -[hidden]-> LogicManager : result
-destroy UndoCommand
-
-[<--LogicManager
-deactivate LogicManager
-@enduml
diff --git a/docs/diagrams/UndoSequenceDiagram-Model.puml b/docs/diagrams/UndoSequenceDiagram-Model.puml
deleted file mode 100644
index 54d83208cb8..00000000000
--- a/docs/diagrams/UndoSequenceDiagram-Model.puml
+++ /dev/null
@@ -1,23 +0,0 @@
-@startuml
-!include style.puml
-skinparam ArrowFontStyle plain
-
-box Model MODEL_COLOR_T1
-participant ":Model" as Model MODEL_COLOR
-participant ":VersionedAddressBook" as VersionedAddressBook MODEL_COLOR
-end box
-
-[-> Model : undoAddressBook()
-activate Model
-
-Model -> VersionedAddressBook : undo()
-activate VersionedAddressBook
-
-VersionedAddressBook -> VersionedAddressBook :resetData(ReadOnlyAddressBook)
-VersionedAddressBook --> Model :
-deactivate VersionedAddressBook
-
-[<-- Model
-deactivate Model
-
-@enduml
diff --git a/docs/diagrams/VisitModelClassDiagram.puml b/docs/diagrams/VisitModelClassDiagram.puml
new file mode 100644
index 00000000000..db6141f8708
--- /dev/null
+++ b/docs/diagrams/VisitModelClassDiagram.puml
@@ -0,0 +1,14 @@
+@startuml
+!include style.puml
+skinparam arrowThickness 1.1
+skinparam arrowColor MODEL_COLOR
+skinparam classBackgroundColor MODEL_COLOR
+
+Patient *--> "1" UniqueVisitList
+
+UniqueVisitList -down->"*" Visit
+
+Visit *--> "1"Condition
+Visit *--> "1"Severity
+Visit *--> "1"DateOfVisit
+@enduml
diff --git a/docs/diagrams/tracing/LogicSequenceDiagram.puml b/docs/diagrams/tracing/LogicSequenceDiagram.puml
index 42bf46d3ce8..76d1fd43db3 100644
--- a/docs/diagrams/tracing/LogicSequenceDiagram.puml
+++ b/docs/diagrams/tracing/LogicSequenceDiagram.puml
@@ -3,20 +3,20 @@
skinparam ArrowFontStyle plain
Participant ":LogicManager" as logic LOGIC_COLOR
-Participant ":AddressBookParser" as abp LOGIC_COLOR
+Participant ":InputParser" as ip LOGIC_COLOR
Participant ":EditCommandParser" as ecp LOGIC_COLOR
Participant "command:EditCommand" as ec LOGIC_COLOR
[-> logic : execute
activate logic
-logic -> abp ++: parseCommand(commandText)
+logic -> ip ++: parseCommand(commandText)
create ecp
-abp -> ecp
-abp -> ecp ++: parse(arguments)
+ip -> ecp
+ip -> ecp ++: parse(arguments)
create ec
-ecp -> ec ++: index, editPersonDescriptor
+ecp -> ec ++: index, editPatientDescriptor
ec --> ecp --
-ecp --> abp --: command
-abp --> logic --: command
+ecp --> ip --: command
+ip --> logic --: command
@enduml
diff --git a/docs/images/ArchitectureDiagram.png b/docs/images/ArchitectureDiagram.png
deleted file mode 100644
index cd540665053..00000000000
Binary files a/docs/images/ArchitectureDiagram.png and /dev/null differ
diff --git a/docs/images/ArchitectureSequenceDiagram.png b/docs/images/ArchitectureSequenceDiagram.png
deleted file mode 100644
index 37ad06a2803..00000000000
Binary files a/docs/images/ArchitectureSequenceDiagram.png and /dev/null differ
diff --git a/docs/images/BetterModelClassDiagram.png b/docs/images/BetterModelClassDiagram.png
deleted file mode 100644
index 02a42e35e76..00000000000
Binary files a/docs/images/BetterModelClassDiagram.png and /dev/null differ
diff --git a/docs/images/CommitActivityDiagram.png b/docs/images/CommitActivityDiagram.png
deleted file mode 100644
index 5b464126b35..00000000000
Binary files a/docs/images/CommitActivityDiagram.png and /dev/null differ
diff --git a/docs/images/ComponentManagers.png b/docs/images/ComponentManagers.png
deleted file mode 100644
index ae52a35718a..00000000000
Binary files a/docs/images/ComponentManagers.png and /dev/null differ
diff --git a/docs/images/DeleteSequenceDiagram.png b/docs/images/DeleteSequenceDiagram.png
deleted file mode 100644
index ac2ae217c51..00000000000
Binary files a/docs/images/DeleteSequenceDiagram.png and /dev/null differ
diff --git a/docs/images/LogicClassDiagram.png b/docs/images/LogicClassDiagram.png
deleted file mode 100644
index fe91c69efe7..00000000000
Binary files a/docs/images/LogicClassDiagram.png and /dev/null differ
diff --git a/docs/images/LogicStorageDIP.png b/docs/images/LogicStorageDIP.png
deleted file mode 100644
index 871157f5a9c..00000000000
Binary files a/docs/images/LogicStorageDIP.png and /dev/null differ
diff --git a/docs/images/ModelClassDiagram.png b/docs/images/ModelClassDiagram.png
deleted file mode 100644
index a19fb1b4ac8..00000000000
Binary files a/docs/images/ModelClassDiagram.png and /dev/null differ
diff --git a/docs/images/ParserClasses.png b/docs/images/ParserClasses.png
deleted file mode 100644
index 2caeeb1a067..00000000000
Binary files a/docs/images/ParserClasses.png and /dev/null differ
diff --git a/docs/images/StorageClassDiagram.png b/docs/images/StorageClassDiagram.png
deleted file mode 100644
index 18fa4d0d51f..00000000000
Binary files a/docs/images/StorageClassDiagram.png and /dev/null differ
diff --git a/docs/images/Ui.png b/docs/images/Ui.png
index 5bd77847aa2..e60f310221e 100644
Binary files a/docs/images/Ui.png and b/docs/images/Ui.png differ
diff --git a/docs/images/UiClassDiagram.png b/docs/images/UiClassDiagram.png
deleted file mode 100644
index 11f06d68671..00000000000
Binary files a/docs/images/UiClassDiagram.png and /dev/null differ
diff --git a/docs/images/UndoRedoState0.png b/docs/images/UndoRedoState0.png
deleted file mode 100644
index c5f91b58533..00000000000
Binary files a/docs/images/UndoRedoState0.png and /dev/null differ
diff --git a/docs/images/UndoRedoState1.png b/docs/images/UndoRedoState1.png
deleted file mode 100644
index 2d3ad09c047..00000000000
Binary files a/docs/images/UndoRedoState1.png and /dev/null differ
diff --git a/docs/images/UndoRedoState2.png b/docs/images/UndoRedoState2.png
deleted file mode 100644
index 20853694e03..00000000000
Binary files a/docs/images/UndoRedoState2.png and /dev/null differ
diff --git a/docs/images/UndoRedoState3.png b/docs/images/UndoRedoState3.png
deleted file mode 100644
index 1a9551b31be..00000000000
Binary files a/docs/images/UndoRedoState3.png and /dev/null differ
diff --git a/docs/images/UndoRedoState4.png b/docs/images/UndoRedoState4.png
deleted file mode 100644
index 46dfae78c94..00000000000
Binary files a/docs/images/UndoRedoState4.png and /dev/null differ
diff --git a/docs/images/UndoRedoState5.png b/docs/images/UndoRedoState5.png
deleted file mode 100644
index f45889b5fdf..00000000000
Binary files a/docs/images/UndoRedoState5.png and /dev/null differ
diff --git a/docs/images/findAlexDavidResult.png b/docs/images/findAlexDavidResult.png
deleted file mode 100644
index 235da1c273e..00000000000
Binary files a/docs/images/findAlexDavidResult.png and /dev/null differ
diff --git a/docs/images/findAlexRoyResult.png b/docs/images/findAlexRoyResult.png
new file mode 100644
index 00000000000..e75c80341ef
Binary files /dev/null and b/docs/images/findAlexRoyResult.png differ
diff --git a/docs/images/helpMessage.png b/docs/images/helpMessage.png
index b1f70470137..8767c2780fc 100644
Binary files a/docs/images/helpMessage.png and b/docs/images/helpMessage.png differ
diff --git a/docs/images/jeong-jaeho.png b/docs/images/jeong-jaeho.png
new file mode 100644
index 00000000000..054c3430559
Binary files /dev/null and b/docs/images/jeong-jaeho.png differ
diff --git a/docs/images/jskimdev.png b/docs/images/jskimdev.png
new file mode 100644
index 00000000000..39a45e17eba
Binary files /dev/null and b/docs/images/jskimdev.png differ
diff --git a/docs/images/s-aishvarya.png b/docs/images/s-aishvarya.png
new file mode 100644
index 00000000000..c759ee8a522
Binary files /dev/null and b/docs/images/s-aishvarya.png differ
diff --git a/docs/images/tracing/LogicSequenceDiagram.png b/docs/images/tracing/LogicSequenceDiagram.png
deleted file mode 100644
index 25c8b66b9f1..00000000000
Binary files a/docs/images/tracing/LogicSequenceDiagram.png and /dev/null differ
diff --git a/docs/images/vision-2000.png b/docs/images/vision-2000.png
new file mode 100644
index 00000000000..b5a1af93526
Binary files /dev/null and b/docs/images/vision-2000.png differ
diff --git a/docs/index.md b/docs/index.md
index 7601dbaad0d..42b567aa653 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -1,19 +1,21 @@
---
-layout: page
-title: AddressBook Level-3
+ layout: default.md
+ title: ""
---
-[![CI Status](https://github.com/se-edu/addressbook-level3/workflows/Java%20CI/badge.svg)](https://github.com/se-edu/addressbook-level3/actions)
-[![codecov](https://codecov.io/gh/se-edu/addressbook-level3/branch/master/graph/badge.svg)](https://codecov.io/gh/se-edu/addressbook-level3)
+# MediTrack
+
+[![CI Status](https://github.com/AY2324S2-CS2103T-T14-2/tp/workflows/Java%20CI/badge.svg)](https://github.com/AY2324S2-CS2103T-T14-2/tp/actions)
+[![codecov](https://codecov.io/gh/AY2324S2-CS2103T-T14-2/tp/graph/badge.svg?token=yYHlxxXkJQ)](https://codecov.io/gh/AY2324S2-CS2103T-T14-2/tp)
![Ui](images/Ui.png)
-**AddressBook is a desktop application for managing your contact details.** While it has a GUI, most of the user interactions happen using a CLI (Command Line Interface).
+**MediTrack is a desktop application for managing your patient details.** While it has a GUI, most of the user interactions happen using a CLI (Command Line Interface).
-* If you are interested in using AddressBook, head over to the [_Quick Start_ section of the **User Guide**](UserGuide.html#quick-start).
-* If you are interested about developing AddressBook, the [**Developer Guide**](DeveloperGuide.html) is a good place to start.
+* If you are interested in using MediTrack, head over to the [_Quick Start_ section of the **User Guide**](UserGuide.html#quick-start).
+* If you are interested about developing MediTrack, the [**Developer Guide**](DeveloperGuide.html) is a good place to start.
**Acknowledgements**
-* Libraries used: [JavaFX](https://openjfx.io/), [Jackson](https://github.com/FasterXML/jackson), [JUnit5](https://github.com/junit-team/junit5)
+* This project is based on the AddressBook-Level3 project created by the [SE-EDU initiative](https://se-education.org).
diff --git a/docs/package-lock.json b/docs/package-lock.json
new file mode 100644
index 00000000000..63a232e05dc
--- /dev/null
+++ b/docs/package-lock.json
@@ -0,0 +1,8587 @@
+{
+ "name": "docs",
+ "version": "1.0.0",
+ "lockfileVersion": 2,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "docs",
+ "version": "1.0.0",
+ "devDependencies": {
+ "markbind-cli": "^5.1.0"
+ }
+ },
+ "node_modules/@colors/colors": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz",
+ "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.1.90"
+ }
+ },
+ "node_modules/@fortawesome/fontawesome-free": {
+ "version": "6.4.2",
+ "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.4.2.tgz",
+ "integrity": "sha512-m5cPn3e2+FDCOgi1mz0RexTUvvQibBebOUlUlW0+YrMjDTPkiJ6VTKukA1GRsvRw+12KyJndNjj0O4AgTxm2Pg==",
+ "dev": true,
+ "hasInstallScript": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/@kwsites/file-exists": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz",
+ "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==",
+ "dev": true,
+ "dependencies": {
+ "debug": "^4.1.1"
+ }
+ },
+ "node_modules/@kwsites/file-exists/node_modules/debug": {
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+ "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+ "dev": true,
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@kwsites/file-exists/node_modules/ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ },
+ "node_modules/@kwsites/promise-deferred": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz",
+ "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==",
+ "dev": true
+ },
+ "node_modules/@markbind/core": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/@markbind/core/-/core-5.1.0.tgz",
+ "integrity": "sha512-YAXjH+qCXnrBzpKIAJkayVLmyIUaG/8Dms3Gpd2VIufeZyW8w0diXdgKSsymjzodTMgghZMdxG3Qpng833ARPg==",
+ "dev": true,
+ "dependencies": {
+ "@fortawesome/fontawesome-free": "^6.4.0",
+ "@markbind/core-web": "5.1.0",
+ "@primer/octicons": "^15.0.1",
+ "@sindresorhus/slugify": "^0.9.1",
+ "@tlylt/markdown-it-imsize": "^3.0.0",
+ "bluebird": "^3.7.2",
+ "bootswatch": "5.1.3",
+ "cheerio": "^0.22.0",
+ "crypto-js": "^4.0.0",
+ "csv-parse": "^4.14.2",
+ "ensure-posix-path": "^1.1.1",
+ "fastmatter": "^2.1.1",
+ "fs-extra": "^9.0.1",
+ "gh-pages": "^2.1.1",
+ "highlight.js": "^10.4.1",
+ "htmlparser2": "^3.10.1",
+ "ignore": "^5.1.4",
+ "js-beautify": "1.14.3",
+ "katex": "^0.15.6",
+ "lodash": "^4.17.15",
+ "markdown-it": "^12.3.2",
+ "markdown-it-attrs": "^4.1.3",
+ "markdown-it-emoji": "^1.4.0",
+ "markdown-it-linkify-images": "^3.0.0",
+ "markdown-it-mark": "^3.0.0",
+ "markdown-it-regexp": "^0.4.0",
+ "markdown-it-sub": "^1.0.0",
+ "markdown-it-sup": "^1.0.0",
+ "markdown-it-table-of-contents": "^0.4.4",
+ "markdown-it-task-lists": "^2.1.1",
+ "markdown-it-texmath": "^1.0.0",
+ "markdown-it-video": "^0.6.3",
+ "material-icons": "^1.9.1",
+ "moment": "^2.29.4",
+ "nunjucks": "3.2.2",
+ "path-is-inside": "^1.0.2",
+ "simple-git": "^2.17.0",
+ "url-parse": "^1.5.10",
+ "uuid": "^8.3.1",
+ "vue": "2.6.14",
+ "vue-server-renderer": "2.6.14",
+ "vue-template-compiler": "2.6.14",
+ "walk-sync": "^2.0.2",
+ "winston": "^2.4.4"
+ }
+ },
+ "node_modules/@markbind/core-web": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/@markbind/core-web/-/core-web-5.1.0.tgz",
+ "integrity": "sha512-TRzz8ZCr25pylKvFxF/WwXDi4Gbtsb2OLXV61WyTFqVy03tFoEJ2mqncpbliI9DrfDdKWcm1YZPgDCedVkYjKA==",
+ "dev": true
+ },
+ "node_modules/@primer/octicons": {
+ "version": "15.2.0",
+ "resolved": "https://registry.npmjs.org/@primer/octicons/-/octicons-15.2.0.tgz",
+ "integrity": "sha512-4cHZzcZ3F/HQNL4EKSaFyVsW7XtITiJkTeB1JDDmRuP/XobyWyF9gWxuV9c+byUa8dOB5KNQn37iRvNrIehPUQ==",
+ "dev": true,
+ "dependencies": {
+ "object-assign": "^4.1.1"
+ }
+ },
+ "node_modules/@sindresorhus/slugify": {
+ "version": "0.9.1",
+ "resolved": "https://registry.npmjs.org/@sindresorhus/slugify/-/slugify-0.9.1.tgz",
+ "integrity": "sha512-b6heYM9dzZD13t2GOiEQTDE0qX+I1GyOotMwKh9VQqzuNiVdPVT8dM43fe9HNb/3ul+Qwd5oKSEDrDIfhq3bnQ==",
+ "dev": true,
+ "dependencies": {
+ "escape-string-regexp": "^1.0.5",
+ "lodash.deburr": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@tlylt/markdown-it-imsize": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/@tlylt/markdown-it-imsize/-/markdown-it-imsize-3.0.0.tgz",
+ "integrity": "sha512-6kTM+vRJTuN2UxNPyJ8yC+NHrzS+MxVHV+z+bDxSr/Fd7eTah2+otLKC2B17YI/1lQnSumA2qokPGuzsA98c6g==",
+ "dev": true
+ },
+ "node_modules/@types/minimatch": {
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz",
+ "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==",
+ "dev": true
+ },
+ "node_modules/a-sync-waterfall": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/a-sync-waterfall/-/a-sync-waterfall-1.0.1.tgz",
+ "integrity": "sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA==",
+ "dev": true
+ },
+ "node_modules/abbrev": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
+ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
+ "dev": true
+ },
+ "node_modules/accepts": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
+ "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
+ "dev": true,
+ "dependencies": {
+ "mime-types": "~2.1.34",
+ "negotiator": "0.6.3"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "dev": true,
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/apache-crypt": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/apache-crypt/-/apache-crypt-1.2.5.tgz",
+ "integrity": "sha512-ICnYQH+DFVmw+S4Q0QY2XRXD8Ne8ewh8HgbuFH4K7022zCxgHM0Hz1xkRnUlEfAXNbwp1Cnhbedu60USIfDxvg==",
+ "dev": true,
+ "dependencies": {
+ "unix-crypt-td-js": "^1.1.4"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/apache-md5": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/apache-md5/-/apache-md5-1.1.7.tgz",
+ "integrity": "sha512-JtHjzZmJxtzfTSjsCyHgPR155HBe5WGyUyHTaEkfy46qhwCFKx1Epm6nAxgUG3WfUZP1dWhGqj9Z2NOBeZ+uBw==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "dev": true,
+ "dependencies": {
+ "sprintf-js": "~1.0.2"
+ }
+ },
+ "node_modules/arr-diff": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
+ "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/arr-flatten": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
+ "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/arr-union": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
+ "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/array-union": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
+ "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==",
+ "dev": true,
+ "dependencies": {
+ "array-uniq": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/array-uniq": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
+ "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/array-unique": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
+ "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/asap": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
+ "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==",
+ "dev": true
+ },
+ "node_modules/assign-symbols": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
+ "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/async": {
+ "version": "2.6.4",
+ "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz",
+ "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==",
+ "dev": true,
+ "dependencies": {
+ "lodash": "^4.17.14"
+ }
+ },
+ "node_modules/async-each": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz",
+ "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==",
+ "dev": true
+ },
+ "node_modules/at-least-node": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
+ "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 4.0.0"
+ }
+ },
+ "node_modules/atob": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
+ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
+ "dev": true,
+ "bin": {
+ "atob": "bin/atob.js"
+ },
+ "engines": {
+ "node": ">= 4.5.0"
+ }
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true
+ },
+ "node_modules/base": {
+ "version": "0.11.2",
+ "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
+ "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==",
+ "dev": true,
+ "dependencies": {
+ "cache-base": "^1.0.1",
+ "class-utils": "^0.3.5",
+ "component-emitter": "^1.2.1",
+ "define-property": "^1.0.0",
+ "isobject": "^3.0.1",
+ "mixin-deep": "^1.2.0",
+ "pascalcase": "^0.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/base/node_modules/define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==",
+ "dev": true,
+ "dependencies": {
+ "is-descriptor": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/basic-auth": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz",
+ "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==",
+ "dev": true,
+ "dependencies": {
+ "safe-buffer": "5.1.2"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/batch": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
+ "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==",
+ "dev": true
+ },
+ "node_modules/bcryptjs": {
+ "version": "2.4.3",
+ "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz",
+ "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==",
+ "dev": true
+ },
+ "node_modules/binary-extensions": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/bindings": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
+ "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "file-uri-to-path": "1.0.0"
+ }
+ },
+ "node_modules/bluebird": {
+ "version": "3.7.2",
+ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
+ "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
+ "dev": true
+ },
+ "node_modules/boolbase": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
+ "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
+ "dev": true
+ },
+ "node_modules/bootswatch": {
+ "version": "5.1.3",
+ "resolved": "https://registry.npmjs.org/bootswatch/-/bootswatch-5.1.3.tgz",
+ "integrity": "sha512-NmZFN6rOCoXWQ/PkzmD8FFWDe24kocX9OXWHNVaLxVVnpqpAzEbMFsf8bAfKwVtpNXibasZCzv09B5fLieAh2g==",
+ "dev": true
+ },
+ "node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "dev": true,
+ "dependencies": {
+ "fill-range": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cache-base": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
+ "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==",
+ "dev": true,
+ "dependencies": {
+ "collection-visit": "^1.0.0",
+ "component-emitter": "^1.2.1",
+ "get-value": "^2.0.6",
+ "has-value": "^1.0.0",
+ "isobject": "^3.0.1",
+ "set-value": "^2.0.0",
+ "to-object-path": "^0.3.0",
+ "union-value": "^1.0.0",
+ "unset-value": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/chalk": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
+ "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cheerio": {
+ "version": "0.22.0",
+ "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz",
+ "integrity": "sha512-8/MzidM6G/TgRelkzDG13y3Y9LxBjCb+8yOEZ9+wwq5gVF2w2pV0wmHvjfT0RvuxGyR7UEuK36r+yYMbT4uKgA==",
+ "dev": true,
+ "dependencies": {
+ "css-select": "~1.2.0",
+ "dom-serializer": "~0.1.0",
+ "entities": "~1.1.1",
+ "htmlparser2": "^3.9.1",
+ "lodash.assignin": "^4.0.9",
+ "lodash.bind": "^4.1.4",
+ "lodash.defaults": "^4.0.1",
+ "lodash.filter": "^4.4.0",
+ "lodash.flatten": "^4.2.0",
+ "lodash.foreach": "^4.3.0",
+ "lodash.map": "^4.4.0",
+ "lodash.merge": "^4.4.0",
+ "lodash.pick": "^4.2.1",
+ "lodash.reduce": "^4.4.0",
+ "lodash.reject": "^4.4.0",
+ "lodash.some": "^4.4.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/chokidar": {
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
+ "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ ],
+ "dependencies": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ },
+ "engines": {
+ "node": ">= 8.10.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/class-utils": {
+ "version": "0.3.6",
+ "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
+ "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==",
+ "dev": true,
+ "dependencies": {
+ "arr-union": "^3.1.0",
+ "define-property": "^0.2.5",
+ "isobject": "^3.0.0",
+ "static-extend": "^0.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/class-utils/node_modules/define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==",
+ "dev": true,
+ "dependencies": {
+ "is-descriptor": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/class-utils/node_modules/is-accessor-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+ "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==",
+ "dev": true,
+ "dependencies": {
+ "kind-of": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/class-utils/node_modules/is-accessor-descriptor/node_modules/kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+ "dev": true,
+ "dependencies": {
+ "is-buffer": "^1.1.5"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/class-utils/node_modules/is-data-descriptor": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+ "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==",
+ "dev": true,
+ "dependencies": {
+ "kind-of": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/class-utils/node_modules/is-data-descriptor/node_modules/kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+ "dev": true,
+ "dependencies": {
+ "is-buffer": "^1.1.5"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/class-utils/node_modules/is-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+ "dev": true,
+ "dependencies": {
+ "is-accessor-descriptor": "^0.1.6",
+ "is-data-descriptor": "^0.1.4",
+ "kind-of": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/class-utils/node_modules/kind-of": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+ "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/collection-visit": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
+ "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==",
+ "dev": true,
+ "dependencies": {
+ "map-visit": "^1.0.0",
+ "object-visit": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/colors": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
+ "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.1.90"
+ }
+ },
+ "node_modules/commander": {
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz",
+ "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==",
+ "dev": true,
+ "engines": {
+ "node": ">= 12"
+ }
+ },
+ "node_modules/component-emitter": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
+ "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==",
+ "dev": true
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "dev": true
+ },
+ "node_modules/config-chain": {
+ "version": "1.1.13",
+ "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz",
+ "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==",
+ "dev": true,
+ "dependencies": {
+ "ini": "^1.3.4",
+ "proto-list": "~1.2.1"
+ }
+ },
+ "node_modules/connect": {
+ "version": "3.7.0",
+ "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz",
+ "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==",
+ "dev": true,
+ "dependencies": {
+ "debug": "2.6.9",
+ "finalhandler": "1.1.2",
+ "parseurl": "~1.3.3",
+ "utils-merge": "1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.10.0"
+ }
+ },
+ "node_modules/copy-descriptor": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
+ "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/core-util-is": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
+ "dev": true
+ },
+ "node_modules/cors": {
+ "version": "2.8.5",
+ "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
+ "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
+ "dev": true,
+ "dependencies": {
+ "object-assign": "^4",
+ "vary": "^1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/crypto-js": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz",
+ "integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==",
+ "dev": true
+ },
+ "node_modules/css-select": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz",
+ "integrity": "sha512-dUQOBoqdR7QwV90WysXPLXG5LO7nhYBgiWVfxF80DKPF8zx1t/pUd2FYy73emg3zrjtM6dzmYgbHKfV2rxiHQA==",
+ "dev": true,
+ "dependencies": {
+ "boolbase": "~1.0.0",
+ "css-what": "2.1",
+ "domutils": "1.5.1",
+ "nth-check": "~1.0.1"
+ }
+ },
+ "node_modules/css-what": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz",
+ "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/csv-parse": {
+ "version": "4.16.3",
+ "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-4.16.3.tgz",
+ "integrity": "sha512-cO1I/zmz4w2dcKHVvpCr7JVRu8/FymG5OEpmvsZYlccYolPBLoVGKUHgNoc4ZGkFeFlWGEDmMyBM+TTqRdW/wg==",
+ "dev": true
+ },
+ "node_modules/cycle": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz",
+ "integrity": "sha512-TVF6svNzeQCOpjCqsy0/CSy8VgObG3wXusJ73xW2GbG5rGx7lC8zxDSURicsXI2UsGdi2L0QNRCi745/wUDvsA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/de-indent": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz",
+ "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==",
+ "dev": true
+ },
+ "node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dev": true,
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/decode-uri-component": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
+ "integrity": "sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/define-property": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
+ "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
+ "dev": true,
+ "dependencies": {
+ "is-descriptor": "^1.0.2",
+ "isobject": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/destroy": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
+ "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.8",
+ "npm": "1.2.8000 || >= 1.4.16"
+ }
+ },
+ "node_modules/dom-serializer": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz",
+ "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==",
+ "dev": true,
+ "dependencies": {
+ "domelementtype": "^1.3.0",
+ "entities": "^1.1.1"
+ }
+ },
+ "node_modules/domelementtype": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
+ "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==",
+ "dev": true
+ },
+ "node_modules/domhandler": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz",
+ "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==",
+ "dev": true,
+ "dependencies": {
+ "domelementtype": "1"
+ }
+ },
+ "node_modules/domutils": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz",
+ "integrity": "sha512-gSu5Oi/I+3wDENBsOWBiRK1eoGxcywYSqg3rR960/+EfY0CF4EX1VPkgHOZ3WiS/Jg2DtliF6BhWcHlfpYUcGw==",
+ "dev": true,
+ "dependencies": {
+ "dom-serializer": "0",
+ "domelementtype": "1"
+ }
+ },
+ "node_modules/duplexer": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
+ "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==",
+ "dev": true
+ },
+ "node_modules/editorconfig": {
+ "version": "0.15.3",
+ "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz",
+ "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==",
+ "dev": true,
+ "dependencies": {
+ "commander": "^2.19.0",
+ "lru-cache": "^4.1.5",
+ "semver": "^5.6.0",
+ "sigmund": "^1.0.1"
+ },
+ "bin": {
+ "editorconfig": "bin/editorconfig"
+ }
+ },
+ "node_modules/editorconfig/node_modules/commander": {
+ "version": "2.20.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+ "dev": true
+ },
+ "node_modules/ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
+ "dev": true
+ },
+ "node_modules/email-addresses": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-3.1.0.tgz",
+ "integrity": "sha512-k0/r7GrWVL32kZlGwfPNgB2Y/mMXVTq/decgLczm/j34whdaspNrZO8CnXPf1laaHxI6ptUlsnAxN+UAPw+fzg==",
+ "dev": true
+ },
+ "node_modules/encodeurl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+ "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/ensure-posix-path": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ensure-posix-path/-/ensure-posix-path-1.1.1.tgz",
+ "integrity": "sha512-VWU0/zXzVbeJNXvME/5EmLuEj2TauvoaTz6aFYK1Z92JCBlDlZ3Gu0tuGR42kpW1754ywTs+QB0g5TP0oj9Zaw==",
+ "dev": true
+ },
+ "node_modules/entities": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
+ "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==",
+ "dev": true
+ },
+ "node_modules/escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
+ "dev": true
+ },
+ "node_modules/escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+ "dev": true,
+ "bin": {
+ "esparse": "bin/esparse.js",
+ "esvalidate": "bin/esvalidate.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/event-stream": {
+ "version": "3.3.4",
+ "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz",
+ "integrity": "sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==",
+ "dev": true,
+ "dependencies": {
+ "duplexer": "~0.1.1",
+ "from": "~0",
+ "map-stream": "~0.1.0",
+ "pause-stream": "0.0.11",
+ "split": "0.3",
+ "stream-combiner": "~0.0.4",
+ "through": "~2.3.1"
+ }
+ },
+ "node_modules/event-stream/node_modules/split": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz",
+ "integrity": "sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==",
+ "dev": true,
+ "dependencies": {
+ "through": "2"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/event-stream/node_modules/stream-combiner": {
+ "version": "0.0.4",
+ "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz",
+ "integrity": "sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==",
+ "dev": true,
+ "dependencies": {
+ "duplexer": "~0.1.1"
+ }
+ },
+ "node_modules/expand-brackets": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
+ "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==",
+ "dev": true,
+ "dependencies": {
+ "debug": "^2.3.3",
+ "define-property": "^0.2.5",
+ "extend-shallow": "^2.0.1",
+ "posix-character-classes": "^0.1.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/expand-brackets/node_modules/define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==",
+ "dev": true,
+ "dependencies": {
+ "is-descriptor": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/expand-brackets/node_modules/extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
+ "dev": true,
+ "dependencies": {
+ "is-extendable": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/expand-brackets/node_modules/is-accessor-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+ "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==",
+ "dev": true,
+ "dependencies": {
+ "kind-of": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/expand-brackets/node_modules/is-accessor-descriptor/node_modules/kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+ "dev": true,
+ "dependencies": {
+ "is-buffer": "^1.1.5"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/expand-brackets/node_modules/is-data-descriptor": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+ "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==",
+ "dev": true,
+ "dependencies": {
+ "kind-of": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/expand-brackets/node_modules/is-data-descriptor/node_modules/kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+ "dev": true,
+ "dependencies": {
+ "is-buffer": "^1.1.5"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/expand-brackets/node_modules/is-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+ "dev": true,
+ "dependencies": {
+ "is-accessor-descriptor": "^0.1.6",
+ "is-data-descriptor": "^0.1.4",
+ "kind-of": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/expand-brackets/node_modules/is-extendable": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+ "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/expand-brackets/node_modules/kind-of": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+ "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/extend-shallow": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+ "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==",
+ "dev": true,
+ "dependencies": {
+ "assign-symbols": "^1.0.0",
+ "is-extendable": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/extglob": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
+ "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
+ "dev": true,
+ "dependencies": {
+ "array-unique": "^0.3.2",
+ "define-property": "^1.0.0",
+ "expand-brackets": "^2.1.4",
+ "extend-shallow": "^2.0.1",
+ "fragment-cache": "^0.2.1",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/extglob/node_modules/define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==",
+ "dev": true,
+ "dependencies": {
+ "is-descriptor": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/extglob/node_modules/extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
+ "dev": true,
+ "dependencies": {
+ "is-extendable": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/extglob/node_modules/is-extendable": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+ "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/eyes": {
+ "version": "0.1.8",
+ "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz",
+ "integrity": "sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==",
+ "dev": true,
+ "engines": {
+ "node": "> 0.1.90"
+ }
+ },
+ "node_modules/fast-safe-stringify": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz",
+ "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==",
+ "dev": true
+ },
+ "node_modules/fastmatter": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/fastmatter/-/fastmatter-2.1.1.tgz",
+ "integrity": "sha512-NFrjZEPJZTexoJEuyM5J7n4uFaLf0dOI7Ok4b2IZXOYBqCp1Bh5RskANmQ2TuDsz3M35B1yL2AP/Rn+kp85KeA==",
+ "dev": true,
+ "dependencies": {
+ "js-yaml": "^3.13.0",
+ "split": "^1.0.1",
+ "stream-combiner": "^0.2.2",
+ "through2": "^3.0.1"
+ }
+ },
+ "node_modules/faye-websocket": {
+ "version": "0.11.4",
+ "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz",
+ "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==",
+ "dev": true,
+ "dependencies": {
+ "websocket-driver": ">=0.5.1"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/fecha": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz",
+ "integrity": "sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==",
+ "dev": true
+ },
+ "node_modules/figlet": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/figlet/-/figlet-1.5.2.tgz",
+ "integrity": "sha512-WOn21V8AhyE1QqVfPIVxe3tupJacq1xGkPTB4iagT6o+P2cAgEOOwIxMftr4+ZCTI6d551ij9j61DFr0nsP2uQ==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/file-stream-rotator": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/file-stream-rotator/-/file-stream-rotator-0.4.1.tgz",
+ "integrity": "sha512-W3aa3QJEc8BS2MmdVpQiYLKHj3ijpto1gMDlsgCRSKfIUe6MwkcpODGPQ3vZfb0XvCeCqlu9CBQTN7oQri2TZQ==",
+ "dev": true,
+ "dependencies": {
+ "moment": "^2.11.2"
+ }
+ },
+ "node_modules/file-uri-to-path": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
+ "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
+ "dev": true,
+ "optional": true
+ },
+ "node_modules/filename-reserved-regex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-1.0.0.tgz",
+ "integrity": "sha512-UZArj7+U+2reBBVCvVmRlyq9D7EYQdUtuNN+1iz7pF1jGcJ2L0TjiRCxsTZfj2xFbM4c25uGCUDpKTHA7L2TKg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/filenamify": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-1.2.1.tgz",
+ "integrity": "sha512-DKVP0WQcB7WaIMSwDETqImRej2fepPqvXQjaVib7LRZn9Rxn5UbvK2tYTqGf1A1DkIprQQkG4XSQXSOZp7Q3GQ==",
+ "dev": true,
+ "dependencies": {
+ "filename-reserved-regex": "^1.0.0",
+ "strip-outer": "^1.0.0",
+ "trim-repeated": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/filenamify-url": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/filenamify-url/-/filenamify-url-1.0.0.tgz",
+ "integrity": "sha512-O9K9JcZeF5VdZWM1qR92NSv1WY2EofwudQayPx5dbnnFl9k0IcZha4eV/FGkjnBK+1irOQInij0yiooCHu/0Fg==",
+ "dev": true,
+ "dependencies": {
+ "filenamify": "^1.0.0",
+ "humanize-url": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "dev": true,
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/finalhandler": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
+ "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
+ "dev": true,
+ "dependencies": {
+ "debug": "2.6.9",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "on-finished": "~2.3.0",
+ "parseurl": "~1.3.3",
+ "statuses": "~1.5.0",
+ "unpipe": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/find-up": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+ "dev": true,
+ "dependencies": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/for-in": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
+ "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fragment-cache": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
+ "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==",
+ "dev": true,
+ "dependencies": {
+ "map-cache": "^0.2.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fresh": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+ "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/from": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz",
+ "integrity": "sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==",
+ "dev": true
+ },
+ "node_modules/fs-extra": {
+ "version": "9.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
+ "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
+ "dev": true,
+ "dependencies": {
+ "at-least-node": "^1.0.0",
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^6.0.1",
+ "universalify": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+ "dev": true
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
+ "dev": true
+ },
+ "node_modules/get-value": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
+ "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/gh-pages": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-2.2.0.tgz",
+ "integrity": "sha512-c+yPkNOPMFGNisYg9r4qvsMIjVYikJv7ImFOhPIVPt0+AcRUamZ7zkGRLHz7FKB0xrlZ+ddSOJsZv9XAFVXLmA==",
+ "dev": true,
+ "dependencies": {
+ "async": "^2.6.1",
+ "commander": "^2.18.0",
+ "email-addresses": "^3.0.1",
+ "filenamify-url": "^1.0.0",
+ "fs-extra": "^8.1.0",
+ "globby": "^6.1.0"
+ },
+ "bin": {
+ "gh-pages": "bin/gh-pages.js",
+ "gh-pages-clean": "bin/gh-pages-clean.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/gh-pages/node_modules/commander": {
+ "version": "2.20.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+ "dev": true
+ },
+ "node_modules/gh-pages/node_modules/fs-extra": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
+ "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
+ "dev": true,
+ "dependencies": {
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^4.0.0",
+ "universalify": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=6 <7 || >=8"
+ }
+ },
+ "node_modules/gh-pages/node_modules/jsonfile": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
+ "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==",
+ "dev": true,
+ "optionalDependencies": {
+ "graceful-fs": "^4.1.6"
+ }
+ },
+ "node_modules/gh-pages/node_modules/universalify": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
+ "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 4.0.0"
+ }
+ },
+ "node_modules/glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "dev": true,
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/globby": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz",
+ "integrity": "sha512-KVbFv2TQtbzCoxAnfD6JcHZTYCzyliEaaeM/gH8qQdkKr5s0OP9scEgvdcngyk7AVdY6YVW/TJHd+lQ/Df3Daw==",
+ "dev": true,
+ "dependencies": {
+ "array-union": "^1.0.1",
+ "glob": "^7.0.3",
+ "object-assign": "^4.0.1",
+ "pify": "^2.0.0",
+ "pinkie-promise": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/graceful-fs": {
+ "version": "4.2.10",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
+ "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
+ "dev": true
+ },
+ "node_modules/has": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+ "dev": true,
+ "dependencies": {
+ "function-bind": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/has-ansi": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
+ "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/has-value": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
+ "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==",
+ "dev": true,
+ "dependencies": {
+ "get-value": "^2.0.6",
+ "has-values": "^1.0.0",
+ "isobject": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/has-values": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz",
+ "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==",
+ "dev": true,
+ "dependencies": {
+ "is-number": "^3.0.0",
+ "kind-of": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/has-values/node_modules/is-number": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+ "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==",
+ "dev": true,
+ "dependencies": {
+ "kind-of": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/has-values/node_modules/is-number/node_modules/kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+ "dev": true,
+ "dependencies": {
+ "is-buffer": "^1.1.5"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/has-values/node_modules/kind-of": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
+ "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==",
+ "dev": true,
+ "dependencies": {
+ "is-buffer": "^1.1.5"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/hash-sum": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz",
+ "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==",
+ "dev": true
+ },
+ "node_modules/he": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
+ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
+ "dev": true,
+ "bin": {
+ "he": "bin/he"
+ }
+ },
+ "node_modules/highlight.js": {
+ "version": "10.7.3",
+ "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz",
+ "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/htmlparser2": {
+ "version": "3.10.1",
+ "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
+ "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==",
+ "dev": true,
+ "dependencies": {
+ "domelementtype": "^1.3.1",
+ "domhandler": "^2.3.0",
+ "domutils": "^1.5.1",
+ "entities": "^1.1.1",
+ "inherits": "^2.0.1",
+ "readable-stream": "^3.1.1"
+ }
+ },
+ "node_modules/http-auth": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/http-auth/-/http-auth-3.1.3.tgz",
+ "integrity": "sha512-Jbx0+ejo2IOx+cRUYAGS1z6RGc6JfYUNkysZM4u4Sfk1uLlGv814F7/PIjQQAuThLdAWxb74JMGd5J8zex1VQg==",
+ "dev": true,
+ "dependencies": {
+ "apache-crypt": "^1.1.2",
+ "apache-md5": "^1.0.6",
+ "bcryptjs": "^2.3.0",
+ "uuid": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4.6.1"
+ }
+ },
+ "node_modules/http-auth/node_modules/uuid": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
+ "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
+ "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
+ "dev": true,
+ "bin": {
+ "uuid": "bin/uuid"
+ }
+ },
+ "node_modules/http-errors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+ "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+ "dev": true,
+ "dependencies": {
+ "depd": "2.0.0",
+ "inherits": "2.0.4",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "toidentifier": "1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/http-errors/node_modules/statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/http-parser-js": {
+ "version": "0.5.8",
+ "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz",
+ "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==",
+ "dev": true
+ },
+ "node_modules/humanize-url": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/humanize-url/-/humanize-url-1.0.1.tgz",
+ "integrity": "sha512-RtgTzXCPVb/te+e82NDhAc5paj+DuKSratIGAr+v+HZK24eAQ8LMoBGYoL7N/O+9iEc33AKHg45dOMKw3DNldQ==",
+ "dev": true,
+ "dependencies": {
+ "normalize-url": "^1.0.0",
+ "strip-url-auth": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/ignore": {
+ "version": "5.2.4",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
+ "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
+ "dev": true,
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+ "dev": true,
+ "dependencies": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true
+ },
+ "node_modules/ini": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
+ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
+ "dev": true
+ },
+ "node_modules/is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "dev": true,
+ "dependencies": {
+ "kind-of": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dev": true,
+ "dependencies": {
+ "binary-extensions": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-buffer": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+ "dev": true
+ },
+ "node_modules/is-core-module": {
+ "version": "2.13.0",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz",
+ "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==",
+ "dev": true,
+ "dependencies": {
+ "has": "^1.0.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "dev": true,
+ "dependencies": {
+ "kind-of": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "dev": true,
+ "dependencies": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-extendable": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+ "dev": true,
+ "dependencies": {
+ "is-plain-object": "^2.0.4"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/is-plain-obj": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
+ "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-plain-object": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+ "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+ "dev": true,
+ "dependencies": {
+ "isobject": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-windows": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
+ "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-wsl": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz",
+ "integrity": "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
+ "dev": true
+ },
+ "node_modules/isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/isstream": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
+ "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==",
+ "dev": true
+ },
+ "node_modules/js-beautify": {
+ "version": "1.14.3",
+ "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.14.3.tgz",
+ "integrity": "sha512-f1ra8PHtOEu/70EBnmiUlV8nJePS58y9qKjl4JHfYWlFH6bo7ogZBz//FAZp7jDuXtYnGYKymZPlrg2I/9Zo4g==",
+ "dev": true,
+ "dependencies": {
+ "config-chain": "^1.1.13",
+ "editorconfig": "^0.15.3",
+ "glob": "^7.1.3",
+ "nopt": "^5.0.0"
+ },
+ "bin": {
+ "css-beautify": "js/bin/css-beautify.js",
+ "html-beautify": "js/bin/html-beautify.js",
+ "js-beautify": "js/bin/js-beautify.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/js-yaml": {
+ "version": "3.14.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+ "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+ "dev": true,
+ "dependencies": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/jsonfile": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
+ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
+ "dev": true,
+ "dependencies": {
+ "universalify": "^2.0.0"
+ },
+ "optionalDependencies": {
+ "graceful-fs": "^4.1.6"
+ }
+ },
+ "node_modules/katex": {
+ "version": "0.15.6",
+ "resolved": "https://registry.npmjs.org/katex/-/katex-0.15.6.tgz",
+ "integrity": "sha512-UpzJy4yrnqnhXvRPhjEuLA4lcPn6eRngixW7Q3TJErjg3Aw2PuLFBzTkdUb89UtumxjhHTqL3a5GDGETMSwgJA==",
+ "dev": true,
+ "funding": [
+ "https://opencollective.com/katex",
+ "https://github.com/sponsors/katex"
+ ],
+ "dependencies": {
+ "commander": "^8.0.0"
+ },
+ "bin": {
+ "katex": "cli.js"
+ }
+ },
+ "node_modules/kind-of": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/linkify-it": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz",
+ "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==",
+ "dev": true,
+ "dependencies": {
+ "uc.micro": "^1.0.1"
+ }
+ },
+ "node_modules/live-server": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/live-server/-/live-server-1.2.1.tgz",
+ "integrity": "sha512-Yn2XCVjErTkqnM3FfTmM7/kWy3zP7+cEtC7x6u+wUzlQ+1UW3zEYbbyJrc0jNDwiMDZI0m4a0i3dxlGHVyXczw==",
+ "dev": true,
+ "dependencies": {
+ "chokidar": "^2.0.4",
+ "colors": "latest",
+ "connect": "^3.6.6",
+ "cors": "latest",
+ "event-stream": "3.3.4",
+ "faye-websocket": "0.11.x",
+ "http-auth": "3.1.x",
+ "morgan": "^1.9.1",
+ "object-assign": "latest",
+ "opn": "latest",
+ "proxy-middleware": "latest",
+ "send": "latest",
+ "serve-index": "^1.9.1"
+ },
+ "bin": {
+ "live-server": "live-server.js"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/live-server/node_modules/anymatch": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
+ "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
+ "dev": true,
+ "dependencies": {
+ "micromatch": "^3.1.4",
+ "normalize-path": "^2.1.1"
+ }
+ },
+ "node_modules/live-server/node_modules/anymatch/node_modules/normalize-path": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+ "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==",
+ "dev": true,
+ "dependencies": {
+ "remove-trailing-separator": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/live-server/node_modules/binary-extensions": {
+ "version": "1.13.1",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz",
+ "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/live-server/node_modules/braces": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
+ "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
+ "dev": true,
+ "dependencies": {
+ "arr-flatten": "^1.1.0",
+ "array-unique": "^0.3.2",
+ "extend-shallow": "^2.0.1",
+ "fill-range": "^4.0.0",
+ "isobject": "^3.0.1",
+ "repeat-element": "^1.1.2",
+ "snapdragon": "^0.8.1",
+ "snapdragon-node": "^2.0.1",
+ "split-string": "^3.0.2",
+ "to-regex": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/live-server/node_modules/chokidar": {
+ "version": "2.1.8",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
+ "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==",
+ "deprecated": "Chokidar 2 does not receive security updates since 2019. Upgrade to chokidar 3 with 15x fewer dependencies",
+ "dev": true,
+ "dependencies": {
+ "anymatch": "^2.0.0",
+ "async-each": "^1.0.1",
+ "braces": "^2.3.2",
+ "glob-parent": "^3.1.0",
+ "inherits": "^2.0.3",
+ "is-binary-path": "^1.0.0",
+ "is-glob": "^4.0.0",
+ "normalize-path": "^3.0.0",
+ "path-is-absolute": "^1.0.0",
+ "readdirp": "^2.2.1",
+ "upath": "^1.1.1"
+ },
+ "optionalDependencies": {
+ "fsevents": "^1.2.7"
+ }
+ },
+ "node_modules/live-server/node_modules/extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
+ "dev": true,
+ "dependencies": {
+ "is-extendable": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/live-server/node_modules/fill-range": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
+ "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==",
+ "dev": true,
+ "dependencies": {
+ "extend-shallow": "^2.0.1",
+ "is-number": "^3.0.0",
+ "repeat-string": "^1.6.1",
+ "to-regex-range": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/live-server/node_modules/fsevents": {
+ "version": "1.2.13",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
+ "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
+ "deprecated": "fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.",
+ "dev": true,
+ "hasInstallScript": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "dependencies": {
+ "bindings": "^1.5.0",
+ "nan": "^2.12.1"
+ },
+ "engines": {
+ "node": ">= 4.0"
+ }
+ },
+ "node_modules/live-server/node_modules/glob-parent": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
+ "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==",
+ "dev": true,
+ "dependencies": {
+ "is-glob": "^3.1.0",
+ "path-dirname": "^1.0.0"
+ }
+ },
+ "node_modules/live-server/node_modules/glob-parent/node_modules/is-glob": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+ "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==",
+ "dev": true,
+ "dependencies": {
+ "is-extglob": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/live-server/node_modules/is-binary-path": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
+ "integrity": "sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==",
+ "dev": true,
+ "dependencies": {
+ "binary-extensions": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/live-server/node_modules/is-extendable": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+ "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/live-server/node_modules/is-number": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+ "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==",
+ "dev": true,
+ "dependencies": {
+ "kind-of": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/live-server/node_modules/kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+ "dev": true,
+ "dependencies": {
+ "is-buffer": "^1.1.5"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/live-server/node_modules/readable-stream": {
+ "version": "2.3.7",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+ "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+ "dev": true,
+ "dependencies": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "node_modules/live-server/node_modules/readdirp": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
+ "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==",
+ "dev": true,
+ "dependencies": {
+ "graceful-fs": "^4.1.11",
+ "micromatch": "^3.1.10",
+ "readable-stream": "^2.0.2"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/live-server/node_modules/string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dev": true,
+ "dependencies": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "node_modules/live-server/node_modules/to-regex-range": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
+ "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==",
+ "dev": true,
+ "dependencies": {
+ "is-number": "^3.0.0",
+ "repeat-string": "^1.6.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/locate-path": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+ "dev": true,
+ "dependencies": {
+ "p-locate": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/lodash": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
+ "dev": true
+ },
+ "node_modules/lodash._reinterpolate": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
+ "integrity": "sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA==",
+ "dev": true
+ },
+ "node_modules/lodash.assignin": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz",
+ "integrity": "sha512-yX/rx6d/UTVh7sSVWVSIMjfnz95evAgDFdb1ZozC35I9mSFCkmzptOzevxjgbQUsc78NR44LVHWjsoMQXy9FDg==",
+ "dev": true
+ },
+ "node_modules/lodash.bind": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/lodash.bind/-/lodash.bind-4.2.1.tgz",
+ "integrity": "sha512-lxdsn7xxlCymgLYo1gGvVrfHmkjDiyqVv62FAeF2i5ta72BipE1SLxw8hPEPLhD4/247Ijw07UQH7Hq/chT5LA==",
+ "dev": true
+ },
+ "node_modules/lodash.deburr": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/lodash.deburr/-/lodash.deburr-4.1.0.tgz",
+ "integrity": "sha512-m/M1U1f3ddMCs6Hq2tAsYThTBDaAKFDX3dwDo97GEYzamXi9SqUpjWi/Rrj/gf3X2n8ktwgZrlP1z6E3v/IExQ==",
+ "dev": true
+ },
+ "node_modules/lodash.defaults": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
+ "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==",
+ "dev": true
+ },
+ "node_modules/lodash.filter": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/lodash.filter/-/lodash.filter-4.6.0.tgz",
+ "integrity": "sha512-pXYUy7PR8BCLwX5mgJ/aNtyOvuJTdZAo9EQFUvMIYugqmJxnrYaANvTbgndOzHSCSR0wnlBBfRXJL5SbWxo3FQ==",
+ "dev": true
+ },
+ "node_modules/lodash.flatten": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz",
+ "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==",
+ "dev": true
+ },
+ "node_modules/lodash.foreach": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz",
+ "integrity": "sha512-aEXTF4d+m05rVOAUG3z4vZZ4xVexLKZGF0lIxuHZ1Hplpk/3B6Z1+/ICICYRLm7c41Z2xiejbkCkJoTlypoXhQ==",
+ "dev": true
+ },
+ "node_modules/lodash.map": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz",
+ "integrity": "sha512-worNHGKLDetmcEYDvh2stPCrrQRkP20E4l0iIS7F8EvzMqBBi7ltvFN5m1HvTf1P7Jk1txKhvFcmYsCr8O2F1Q==",
+ "dev": true
+ },
+ "node_modules/lodash.merge": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+ "dev": true
+ },
+ "node_modules/lodash.pick": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz",
+ "integrity": "sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q==",
+ "dev": true
+ },
+ "node_modules/lodash.reduce": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/lodash.reduce/-/lodash.reduce-4.6.0.tgz",
+ "integrity": "sha512-6raRe2vxCYBhpBu+B+TtNGUzah+hQjVdu3E17wfusjyrXBka2nBS8OH/gjVZ5PvHOhWmIZTYri09Z6n/QfnNMw==",
+ "dev": true
+ },
+ "node_modules/lodash.reject": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/lodash.reject/-/lodash.reject-4.6.0.tgz",
+ "integrity": "sha512-qkTuvgEzYdyhiJBx42YPzPo71R1aEr0z79kAv7Ixg8wPFEjgRgJdUsGMG3Hf3OYSF/kHI79XhNlt+5Ar6OzwxQ==",
+ "dev": true
+ },
+ "node_modules/lodash.some": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz",
+ "integrity": "sha512-j7MJE+TuT51q9ggt4fSgVqro163BEFjAt3u97IqU+JA2DkWl80nFTrowzLpZ/BnpN7rrl0JA/593NAdd8p/scQ==",
+ "dev": true
+ },
+ "node_modules/lodash.template": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz",
+ "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==",
+ "dev": true,
+ "dependencies": {
+ "lodash._reinterpolate": "^3.0.0",
+ "lodash.templatesettings": "^4.0.0"
+ }
+ },
+ "node_modules/lodash.templatesettings": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz",
+ "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==",
+ "dev": true,
+ "dependencies": {
+ "lodash._reinterpolate": "^3.0.0"
+ }
+ },
+ "node_modules/lodash.uniq": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
+ "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==",
+ "dev": true
+ },
+ "node_modules/logform": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/logform/-/logform-1.10.0.tgz",
+ "integrity": "sha512-em5ojIhU18fIMOw/333mD+ZLE2fis0EzXl1ZwHx4iQzmpQi6odNiY/t+ITNr33JZhT9/KEaH+UPIipr6a9EjWg==",
+ "dev": true,
+ "dependencies": {
+ "colors": "^1.2.1",
+ "fast-safe-stringify": "^2.0.4",
+ "fecha": "^2.3.3",
+ "ms": "^2.1.1",
+ "triple-beam": "^1.2.0"
+ }
+ },
+ "node_modules/logform/node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true
+ },
+ "node_modules/lru-cache": {
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
+ "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
+ "dev": true,
+ "dependencies": {
+ "pseudomap": "^1.0.2",
+ "yallist": "^2.1.2"
+ }
+ },
+ "node_modules/map-cache": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
+ "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/map-stream": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz",
+ "integrity": "sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==",
+ "dev": true
+ },
+ "node_modules/map-visit": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
+ "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==",
+ "dev": true,
+ "dependencies": {
+ "object-visit": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/markbind-cli": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/markbind-cli/-/markbind-cli-5.1.0.tgz",
+ "integrity": "sha512-6POI1Q++2aZa+Udk/oQ6LX1oNPbKUBDY0mN3Up7VOFeK+XYW51faxuCk2Q91JTBxYRKLNtshxf0y12kB4Cj9Qw==",
+ "dev": true,
+ "dependencies": {
+ "@markbind/core": "5.1.0",
+ "@markbind/core-web": "5.1.0",
+ "bluebird": "^3.7.2",
+ "chalk": "^3.0.0",
+ "cheerio": "^0.22.0",
+ "chokidar": "^3.3.0",
+ "colors": "1.4.0",
+ "commander": "^8.1.0",
+ "figlet": "^1.2.4",
+ "find-up": "^4.1.0",
+ "fs-extra": "^9.0.1",
+ "live-server": "1.2.1",
+ "lodash": "^4.17.15",
+ "url-parse": "^1.5.10",
+ "winston": "^2.4.4",
+ "winston-daily-rotate-file": "^3.10.0"
+ },
+ "bin": {
+ "markbind": "index.js"
+ }
+ },
+ "node_modules/markdown-it": {
+ "version": "12.3.2",
+ "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz",
+ "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==",
+ "dev": true,
+ "dependencies": {
+ "argparse": "^2.0.1",
+ "entities": "~2.1.0",
+ "linkify-it": "^3.0.1",
+ "mdurl": "^1.0.1",
+ "uc.micro": "^1.0.5"
+ },
+ "bin": {
+ "markdown-it": "bin/markdown-it.js"
+ }
+ },
+ "node_modules/markdown-it-attrs": {
+ "version": "4.1.6",
+ "resolved": "https://registry.npmjs.org/markdown-it-attrs/-/markdown-it-attrs-4.1.6.tgz",
+ "integrity": "sha512-O7PDKZlN8RFMyDX13JnctQompwrrILuz2y43pW2GagcwpIIElkAdfeek+erHfxUOlXWPsjFeWmZ8ch1xtRLWpA==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ },
+ "peerDependencies": {
+ "markdown-it": ">= 9.0.0"
+ }
+ },
+ "node_modules/markdown-it-emoji": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/markdown-it-emoji/-/markdown-it-emoji-1.4.0.tgz",
+ "integrity": "sha512-QCz3Hkd+r5gDYtS2xsFXmBYrgw6KuWcJZLCEkdfAuwzZbShCmCfta+hwAMq4NX/4xPzkSHduMKgMkkPUJxSXNg==",
+ "dev": true
+ },
+ "node_modules/markdown-it-linkify-images": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/markdown-it-linkify-images/-/markdown-it-linkify-images-3.0.0.tgz",
+ "integrity": "sha512-Vs5yGJa5MWjFgytzgtn8c1U6RcStj3FZKhhx459U8dYbEE5FTWZ6mMRkYMiDlkFO0j4VCsQT1LT557bY0ETgtg==",
+ "dev": true,
+ "dependencies": {
+ "markdown-it": "^13.0.1"
+ }
+ },
+ "node_modules/markdown-it-linkify-images/node_modules/argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true
+ },
+ "node_modules/markdown-it-linkify-images/node_modules/entities": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
+ "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/markdown-it-linkify-images/node_modules/linkify-it": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-4.0.1.tgz",
+ "integrity": "sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==",
+ "dev": true,
+ "dependencies": {
+ "uc.micro": "^1.0.1"
+ }
+ },
+ "node_modules/markdown-it-linkify-images/node_modules/markdown-it": {
+ "version": "13.0.1",
+ "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.1.tgz",
+ "integrity": "sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==",
+ "dev": true,
+ "dependencies": {
+ "argparse": "^2.0.1",
+ "entities": "~3.0.1",
+ "linkify-it": "^4.0.1",
+ "mdurl": "^1.0.1",
+ "uc.micro": "^1.0.5"
+ },
+ "bin": {
+ "markdown-it": "bin/markdown-it.js"
+ }
+ },
+ "node_modules/markdown-it-mark": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/markdown-it-mark/-/markdown-it-mark-3.0.1.tgz",
+ "integrity": "sha512-HyxjAu6BRsdt6Xcv6TKVQnkz/E70TdGXEFHRYBGLncRE9lBFwDNLVtFojKxjJWgJ+5XxUwLaHXy+2sGBbDn+4A==",
+ "dev": true
+ },
+ "node_modules/markdown-it-regexp": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/markdown-it-regexp/-/markdown-it-regexp-0.4.0.tgz",
+ "integrity": "sha512-0XQmr46K/rMKnI93Y3CLXsHj4jIioRETTAiVnJnjrZCEkGaDOmUxTbZj/aZ17G5NlRcVpWBYjqpwSlQ9lj+Kxw==",
+ "dev": true
+ },
+ "node_modules/markdown-it-sub": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/markdown-it-sub/-/markdown-it-sub-1.0.0.tgz",
+ "integrity": "sha512-z2Rm/LzEE1wzwTSDrI+FlPEveAAbgdAdPhdWarq/ZGJrGW/uCQbKAnhoCsE4hAbc3SEym26+W2z/VQB0cQiA9Q==",
+ "dev": true
+ },
+ "node_modules/markdown-it-sup": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/markdown-it-sup/-/markdown-it-sup-1.0.0.tgz",
+ "integrity": "sha512-E32m0nV9iyhRR7CrhnzL5msqic7rL1juWre6TQNxsnApg7Uf+F97JOKxUijg5YwXz86lZ0mqfOnutoryyNdntQ==",
+ "dev": true
+ },
+ "node_modules/markdown-it-table-of-contents": {
+ "version": "0.4.4",
+ "resolved": "https://registry.npmjs.org/markdown-it-table-of-contents/-/markdown-it-table-of-contents-0.4.4.tgz",
+ "integrity": "sha512-TAIHTHPwa9+ltKvKPWulm/beozQU41Ab+FIefRaQV1NRnpzwcV9QOe6wXQS5WLivm5Q/nlo0rl6laGkMDZE7Gw==",
+ "dev": true,
+ "engines": {
+ "node": ">6.4.0"
+ }
+ },
+ "node_modules/markdown-it-task-lists": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/markdown-it-task-lists/-/markdown-it-task-lists-2.1.1.tgz",
+ "integrity": "sha512-TxFAc76Jnhb2OUu+n3yz9RMu4CwGfaT788br6HhEDlvWfdeJcLUsxk1Hgw2yJio0OXsxv7pyIPmvECY7bMbluA==",
+ "dev": true
+ },
+ "node_modules/markdown-it-texmath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/markdown-it-texmath/-/markdown-it-texmath-1.0.0.tgz",
+ "integrity": "sha512-4hhkiX8/gus+6e53PLCUmUrsa6ZWGgJW2XCW6O0ASvZUiezIK900ZicinTDtG3kAO2kon7oUA/ReWmpW2FByxg==",
+ "dev": true
+ },
+ "node_modules/markdown-it-video": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/markdown-it-video/-/markdown-it-video-0.6.3.tgz",
+ "integrity": "sha512-T4th1kwy0OcvyWSN4u3rqPGxvbDclpucnVSSaH3ZacbGsAts964dxokx9s/I3GYsrDCJs4ogtEeEeVP18DQj0Q==",
+ "dev": true
+ },
+ "node_modules/markdown-it/node_modules/argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true
+ },
+ "node_modules/markdown-it/node_modules/entities": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
+ "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==",
+ "dev": true,
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/matcher-collection": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/matcher-collection/-/matcher-collection-2.0.1.tgz",
+ "integrity": "sha512-daE62nS2ZQsDg9raM0IlZzLmI2u+7ZapXBwdoeBUKAYERPDDIc0qNqA8E0Rp2D+gspKR7BgIFP52GeujaGXWeQ==",
+ "dev": true,
+ "dependencies": {
+ "@types/minimatch": "^3.0.3",
+ "minimatch": "^3.0.2"
+ },
+ "engines": {
+ "node": "6.* || 8.* || >= 10.*"
+ }
+ },
+ "node_modules/material-icons": {
+ "version": "1.13.11",
+ "resolved": "https://registry.npmjs.org/material-icons/-/material-icons-1.13.11.tgz",
+ "integrity": "sha512-kp2oAdaqo/Zp6hpTZW01rOgDPWmxBUszSdDzkRm1idCjjNvdUMnqu8qu58cll6CObo+o0cydOiPLdoSugLm+mQ==",
+ "dev": true
+ },
+ "node_modules/mdurl": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
+ "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==",
+ "dev": true
+ },
+ "node_modules/micromatch": {
+ "version": "3.1.10",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+ "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
+ "dev": true,
+ "dependencies": {
+ "arr-diff": "^4.0.0",
+ "array-unique": "^0.3.2",
+ "braces": "^2.3.1",
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "extglob": "^2.0.4",
+ "fragment-cache": "^0.2.1",
+ "kind-of": "^6.0.2",
+ "nanomatch": "^1.2.9",
+ "object.pick": "^1.3.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/micromatch/node_modules/braces": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
+ "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
+ "dev": true,
+ "dependencies": {
+ "arr-flatten": "^1.1.0",
+ "array-unique": "^0.3.2",
+ "extend-shallow": "^2.0.1",
+ "fill-range": "^4.0.0",
+ "isobject": "^3.0.1",
+ "repeat-element": "^1.1.2",
+ "snapdragon": "^0.8.1",
+ "snapdragon-node": "^2.0.1",
+ "split-string": "^3.0.2",
+ "to-regex": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/micromatch/node_modules/braces/node_modules/extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
+ "dev": true,
+ "dependencies": {
+ "is-extendable": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/micromatch/node_modules/fill-range": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
+ "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==",
+ "dev": true,
+ "dependencies": {
+ "extend-shallow": "^2.0.1",
+ "is-number": "^3.0.0",
+ "repeat-string": "^1.6.1",
+ "to-regex-range": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/micromatch/node_modules/fill-range/node_modules/extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
+ "dev": true,
+ "dependencies": {
+ "is-extendable": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/micromatch/node_modules/is-extendable": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+ "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/micromatch/node_modules/is-number": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+ "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==",
+ "dev": true,
+ "dependencies": {
+ "kind-of": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/micromatch/node_modules/is-number/node_modules/kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+ "dev": true,
+ "dependencies": {
+ "is-buffer": "^1.1.5"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/micromatch/node_modules/to-regex-range": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
+ "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==",
+ "dev": true,
+ "dependencies": {
+ "is-number": "^3.0.0",
+ "repeat-string": "^1.6.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+ "dev": true,
+ "bin": {
+ "mime": "cli.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "dev": true,
+ "dependencies": {
+ "mime-db": "1.52.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/mixin-deep": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
+ "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
+ "dev": true,
+ "dependencies": {
+ "for-in": "^1.0.2",
+ "is-extendable": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/moment": {
+ "version": "2.29.4",
+ "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
+ "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/morgan": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz",
+ "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==",
+ "dev": true,
+ "dependencies": {
+ "basic-auth": "~2.0.1",
+ "debug": "2.6.9",
+ "depd": "~2.0.0",
+ "on-finished": "~2.3.0",
+ "on-headers": "~1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+ "dev": true
+ },
+ "node_modules/nan": {
+ "version": "2.16.0",
+ "resolved": "https://registry.npmjs.org/nan/-/nan-2.16.0.tgz",
+ "integrity": "sha512-UdAqHyFngu7TfQKsCBgAA6pWDkT8MAO7d0jyOecVhN5354xbLqdn8mV9Tat9gepAupm0bt2DbeaSC8vS52MuFA==",
+ "dev": true,
+ "optional": true
+ },
+ "node_modules/nanomatch": {
+ "version": "1.2.13",
+ "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
+ "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==",
+ "dev": true,
+ "dependencies": {
+ "arr-diff": "^4.0.0",
+ "array-unique": "^0.3.2",
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "fragment-cache": "^0.2.1",
+ "is-windows": "^1.0.2",
+ "kind-of": "^6.0.2",
+ "object.pick": "^1.3.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/negotiator": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
+ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/nopt": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
+ "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==",
+ "dev": true,
+ "dependencies": {
+ "abbrev": "1"
+ },
+ "bin": {
+ "nopt": "bin/nopt.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/normalize-url": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz",
+ "integrity": "sha512-A48My/mtCklowHBlI8Fq2jFWK4tX4lJ5E6ytFsSOq1fzpvT0SQSgKhSg7lN5c2uYFOrUAOQp6zhhJnpp1eMloQ==",
+ "dev": true,
+ "dependencies": {
+ "object-assign": "^4.0.1",
+ "prepend-http": "^1.0.0",
+ "query-string": "^4.1.0",
+ "sort-keys": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/nth-check": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz",
+ "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==",
+ "dev": true,
+ "dependencies": {
+ "boolbase": "~1.0.0"
+ }
+ },
+ "node_modules/nunjucks": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/nunjucks/-/nunjucks-3.2.2.tgz",
+ "integrity": "sha512-KUi85OoF2NMygwODAy28Lh9qHmq5hO3rBlbkYoC8v377h4l8Pt5qFjILl0LWpMbOrZ18CzfVVUvIHUIrtED3sA==",
+ "dev": true,
+ "dependencies": {
+ "a-sync-waterfall": "^1.0.0",
+ "asap": "^2.0.3",
+ "commander": "^5.1.0"
+ },
+ "bin": {
+ "nunjucks-precompile": "bin/precompile"
+ },
+ "engines": {
+ "node": ">= 6.9.0"
+ },
+ "optionalDependencies": {
+ "chokidar": "^3.3.0"
+ }
+ },
+ "node_modules/nunjucks/node_modules/commander": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz",
+ "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object-copy": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
+ "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==",
+ "dev": true,
+ "dependencies": {
+ "copy-descriptor": "^0.1.0",
+ "define-property": "^0.2.5",
+ "kind-of": "^3.0.3"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object-copy/node_modules/define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==",
+ "dev": true,
+ "dependencies": {
+ "is-descriptor": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object-copy/node_modules/is-accessor-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+ "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==",
+ "dev": true,
+ "dependencies": {
+ "kind-of": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object-copy/node_modules/is-data-descriptor": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+ "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==",
+ "dev": true,
+ "dependencies": {
+ "kind-of": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object-copy/node_modules/is-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+ "dev": true,
+ "dependencies": {
+ "is-accessor-descriptor": "^0.1.6",
+ "is-data-descriptor": "^0.1.4",
+ "kind-of": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object-copy/node_modules/is-descriptor/node_modules/kind-of": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+ "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object-copy/node_modules/kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+ "dev": true,
+ "dependencies": {
+ "is-buffer": "^1.1.5"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object-hash": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-1.3.1.tgz",
+ "integrity": "sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.10.0"
+ }
+ },
+ "node_modules/object-visit": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
+ "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==",
+ "dev": true,
+ "dependencies": {
+ "isobject": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object.pick": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
+ "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==",
+ "dev": true,
+ "dependencies": {
+ "isobject": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/on-finished": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+ "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==",
+ "dev": true,
+ "dependencies": {
+ "ee-first": "1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/on-headers": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
+ "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "dev": true,
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/opn": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/opn/-/opn-6.0.0.tgz",
+ "integrity": "sha512-I9PKfIZC+e4RXZ/qr1RhgyCnGgYX0UEIlXgWnCOVACIvFgaC9rz6Won7xbdhoHrd8IIhV7YEpHjreNUNkqCGkQ==",
+ "deprecated": "The package has been renamed to `open`",
+ "dev": true,
+ "dependencies": {
+ "is-wsl": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dev": true,
+ "dependencies": {
+ "p-try": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-locate": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+ "dev": true,
+ "dependencies": {
+ "p-limit": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/p-try": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/pascalcase": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
+ "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/path-dirname": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz",
+ "integrity": "sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==",
+ "dev": true
+ },
+ "node_modules/path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/path-is-inside": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",
+ "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==",
+ "dev": true
+ },
+ "node_modules/path-parse": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+ "dev": true
+ },
+ "node_modules/pause-stream": {
+ "version": "0.0.11",
+ "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz",
+ "integrity": "sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==",
+ "dev": true,
+ "dependencies": {
+ "through": "~2.3"
+ }
+ },
+ "node_modules/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/pinkie": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
+ "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/pinkie-promise": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
+ "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==",
+ "dev": true,
+ "dependencies": {
+ "pinkie": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/posix-character-classes": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
+ "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/prepend-http": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz",
+ "integrity": "sha512-PhmXi5XmoyKw1Un4E+opM2KcsJInDvKyuOumcjjw3waw86ZNjHwVUOOWLc4bCzLdcKNaWBH9e99sbWzDQsVaYg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/process-nextick-args": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+ "dev": true
+ },
+ "node_modules/proto-list": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
+ "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==",
+ "dev": true
+ },
+ "node_modules/proxy-middleware": {
+ "version": "0.15.0",
+ "resolved": "https://registry.npmjs.org/proxy-middleware/-/proxy-middleware-0.15.0.tgz",
+ "integrity": "sha512-EGCG8SeoIRVMhsqHQUdDigB2i7qU7fCsWASwn54+nPutYO8n4q6EiwMzyfWlC+dzRFExP+kvcnDFdBDHoZBU7Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/pseudomap": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
+ "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==",
+ "dev": true
+ },
+ "node_modules/query-string": {
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz",
+ "integrity": "sha512-O2XLNDBIg1DnTOa+2XrIwSiXEV8h2KImXUnjhhn2+UsvZ+Es2uyd5CCRTNQlDGbzUQOW3aYCBx9rVA6dzsiY7Q==",
+ "dev": true,
+ "dependencies": {
+ "object-assign": "^4.1.0",
+ "strict-uri-encode": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/querystringify": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
+ "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==",
+ "dev": true
+ },
+ "node_modules/randombytes": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
+ "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
+ "dev": true,
+ "dependencies": {
+ "safe-buffer": "^5.1.0"
+ }
+ },
+ "node_modules/range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/readable-stream": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+ "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+ "dev": true,
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "dev": true,
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
+ "node_modules/regex-not": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
+ "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==",
+ "dev": true,
+ "dependencies": {
+ "extend-shallow": "^3.0.2",
+ "safe-regex": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/remove-trailing-separator": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
+ "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==",
+ "dev": true
+ },
+ "node_modules/repeat-element": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz",
+ "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/repeat-string": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
+ "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/requires-port": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
+ "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
+ "dev": true
+ },
+ "node_modules/resolve": {
+ "version": "1.22.4",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz",
+ "integrity": "sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==",
+ "dev": true,
+ "dependencies": {
+ "is-core-module": "^2.13.0",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
+ },
+ "bin": {
+ "resolve": "bin/resolve"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/resolve-url": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
+ "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==",
+ "deprecated": "https://github.com/lydell/resolve-url#deprecated",
+ "dev": true
+ },
+ "node_modules/ret": {
+ "version": "0.1.15",
+ "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
+ "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ },
+ "node_modules/safe-regex": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
+ "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==",
+ "dev": true,
+ "dependencies": {
+ "ret": "~0.1.10"
+ }
+ },
+ "node_modules/safe-stable-stringify": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.3.1.tgz",
+ "integrity": "sha512-kYBSfT+troD9cDA85VDnHZ1rpHC50O0g1e6WlGHVCz/g+JS+9WKLj+XwFYyR8UbrZN8ll9HUpDAAddY58MGisg==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/semver": {
+ "version": "5.7.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
+ "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver"
+ }
+ },
+ "node_modules/send": {
+ "version": "0.18.0",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
+ "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
+ "dev": true,
+ "dependencies": {
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "fresh": "0.5.2",
+ "http-errors": "2.0.0",
+ "mime": "1.6.0",
+ "ms": "2.1.3",
+ "on-finished": "2.4.1",
+ "range-parser": "~1.2.1",
+ "statuses": "2.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/send/node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true
+ },
+ "node_modules/send/node_modules/on-finished": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+ "dev": true,
+ "dependencies": {
+ "ee-first": "1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/send/node_modules/statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/serialize-javascript": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-3.1.0.tgz",
+ "integrity": "sha512-JIJT1DGiWmIKhzRsG91aS6Ze4sFUrYbltlkg2onR5OrnNM02Kl/hnY/T4FN2omvyeBbQmMJv+K4cPOpGzOTFBg==",
+ "dev": true,
+ "dependencies": {
+ "randombytes": "^2.1.0"
+ }
+ },
+ "node_modules/serve-index": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz",
+ "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==",
+ "dev": true,
+ "dependencies": {
+ "accepts": "~1.3.4",
+ "batch": "0.6.1",
+ "debug": "2.6.9",
+ "escape-html": "~1.0.3",
+ "http-errors": "~1.6.2",
+ "mime-types": "~2.1.17",
+ "parseurl": "~1.3.2"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/serve-index/node_modules/depd": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
+ "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/serve-index/node_modules/http-errors": {
+ "version": "1.6.3",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
+ "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==",
+ "dev": true,
+ "dependencies": {
+ "depd": "~1.1.2",
+ "inherits": "2.0.3",
+ "setprototypeof": "1.1.0",
+ "statuses": ">= 1.4.0 < 2"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/serve-index/node_modules/inherits": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==",
+ "dev": true
+ },
+ "node_modules/serve-index/node_modules/setprototypeof": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
+ "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==",
+ "dev": true
+ },
+ "node_modules/set-value": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
+ "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
+ "dev": true,
+ "dependencies": {
+ "extend-shallow": "^2.0.1",
+ "is-extendable": "^0.1.1",
+ "is-plain-object": "^2.0.3",
+ "split-string": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/set-value/node_modules/extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
+ "dev": true,
+ "dependencies": {
+ "is-extendable": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/set-value/node_modules/is-extendable": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+ "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/setprototypeof": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
+ "dev": true
+ },
+ "node_modules/sigmund": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz",
+ "integrity": "sha512-fCvEXfh6NWpm+YSuY2bpXb/VIihqWA6hLsgboC+0nl71Q7N7o2eaCW8mJa/NLvQhs6jpd3VZV4UiUQlV6+lc8g==",
+ "dev": true
+ },
+ "node_modules/simple-git": {
+ "version": "2.48.0",
+ "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-2.48.0.tgz",
+ "integrity": "sha512-z4qtrRuaAFJS4PUd0g+xy7aN4y+RvEt/QTJpR184lhJguBA1S/LsVlvE/CM95RsYMOFJG3NGGDjqFCzKU19S/A==",
+ "dev": true,
+ "dependencies": {
+ "@kwsites/file-exists": "^1.1.1",
+ "@kwsites/promise-deferred": "^1.1.1",
+ "debug": "^4.3.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/steveukx/"
+ }
+ },
+ "node_modules/simple-git/node_modules/debug": {
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+ "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+ "dev": true,
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/simple-git/node_modules/ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ },
+ "node_modules/snapdragon": {
+ "version": "0.8.2",
+ "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
+ "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==",
+ "dev": true,
+ "dependencies": {
+ "base": "^0.11.1",
+ "debug": "^2.2.0",
+ "define-property": "^0.2.5",
+ "extend-shallow": "^2.0.1",
+ "map-cache": "^0.2.2",
+ "source-map": "^0.5.6",
+ "source-map-resolve": "^0.5.0",
+ "use": "^3.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/snapdragon-node": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz",
+ "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==",
+ "dev": true,
+ "dependencies": {
+ "define-property": "^1.0.0",
+ "isobject": "^3.0.0",
+ "snapdragon-util": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/snapdragon-node/node_modules/define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==",
+ "dev": true,
+ "dependencies": {
+ "is-descriptor": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/snapdragon-util": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz",
+ "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==",
+ "dev": true,
+ "dependencies": {
+ "kind-of": "^3.2.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/snapdragon-util/node_modules/kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+ "dev": true,
+ "dependencies": {
+ "is-buffer": "^1.1.5"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/snapdragon/node_modules/define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==",
+ "dev": true,
+ "dependencies": {
+ "is-descriptor": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/snapdragon/node_modules/extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
+ "dev": true,
+ "dependencies": {
+ "is-extendable": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/snapdragon/node_modules/is-accessor-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+ "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==",
+ "dev": true,
+ "dependencies": {
+ "kind-of": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/snapdragon/node_modules/is-accessor-descriptor/node_modules/kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+ "dev": true,
+ "dependencies": {
+ "is-buffer": "^1.1.5"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/snapdragon/node_modules/is-data-descriptor": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+ "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==",
+ "dev": true,
+ "dependencies": {
+ "kind-of": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/snapdragon/node_modules/is-data-descriptor/node_modules/kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+ "dev": true,
+ "dependencies": {
+ "is-buffer": "^1.1.5"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/snapdragon/node_modules/is-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+ "dev": true,
+ "dependencies": {
+ "is-accessor-descriptor": "^0.1.6",
+ "is-data-descriptor": "^0.1.4",
+ "kind-of": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/snapdragon/node_modules/is-extendable": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+ "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/snapdragon/node_modules/kind-of": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+ "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/sort-keys": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz",
+ "integrity": "sha512-vzn8aSqKgytVik0iwdBEi+zevbTYZogewTUM6dtpmGwEcdzbub/TX4bCzRhebDCRC3QzXgJsLRKB2V/Oof7HXg==",
+ "dev": true,
+ "dependencies": {
+ "is-plain-obj": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/source-map": {
+ "version": "0.5.6",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz",
+ "integrity": "sha512-MjZkVp0NHr5+TPihLcadqnlVoGIoWo4IBHptutGh9wI3ttUYvCG26HkSuDi+K6lsZ25syXJXcctwgyVCt//xqA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/source-map-resolve": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz",
+ "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==",
+ "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated",
+ "dev": true,
+ "dependencies": {
+ "atob": "^2.1.2",
+ "decode-uri-component": "^0.2.0",
+ "resolve-url": "^0.2.1",
+ "source-map-url": "^0.4.0",
+ "urix": "^0.1.0"
+ }
+ },
+ "node_modules/source-map-url": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz",
+ "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==",
+ "deprecated": "See https://github.com/lydell/source-map-url#deprecated",
+ "dev": true
+ },
+ "node_modules/split": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz",
+ "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==",
+ "dev": true,
+ "dependencies": {
+ "through": "2"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/split-string": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
+ "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==",
+ "dev": true,
+ "dependencies": {
+ "extend-shallow": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
+ "dev": true
+ },
+ "node_modules/stack-trace": {
+ "version": "0.0.10",
+ "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
+ "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/static-extend": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
+ "integrity": "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==",
+ "dev": true,
+ "dependencies": {
+ "define-property": "^0.2.5",
+ "object-copy": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/static-extend/node_modules/define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==",
+ "dev": true,
+ "dependencies": {
+ "is-descriptor": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/static-extend/node_modules/is-accessor-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+ "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==",
+ "dev": true,
+ "dependencies": {
+ "kind-of": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/static-extend/node_modules/is-accessor-descriptor/node_modules/kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+ "dev": true,
+ "dependencies": {
+ "is-buffer": "^1.1.5"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/static-extend/node_modules/is-data-descriptor": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+ "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==",
+ "dev": true,
+ "dependencies": {
+ "kind-of": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/static-extend/node_modules/is-data-descriptor/node_modules/kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+ "dev": true,
+ "dependencies": {
+ "is-buffer": "^1.1.5"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/static-extend/node_modules/is-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+ "dev": true,
+ "dependencies": {
+ "is-accessor-descriptor": "^0.1.6",
+ "is-data-descriptor": "^0.1.4",
+ "kind-of": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/static-extend/node_modules/kind-of": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+ "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/statuses": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
+ "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/stream-combiner": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz",
+ "integrity": "sha512-6yHMqgLYDzQDcAkL+tjJDC5nSNuNIx0vZtRZeiPh7Saef7VHX9H5Ijn9l2VIol2zaNYlYEX6KyuT/237A58qEQ==",
+ "dev": true,
+ "dependencies": {
+ "duplexer": "~0.1.1",
+ "through": "~2.3.4"
+ }
+ },
+ "node_modules/strict-uri-encode": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
+ "integrity": "sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/string_decoder": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+ "dev": true,
+ "dependencies": {
+ "safe-buffer": "~5.2.0"
+ }
+ },
+ "node_modules/string_decoder/node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/strip-outer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz",
+ "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==",
+ "dev": true,
+ "dependencies": {
+ "escape-string-regexp": "^1.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/strip-url-auth": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/strip-url-auth/-/strip-url-auth-1.0.1.tgz",
+ "integrity": "sha512-++41PnXftlL3pvI6lpvhSEO+89g1kIJC4MYB5E6yH+WHa5InIqz51yGd1YOGd7VNSNdoEOfzTMqbAM/2PbgaHQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/supports-preserve-symlinks-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/through": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+ "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
+ "dev": true
+ },
+ "node_modules/through2": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz",
+ "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==",
+ "dev": true,
+ "dependencies": {
+ "inherits": "^2.0.4",
+ "readable-stream": "2 || 3"
+ }
+ },
+ "node_modules/to-object-path": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
+ "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==",
+ "dev": true,
+ "dependencies": {
+ "kind-of": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/to-object-path/node_modules/kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+ "dev": true,
+ "dependencies": {
+ "is-buffer": "^1.1.5"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/to-regex": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz",
+ "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==",
+ "dev": true,
+ "dependencies": {
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "regex-not": "^1.0.2",
+ "safe-regex": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/toidentifier": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/trim-repeated": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz",
+ "integrity": "sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==",
+ "dev": true,
+ "dependencies": {
+ "escape-string-regexp": "^1.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/triple-beam": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz",
+ "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==",
+ "dev": true
+ },
+ "node_modules/uc.micro": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
+ "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==",
+ "dev": true
+ },
+ "node_modules/union-value": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
+ "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
+ "dev": true,
+ "dependencies": {
+ "arr-union": "^3.1.0",
+ "get-value": "^2.0.6",
+ "is-extendable": "^0.1.1",
+ "set-value": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/union-value/node_modules/is-extendable": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+ "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/universalify": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
+ "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
+ "dev": true,
+ "engines": {
+ "node": ">= 10.0.0"
+ }
+ },
+ "node_modules/unix-crypt-td-js": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/unix-crypt-td-js/-/unix-crypt-td-js-1.1.4.tgz",
+ "integrity": "sha512-8rMeVYWSIyccIJscb9NdCfZKSRBKYTeVnwmiRYT2ulE3qd1RaDQ0xQDP+rI3ccIWbhu/zuo5cgN8z73belNZgw==",
+ "dev": true
+ },
+ "node_modules/unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/unset-value": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
+ "integrity": "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==",
+ "dev": true,
+ "dependencies": {
+ "has-value": "^0.3.1",
+ "isobject": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/unset-value/node_modules/has-value": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz",
+ "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==",
+ "dev": true,
+ "dependencies": {
+ "get-value": "^2.0.3",
+ "has-values": "^0.1.4",
+ "isobject": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/unset-value/node_modules/has-value/node_modules/isobject": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+ "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==",
+ "dev": true,
+ "dependencies": {
+ "isarray": "1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/unset-value/node_modules/has-values": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
+ "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/upath": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz",
+ "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==",
+ "dev": true,
+ "engines": {
+ "node": ">=4",
+ "yarn": "*"
+ }
+ },
+ "node_modules/urix": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
+ "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==",
+ "deprecated": "Please see https://github.com/lydell/urix#deprecated",
+ "dev": true
+ },
+ "node_modules/url-parse": {
+ "version": "1.5.10",
+ "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
+ "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
+ "dev": true,
+ "dependencies": {
+ "querystringify": "^2.1.1",
+ "requires-port": "^1.0.0"
+ }
+ },
+ "node_modules/use": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
+ "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+ "dev": true
+ },
+ "node_modules/utils-merge": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+ "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/uuid": {
+ "version": "8.3.2",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
+ "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
+ "dev": true,
+ "bin": {
+ "uuid": "dist/bin/uuid"
+ }
+ },
+ "node_modules/vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/vue": {
+ "version": "2.6.14",
+ "resolved": "https://registry.npmjs.org/vue/-/vue-2.6.14.tgz",
+ "integrity": "sha512-x2284lgYvjOMj3Za7kqzRcUSxBboHqtgRE2zlos1qWaOye5yUmHn42LB1250NJBLRwEcdrB0JRwyPTEPhfQjiQ==",
+ "dev": true
+ },
+ "node_modules/vue-server-renderer": {
+ "version": "2.6.14",
+ "resolved": "https://registry.npmjs.org/vue-server-renderer/-/vue-server-renderer-2.6.14.tgz",
+ "integrity": "sha512-HifYRa/LW7cKywg9gd4ZtvtRuBlstQBao5ZCWlg40fyB4OPoGfEXAzxb0emSLv4pBDOHYx0UjpqvxpiQFEuoLA==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^1.1.3",
+ "hash-sum": "^1.0.2",
+ "he": "^1.1.0",
+ "lodash.template": "^4.5.0",
+ "lodash.uniq": "^4.5.0",
+ "resolve": "^1.2.0",
+ "serialize-javascript": "^3.1.0",
+ "source-map": "0.5.6"
+ }
+ },
+ "node_modules/vue-server-renderer/node_modules/ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/vue-server-renderer/node_modules/chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/vue-server-renderer/node_modules/supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/vue-template-compiler": {
+ "version": "2.6.14",
+ "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.6.14.tgz",
+ "integrity": "sha512-ODQS1SyMbjKoO1JBJZojSw6FE4qnh9rIpUZn2EUT86FKizx9uH5z6uXiIrm4/Nb/gwxTi/o17ZDEGWAXHvtC7g==",
+ "dev": true,
+ "dependencies": {
+ "de-indent": "^1.0.2",
+ "he": "^1.1.0"
+ }
+ },
+ "node_modules/walk-sync": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/walk-sync/-/walk-sync-2.2.0.tgz",
+ "integrity": "sha512-IC8sL7aB4/ZgFcGI2T1LczZeFWZ06b3zoHH7jBPyHxOtIIz1jppWHjjEXkOFvFojBVAK9pV7g47xOZ4LW3QLfg==",
+ "dev": true,
+ "dependencies": {
+ "@types/minimatch": "^3.0.3",
+ "ensure-posix-path": "^1.1.0",
+ "matcher-collection": "^2.0.0",
+ "minimatch": "^3.0.4"
+ },
+ "engines": {
+ "node": "8.* || >= 10.*"
+ }
+ },
+ "node_modules/websocket-driver": {
+ "version": "0.7.4",
+ "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
+ "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==",
+ "dev": true,
+ "dependencies": {
+ "http-parser-js": ">=0.5.1",
+ "safe-buffer": ">=5.1.0",
+ "websocket-extensions": ">=0.1.1"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/websocket-extensions": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz",
+ "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/winston": {
+ "version": "2.4.6",
+ "resolved": "https://registry.npmjs.org/winston/-/winston-2.4.6.tgz",
+ "integrity": "sha512-J5Zu4p0tojLde8mIOyDSsmLmcP8I3Z6wtwpTDHx1+hGcdhxcJaAmG4CFtagkb+NiN1M9Ek4b42pzMWqfc9jm8w==",
+ "dev": true,
+ "dependencies": {
+ "async": "^3.2.3",
+ "colors": "1.0.x",
+ "cycle": "1.0.x",
+ "eyes": "0.1.x",
+ "isstream": "0.1.x",
+ "stack-trace": "0.0.x"
+ },
+ "engines": {
+ "node": ">= 0.10.0"
+ }
+ },
+ "node_modules/winston-compat": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/winston-compat/-/winston-compat-0.1.5.tgz",
+ "integrity": "sha512-EPvPcHT604AV3Ji6d3+vX8ENKIml9VSxMRnPQ+cuK/FX6f3hvPP2hxyoeeCOCFvDrJEujalfcKWlWPvAnFyS9g==",
+ "dev": true,
+ "dependencies": {
+ "cycle": "~1.0.3",
+ "logform": "^1.6.0",
+ "triple-beam": "^1.2.0"
+ },
+ "engines": {
+ "node": ">= 6.4.0"
+ }
+ },
+ "node_modules/winston-daily-rotate-file": {
+ "version": "3.10.0",
+ "resolved": "https://registry.npmjs.org/winston-daily-rotate-file/-/winston-daily-rotate-file-3.10.0.tgz",
+ "integrity": "sha512-KO8CfbI2CvdR3PaFApEH02GPXiwJ+vbkF1mCkTlvRIoXFI8EFlf1ACcuaahXTEiDEKCii6cNe95gsL4ZkbnphA==",
+ "dev": true,
+ "dependencies": {
+ "file-stream-rotator": "^0.4.1",
+ "object-hash": "^1.3.0",
+ "semver": "^6.2.0",
+ "triple-beam": "^1.3.0",
+ "winston-compat": "^0.1.4",
+ "winston-transport": "^4.2.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "peerDependencies": {
+ "winston": "^2 || ^3"
+ }
+ },
+ "node_modules/winston-daily-rotate-file/node_modules/semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/winston-transport": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.5.0.tgz",
+ "integrity": "sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q==",
+ "dev": true,
+ "dependencies": {
+ "logform": "^2.3.2",
+ "readable-stream": "^3.6.0",
+ "triple-beam": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 6.4.0"
+ }
+ },
+ "node_modules/winston-transport/node_modules/fecha": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz",
+ "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==",
+ "dev": true
+ },
+ "node_modules/winston-transport/node_modules/logform": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/logform/-/logform-2.4.2.tgz",
+ "integrity": "sha512-W4c9himeAwXEdZ05dQNerhFz2XG80P9Oj0loPUMV23VC2it0orMHQhJm4hdnnor3rd1HsGf6a2lPwBM1zeXHGw==",
+ "dev": true,
+ "dependencies": {
+ "@colors/colors": "1.5.0",
+ "fecha": "^4.2.0",
+ "ms": "^2.1.1",
+ "safe-stable-stringify": "^2.3.1",
+ "triple-beam": "^1.3.0"
+ }
+ },
+ "node_modules/winston-transport/node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true
+ },
+ "node_modules/winston/node_modules/async": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz",
+ "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==",
+ "dev": true
+ },
+ "node_modules/winston/node_modules/colors": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz",
+ "integrity": "sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.1.90"
+ }
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "dev": true
+ },
+ "node_modules/yallist": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
+ "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==",
+ "dev": true
+ }
+ },
+ "dependencies": {
+ "@colors/colors": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz",
+ "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==",
+ "dev": true
+ },
+ "@fortawesome/fontawesome-free": {
+ "version": "6.4.2",
+ "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.4.2.tgz",
+ "integrity": "sha512-m5cPn3e2+FDCOgi1mz0RexTUvvQibBebOUlUlW0+YrMjDTPkiJ6VTKukA1GRsvRw+12KyJndNjj0O4AgTxm2Pg==",
+ "dev": true
+ },
+ "@kwsites/file-exists": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz",
+ "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==",
+ "dev": true,
+ "requires": {
+ "debug": "^4.1.1"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+ "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+ "dev": true,
+ "requires": {
+ "ms": "2.1.2"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ }
+ }
+ },
+ "@kwsites/promise-deferred": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz",
+ "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==",
+ "dev": true
+ },
+ "@markbind/core": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/@markbind/core/-/core-5.1.0.tgz",
+ "integrity": "sha512-YAXjH+qCXnrBzpKIAJkayVLmyIUaG/8Dms3Gpd2VIufeZyW8w0diXdgKSsymjzodTMgghZMdxG3Qpng833ARPg==",
+ "dev": true,
+ "requires": {
+ "@fortawesome/fontawesome-free": "^6.4.0",
+ "@markbind/core-web": "5.1.0",
+ "@primer/octicons": "^15.0.1",
+ "@sindresorhus/slugify": "^0.9.1",
+ "@tlylt/markdown-it-imsize": "^3.0.0",
+ "bluebird": "^3.7.2",
+ "bootswatch": "5.1.3",
+ "cheerio": "^0.22.0",
+ "crypto-js": "^4.0.0",
+ "csv-parse": "^4.14.2",
+ "ensure-posix-path": "^1.1.1",
+ "fastmatter": "^2.1.1",
+ "fs-extra": "^9.0.1",
+ "gh-pages": "^2.1.1",
+ "highlight.js": "^10.4.1",
+ "htmlparser2": "^3.10.1",
+ "ignore": "^5.1.4",
+ "js-beautify": "1.14.3",
+ "katex": "^0.15.6",
+ "lodash": "^4.17.15",
+ "markdown-it": "^12.3.2",
+ "markdown-it-attrs": "^4.1.3",
+ "markdown-it-emoji": "^1.4.0",
+ "markdown-it-linkify-images": "^3.0.0",
+ "markdown-it-mark": "^3.0.0",
+ "markdown-it-regexp": "^0.4.0",
+ "markdown-it-sub": "^1.0.0",
+ "markdown-it-sup": "^1.0.0",
+ "markdown-it-table-of-contents": "^0.4.4",
+ "markdown-it-task-lists": "^2.1.1",
+ "markdown-it-texmath": "^1.0.0",
+ "markdown-it-video": "^0.6.3",
+ "material-icons": "^1.9.1",
+ "moment": "^2.29.4",
+ "nunjucks": "3.2.2",
+ "path-is-inside": "^1.0.2",
+ "simple-git": "^2.17.0",
+ "url-parse": "^1.5.10",
+ "uuid": "^8.3.1",
+ "vue": "2.6.14",
+ "vue-server-renderer": "2.6.14",
+ "vue-template-compiler": "2.6.14",
+ "walk-sync": "^2.0.2",
+ "winston": "^2.4.4"
+ }
+ },
+ "@markbind/core-web": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/@markbind/core-web/-/core-web-5.1.0.tgz",
+ "integrity": "sha512-TRzz8ZCr25pylKvFxF/WwXDi4Gbtsb2OLXV61WyTFqVy03tFoEJ2mqncpbliI9DrfDdKWcm1YZPgDCedVkYjKA==",
+ "dev": true
+ },
+ "@primer/octicons": {
+ "version": "15.2.0",
+ "resolved": "https://registry.npmjs.org/@primer/octicons/-/octicons-15.2.0.tgz",
+ "integrity": "sha512-4cHZzcZ3F/HQNL4EKSaFyVsW7XtITiJkTeB1JDDmRuP/XobyWyF9gWxuV9c+byUa8dOB5KNQn37iRvNrIehPUQ==",
+ "dev": true,
+ "requires": {
+ "object-assign": "^4.1.1"
+ }
+ },
+ "@sindresorhus/slugify": {
+ "version": "0.9.1",
+ "resolved": "https://registry.npmjs.org/@sindresorhus/slugify/-/slugify-0.9.1.tgz",
+ "integrity": "sha512-b6heYM9dzZD13t2GOiEQTDE0qX+I1GyOotMwKh9VQqzuNiVdPVT8dM43fe9HNb/3ul+Qwd5oKSEDrDIfhq3bnQ==",
+ "dev": true,
+ "requires": {
+ "escape-string-regexp": "^1.0.5",
+ "lodash.deburr": "^4.1.0"
+ }
+ },
+ "@tlylt/markdown-it-imsize": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/@tlylt/markdown-it-imsize/-/markdown-it-imsize-3.0.0.tgz",
+ "integrity": "sha512-6kTM+vRJTuN2UxNPyJ8yC+NHrzS+MxVHV+z+bDxSr/Fd7eTah2+otLKC2B17YI/1lQnSumA2qokPGuzsA98c6g==",
+ "dev": true
+ },
+ "@types/minimatch": {
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz",
+ "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==",
+ "dev": true
+ },
+ "a-sync-waterfall": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/a-sync-waterfall/-/a-sync-waterfall-1.0.1.tgz",
+ "integrity": "sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA==",
+ "dev": true
+ },
+ "abbrev": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
+ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
+ "dev": true
+ },
+ "accepts": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
+ "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
+ "dev": true,
+ "requires": {
+ "mime-types": "~2.1.34",
+ "negotiator": "0.6.3"
+ }
+ },
+ "ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^2.0.1"
+ }
+ },
+ "anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "dev": true,
+ "requires": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ }
+ },
+ "apache-crypt": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/apache-crypt/-/apache-crypt-1.2.5.tgz",
+ "integrity": "sha512-ICnYQH+DFVmw+S4Q0QY2XRXD8Ne8ewh8HgbuFH4K7022zCxgHM0Hz1xkRnUlEfAXNbwp1Cnhbedu60USIfDxvg==",
+ "dev": true,
+ "requires": {
+ "unix-crypt-td-js": "^1.1.4"
+ }
+ },
+ "apache-md5": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/apache-md5/-/apache-md5-1.1.7.tgz",
+ "integrity": "sha512-JtHjzZmJxtzfTSjsCyHgPR155HBe5WGyUyHTaEkfy46qhwCFKx1Epm6nAxgUG3WfUZP1dWhGqj9Z2NOBeZ+uBw==",
+ "dev": true
+ },
+ "argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "dev": true,
+ "requires": {
+ "sprintf-js": "~1.0.2"
+ }
+ },
+ "arr-diff": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
+ "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==",
+ "dev": true
+ },
+ "arr-flatten": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
+ "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
+ "dev": true
+ },
+ "arr-union": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
+ "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==",
+ "dev": true
+ },
+ "array-union": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
+ "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==",
+ "dev": true,
+ "requires": {
+ "array-uniq": "^1.0.1"
+ }
+ },
+ "array-uniq": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
+ "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==",
+ "dev": true
+ },
+ "array-unique": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
+ "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==",
+ "dev": true
+ },
+ "asap": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
+ "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==",
+ "dev": true
+ },
+ "assign-symbols": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
+ "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==",
+ "dev": true
+ },
+ "async": {
+ "version": "2.6.4",
+ "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz",
+ "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==",
+ "dev": true,
+ "requires": {
+ "lodash": "^4.17.14"
+ }
+ },
+ "async-each": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz",
+ "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==",
+ "dev": true
+ },
+ "at-least-node": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
+ "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==",
+ "dev": true
+ },
+ "atob": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
+ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
+ "dev": true
+ },
+ "balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true
+ },
+ "base": {
+ "version": "0.11.2",
+ "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
+ "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==",
+ "dev": true,
+ "requires": {
+ "cache-base": "^1.0.1",
+ "class-utils": "^0.3.5",
+ "component-emitter": "^1.2.1",
+ "define-property": "^1.0.0",
+ "isobject": "^3.0.1",
+ "mixin-deep": "^1.2.0",
+ "pascalcase": "^0.1.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^1.0.0"
+ }
+ }
+ }
+ },
+ "basic-auth": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz",
+ "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "5.1.2"
+ }
+ },
+ "batch": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
+ "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==",
+ "dev": true
+ },
+ "bcryptjs": {
+ "version": "2.4.3",
+ "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz",
+ "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==",
+ "dev": true
+ },
+ "binary-extensions": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
+ "dev": true
+ },
+ "bindings": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
+ "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "file-uri-to-path": "1.0.0"
+ }
+ },
+ "bluebird": {
+ "version": "3.7.2",
+ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
+ "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
+ "dev": true
+ },
+ "boolbase": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
+ "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
+ "dev": true
+ },
+ "bootswatch": {
+ "version": "5.1.3",
+ "resolved": "https://registry.npmjs.org/bootswatch/-/bootswatch-5.1.3.tgz",
+ "integrity": "sha512-NmZFN6rOCoXWQ/PkzmD8FFWDe24kocX9OXWHNVaLxVVnpqpAzEbMFsf8bAfKwVtpNXibasZCzv09B5fLieAh2g==",
+ "dev": true
+ },
+ "brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "requires": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "braces": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "dev": true,
+ "requires": {
+ "fill-range": "^7.0.1"
+ }
+ },
+ "cache-base": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
+ "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==",
+ "dev": true,
+ "requires": {
+ "collection-visit": "^1.0.0",
+ "component-emitter": "^1.2.1",
+ "get-value": "^2.0.6",
+ "has-value": "^1.0.0",
+ "isobject": "^3.0.1",
+ "set-value": "^2.0.0",
+ "to-object-path": "^0.3.0",
+ "union-value": "^1.0.0",
+ "unset-value": "^1.0.0"
+ }
+ },
+ "chalk": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
+ "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ }
+ },
+ "cheerio": {
+ "version": "0.22.0",
+ "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz",
+ "integrity": "sha512-8/MzidM6G/TgRelkzDG13y3Y9LxBjCb+8yOEZ9+wwq5gVF2w2pV0wmHvjfT0RvuxGyR7UEuK36r+yYMbT4uKgA==",
+ "dev": true,
+ "requires": {
+ "css-select": "~1.2.0",
+ "dom-serializer": "~0.1.0",
+ "entities": "~1.1.1",
+ "htmlparser2": "^3.9.1",
+ "lodash.assignin": "^4.0.9",
+ "lodash.bind": "^4.1.4",
+ "lodash.defaults": "^4.0.1",
+ "lodash.filter": "^4.4.0",
+ "lodash.flatten": "^4.2.0",
+ "lodash.foreach": "^4.3.0",
+ "lodash.map": "^4.4.0",
+ "lodash.merge": "^4.4.0",
+ "lodash.pick": "^4.2.1",
+ "lodash.reduce": "^4.4.0",
+ "lodash.reject": "^4.4.0",
+ "lodash.some": "^4.4.0"
+ }
+ },
+ "chokidar": {
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
+ "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
+ "dev": true,
+ "requires": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "fsevents": "~2.3.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ }
+ },
+ "class-utils": {
+ "version": "0.3.6",
+ "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
+ "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==",
+ "dev": true,
+ "requires": {
+ "arr-union": "^3.1.0",
+ "define-property": "^0.2.5",
+ "isobject": "^3.0.0",
+ "static-extend": "^0.1.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+ "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "is-data-descriptor": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+ "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "is-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+ "dev": true,
+ "requires": {
+ "is-accessor-descriptor": "^0.1.6",
+ "is-data-descriptor": "^0.1.4",
+ "kind-of": "^5.0.0"
+ }
+ },
+ "kind-of": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+ "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+ "dev": true
+ }
+ }
+ },
+ "collection-visit": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
+ "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==",
+ "dev": true,
+ "requires": {
+ "map-visit": "^1.0.0",
+ "object-visit": "^1.0.0"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "colors": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
+ "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==",
+ "dev": true
+ },
+ "commander": {
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz",
+ "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==",
+ "dev": true
+ },
+ "component-emitter": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
+ "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==",
+ "dev": true
+ },
+ "concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "dev": true
+ },
+ "config-chain": {
+ "version": "1.1.13",
+ "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz",
+ "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==",
+ "dev": true,
+ "requires": {
+ "ini": "^1.3.4",
+ "proto-list": "~1.2.1"
+ }
+ },
+ "connect": {
+ "version": "3.7.0",
+ "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz",
+ "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==",
+ "dev": true,
+ "requires": {
+ "debug": "2.6.9",
+ "finalhandler": "1.1.2",
+ "parseurl": "~1.3.3",
+ "utils-merge": "1.0.1"
+ }
+ },
+ "copy-descriptor": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
+ "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==",
+ "dev": true
+ },
+ "core-util-is": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
+ "dev": true
+ },
+ "cors": {
+ "version": "2.8.5",
+ "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
+ "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
+ "dev": true,
+ "requires": {
+ "object-assign": "^4",
+ "vary": "^1"
+ }
+ },
+ "crypto-js": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz",
+ "integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==",
+ "dev": true
+ },
+ "css-select": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz",
+ "integrity": "sha512-dUQOBoqdR7QwV90WysXPLXG5LO7nhYBgiWVfxF80DKPF8zx1t/pUd2FYy73emg3zrjtM6dzmYgbHKfV2rxiHQA==",
+ "dev": true,
+ "requires": {
+ "boolbase": "~1.0.0",
+ "css-what": "2.1",
+ "domutils": "1.5.1",
+ "nth-check": "~1.0.1"
+ }
+ },
+ "css-what": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz",
+ "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==",
+ "dev": true
+ },
+ "csv-parse": {
+ "version": "4.16.3",
+ "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-4.16.3.tgz",
+ "integrity": "sha512-cO1I/zmz4w2dcKHVvpCr7JVRu8/FymG5OEpmvsZYlccYolPBLoVGKUHgNoc4ZGkFeFlWGEDmMyBM+TTqRdW/wg==",
+ "dev": true
+ },
+ "cycle": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz",
+ "integrity": "sha512-TVF6svNzeQCOpjCqsy0/CSy8VgObG3wXusJ73xW2GbG5rGx7lC8zxDSURicsXI2UsGdi2L0QNRCi745/wUDvsA==",
+ "dev": true
+ },
+ "de-indent": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz",
+ "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==",
+ "dev": true
+ },
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "decode-uri-component": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
+ "integrity": "sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og==",
+ "dev": true
+ },
+ "define-property": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
+ "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^1.0.2",
+ "isobject": "^3.0.1"
+ }
+ },
+ "depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+ "dev": true
+ },
+ "destroy": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
+ "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
+ "dev": true
+ },
+ "dom-serializer": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz",
+ "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==",
+ "dev": true,
+ "requires": {
+ "domelementtype": "^1.3.0",
+ "entities": "^1.1.1"
+ }
+ },
+ "domelementtype": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
+ "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==",
+ "dev": true
+ },
+ "domhandler": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz",
+ "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==",
+ "dev": true,
+ "requires": {
+ "domelementtype": "1"
+ }
+ },
+ "domutils": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz",
+ "integrity": "sha512-gSu5Oi/I+3wDENBsOWBiRK1eoGxcywYSqg3rR960/+EfY0CF4EX1VPkgHOZ3WiS/Jg2DtliF6BhWcHlfpYUcGw==",
+ "dev": true,
+ "requires": {
+ "dom-serializer": "0",
+ "domelementtype": "1"
+ }
+ },
+ "duplexer": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
+ "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==",
+ "dev": true
+ },
+ "editorconfig": {
+ "version": "0.15.3",
+ "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz",
+ "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==",
+ "dev": true,
+ "requires": {
+ "commander": "^2.19.0",
+ "lru-cache": "^4.1.5",
+ "semver": "^5.6.0",
+ "sigmund": "^1.0.1"
+ },
+ "dependencies": {
+ "commander": {
+ "version": "2.20.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+ "dev": true
+ }
+ }
+ },
+ "ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
+ "dev": true
+ },
+ "email-addresses": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-3.1.0.tgz",
+ "integrity": "sha512-k0/r7GrWVL32kZlGwfPNgB2Y/mMXVTq/decgLczm/j34whdaspNrZO8CnXPf1laaHxI6ptUlsnAxN+UAPw+fzg==",
+ "dev": true
+ },
+ "encodeurl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+ "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
+ "dev": true
+ },
+ "ensure-posix-path": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ensure-posix-path/-/ensure-posix-path-1.1.1.tgz",
+ "integrity": "sha512-VWU0/zXzVbeJNXvME/5EmLuEj2TauvoaTz6aFYK1Z92JCBlDlZ3Gu0tuGR42kpW1754ywTs+QB0g5TP0oj9Zaw==",
+ "dev": true
+ },
+ "entities": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
+ "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==",
+ "dev": true
+ },
+ "escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
+ "dev": true
+ },
+ "escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+ "dev": true
+ },
+ "esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+ "dev": true
+ },
+ "etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
+ "dev": true
+ },
+ "event-stream": {
+ "version": "3.3.4",
+ "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz",
+ "integrity": "sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==",
+ "dev": true,
+ "requires": {
+ "duplexer": "~0.1.1",
+ "from": "~0",
+ "map-stream": "~0.1.0",
+ "pause-stream": "0.0.11",
+ "split": "0.3",
+ "stream-combiner": "~0.0.4",
+ "through": "~2.3.1"
+ },
+ "dependencies": {
+ "split": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz",
+ "integrity": "sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==",
+ "dev": true,
+ "requires": {
+ "through": "2"
+ }
+ },
+ "stream-combiner": {
+ "version": "0.0.4",
+ "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz",
+ "integrity": "sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==",
+ "dev": true,
+ "requires": {
+ "duplexer": "~0.1.1"
+ }
+ }
+ }
+ },
+ "expand-brackets": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
+ "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==",
+ "dev": true,
+ "requires": {
+ "debug": "^2.3.3",
+ "define-property": "^0.2.5",
+ "extend-shallow": "^2.0.1",
+ "posix-character-classes": "^0.1.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
+ "dev": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+ "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "is-data-descriptor": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+ "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "is-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+ "dev": true,
+ "requires": {
+ "is-accessor-descriptor": "^0.1.6",
+ "is-data-descriptor": "^0.1.4",
+ "kind-of": "^5.0.0"
+ }
+ },
+ "is-extendable": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+ "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
+ "dev": true
+ },
+ "kind-of": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+ "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+ "dev": true
+ }
+ }
+ },
+ "extend-shallow": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+ "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==",
+ "dev": true,
+ "requires": {
+ "assign-symbols": "^1.0.0",
+ "is-extendable": "^1.0.1"
+ }
+ },
+ "extglob": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
+ "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
+ "dev": true,
+ "requires": {
+ "array-unique": "^0.3.2",
+ "define-property": "^1.0.0",
+ "expand-brackets": "^2.1.4",
+ "extend-shallow": "^2.0.1",
+ "fragment-cache": "^0.2.1",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^1.0.0"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
+ "dev": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ },
+ "is-extendable": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+ "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
+ "dev": true
+ }
+ }
+ },
+ "eyes": {
+ "version": "0.1.8",
+ "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz",
+ "integrity": "sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==",
+ "dev": true
+ },
+ "fast-safe-stringify": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz",
+ "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==",
+ "dev": true
+ },
+ "fastmatter": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/fastmatter/-/fastmatter-2.1.1.tgz",
+ "integrity": "sha512-NFrjZEPJZTexoJEuyM5J7n4uFaLf0dOI7Ok4b2IZXOYBqCp1Bh5RskANmQ2TuDsz3M35B1yL2AP/Rn+kp85KeA==",
+ "dev": true,
+ "requires": {
+ "js-yaml": "^3.13.0",
+ "split": "^1.0.1",
+ "stream-combiner": "^0.2.2",
+ "through2": "^3.0.1"
+ }
+ },
+ "faye-websocket": {
+ "version": "0.11.4",
+ "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz",
+ "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==",
+ "dev": true,
+ "requires": {
+ "websocket-driver": ">=0.5.1"
+ }
+ },
+ "fecha": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz",
+ "integrity": "sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==",
+ "dev": true
+ },
+ "figlet": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/figlet/-/figlet-1.5.2.tgz",
+ "integrity": "sha512-WOn21V8AhyE1QqVfPIVxe3tupJacq1xGkPTB4iagT6o+P2cAgEOOwIxMftr4+ZCTI6d551ij9j61DFr0nsP2uQ==",
+ "dev": true
+ },
+ "file-stream-rotator": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/file-stream-rotator/-/file-stream-rotator-0.4.1.tgz",
+ "integrity": "sha512-W3aa3QJEc8BS2MmdVpQiYLKHj3ijpto1gMDlsgCRSKfIUe6MwkcpODGPQ3vZfb0XvCeCqlu9CBQTN7oQri2TZQ==",
+ "dev": true,
+ "requires": {
+ "moment": "^2.11.2"
+ }
+ },
+ "file-uri-to-path": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
+ "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
+ "dev": true,
+ "optional": true
+ },
+ "filename-reserved-regex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-1.0.0.tgz",
+ "integrity": "sha512-UZArj7+U+2reBBVCvVmRlyq9D7EYQdUtuNN+1iz7pF1jGcJ2L0TjiRCxsTZfj2xFbM4c25uGCUDpKTHA7L2TKg==",
+ "dev": true
+ },
+ "filenamify": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-1.2.1.tgz",
+ "integrity": "sha512-DKVP0WQcB7WaIMSwDETqImRej2fepPqvXQjaVib7LRZn9Rxn5UbvK2tYTqGf1A1DkIprQQkG4XSQXSOZp7Q3GQ==",
+ "dev": true,
+ "requires": {
+ "filename-reserved-regex": "^1.0.0",
+ "strip-outer": "^1.0.0",
+ "trim-repeated": "^1.0.0"
+ }
+ },
+ "filenamify-url": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/filenamify-url/-/filenamify-url-1.0.0.tgz",
+ "integrity": "sha512-O9K9JcZeF5VdZWM1qR92NSv1WY2EofwudQayPx5dbnnFl9k0IcZha4eV/FGkjnBK+1irOQInij0yiooCHu/0Fg==",
+ "dev": true,
+ "requires": {
+ "filenamify": "^1.0.0",
+ "humanize-url": "^1.0.0"
+ }
+ },
+ "fill-range": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "dev": true,
+ "requires": {
+ "to-regex-range": "^5.0.1"
+ }
+ },
+ "finalhandler": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
+ "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
+ "dev": true,
+ "requires": {
+ "debug": "2.6.9",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "on-finished": "~2.3.0",
+ "parseurl": "~1.3.3",
+ "statuses": "~1.5.0",
+ "unpipe": "~1.0.0"
+ }
+ },
+ "find-up": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+ "dev": true,
+ "requires": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ }
+ },
+ "for-in": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
+ "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==",
+ "dev": true
+ },
+ "fragment-cache": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
+ "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==",
+ "dev": true,
+ "requires": {
+ "map-cache": "^0.2.2"
+ }
+ },
+ "fresh": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+ "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
+ "dev": true
+ },
+ "from": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz",
+ "integrity": "sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==",
+ "dev": true
+ },
+ "fs-extra": {
+ "version": "9.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
+ "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
+ "dev": true,
+ "requires": {
+ "at-least-node": "^1.0.0",
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^6.0.1",
+ "universalify": "^2.0.0"
+ }
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+ "dev": true
+ },
+ "fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "dev": true,
+ "optional": true
+ },
+ "function-bind": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
+ "dev": true
+ },
+ "get-value": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
+ "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==",
+ "dev": true
+ },
+ "gh-pages": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-2.2.0.tgz",
+ "integrity": "sha512-c+yPkNOPMFGNisYg9r4qvsMIjVYikJv7ImFOhPIVPt0+AcRUamZ7zkGRLHz7FKB0xrlZ+ddSOJsZv9XAFVXLmA==",
+ "dev": true,
+ "requires": {
+ "async": "^2.6.1",
+ "commander": "^2.18.0",
+ "email-addresses": "^3.0.1",
+ "filenamify-url": "^1.0.0",
+ "fs-extra": "^8.1.0",
+ "globby": "^6.1.0"
+ },
+ "dependencies": {
+ "commander": {
+ "version": "2.20.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+ "dev": true
+ },
+ "fs-extra": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
+ "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^4.0.0",
+ "universalify": "^0.1.0"
+ }
+ },
+ "jsonfile": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
+ "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.6"
+ }
+ },
+ "universalify": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
+ "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
+ "dev": true
+ }
+ }
+ },
+ "glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "dev": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "requires": {
+ "is-glob": "^4.0.1"
+ }
+ },
+ "globby": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz",
+ "integrity": "sha512-KVbFv2TQtbzCoxAnfD6JcHZTYCzyliEaaeM/gH8qQdkKr5s0OP9scEgvdcngyk7AVdY6YVW/TJHd+lQ/Df3Daw==",
+ "dev": true,
+ "requires": {
+ "array-union": "^1.0.1",
+ "glob": "^7.0.3",
+ "object-assign": "^4.0.1",
+ "pify": "^2.0.0",
+ "pinkie-promise": "^2.0.0"
+ }
+ },
+ "graceful-fs": {
+ "version": "4.2.10",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
+ "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
+ "dev": true
+ },
+ "has": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+ "dev": true,
+ "requires": {
+ "function-bind": "^1.1.1"
+ }
+ },
+ "has-ansi": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
+ "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ },
+ "has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true
+ },
+ "has-value": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
+ "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==",
+ "dev": true,
+ "requires": {
+ "get-value": "^2.0.6",
+ "has-values": "^1.0.0",
+ "isobject": "^3.0.0"
+ }
+ },
+ "has-values": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz",
+ "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==",
+ "dev": true,
+ "requires": {
+ "is-number": "^3.0.0",
+ "kind-of": "^4.0.0"
+ },
+ "dependencies": {
+ "is-number": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+ "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "kind-of": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
+ "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "hash-sum": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz",
+ "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==",
+ "dev": true
+ },
+ "he": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
+ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
+ "dev": true
+ },
+ "highlight.js": {
+ "version": "10.7.3",
+ "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz",
+ "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==",
+ "dev": true
+ },
+ "htmlparser2": {
+ "version": "3.10.1",
+ "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
+ "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==",
+ "dev": true,
+ "requires": {
+ "domelementtype": "^1.3.1",
+ "domhandler": "^2.3.0",
+ "domutils": "^1.5.1",
+ "entities": "^1.1.1",
+ "inherits": "^2.0.1",
+ "readable-stream": "^3.1.1"
+ }
+ },
+ "http-auth": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/http-auth/-/http-auth-3.1.3.tgz",
+ "integrity": "sha512-Jbx0+ejo2IOx+cRUYAGS1z6RGc6JfYUNkysZM4u4Sfk1uLlGv814F7/PIjQQAuThLdAWxb74JMGd5J8zex1VQg==",
+ "dev": true,
+ "requires": {
+ "apache-crypt": "^1.1.2",
+ "apache-md5": "^1.0.6",
+ "bcryptjs": "^2.3.0",
+ "uuid": "^3.0.0"
+ },
+ "dependencies": {
+ "uuid": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
+ "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
+ "dev": true
+ }
+ }
+ },
+ "http-errors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+ "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+ "dev": true,
+ "requires": {
+ "depd": "2.0.0",
+ "inherits": "2.0.4",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "toidentifier": "1.0.1"
+ },
+ "dependencies": {
+ "statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
+ "dev": true
+ }
+ }
+ },
+ "http-parser-js": {
+ "version": "0.5.8",
+ "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz",
+ "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==",
+ "dev": true
+ },
+ "humanize-url": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/humanize-url/-/humanize-url-1.0.1.tgz",
+ "integrity": "sha512-RtgTzXCPVb/te+e82NDhAc5paj+DuKSratIGAr+v+HZK24eAQ8LMoBGYoL7N/O+9iEc33AKHg45dOMKw3DNldQ==",
+ "dev": true,
+ "requires": {
+ "normalize-url": "^1.0.0",
+ "strip-url-auth": "^1.0.0"
+ }
+ },
+ "ignore": {
+ "version": "5.2.4",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
+ "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
+ "dev": true
+ },
+ "inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+ "dev": true,
+ "requires": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true
+ },
+ "ini": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
+ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
+ "dev": true
+ },
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dev": true,
+ "requires": {
+ "binary-extensions": "^2.0.0"
+ }
+ },
+ "is-buffer": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+ "dev": true
+ },
+ "is-core-module": {
+ "version": "2.13.0",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz",
+ "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==",
+ "dev": true,
+ "requires": {
+ "has": "^1.0.3"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "dev": true,
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ },
+ "is-extendable": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+ "dev": true,
+ "requires": {
+ "is-plain-object": "^2.0.4"
+ }
+ },
+ "is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true
+ },
+ "is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
+ "requires": {
+ "is-extglob": "^2.1.1"
+ }
+ },
+ "is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true
+ },
+ "is-plain-obj": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
+ "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==",
+ "dev": true
+ },
+ "is-plain-object": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+ "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+ "dev": true,
+ "requires": {
+ "isobject": "^3.0.1"
+ }
+ },
+ "is-windows": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
+ "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
+ "dev": true
+ },
+ "is-wsl": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz",
+ "integrity": "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==",
+ "dev": true
+ },
+ "isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
+ "dev": true
+ },
+ "isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==",
+ "dev": true
+ },
+ "isstream": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
+ "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==",
+ "dev": true
+ },
+ "js-beautify": {
+ "version": "1.14.3",
+ "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.14.3.tgz",
+ "integrity": "sha512-f1ra8PHtOEu/70EBnmiUlV8nJePS58y9qKjl4JHfYWlFH6bo7ogZBz//FAZp7jDuXtYnGYKymZPlrg2I/9Zo4g==",
+ "dev": true,
+ "requires": {
+ "config-chain": "^1.1.13",
+ "editorconfig": "^0.15.3",
+ "glob": "^7.1.3",
+ "nopt": "^5.0.0"
+ }
+ },
+ "js-yaml": {
+ "version": "3.14.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+ "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+ "dev": true,
+ "requires": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ }
+ },
+ "jsonfile": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
+ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.6",
+ "universalify": "^2.0.0"
+ }
+ },
+ "katex": {
+ "version": "0.15.6",
+ "resolved": "https://registry.npmjs.org/katex/-/katex-0.15.6.tgz",
+ "integrity": "sha512-UpzJy4yrnqnhXvRPhjEuLA4lcPn6eRngixW7Q3TJErjg3Aw2PuLFBzTkdUb89UtumxjhHTqL3a5GDGETMSwgJA==",
+ "dev": true,
+ "requires": {
+ "commander": "^8.0.0"
+ }
+ },
+ "kind-of": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+ "dev": true
+ },
+ "linkify-it": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz",
+ "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==",
+ "dev": true,
+ "requires": {
+ "uc.micro": "^1.0.1"
+ }
+ },
+ "live-server": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/live-server/-/live-server-1.2.1.tgz",
+ "integrity": "sha512-Yn2XCVjErTkqnM3FfTmM7/kWy3zP7+cEtC7x6u+wUzlQ+1UW3zEYbbyJrc0jNDwiMDZI0m4a0i3dxlGHVyXczw==",
+ "dev": true,
+ "requires": {
+ "chokidar": "^2.0.4",
+ "colors": "latest",
+ "connect": "^3.6.6",
+ "cors": "latest",
+ "event-stream": "3.3.4",
+ "faye-websocket": "0.11.x",
+ "http-auth": "3.1.x",
+ "morgan": "^1.9.1",
+ "object-assign": "latest",
+ "opn": "latest",
+ "proxy-middleware": "latest",
+ "send": "latest",
+ "serve-index": "^1.9.1"
+ },
+ "dependencies": {
+ "anymatch": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
+ "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
+ "dev": true,
+ "requires": {
+ "micromatch": "^3.1.4",
+ "normalize-path": "^2.1.1"
+ },
+ "dependencies": {
+ "normalize-path": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+ "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==",
+ "dev": true,
+ "requires": {
+ "remove-trailing-separator": "^1.0.1"
+ }
+ }
+ }
+ },
+ "binary-extensions": {
+ "version": "1.13.1",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz",
+ "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==",
+ "dev": true
+ },
+ "braces": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
+ "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
+ "dev": true,
+ "requires": {
+ "arr-flatten": "^1.1.0",
+ "array-unique": "^0.3.2",
+ "extend-shallow": "^2.0.1",
+ "fill-range": "^4.0.0",
+ "isobject": "^3.0.1",
+ "repeat-element": "^1.1.2",
+ "snapdragon": "^0.8.1",
+ "snapdragon-node": "^2.0.1",
+ "split-string": "^3.0.2",
+ "to-regex": "^3.0.1"
+ }
+ },
+ "chokidar": {
+ "version": "2.1.8",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
+ "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==",
+ "dev": true,
+ "requires": {
+ "anymatch": "^2.0.0",
+ "async-each": "^1.0.1",
+ "braces": "^2.3.2",
+ "fsevents": "^1.2.7",
+ "glob-parent": "^3.1.0",
+ "inherits": "^2.0.3",
+ "is-binary-path": "^1.0.0",
+ "is-glob": "^4.0.0",
+ "normalize-path": "^3.0.0",
+ "path-is-absolute": "^1.0.0",
+ "readdirp": "^2.2.1",
+ "upath": "^1.1.1"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
+ "dev": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ },
+ "fill-range": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
+ "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==",
+ "dev": true,
+ "requires": {
+ "extend-shallow": "^2.0.1",
+ "is-number": "^3.0.0",
+ "repeat-string": "^1.6.1",
+ "to-regex-range": "^2.1.0"
+ }
+ },
+ "fsevents": {
+ "version": "1.2.13",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
+ "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "bindings": "^1.5.0",
+ "nan": "^2.12.1"
+ }
+ },
+ "glob-parent": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
+ "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==",
+ "dev": true,
+ "requires": {
+ "is-glob": "^3.1.0",
+ "path-dirname": "^1.0.0"
+ },
+ "dependencies": {
+ "is-glob": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+ "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==",
+ "dev": true,
+ "requires": {
+ "is-extglob": "^2.1.0"
+ }
+ }
+ }
+ },
+ "is-binary-path": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
+ "integrity": "sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==",
+ "dev": true,
+ "requires": {
+ "binary-extensions": "^1.0.0"
+ }
+ },
+ "is-extendable": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+ "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
+ "dev": true
+ },
+ "is-number": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+ "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ }
+ },
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ },
+ "readable-stream": {
+ "version": "2.3.7",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+ "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+ "dev": true,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "readdirp": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
+ "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.11",
+ "micromatch": "^3.1.10",
+ "readable-stream": "^2.0.2"
+ }
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "to-regex-range": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
+ "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==",
+ "dev": true,
+ "requires": {
+ "is-number": "^3.0.0",
+ "repeat-string": "^1.6.1"
+ }
+ }
+ }
+ },
+ "locate-path": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+ "dev": true,
+ "requires": {
+ "p-locate": "^4.1.0"
+ }
+ },
+ "lodash": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
+ "dev": true
+ },
+ "lodash._reinterpolate": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
+ "integrity": "sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA==",
+ "dev": true
+ },
+ "lodash.assignin": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz",
+ "integrity": "sha512-yX/rx6d/UTVh7sSVWVSIMjfnz95evAgDFdb1ZozC35I9mSFCkmzptOzevxjgbQUsc78NR44LVHWjsoMQXy9FDg==",
+ "dev": true
+ },
+ "lodash.bind": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/lodash.bind/-/lodash.bind-4.2.1.tgz",
+ "integrity": "sha512-lxdsn7xxlCymgLYo1gGvVrfHmkjDiyqVv62FAeF2i5ta72BipE1SLxw8hPEPLhD4/247Ijw07UQH7Hq/chT5LA==",
+ "dev": true
+ },
+ "lodash.deburr": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/lodash.deburr/-/lodash.deburr-4.1.0.tgz",
+ "integrity": "sha512-m/M1U1f3ddMCs6Hq2tAsYThTBDaAKFDX3dwDo97GEYzamXi9SqUpjWi/Rrj/gf3X2n8ktwgZrlP1z6E3v/IExQ==",
+ "dev": true
+ },
+ "lodash.defaults": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
+ "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==",
+ "dev": true
+ },
+ "lodash.filter": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/lodash.filter/-/lodash.filter-4.6.0.tgz",
+ "integrity": "sha512-pXYUy7PR8BCLwX5mgJ/aNtyOvuJTdZAo9EQFUvMIYugqmJxnrYaANvTbgndOzHSCSR0wnlBBfRXJL5SbWxo3FQ==",
+ "dev": true
+ },
+ "lodash.flatten": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz",
+ "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==",
+ "dev": true
+ },
+ "lodash.foreach": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz",
+ "integrity": "sha512-aEXTF4d+m05rVOAUG3z4vZZ4xVexLKZGF0lIxuHZ1Hplpk/3B6Z1+/ICICYRLm7c41Z2xiejbkCkJoTlypoXhQ==",
+ "dev": true
+ },
+ "lodash.map": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz",
+ "integrity": "sha512-worNHGKLDetmcEYDvh2stPCrrQRkP20E4l0iIS7F8EvzMqBBi7ltvFN5m1HvTf1P7Jk1txKhvFcmYsCr8O2F1Q==",
+ "dev": true
+ },
+ "lodash.merge": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+ "dev": true
+ },
+ "lodash.pick": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz",
+ "integrity": "sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q==",
+ "dev": true
+ },
+ "lodash.reduce": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/lodash.reduce/-/lodash.reduce-4.6.0.tgz",
+ "integrity": "sha512-6raRe2vxCYBhpBu+B+TtNGUzah+hQjVdu3E17wfusjyrXBka2nBS8OH/gjVZ5PvHOhWmIZTYri09Z6n/QfnNMw==",
+ "dev": true
+ },
+ "lodash.reject": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/lodash.reject/-/lodash.reject-4.6.0.tgz",
+ "integrity": "sha512-qkTuvgEzYdyhiJBx42YPzPo71R1aEr0z79kAv7Ixg8wPFEjgRgJdUsGMG3Hf3OYSF/kHI79XhNlt+5Ar6OzwxQ==",
+ "dev": true
+ },
+ "lodash.some": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz",
+ "integrity": "sha512-j7MJE+TuT51q9ggt4fSgVqro163BEFjAt3u97IqU+JA2DkWl80nFTrowzLpZ/BnpN7rrl0JA/593NAdd8p/scQ==",
+ "dev": true
+ },
+ "lodash.template": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz",
+ "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==",
+ "dev": true,
+ "requires": {
+ "lodash._reinterpolate": "^3.0.0",
+ "lodash.templatesettings": "^4.0.0"
+ }
+ },
+ "lodash.templatesettings": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz",
+ "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==",
+ "dev": true,
+ "requires": {
+ "lodash._reinterpolate": "^3.0.0"
+ }
+ },
+ "lodash.uniq": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
+ "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==",
+ "dev": true
+ },
+ "logform": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/logform/-/logform-1.10.0.tgz",
+ "integrity": "sha512-em5ojIhU18fIMOw/333mD+ZLE2fis0EzXl1ZwHx4iQzmpQi6odNiY/t+ITNr33JZhT9/KEaH+UPIipr6a9EjWg==",
+ "dev": true,
+ "requires": {
+ "colors": "^1.2.1",
+ "fast-safe-stringify": "^2.0.4",
+ "fecha": "^2.3.3",
+ "ms": "^2.1.1",
+ "triple-beam": "^1.2.0"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true
+ }
+ }
+ },
+ "lru-cache": {
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
+ "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
+ "dev": true,
+ "requires": {
+ "pseudomap": "^1.0.2",
+ "yallist": "^2.1.2"
+ }
+ },
+ "map-cache": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
+ "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==",
+ "dev": true
+ },
+ "map-stream": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz",
+ "integrity": "sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==",
+ "dev": true
+ },
+ "map-visit": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
+ "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==",
+ "dev": true,
+ "requires": {
+ "object-visit": "^1.0.0"
+ }
+ },
+ "markbind-cli": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/markbind-cli/-/markbind-cli-5.1.0.tgz",
+ "integrity": "sha512-6POI1Q++2aZa+Udk/oQ6LX1oNPbKUBDY0mN3Up7VOFeK+XYW51faxuCk2Q91JTBxYRKLNtshxf0y12kB4Cj9Qw==",
+ "dev": true,
+ "requires": {
+ "@markbind/core": "5.1.0",
+ "@markbind/core-web": "5.1.0",
+ "bluebird": "^3.7.2",
+ "chalk": "^3.0.0",
+ "cheerio": "^0.22.0",
+ "chokidar": "^3.3.0",
+ "colors": "1.4.0",
+ "commander": "^8.1.0",
+ "figlet": "^1.2.4",
+ "find-up": "^4.1.0",
+ "fs-extra": "^9.0.1",
+ "live-server": "1.2.1",
+ "lodash": "^4.17.15",
+ "url-parse": "^1.5.10",
+ "winston": "^2.4.4",
+ "winston-daily-rotate-file": "^3.10.0"
+ }
+ },
+ "markdown-it": {
+ "version": "12.3.2",
+ "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz",
+ "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==",
+ "dev": true,
+ "requires": {
+ "argparse": "^2.0.1",
+ "entities": "~2.1.0",
+ "linkify-it": "^3.0.1",
+ "mdurl": "^1.0.1",
+ "uc.micro": "^1.0.5"
+ },
+ "dependencies": {
+ "argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true
+ },
+ "entities": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
+ "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==",
+ "dev": true
+ }
+ }
+ },
+ "markdown-it-attrs": {
+ "version": "4.1.6",
+ "resolved": "https://registry.npmjs.org/markdown-it-attrs/-/markdown-it-attrs-4.1.6.tgz",
+ "integrity": "sha512-O7PDKZlN8RFMyDX13JnctQompwrrILuz2y43pW2GagcwpIIElkAdfeek+erHfxUOlXWPsjFeWmZ8ch1xtRLWpA==",
+ "dev": true,
+ "requires": {}
+ },
+ "markdown-it-emoji": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/markdown-it-emoji/-/markdown-it-emoji-1.4.0.tgz",
+ "integrity": "sha512-QCz3Hkd+r5gDYtS2xsFXmBYrgw6KuWcJZLCEkdfAuwzZbShCmCfta+hwAMq4NX/4xPzkSHduMKgMkkPUJxSXNg==",
+ "dev": true
+ },
+ "markdown-it-linkify-images": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/markdown-it-linkify-images/-/markdown-it-linkify-images-3.0.0.tgz",
+ "integrity": "sha512-Vs5yGJa5MWjFgytzgtn8c1U6RcStj3FZKhhx459U8dYbEE5FTWZ6mMRkYMiDlkFO0j4VCsQT1LT557bY0ETgtg==",
+ "dev": true,
+ "requires": {
+ "markdown-it": "^13.0.1"
+ },
+ "dependencies": {
+ "argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true
+ },
+ "entities": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
+ "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==",
+ "dev": true
+ },
+ "linkify-it": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-4.0.1.tgz",
+ "integrity": "sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==",
+ "dev": true,
+ "requires": {
+ "uc.micro": "^1.0.1"
+ }
+ },
+ "markdown-it": {
+ "version": "13.0.1",
+ "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.1.tgz",
+ "integrity": "sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==",
+ "dev": true,
+ "requires": {
+ "argparse": "^2.0.1",
+ "entities": "~3.0.1",
+ "linkify-it": "^4.0.1",
+ "mdurl": "^1.0.1",
+ "uc.micro": "^1.0.5"
+ }
+ }
+ }
+ },
+ "markdown-it-mark": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/markdown-it-mark/-/markdown-it-mark-3.0.1.tgz",
+ "integrity": "sha512-HyxjAu6BRsdt6Xcv6TKVQnkz/E70TdGXEFHRYBGLncRE9lBFwDNLVtFojKxjJWgJ+5XxUwLaHXy+2sGBbDn+4A==",
+ "dev": true
+ },
+ "markdown-it-regexp": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/markdown-it-regexp/-/markdown-it-regexp-0.4.0.tgz",
+ "integrity": "sha512-0XQmr46K/rMKnI93Y3CLXsHj4jIioRETTAiVnJnjrZCEkGaDOmUxTbZj/aZ17G5NlRcVpWBYjqpwSlQ9lj+Kxw==",
+ "dev": true
+ },
+ "markdown-it-sub": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/markdown-it-sub/-/markdown-it-sub-1.0.0.tgz",
+ "integrity": "sha512-z2Rm/LzEE1wzwTSDrI+FlPEveAAbgdAdPhdWarq/ZGJrGW/uCQbKAnhoCsE4hAbc3SEym26+W2z/VQB0cQiA9Q==",
+ "dev": true
+ },
+ "markdown-it-sup": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/markdown-it-sup/-/markdown-it-sup-1.0.0.tgz",
+ "integrity": "sha512-E32m0nV9iyhRR7CrhnzL5msqic7rL1juWre6TQNxsnApg7Uf+F97JOKxUijg5YwXz86lZ0mqfOnutoryyNdntQ==",
+ "dev": true
+ },
+ "markdown-it-table-of-contents": {
+ "version": "0.4.4",
+ "resolved": "https://registry.npmjs.org/markdown-it-table-of-contents/-/markdown-it-table-of-contents-0.4.4.tgz",
+ "integrity": "sha512-TAIHTHPwa9+ltKvKPWulm/beozQU41Ab+FIefRaQV1NRnpzwcV9QOe6wXQS5WLivm5Q/nlo0rl6laGkMDZE7Gw==",
+ "dev": true
+ },
+ "markdown-it-task-lists": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/markdown-it-task-lists/-/markdown-it-task-lists-2.1.1.tgz",
+ "integrity": "sha512-TxFAc76Jnhb2OUu+n3yz9RMu4CwGfaT788br6HhEDlvWfdeJcLUsxk1Hgw2yJio0OXsxv7pyIPmvECY7bMbluA==",
+ "dev": true
+ },
+ "markdown-it-texmath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/markdown-it-texmath/-/markdown-it-texmath-1.0.0.tgz",
+ "integrity": "sha512-4hhkiX8/gus+6e53PLCUmUrsa6ZWGgJW2XCW6O0ASvZUiezIK900ZicinTDtG3kAO2kon7oUA/ReWmpW2FByxg==",
+ "dev": true
+ },
+ "markdown-it-video": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/markdown-it-video/-/markdown-it-video-0.6.3.tgz",
+ "integrity": "sha512-T4th1kwy0OcvyWSN4u3rqPGxvbDclpucnVSSaH3ZacbGsAts964dxokx9s/I3GYsrDCJs4ogtEeEeVP18DQj0Q==",
+ "dev": true
+ },
+ "matcher-collection": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/matcher-collection/-/matcher-collection-2.0.1.tgz",
+ "integrity": "sha512-daE62nS2ZQsDg9raM0IlZzLmI2u+7ZapXBwdoeBUKAYERPDDIc0qNqA8E0Rp2D+gspKR7BgIFP52GeujaGXWeQ==",
+ "dev": true,
+ "requires": {
+ "@types/minimatch": "^3.0.3",
+ "minimatch": "^3.0.2"
+ }
+ },
+ "material-icons": {
+ "version": "1.13.11",
+ "resolved": "https://registry.npmjs.org/material-icons/-/material-icons-1.13.11.tgz",
+ "integrity": "sha512-kp2oAdaqo/Zp6hpTZW01rOgDPWmxBUszSdDzkRm1idCjjNvdUMnqu8qu58cll6CObo+o0cydOiPLdoSugLm+mQ==",
+ "dev": true
+ },
+ "mdurl": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
+ "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==",
+ "dev": true
+ },
+ "micromatch": {
+ "version": "3.1.10",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+ "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
+ "dev": true,
+ "requires": {
+ "arr-diff": "^4.0.0",
+ "array-unique": "^0.3.2",
+ "braces": "^2.3.1",
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "extglob": "^2.0.4",
+ "fragment-cache": "^0.2.1",
+ "kind-of": "^6.0.2",
+ "nanomatch": "^1.2.9",
+ "object.pick": "^1.3.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.2"
+ },
+ "dependencies": {
+ "braces": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
+ "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
+ "dev": true,
+ "requires": {
+ "arr-flatten": "^1.1.0",
+ "array-unique": "^0.3.2",
+ "extend-shallow": "^2.0.1",
+ "fill-range": "^4.0.0",
+ "isobject": "^3.0.1",
+ "repeat-element": "^1.1.2",
+ "snapdragon": "^0.8.1",
+ "snapdragon-node": "^2.0.1",
+ "split-string": "^3.0.2",
+ "to-regex": "^3.0.1"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
+ "dev": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "fill-range": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
+ "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==",
+ "dev": true,
+ "requires": {
+ "extend-shallow": "^2.0.1",
+ "is-number": "^3.0.0",
+ "repeat-string": "^1.6.1",
+ "to-regex-range": "^2.1.0"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
+ "dev": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "is-extendable": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+ "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
+ "dev": true
+ },
+ "is-number": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+ "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "to-regex-range": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
+ "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==",
+ "dev": true,
+ "requires": {
+ "is-number": "^3.0.0",
+ "repeat-string": "^1.6.1"
+ }
+ }
+ }
+ },
+ "mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+ "dev": true
+ },
+ "mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+ "dev": true
+ },
+ "mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "dev": true,
+ "requires": {
+ "mime-db": "1.52.0"
+ }
+ },
+ "minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "requires": {
+ "brace-expansion": "^1.1.7"
+ }
+ },
+ "mixin-deep": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
+ "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
+ "dev": true,
+ "requires": {
+ "for-in": "^1.0.2",
+ "is-extendable": "^1.0.1"
+ }
+ },
+ "moment": {
+ "version": "2.29.4",
+ "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
+ "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==",
+ "dev": true
+ },
+ "morgan": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz",
+ "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==",
+ "dev": true,
+ "requires": {
+ "basic-auth": "~2.0.1",
+ "debug": "2.6.9",
+ "depd": "~2.0.0",
+ "on-finished": "~2.3.0",
+ "on-headers": "~1.0.2"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+ "dev": true
+ },
+ "nan": {
+ "version": "2.16.0",
+ "resolved": "https://registry.npmjs.org/nan/-/nan-2.16.0.tgz",
+ "integrity": "sha512-UdAqHyFngu7TfQKsCBgAA6pWDkT8MAO7d0jyOecVhN5354xbLqdn8mV9Tat9gepAupm0bt2DbeaSC8vS52MuFA==",
+ "dev": true,
+ "optional": true
+ },
+ "nanomatch": {
+ "version": "1.2.13",
+ "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
+ "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==",
+ "dev": true,
+ "requires": {
+ "arr-diff": "^4.0.0",
+ "array-unique": "^0.3.2",
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "fragment-cache": "^0.2.1",
+ "is-windows": "^1.0.2",
+ "kind-of": "^6.0.2",
+ "object.pick": "^1.3.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ }
+ },
+ "negotiator": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
+ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
+ "dev": true
+ },
+ "nopt": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
+ "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==",
+ "dev": true,
+ "requires": {
+ "abbrev": "1"
+ }
+ },
+ "normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "dev": true
+ },
+ "normalize-url": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz",
+ "integrity": "sha512-A48My/mtCklowHBlI8Fq2jFWK4tX4lJ5E6ytFsSOq1fzpvT0SQSgKhSg7lN5c2uYFOrUAOQp6zhhJnpp1eMloQ==",
+ "dev": true,
+ "requires": {
+ "object-assign": "^4.0.1",
+ "prepend-http": "^1.0.0",
+ "query-string": "^4.1.0",
+ "sort-keys": "^1.0.0"
+ }
+ },
+ "nth-check": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz",
+ "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==",
+ "dev": true,
+ "requires": {
+ "boolbase": "~1.0.0"
+ }
+ },
+ "nunjucks": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/nunjucks/-/nunjucks-3.2.2.tgz",
+ "integrity": "sha512-KUi85OoF2NMygwODAy28Lh9qHmq5hO3rBlbkYoC8v377h4l8Pt5qFjILl0LWpMbOrZ18CzfVVUvIHUIrtED3sA==",
+ "dev": true,
+ "requires": {
+ "a-sync-waterfall": "^1.0.0",
+ "asap": "^2.0.3",
+ "chokidar": "^3.3.0",
+ "commander": "^5.1.0"
+ },
+ "dependencies": {
+ "commander": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz",
+ "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==",
+ "dev": true
+ }
+ }
+ },
+ "object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+ "dev": true
+ },
+ "object-copy": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
+ "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==",
+ "dev": true,
+ "requires": {
+ "copy-descriptor": "^0.1.0",
+ "define-property": "^0.2.5",
+ "kind-of": "^3.0.3"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+ "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+ "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ }
+ },
+ "is-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+ "dev": true,
+ "requires": {
+ "is-accessor-descriptor": "^0.1.6",
+ "is-data-descriptor": "^0.1.4",
+ "kind-of": "^5.0.0"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+ "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+ "dev": true
+ }
+ }
+ },
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "object-hash": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-1.3.1.tgz",
+ "integrity": "sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA==",
+ "dev": true
+ },
+ "object-visit": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
+ "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==",
+ "dev": true,
+ "requires": {
+ "isobject": "^3.0.0"
+ }
+ },
+ "object.pick": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
+ "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==",
+ "dev": true,
+ "requires": {
+ "isobject": "^3.0.1"
+ }
+ },
+ "on-finished": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+ "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==",
+ "dev": true,
+ "requires": {
+ "ee-first": "1.1.1"
+ }
+ },
+ "on-headers": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
+ "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==",
+ "dev": true
+ },
+ "once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "dev": true,
+ "requires": {
+ "wrappy": "1"
+ }
+ },
+ "opn": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/opn/-/opn-6.0.0.tgz",
+ "integrity": "sha512-I9PKfIZC+e4RXZ/qr1RhgyCnGgYX0UEIlXgWnCOVACIvFgaC9rz6Won7xbdhoHrd8IIhV7YEpHjreNUNkqCGkQ==",
+ "dev": true,
+ "requires": {
+ "is-wsl": "^1.1.0"
+ }
+ },
+ "p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dev": true,
+ "requires": {
+ "p-try": "^2.0.0"
+ }
+ },
+ "p-locate": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+ "dev": true,
+ "requires": {
+ "p-limit": "^2.2.0"
+ }
+ },
+ "p-try": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+ "dev": true
+ },
+ "parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+ "dev": true
+ },
+ "pascalcase": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
+ "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==",
+ "dev": true
+ },
+ "path-dirname": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz",
+ "integrity": "sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==",
+ "dev": true
+ },
+ "path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true
+ },
+ "path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+ "dev": true
+ },
+ "path-is-inside": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",
+ "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==",
+ "dev": true
+ },
+ "path-parse": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+ "dev": true
+ },
+ "pause-stream": {
+ "version": "0.0.11",
+ "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz",
+ "integrity": "sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==",
+ "dev": true,
+ "requires": {
+ "through": "~2.3"
+ }
+ },
+ "picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "dev": true
+ },
+ "pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
+ "dev": true
+ },
+ "pinkie": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
+ "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==",
+ "dev": true
+ },
+ "pinkie-promise": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
+ "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==",
+ "dev": true,
+ "requires": {
+ "pinkie": "^2.0.0"
+ }
+ },
+ "posix-character-classes": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
+ "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==",
+ "dev": true
+ },
+ "prepend-http": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz",
+ "integrity": "sha512-PhmXi5XmoyKw1Un4E+opM2KcsJInDvKyuOumcjjw3waw86ZNjHwVUOOWLc4bCzLdcKNaWBH9e99sbWzDQsVaYg==",
+ "dev": true
+ },
+ "process-nextick-args": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+ "dev": true
+ },
+ "proto-list": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
+ "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==",
+ "dev": true
+ },
+ "proxy-middleware": {
+ "version": "0.15.0",
+ "resolved": "https://registry.npmjs.org/proxy-middleware/-/proxy-middleware-0.15.0.tgz",
+ "integrity": "sha512-EGCG8SeoIRVMhsqHQUdDigB2i7qU7fCsWASwn54+nPutYO8n4q6EiwMzyfWlC+dzRFExP+kvcnDFdBDHoZBU7Q==",
+ "dev": true
+ },
+ "pseudomap": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
+ "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==",
+ "dev": true
+ },
+ "query-string": {
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz",
+ "integrity": "sha512-O2XLNDBIg1DnTOa+2XrIwSiXEV8h2KImXUnjhhn2+UsvZ+Es2uyd5CCRTNQlDGbzUQOW3aYCBx9rVA6dzsiY7Q==",
+ "dev": true,
+ "requires": {
+ "object-assign": "^4.1.0",
+ "strict-uri-encode": "^1.0.0"
+ }
+ },
+ "querystringify": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
+ "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==",
+ "dev": true
+ },
+ "randombytes": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
+ "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "^5.1.0"
+ }
+ },
+ "range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+ "dev": true
+ },
+ "readable-stream": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+ "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ }
+ },
+ "readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "dev": true,
+ "requires": {
+ "picomatch": "^2.2.1"
+ }
+ },
+ "regex-not": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
+ "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==",
+ "dev": true,
+ "requires": {
+ "extend-shallow": "^3.0.2",
+ "safe-regex": "^1.1.0"
+ }
+ },
+ "remove-trailing-separator": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
+ "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==",
+ "dev": true
+ },
+ "repeat-element": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz",
+ "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==",
+ "dev": true
+ },
+ "repeat-string": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
+ "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==",
+ "dev": true
+ },
+ "requires-port": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
+ "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
+ "dev": true
+ },
+ "resolve": {
+ "version": "1.22.4",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz",
+ "integrity": "sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==",
+ "dev": true,
+ "requires": {
+ "is-core-module": "^2.13.0",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
+ }
+ },
+ "resolve-url": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
+ "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==",
+ "dev": true
+ },
+ "ret": {
+ "version": "0.1.15",
+ "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
+ "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
+ "dev": true
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ },
+ "safe-regex": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
+ "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==",
+ "dev": true,
+ "requires": {
+ "ret": "~0.1.10"
+ }
+ },
+ "safe-stable-stringify": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.3.1.tgz",
+ "integrity": "sha512-kYBSfT+troD9cDA85VDnHZ1rpHC50O0g1e6WlGHVCz/g+JS+9WKLj+XwFYyR8UbrZN8ll9HUpDAAddY58MGisg==",
+ "dev": true
+ },
+ "semver": {
+ "version": "5.7.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
+ "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
+ "dev": true
+ },
+ "send": {
+ "version": "0.18.0",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
+ "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
+ "dev": true,
+ "requires": {
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "fresh": "0.5.2",
+ "http-errors": "2.0.0",
+ "mime": "1.6.0",
+ "ms": "2.1.3",
+ "on-finished": "2.4.1",
+ "range-parser": "~1.2.1",
+ "statuses": "2.0.1"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true
+ },
+ "on-finished": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+ "dev": true,
+ "requires": {
+ "ee-first": "1.1.1"
+ }
+ },
+ "statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
+ "dev": true
+ }
+ }
+ },
+ "serialize-javascript": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-3.1.0.tgz",
+ "integrity": "sha512-JIJT1DGiWmIKhzRsG91aS6Ze4sFUrYbltlkg2onR5OrnNM02Kl/hnY/T4FN2omvyeBbQmMJv+K4cPOpGzOTFBg==",
+ "dev": true,
+ "requires": {
+ "randombytes": "^2.1.0"
+ }
+ },
+ "serve-index": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz",
+ "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==",
+ "dev": true,
+ "requires": {
+ "accepts": "~1.3.4",
+ "batch": "0.6.1",
+ "debug": "2.6.9",
+ "escape-html": "~1.0.3",
+ "http-errors": "~1.6.2",
+ "mime-types": "~2.1.17",
+ "parseurl": "~1.3.2"
+ },
+ "dependencies": {
+ "depd": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
+ "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==",
+ "dev": true
+ },
+ "http-errors": {
+ "version": "1.6.3",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
+ "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==",
+ "dev": true,
+ "requires": {
+ "depd": "~1.1.2",
+ "inherits": "2.0.3",
+ "setprototypeof": "1.1.0",
+ "statuses": ">= 1.4.0 < 2"
+ }
+ },
+ "inherits": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==",
+ "dev": true
+ },
+ "setprototypeof": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
+ "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==",
+ "dev": true
+ }
+ }
+ },
+ "set-value": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
+ "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
+ "dev": true,
+ "requires": {
+ "extend-shallow": "^2.0.1",
+ "is-extendable": "^0.1.1",
+ "is-plain-object": "^2.0.3",
+ "split-string": "^3.0.1"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
+ "dev": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ },
+ "is-extendable": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+ "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
+ "dev": true
+ }
+ }
+ },
+ "setprototypeof": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
+ "dev": true
+ },
+ "sigmund": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz",
+ "integrity": "sha512-fCvEXfh6NWpm+YSuY2bpXb/VIihqWA6hLsgboC+0nl71Q7N7o2eaCW8mJa/NLvQhs6jpd3VZV4UiUQlV6+lc8g==",
+ "dev": true
+ },
+ "simple-git": {
+ "version": "2.48.0",
+ "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-2.48.0.tgz",
+ "integrity": "sha512-z4qtrRuaAFJS4PUd0g+xy7aN4y+RvEt/QTJpR184lhJguBA1S/LsVlvE/CM95RsYMOFJG3NGGDjqFCzKU19S/A==",
+ "dev": true,
+ "requires": {
+ "@kwsites/file-exists": "^1.1.1",
+ "@kwsites/promise-deferred": "^1.1.1",
+ "debug": "^4.3.2"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+ "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+ "dev": true,
+ "requires": {
+ "ms": "2.1.2"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ }
+ }
+ },
+ "snapdragon": {
+ "version": "0.8.2",
+ "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
+ "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==",
+ "dev": true,
+ "requires": {
+ "base": "^0.11.1",
+ "debug": "^2.2.0",
+ "define-property": "^0.2.5",
+ "extend-shallow": "^2.0.1",
+ "map-cache": "^0.2.2",
+ "source-map": "^0.5.6",
+ "source-map-resolve": "^0.5.0",
+ "use": "^3.1.0"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
+ "dev": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+ "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "is-data-descriptor": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+ "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "is-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+ "dev": true,
+ "requires": {
+ "is-accessor-descriptor": "^0.1.6",
+ "is-data-descriptor": "^0.1.4",
+ "kind-of": "^5.0.0"
+ }
+ },
+ "is-extendable": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+ "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
+ "dev": true
+ },
+ "kind-of": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+ "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+ "dev": true
+ }
+ }
+ },
+ "snapdragon-node": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz",
+ "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==",
+ "dev": true,
+ "requires": {
+ "define-property": "^1.0.0",
+ "isobject": "^3.0.0",
+ "snapdragon-util": "^3.0.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^1.0.0"
+ }
+ }
+ }
+ },
+ "snapdragon-util": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz",
+ "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.2.0"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "sort-keys": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz",
+ "integrity": "sha512-vzn8aSqKgytVik0iwdBEi+zevbTYZogewTUM6dtpmGwEcdzbub/TX4bCzRhebDCRC3QzXgJsLRKB2V/Oof7HXg==",
+ "dev": true,
+ "requires": {
+ "is-plain-obj": "^1.0.0"
+ }
+ },
+ "source-map": {
+ "version": "0.5.6",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz",
+ "integrity": "sha512-MjZkVp0NHr5+TPihLcadqnlVoGIoWo4IBHptutGh9wI3ttUYvCG26HkSuDi+K6lsZ25syXJXcctwgyVCt//xqA==",
+ "dev": true
+ },
+ "source-map-resolve": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz",
+ "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==",
+ "dev": true,
+ "requires": {
+ "atob": "^2.1.2",
+ "decode-uri-component": "^0.2.0",
+ "resolve-url": "^0.2.1",
+ "source-map-url": "^0.4.0",
+ "urix": "^0.1.0"
+ }
+ },
+ "source-map-url": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz",
+ "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==",
+ "dev": true
+ },
+ "split": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz",
+ "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==",
+ "dev": true,
+ "requires": {
+ "through": "2"
+ }
+ },
+ "split-string": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
+ "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==",
+ "dev": true,
+ "requires": {
+ "extend-shallow": "^3.0.0"
+ }
+ },
+ "sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
+ "dev": true
+ },
+ "stack-trace": {
+ "version": "0.0.10",
+ "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
+ "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==",
+ "dev": true
+ },
+ "static-extend": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
+ "integrity": "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==",
+ "dev": true,
+ "requires": {
+ "define-property": "^0.2.5",
+ "object-copy": "^0.1.0"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+ "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "is-data-descriptor": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+ "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "is-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+ "dev": true,
+ "requires": {
+ "is-accessor-descriptor": "^0.1.6",
+ "is-data-descriptor": "^0.1.4",
+ "kind-of": "^5.0.0"
+ }
+ },
+ "kind-of": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+ "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+ "dev": true
+ }
+ }
+ },
+ "statuses": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
+ "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==",
+ "dev": true
+ },
+ "stream-combiner": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz",
+ "integrity": "sha512-6yHMqgLYDzQDcAkL+tjJDC5nSNuNIx0vZtRZeiPh7Saef7VHX9H5Ijn9l2VIol2zaNYlYEX6KyuT/237A58qEQ==",
+ "dev": true,
+ "requires": {
+ "duplexer": "~0.1.1",
+ "through": "~2.3.4"
+ }
+ },
+ "strict-uri-encode": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
+ "integrity": "sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ==",
+ "dev": true
+ },
+ "string_decoder": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "~5.2.0"
+ },
+ "dependencies": {
+ "safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "dev": true
+ }
+ }
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ },
+ "strip-outer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz",
+ "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==",
+ "dev": true,
+ "requires": {
+ "escape-string-regexp": "^1.0.2"
+ }
+ },
+ "strip-url-auth": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/strip-url-auth/-/strip-url-auth-1.0.1.tgz",
+ "integrity": "sha512-++41PnXftlL3pvI6lpvhSEO+89g1kIJC4MYB5E6yH+WHa5InIqz51yGd1YOGd7VNSNdoEOfzTMqbAM/2PbgaHQ==",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
+ },
+ "supports-preserve-symlinks-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+ "dev": true
+ },
+ "through": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+ "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
+ "dev": true
+ },
+ "through2": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz",
+ "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.4",
+ "readable-stream": "2 || 3"
+ }
+ },
+ "to-object-path": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
+ "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "to-regex": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz",
+ "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==",
+ "dev": true,
+ "requires": {
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "regex-not": "^1.0.2",
+ "safe-regex": "^1.1.0"
+ }
+ },
+ "to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "requires": {
+ "is-number": "^7.0.0"
+ }
+ },
+ "toidentifier": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+ "dev": true
+ },
+ "trim-repeated": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz",
+ "integrity": "sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==",
+ "dev": true,
+ "requires": {
+ "escape-string-regexp": "^1.0.2"
+ }
+ },
+ "triple-beam": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz",
+ "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==",
+ "dev": true
+ },
+ "uc.micro": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
+ "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==",
+ "dev": true
+ },
+ "union-value": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
+ "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
+ "dev": true,
+ "requires": {
+ "arr-union": "^3.1.0",
+ "get-value": "^2.0.6",
+ "is-extendable": "^0.1.1",
+ "set-value": "^2.0.1"
+ },
+ "dependencies": {
+ "is-extendable": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+ "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
+ "dev": true
+ }
+ }
+ },
+ "universalify": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
+ "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
+ "dev": true
+ },
+ "unix-crypt-td-js": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/unix-crypt-td-js/-/unix-crypt-td-js-1.1.4.tgz",
+ "integrity": "sha512-8rMeVYWSIyccIJscb9NdCfZKSRBKYTeVnwmiRYT2ulE3qd1RaDQ0xQDP+rI3ccIWbhu/zuo5cgN8z73belNZgw==",
+ "dev": true
+ },
+ "unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
+ "dev": true
+ },
+ "unset-value": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
+ "integrity": "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==",
+ "dev": true,
+ "requires": {
+ "has-value": "^0.3.1",
+ "isobject": "^3.0.0"
+ },
+ "dependencies": {
+ "has-value": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz",
+ "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==",
+ "dev": true,
+ "requires": {
+ "get-value": "^2.0.3",
+ "has-values": "^0.1.4",
+ "isobject": "^2.0.0"
+ },
+ "dependencies": {
+ "isobject": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+ "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==",
+ "dev": true,
+ "requires": {
+ "isarray": "1.0.0"
+ }
+ }
+ }
+ },
+ "has-values": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
+ "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==",
+ "dev": true
+ }
+ }
+ },
+ "upath": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz",
+ "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==",
+ "dev": true
+ },
+ "urix": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
+ "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==",
+ "dev": true
+ },
+ "url-parse": {
+ "version": "1.5.10",
+ "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
+ "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
+ "dev": true,
+ "requires": {
+ "querystringify": "^2.1.1",
+ "requires-port": "^1.0.0"
+ }
+ },
+ "use": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
+ "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==",
+ "dev": true
+ },
+ "util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+ "dev": true
+ },
+ "utils-merge": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+ "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
+ "dev": true
+ },
+ "uuid": {
+ "version": "8.3.2",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
+ "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
+ "dev": true
+ },
+ "vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
+ "dev": true
+ },
+ "vue": {
+ "version": "2.6.14",
+ "resolved": "https://registry.npmjs.org/vue/-/vue-2.6.14.tgz",
+ "integrity": "sha512-x2284lgYvjOMj3Za7kqzRcUSxBboHqtgRE2zlos1qWaOye5yUmHn42LB1250NJBLRwEcdrB0JRwyPTEPhfQjiQ==",
+ "dev": true
+ },
+ "vue-server-renderer": {
+ "version": "2.6.14",
+ "resolved": "https://registry.npmjs.org/vue-server-renderer/-/vue-server-renderer-2.6.14.tgz",
+ "integrity": "sha512-HifYRa/LW7cKywg9gd4ZtvtRuBlstQBao5ZCWlg40fyB4OPoGfEXAzxb0emSLv4pBDOHYx0UjpqvxpiQFEuoLA==",
+ "dev": true,
+ "requires": {
+ "chalk": "^1.1.3",
+ "hash-sum": "^1.0.2",
+ "he": "^1.1.0",
+ "lodash.template": "^4.5.0",
+ "lodash.uniq": "^4.5.0",
+ "resolve": "^1.2.0",
+ "serialize-javascript": "^3.1.0",
+ "source-map": "0.5.6"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==",
+ "dev": true
+ },
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ }
+ },
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==",
+ "dev": true
+ }
+ }
+ },
+ "vue-template-compiler": {
+ "version": "2.6.14",
+ "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.6.14.tgz",
+ "integrity": "sha512-ODQS1SyMbjKoO1JBJZojSw6FE4qnh9rIpUZn2EUT86FKizx9uH5z6uXiIrm4/Nb/gwxTi/o17ZDEGWAXHvtC7g==",
+ "dev": true,
+ "requires": {
+ "de-indent": "^1.0.2",
+ "he": "^1.1.0"
+ }
+ },
+ "walk-sync": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/walk-sync/-/walk-sync-2.2.0.tgz",
+ "integrity": "sha512-IC8sL7aB4/ZgFcGI2T1LczZeFWZ06b3zoHH7jBPyHxOtIIz1jppWHjjEXkOFvFojBVAK9pV7g47xOZ4LW3QLfg==",
+ "dev": true,
+ "requires": {
+ "@types/minimatch": "^3.0.3",
+ "ensure-posix-path": "^1.1.0",
+ "matcher-collection": "^2.0.0",
+ "minimatch": "^3.0.4"
+ }
+ },
+ "websocket-driver": {
+ "version": "0.7.4",
+ "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
+ "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==",
+ "dev": true,
+ "requires": {
+ "http-parser-js": ">=0.5.1",
+ "safe-buffer": ">=5.1.0",
+ "websocket-extensions": ">=0.1.1"
+ }
+ },
+ "websocket-extensions": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz",
+ "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==",
+ "dev": true
+ },
+ "winston": {
+ "version": "2.4.6",
+ "resolved": "https://registry.npmjs.org/winston/-/winston-2.4.6.tgz",
+ "integrity": "sha512-J5Zu4p0tojLde8mIOyDSsmLmcP8I3Z6wtwpTDHx1+hGcdhxcJaAmG4CFtagkb+NiN1M9Ek4b42pzMWqfc9jm8w==",
+ "dev": true,
+ "requires": {
+ "async": "^3.2.3",
+ "colors": "1.0.x",
+ "cycle": "1.0.x",
+ "eyes": "0.1.x",
+ "isstream": "0.1.x",
+ "stack-trace": "0.0.x"
+ },
+ "dependencies": {
+ "async": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz",
+ "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==",
+ "dev": true
+ },
+ "colors": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz",
+ "integrity": "sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw==",
+ "dev": true
+ }
+ }
+ },
+ "winston-compat": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/winston-compat/-/winston-compat-0.1.5.tgz",
+ "integrity": "sha512-EPvPcHT604AV3Ji6d3+vX8ENKIml9VSxMRnPQ+cuK/FX6f3hvPP2hxyoeeCOCFvDrJEujalfcKWlWPvAnFyS9g==",
+ "dev": true,
+ "requires": {
+ "cycle": "~1.0.3",
+ "logform": "^1.6.0",
+ "triple-beam": "^1.2.0"
+ }
+ },
+ "winston-daily-rotate-file": {
+ "version": "3.10.0",
+ "resolved": "https://registry.npmjs.org/winston-daily-rotate-file/-/winston-daily-rotate-file-3.10.0.tgz",
+ "integrity": "sha512-KO8CfbI2CvdR3PaFApEH02GPXiwJ+vbkF1mCkTlvRIoXFI8EFlf1ACcuaahXTEiDEKCii6cNe95gsL4ZkbnphA==",
+ "dev": true,
+ "requires": {
+ "file-stream-rotator": "^0.4.1",
+ "object-hash": "^1.3.0",
+ "semver": "^6.2.0",
+ "triple-beam": "^1.3.0",
+ "winston-compat": "^0.1.4",
+ "winston-transport": "^4.2.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true
+ }
+ }
+ },
+ "winston-transport": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.5.0.tgz",
+ "integrity": "sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q==",
+ "dev": true,
+ "requires": {
+ "logform": "^2.3.2",
+ "readable-stream": "^3.6.0",
+ "triple-beam": "^1.3.0"
+ },
+ "dependencies": {
+ "fecha": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz",
+ "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==",
+ "dev": true
+ },
+ "logform": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/logform/-/logform-2.4.2.tgz",
+ "integrity": "sha512-W4c9himeAwXEdZ05dQNerhFz2XG80P9Oj0loPUMV23VC2it0orMHQhJm4hdnnor3rd1HsGf6a2lPwBM1zeXHGw==",
+ "dev": true,
+ "requires": {
+ "@colors/colors": "1.5.0",
+ "fecha": "^4.2.0",
+ "ms": "^2.1.1",
+ "safe-stable-stringify": "^2.3.1",
+ "triple-beam": "^1.3.0"
+ }
+ },
+ "ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true
+ }
+ }
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "dev": true
+ },
+ "yallist": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
+ "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==",
+ "dev": true
+ }
+ }
+}
diff --git a/docs/package.json b/docs/package.json
new file mode 100644
index 00000000000..aa7083fd8a7
--- /dev/null
+++ b/docs/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "docs",
+ "version": "1.0.0",
+ "description": "AB-3 docs",
+ "scripts": {
+ "init": "markbind init",
+ "build": "markbind build",
+ "serve": "markbind serve",
+ "deploy": "markbind deploy"
+ },
+ "devDependencies": {
+ "markbind-cli": "^5.1.0"
+ }
+}
diff --git a/docs/site.json b/docs/site.json
new file mode 100644
index 00000000000..b61c5002bc8
--- /dev/null
+++ b/docs/site.json
@@ -0,0 +1,29 @@
+{
+ "baseUrl": "",
+ "titlePrefix": "MediTrack",
+ "titleSuffix": "MediTrack",
+ "faviconPath": "images/SeEduLogo.png",
+ "style": {
+ "codeTheme": "light"
+ },
+ "ignore": [
+ "_markbind/layouts/*",
+ "_markbind/logs/*",
+ "_site/*",
+ "site.json",
+ "*.md",
+ "*.njk",
+ ".git/*",
+ "node_modules/*"
+ ],
+ "pagesExclude": ["node_modules/*"],
+ "pages": [
+ {
+ "glob": ["**/index.md", "**/*.md"]
+ }
+ ],
+ "deploy": {
+ "message": "Site Update."
+ },
+ "timeZone": "Asia/Singapore"
+}
diff --git a/docs/stylesheets/main.css b/docs/stylesheets/main.css
new file mode 100644
index 00000000000..ba6f8385d2d
--- /dev/null
+++ b/docs/stylesheets/main.css
@@ -0,0 +1,170 @@
+mark {
+ background-color: #ff0;
+ border-radius: 5px;
+ padding-top: 0;
+ padding-bottom: 0;
+}
+
+.indented {
+ padding-left: 20px;
+}
+
+.theme-card img {
+ width: 100%;
+}
+
+/* Scrollbar */
+
+.slim-scroll::-webkit-scrollbar {
+ width: 5px;
+}
+
+.slim-scroll::-webkit-scrollbar-thumb {
+ background: #808080;
+ border-radius: 20px;
+}
+
+.slim-scroll::-webkit-scrollbar-track {
+ background: transparent;
+ border-radius: 20px;
+}
+
+.slim-scroll-blue::-webkit-scrollbar {
+ width: 5px;
+}
+
+.slim-scroll-blue::-webkit-scrollbar-thumb {
+ background: #00b0ef;
+ border-radius: 20px;
+}
+
+.slim-scroll-blue::-webkit-scrollbar-track {
+ background: transparent;
+ border-radius: 20px;
+}
+
+/* Layout containers */
+
+#flex-body {
+ display: flex;
+ flex: 1;
+ align-items: start;
+}
+
+#content-wrapper {
+ flex: 1;
+ margin: 0 auto;
+ min-width: 0;
+ max-width: 1000px;
+ overflow-x: auto;
+ padding: 0.8rem 20px 0 20px;
+ transition: 0.4s;
+ -webkit-transition: 0.4s;
+}
+
+#site-nav,
+#page-nav {
+ display: flex;
+ flex-direction: column;
+ position: sticky;
+ top: var(--sticky-header-height);
+ flex: 0 0 auto;
+ max-width: 300px;
+ max-height: calc(100vh - var(--sticky-header-height));
+ width: 300px;
+}
+
+#site-nav {
+ border-right: 1px solid lightgrey;
+ padding-bottom: 20px;
+ z-index: 999;
+}
+
+.site-nav-top {
+ margin: 0.8rem 0;
+ padding: 0 12px 12px 12px;
+}
+
+.nav-component {
+ overflow-y: auto;
+}
+
+#page-nav {
+ border-left: 1px solid lightgrey;
+}
+
+@media screen and (max-width: 1299.98px) {
+ #page-nav {
+ display: none;
+ }
+}
+
+/* Bootstrap medium(md) responsive breakpoint */
+@media screen and (max-width: 991.98px) {
+ #site-nav {
+ display: none;
+ }
+}
+
+/* Bootstrap small(sm) responsive breakpoint */
+@media (max-width: 767.98px) {
+ .indented {
+ padding-left: 10px;
+ }
+
+ #content-wrapper {
+ padding: 0 10px;
+ }
+}
+
+/* Bootstrap extra small(xs) responsive breakpoint */
+@media screen and (max-width: 575.98px) {
+ #site-nav {
+ display: none;
+ }
+}
+
+/* Hide site navigation when printing */
+@media print {
+ #site-nav {
+ display: none;
+ }
+
+ #page-nav {
+ display: none;
+ }
+
+ /* Reduce font size when printing */
+ h1 {
+ font-size: 1.2rem !important;
+ }
+ h2 {
+ font-size: 1.0rem !important;
+ }
+ h3 {
+ font-size: 0.9rem !important;
+ }
+ h4 {
+ font-size: 0.8rem !important;
+ }
+ h5 {
+ font-size: 0.7rem !important;
+ }
+ body {
+ font-size: 0.65rem !important;
+ }
+ .btn {
+ font-size: 0.65rem !important;
+ }
+ img {
+ zoom: 0.8; /* might not work on some browsers */
+ }
+}
+
+h2,
+h3,
+h4,
+h5,
+h6 {
+ color: #e46c0a;
+}
diff --git a/docs/team/johndoe.md b/docs/team/johndoe.md
index 773a07794e2..86aa7ebfc34 100644
--- a/docs/team/johndoe.md
+++ b/docs/team/johndoe.md
@@ -1,6 +1,6 @@
---
-layout: page
-title: John Doe's Project Portfolio Page
+ layout: default.md
+ title: "John Doe's Project Portfolio Page"
---
### Project: AddressBook Level 3
diff --git a/docs/tutorials/AddRemark.md b/docs/tutorials/AddRemark.md
index d98f38982e7..aed0a0c9fb2 100644
--- a/docs/tutorials/AddRemark.md
+++ b/docs/tutorials/AddRemark.md
@@ -1,8 +1,11 @@
---
-layout: page
-title: "Tutorial: Adding a command"
+ layout: default.md
+ title: "Tutorial: Adding a command"
+ pageNav: 3
---
+# Tutorial: Adding a command
+
Let's walk you through the implementation of a new command — `remark`.
This command allows users of the AddressBook application to add optional remarks to people in their address book and edit it if required. The command should have the following format:
@@ -22,13 +25,13 @@ For now, let’s keep `RemarkCommand` as simple as possible and print some outpu
**`RemarkCommand.java`:**
-``` java
+```java
package seedu.address.logic.commands;
import seedu.address.model.Model;
/**
- * Changes the remark of an existing person in the address book.
+ * Changes the remark of an existing patient in the address book.
*/
public class RemarkCommand extends Command {
@@ -57,16 +60,16 @@ Run `Main#main` and try out your new `RemarkCommand`. If everything went well, y
While we have successfully printed a message to `ResultDisplay`, the command does not do what it is supposed to do. Let’s change the command to throw a `CommandException` to accurately reflect that our command is still a work in progress.
-![The relationship between RemarkCommand and Command](../images/add-remark/RemarkCommandClass.png)
+
Following the convention in other commands, we add relevant messages as constants and use them.
**`RemarkCommand.java`:**
-``` java
+```java
public static final String MESSAGE_USAGE = COMMAND_WORD
- + ": Edits the remark of the person identified "
- + "by the index number used in the last person listing. "
+ + ": Edits the remark of the patient identified "
+ + "by the index number used in the last patient listing. "
+ "Existing remark will be overwritten by the input.\n"
+ "Parameters: INDEX (must be a positive integer) "
+ "r/ [REMARK]\n"
@@ -90,7 +93,7 @@ Let’s change `RemarkCommand` to parse input from the user.
We start by modifying the constructor of `RemarkCommand` to accept an `Index` and a `String`. While we are at it, let’s change the error message to echo the values. While this is not a replacement for tests, it is an obvious way to tell if our code is functioning as intended.
-``` java
+```java
import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
//...
public class RemarkCommand extends Command {
@@ -101,8 +104,8 @@ public class RemarkCommand extends Command {
private final String remark;
/**
- * @param index of the person in the filtered person list to edit the remark
- * @param remark of the person to be updated to
+ * @param index of the patient in the filtered patient list to edit the remark
+ * @param remark of the patient to be updated to
*/
public RemarkCommand(Index index, String remark) {
requireAllNonNull(index, remark);
@@ -142,13 +145,13 @@ Now let’s move on to writing a parser that will extract the index and remark f
Create a `RemarkCommandParser` class in the `seedu.address.logic.parser` package. The class must extend the `Parser` interface.
-![The relationship between Parser and RemarkCommandParser](../images/add-remark/RemarkCommandParserClass.png)
+
Thankfully, `ArgumentTokenizer#tokenize()` makes it trivial to parse user input. Let’s take a look at the JavaDoc provided for the function to understand what it does.
**`ArgumentTokenizer.java`:**
-``` java
+```java
/**
* Tokenizes an arguments string and returns an {@code ArgumentMultimap}
* object that maps prefixes to their respective argument values. Only the
@@ -166,7 +169,7 @@ We can tell `ArgumentTokenizer#tokenize()` to look out for our new prefix `r/` a
**`ArgumentMultimap.java`:**
-``` java
+```java
/**
* Returns the last value of {@code prefix}.
*/
@@ -181,7 +184,7 @@ This appears to be what we need to get a String of the remark. But what about th
**`DeleteCommandParser.java`:**
-``` java
+```java
Index index = ParserUtil.parseIndex(args);
return new DeleteCommand(index);
```
@@ -192,7 +195,7 @@ Now that we have the know-how to extract the data that we need from the user’s
**`RemarkCommandParser.java`:**
-``` java
+```java
public RemarkCommand parse(String args) throws ParseException {
requireNonNull(args);
ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args,
@@ -212,22 +215,22 @@ public RemarkCommand parse(String args) throws ParseException {
}
```
-
+
-:information_source: Don’t forget to update `AddressBookParser` to use our new `RemarkCommandParser`!
+Don’t forget to update `AddressBookParser` to use our new `RemarkCommandParser`!
-
+
If you are stuck, check out the sample
[here](https://github.com/se-edu/addressbook-level3/commit/dc6d5139d08f6403da0ec624ea32bd79a2ae0cbf#diff-8bf239e8e9529369b577701303ddd96af93178b4ed6735f91c2d8488b20c6b4a).
## Add `Remark` to the model
-Now that we have all the information that we need, let’s lay the groundwork for propagating the remarks added into the in-memory storage of person data. We achieve that by working with the `Person` model. Each field in a Person is implemented as a separate class (e.g. a `Name` object represents the person’s name). That means we should add a `Remark` class so that we can use a `Remark` object to represent a remark given to a person.
+Now that we have all the information that we need, let’s lay the groundwork for propagating the remarks added into the in-memory storage of patient data. We achieve that by working with the `Person` model. Each field in a Person is implemented as a separate class (e.g. a `Name` object represents the patient’s name). That means we should add a `Remark` class so that we can use a `Remark` object to represent a remark given to a patient.
### Add a new `Remark` class
-Create a new `Remark` in `seedu.address.model.person`. Since a `Remark` is a field that is similar to `Address`, we can reuse a significant bit of code.
+Create a new `Remark` in `seedu.address.model.patient`. Since a `Remark` is a field that is similar to `Address`, we can reuse a significant bit of code.
A copy-paste and search-replace later, you should have something like [this](https://github.com/se-edu/addressbook-level3/commit/4516e099699baa9e2d51801bd26f016d812dedcc#diff-41bb13c581e280c686198251ad6cc337cd5e27032772f06ed9bf7f1440995ece). Note how `Remark` has no constrains and thus does not require input
validation.
@@ -238,13 +241,13 @@ Let’s change `RemarkCommand` and `RemarkCommandParser` to use the new `Remark`
## Add a placeholder element for remark to the UI
-Without getting too deep into `fxml`, let’s go on a 5 minute adventure to get some placeholder text to show up for each person.
+Without getting too deep into `fxml`, let’s go on a 5 minute adventure to get some placeholder text to show up for each patient.
-Simply add the following to [`seedu.address.ui.PersonCard`](https://github.com/se-edu/addressbook-level3/commit/850b78879582f38accb05dd20c245963c65ea599#diff-639834f1e05afe2276a86372adf0fe5f69314642c2d93cfa543d614ce5a76688).
+Simply add the following to [`seedu.address.ui.PatientCard`](https://github.com/se-edu/addressbook-level3/commit/850b78879582f38accb05dd20c245963c65ea599#diff-639834f1e05afe2276a86372adf0fe5f69314642c2d93cfa543d614ce5a76688).
**`PersonCard.java`:**
-``` java
+```java
@FXML
private Label remark;
```
@@ -276,11 +279,11 @@ We change the constructor of `Person` to take a `Remark`. We will also need to d
Unfortunately, a change to `Person` will cause other commands to break, you will have to modify these commands to use the updated `Person`!
-
+
-:bulb: Use the `Find Usages` feature in IntelliJ IDEA on the `Person` class to find these commands.
+Use the `Find Usages` feature in IntelliJ IDEA on the `Person` class to find these commands.
-
+
Refer to [this commit](https://github.com/se-edu/addressbook-level3/commit/ce998c37e65b92d35c91d28c7822cd139c2c0a5c) and check that you have got everything in order!
@@ -291,11 +294,11 @@ AddressBook stores data by serializing `JsonAdaptedPerson` into `json` with the
While the changes to code may be minimal, the test data will have to be updated as well.
-
+
-:exclamation: You must delete AddressBook’s storage file located at `/data/addressbook.json` before running it! Not doing so will cause AddressBook to default to an empty address book!
+You must delete AddressBook’s storage file located at `/data/addressbook.json` before running it! Not doing so will cause AddressBook to default to an empty address book!
-
+
Check out [this commit](https://github.com/se-edu/addressbook-level3/commit/556cbd0e03ff224d7a68afba171ad2eb0ce56bbf)
to see what the changes entail.
@@ -308,10 +311,10 @@ Just add [this one line of code!](https://github.com/se-edu/addressbook-level3/c
**`PersonCard.java`:**
-``` java
-public PersonCard(Person person, int displayedIndex) {
+```java
+public PersonCard(Person patient, int displayedIndex) {
//...
- remark.setText(person.getRemark().value);
+ remark.setText(patient.getRemark().value);
}
```
@@ -328,7 +331,7 @@ save it with `Model#setPerson()`.
**`RemarkCommand.java`:**
-``` java
+```java
//...
public static final String MESSAGE_ADD_REMARK_SUCCESS = "Added remark to Person: %1$s";
public static final String MESSAGE_DELETE_REMARK_SUCCESS = "Removed remark from Person: %1$s";
@@ -341,25 +344,25 @@ save it with `Model#setPerson()`.
throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
}
- Person personToEdit = lastShownList.get(index.getZeroBased());
- Person editedPerson = new Person(
- personToEdit.getName(), personToEdit.getPhone(), personToEdit.getEmail(),
- personToEdit.getAddress(), remark, personToEdit.getTags());
+ Person patientToEdit = lastShownList.get(index.getZeroBased());
+ Person editedPatient = new Person(
+ patientToEdit.getName(), patientToEdit.getPhone(), patientToEdit.getEmail(),
+ patientToEdit.getAddress(), remark, patientToEdit.getTags());
- model.setPerson(personToEdit, editedPerson);
+ model.setPerson(patientToEdit, editedPatient);
model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
- return new CommandResult(generateSuccessMessage(editedPerson));
+ return new CommandResult(generateSuccessMessage(editedPatient));
}
/**
* Generates a command execution success message based on whether
* the remark is added to or removed from
- * {@code personToEdit}.
+ * {@code patientToEdit}.
*/
- private String generateSuccessMessage(Person personToEdit) {
+ private String generateSuccessMessage(Person patientToEdit) {
String message = !remark.value.isEmpty() ? MESSAGE_ADD_REMARK_SUCCESS : MESSAGE_DELETE_REMARK_SUCCESS;
- return String.format(message, personToEdit);
+ return String.format(message, patientToEdit);
}
```
diff --git a/docs/tutorials/RemovingFields.md b/docs/tutorials/RemovingFields.md
index f29169bc924..0e03f9e181b 100644
--- a/docs/tutorials/RemovingFields.md
+++ b/docs/tutorials/RemovingFields.md
@@ -1,8 +1,11 @@
---
-layout: page
-title: "Tutorial: Removing Fields"
+ layout: default.md
+ title: "Tutorial: Removing Fields"
+ pageNav: 3
---
+# Tutorial: Removing Fields
+
> Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away.
>
> — Antoine de Saint-Exupery
@@ -10,17 +13,17 @@ title: "Tutorial: Removing Fields"
When working on an existing code base, you will most likely find that some features that are no longer necessary.
This tutorial aims to give you some practice on such a code 'removal' activity by removing the `address` field from `Person` class.
-
+
**If you have done the [Add `remark` command tutorial](AddRemark.html) already**, you should know where the code had to be updated to add the field `remark`. From that experience, you can deduce where the code needs to be changed to _remove_ that field too. The removing of the `address` field can be done similarly.
However, if you have no such prior knowledge, removing a field can take a quite a bit of detective work. This tutorial takes you through that process. **At least have a read even if you don't actually do the steps yourself.**
-
+
-* Table of Contents
-{:toc}
+
+
## Safely deleting `Address`
@@ -28,7 +31,7 @@ IntelliJ IDEA provides a refactoring tool that can identify *most* parts of a re
### Assisted refactoring
-The `address` field in `Person` is actually an instance of the `seedu.address.model.person.Address` class. Since removing the `Address` class will break the application, we start by identifying `Address`'s usages. This allows us to see code that depends on `Address` to function properly and edit them on a case-by-case basis. Right-click the `Address` class and select `Refactor` \> `Safe Delete` through the menu.
+The `address` field in `Person` is actually an instance of the `seedu.address.model.patient.Address` class. Since removing the `Address` class will break the application, we start by identifying `Address`'s usages. This allows us to see code that depends on `Address` to function properly and edit them on a case-by-case basis. Right-click the `Address` class and select `Refactor` \> `Safe Delete` through the menu.
* :bulb: To make things simpler, you can unselect the options `Search in comments and strings` and `Search for text occurrences`
![Usages detected](../images/remove/UnsafeDelete.png)
@@ -50,10 +53,10 @@ Let’s try removing references to `Address` in `EditPersonDescriptor`.
1. Remove the usages of `address` and select `Do refactor` when you are done.
-
+
- :bulb: **Tip:** Removing usages may result in errors. Exercise discretion and fix them. For example, removing the `address` field from the `Person` class will require you to modify its constructor.
-
+ **Tip:** Removing usages may result in errors. Exercise discretion and fix them. For example, removing the `address` field from the `Person` class will require you to modify its constructor.
+
1. Repeat the steps for the remaining usages of `Address`
@@ -71,7 +74,7 @@ A quick look at the `PersonCard` class and its `fxml` file quickly reveals why i
**`PersonCard.java`**
-``` java
+```java
...
@FXML
private Label address;
@@ -100,7 +103,7 @@ In `src/test/data/`, data meant for testing purposes are stored. While keeping t
```json
{
- "persons": [ {
+ "patients": [ {
"name": "Person with invalid name field: Ha!ns Mu@ster",
"phone": "9482424",
"email": "hans@example.com",
diff --git a/docs/tutorials/TracingCode.md b/docs/tutorials/TracingCode.md
index 4fb62a83ef6..6602e8235fd 100644
--- a/docs/tutorials/TracingCode.md
+++ b/docs/tutorials/TracingCode.md
@@ -1,26 +1,30 @@
---
-layout: page
-title: "Tutorial: Tracing code"
+ layout: default.md
+ title: "Tutorial: Tracing code"
+ pageNav: 3
---
+# Tutorial: Tracing code
+
+
> Indeed, the ratio of time spent reading versus writing is well over 10 to 1. We are constantly reading old code as part of the effort to write new code. …\[Therefore,\] making it easy to read makes it easier to write.
>
> — Robert C. Martin Clean Code: A Handbook of Agile Software Craftsmanship
When trying to understand an unfamiliar code base, one common strategy used is to trace some representative execution path through the code base. One easy way to trace an execution path is to use a debugger to step through the code. In this tutorial, you will be using the IntelliJ IDEA’s debugger to trace the execution path of a specific user command.
-* Table of Contents
-{:toc}
+
+
## Before we start
Before we jump into the code, it is useful to get an idea of the overall structure and the high-level behavior of the application. This is provided in the 'Architecture' section of the developer guide. In particular, the architecture diagram (reproduced below), tells us that the App consists of several components.
-![ArchitectureDiagram](../images/ArchitectureDiagram.png)
+
It also has a sequence diagram (reproduced below) that tells us how a command propagates through the App.
-
+
Note how the diagram shows only the execution flows _between_ the main components. That is, it does not show details of the execution path *inside* each component. By hiding those details, the diagram aims to inform the reader about the overall execution path of a command without overwhelming the reader with too much details. In this tutorial, you aim to find those omitted details so that you get a more in-depth understanding of how the code works.
@@ -37,16 +41,16 @@ As you know, the first step of debugging is to put in a breakpoint where you wan
In our case, we would want to begin the tracing at the very point where the App start processing user input (i.e., somewhere in the UI component), and then trace through how the execution proceeds through the UI component. However, the execution path through a GUI is often somewhat obscure due to various *event-driven mechanisms* used by GUI frameworks, which happens to be the case here too. Therefore, let us put the breakpoint where the `UI` transfers control to the `Logic` component.
-
+
According to the sequence diagram you saw earlier (and repeated above for reference), the `UI` component yields control to the `Logic` component through a method named `execute`. Searching through the code base for an `execute()` method that belongs to the `Logic` component yields a promising candidate in `seedu.address.logic.Logic`.
-
+
-:bulb: **Intellij Tip:** The ['**Search Everywhere**' feature](https://www.jetbrains.com/help/idea/searching-everywhere.html) can be used here. In particular, the '**Find Symbol**' ('Symbol' here refers to methods, variables, classes etc.) variant of that feature is quite useful here as we are looking for a _method_ named `execute`, not simply the text `execute`.
-
+**Intellij Tip:** The ['**Search Everywhere**' feature](https://www.jetbrains.com/help/idea/searching-everywhere.html) can be used here. In particular, the '**Find Symbol**' ('Symbol' here refers to methods, variables, classes etc.) variant of that feature is quite useful here as we are looking for a _method_ named `execute`, not simply the text `execute`.
+
A quick look at the `seedu.address.logic.Logic` (an extract given below) confirms that this indeed might be what we’re looking for.
@@ -67,14 +71,14 @@ public interface Logic {
But apparently, this is an interface, not a concrete implementation.
That should be fine because the [Architecture section of the Developer Guide](../DeveloperGuide.html#architecture) tells us that components interact through interfaces. Here's the relevant diagram:
-
+
Next, let's find out which statement(s) in the `UI` code is calling this method, thus transferring control from the `UI` to the `Logic`.
-
+
-:bulb: **Intellij Tip:** The ['**Find Usages**' feature](https://www.jetbrains.com/help/idea/find-highlight-usages.html#find-usages) can find from which parts of the code a class/method/variable is being used.
-
+**Intellij Tip:** The ['**Find Usages**' feature](https://www.jetbrains.com/help/idea/find-highlight-usages.html#find-usages) can find from which parts of the code a class/method/variable is being used.
+
![`Find Usages` tool window. `Edit` \> `Find` \> `Find Usages`.](../images/tracing/FindUsages.png)
@@ -87,10 +91,10 @@ Now let’s set the breakpoint. First, double-click the item to reach the corres
Recall from the User Guide that the `edit` command has the format: `edit INDEX [n/NAME] [p/PHONE] [e/EMAIL] [a/ADDRESS] [t/TAG]…` For this tutorial we will be issuing the command `edit 1 n/Alice Yeoh`.
-
+
-:bulb: **Tip:** Over the course of the debugging session, you will encounter every major component in the application. Try to keep track of what happens inside the component and where the execution transfers to another component.
-
+**Tip:** Over the course of the debugging session, you will encounter every major component in the application. Try to keep track of what happens inside the component and where the execution transfers to another component.
+
1. To start the debugging session, simply `Run` \> `Debug Main`
@@ -110,7 +114,7 @@ Recall from the User Guide that the `edit` command has the format: `edit INDEX [
**LogicManager\#execute().**
- ``` java
+ ```java
@Override
public CommandResult execute(String commandText)
throws CommandException, ParseException {
@@ -142,7 +146,7 @@ Recall from the User Guide that the `edit` command has the format: `edit INDEX [
![StepOver](../images/tracing/StepOver.png)
1. _Step into_ the line where user input in parsed from a String to a Command, which should bring you to the `AddressBookParser#parseCommand()` method (partial code given below):
- ``` java
+ ```java
public Command parseCommand(String userInput) throws ParseException {
...
final String commandWord = matcher.group("commandWord");
@@ -157,7 +161,7 @@ Recall from the User Guide that the `edit` command has the format: `edit INDEX [
1. Stepping through the `switch` block, we end up at a call to `EditCommandParser().parse()` as expected (because the command we typed is an edit command).
- ``` java
+ ```java
...
case EditCommand.COMMAND_WORD:
return new EditCommandParser().parse(arguments);
@@ -166,8 +170,10 @@ Recall from the User Guide that the `edit` command has the format: `edit INDEX [
1. Let’s see what `EditCommandParser#parse()` does by stepping into it. You might have to click the 'step into' button multiple times here because there are two method calls in that statement: `EditCommandParser()` and `parse()`.
- :bulb: **Intellij Tip:** Sometimes, you might end up stepping into functions that are not of interest. Simply use the `step out` button to get out of them!
-
+
+
+ **Intellij Tip:** Sometimes, you might end up stepping into functions that are not of interest. Simply use the `step out` button to get out of them!
+
1. Stepping through the method shows that it calls `ArgumentTokenizer#tokenize()` and `ParserUtil#parseIndex()` to obtain the arguments and index required.
@@ -175,55 +181,58 @@ Recall from the User Guide that the `edit` command has the format: `edit INDEX [
![EditCommand](../images/tracing/EditCommand.png)
1. As you just traced through some code involved in parsing a command, you can take a look at this class diagram to see where the various parsing-related classes you encountered fit into the design of the `Logic` component.
-
+
1. Let’s continue stepping through until we return to `LogicManager#execute()`.
The sequence diagram below shows the details of the execution path through the Logic component. Does the execution path you traced in the code so far match the diagram?
- ![Tracing an `edit` command through the Logic component](../images/tracing/LogicSequenceDiagram.png)
+
1. Now, step over until you read the statement that calls the `execute()` method of the `EditCommand` object received, and step into that `execute()` method (partial code given below):
**`EditCommand#execute()`:**
- ``` java
+ ```java
@Override
public CommandResult execute(Model model) throws CommandException {
...
- Person personToEdit = lastShownList.get(index.getZeroBased());
- Person editedPerson = createEditedPerson(personToEdit, editPersonDescriptor);
- if (!personToEdit.isSamePerson(editedPerson) && model.hasPerson(editedPerson)) {
+ Person patientToEdit = lastShownList.get(index.getZeroBased());
+ Person editedPatient = createEditedPerson(patientToEdit, editPersonDescriptor);
+ if (!patientToEdit.isSamePerson(editedPatient) && model.hasPerson(editedPatient)) {
throw new CommandException(MESSAGE_DUPLICATE_PERSON);
}
- model.setPerson(personToEdit, editedPerson);
+ model.setPerson(patientToEdit, editedPatient);
model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
- return new CommandResult(String.format(MESSAGE_EDIT_PERSON_SUCCESS, editedPerson));
+ return new CommandResult(String.format(MESSAGE_EDIT_PERSON_SUCCESS, editedPatient));
}
```
1. As suspected, `command#execute()` does indeed make changes to the `model` object. Specifically,
- * it uses the `setPerson()` method (defined in the interface `Model` and implemented in `ModelManager` as per the usual pattern) to update the person data.
- * it uses the `updateFilteredPersonList` method to ask the `Model` to populate the 'filtered list' with _all_ persons.
- FYI, The 'filtered list' is the list of persons resulting from the most recent operation that will be shown to the user immediately after. For the `edit` command, we populate it with all the persons so that the user can see the edited person along with all other persons. If this was a `find` command, we would be setting that list to contain the search results instead.
- To provide some context, given below is the class diagram of the `Model` component. See if you can figure out where the 'filtered list' of persons is being tracked.
-
+ * it uses the `setPerson()` method (defined in the interface `Model` and implemented in `ModelManager` as per the usual pattern) to update the patient data.
+ * it uses the `updateFilteredPersonList` method to ask the `Model` to populate the 'filtered list' with _all_ patients.
+ FYI, The 'filtered list' is the list of patients resulting from the most recent operation that will be shown to the user immediately after. For the `edit` command, we populate it with all the patients so that the user can see the edited patient along with all other patients. If this was a `find` command, we would be setting that list to contain the search results instead.
+ To provide some context, given below is the class diagram of the `Model` component. See if you can figure out where the 'filtered list' of patients is being tracked.
+
* :bulb: This may be a good time to read through the [`Model` component section of the DG](../DeveloperGuide.html#model-component)
1. As you step through the rest of the statements in the `EditCommand#execute()` method, you'll see that it creates a `CommandResult` object (containing information about the result of the execution) and returns it.
Advancing the debugger by one more step should take you back to the middle of the `LogicManager#execute()` method.
1. Given that you have already seen quite a few classes in the `Logic` component in action, see if you can identify in this partial class diagram some of the classes you've encountered so far, and see how they fit into the class structure of the `Logic` component:
-
+
+
* :bulb: This may be a good time to read through the [`Logic` component section of the DG](../DeveloperGuide.html#logic-component)
1. Similar to before, you can step over/into statements in the `LogicManager#execute()` method to examine how the control is transferred to the `Storage` component and what happens inside that component.
- :bulb: **Intellij Tip:** When trying to step into a statement such as `storage.saveAddressBook(model.getAddressBook())` which contains multiple method calls, Intellij will let you choose (by clicking) which one you want to step into.
-
+
+
+ **Intellij Tip:** When trying to step into a statement such as `storage.saveAddressBook(model.getAddressBook())` which contains multiple method calls, Intellij will let you choose (by clicking) which one you want to step into.
+
-1. As you step through the code inside the `Storage` component, you will eventually arrive at the `JsonAddressBook#saveAddressBook()` method which calls the `JsonSerializableAddressBook` constructor, to create an object that can be _serialized_ (i.e., stored in storage medium) in JSON format. That constructor is given below (with added line breaks for easier readability):
+1. As you step through the code inside the `Storage` component, you will eventually arrive at the `JsonAddressBook#saveAddressBook()` method which calls the `JsonSerializableAddressBook` constructor, to create an object that can be _serialized_ (i.e., stored in storage medium) in JSON format. That constructor is given below (with added line breaks for easier readability):
**`JsonSerializableAddressBook` constructor:**
- ``` java
+ ```java
/**
* Converts a given {@code ReadOnlyAddressBook} into this class for Jackson use.
*
@@ -231,7 +240,7 @@ Recall from the User Guide that the `edit` command has the format: `edit INDEX [
* {@code JsonSerializableAddressBook}.
*/
public JsonSerializableAddressBook(ReadOnlyAddressBook source) {
- persons.addAll(
+ patients.addAll(
source.getPersonList()
.stream()
.map(JsonAdaptedPerson::new)
@@ -243,7 +252,8 @@ Recall from the User Guide that the `edit` command has the format: `edit INDEX [
This is because regular Java objects need to go through an _adaptation_ for them to be suitable to be saved in JSON format.
1. While you are stepping through the classes in the `Storage` component, here is the component's class diagram to help you understand how those classes fit into the structure of the component.
-
+
+
* :bulb: This may be a good time to read through the [`Storage` component section of the DG](../DeveloperGuide.html#storage-component)
1. We can continue to step through until you reach the end of the `LogicManager#execute()` method and return to the `MainWindow#executeCommand()` method (the place where we put the original breakpoint).
@@ -251,7 +261,7 @@ Recall from the User Guide that the `edit` command has the format: `edit INDEX [
1. Stepping into `resultDisplay.setFeedbackToUser(commandResult.getFeedbackToUser());`, we end up in:
**`ResultDisplay#setFeedbackToUser()`**
- ``` java
+ ```java
public void setFeedbackToUser(String feedbackToUser) {
requireNonNull(feedbackToUser);
resultDisplay.setText(feedbackToUser);
diff --git a/src/main/java/seedu/address/MainApp.java b/src/main/java/seedu/address/MainApp.java
index 3d6bd06d5af..b9059ac4c53 100644
--- a/src/main/java/seedu/address/MainApp.java
+++ b/src/main/java/seedu/address/MainApp.java
@@ -15,16 +15,16 @@
import seedu.address.commons.util.StringUtil;
import seedu.address.logic.Logic;
import seedu.address.logic.LogicManager;
-import seedu.address.model.AddressBook;
import seedu.address.model.Model;
import seedu.address.model.ModelManager;
-import seedu.address.model.ReadOnlyAddressBook;
+import seedu.address.model.PatientList;
+import seedu.address.model.ReadOnlyPatientList;
import seedu.address.model.ReadOnlyUserPrefs;
import seedu.address.model.UserPrefs;
import seedu.address.model.util.SampleDataUtil;
-import seedu.address.storage.AddressBookStorage;
-import seedu.address.storage.JsonAddressBookStorage;
+import seedu.address.storage.JsonPatientListStorage;
import seedu.address.storage.JsonUserPrefsStorage;
+import seedu.address.storage.PatientListStorage;
import seedu.address.storage.Storage;
import seedu.address.storage.StorageManager;
import seedu.address.storage.UserPrefsStorage;
@@ -36,7 +36,7 @@
*/
public class MainApp extends Application {
- public static final Version VERSION = new Version(0, 2, 2, true);
+ public static final Version VERSION = new Version(1, 3, 1, false);
private static final Logger logger = LogsCenter.getLogger(MainApp.class);
@@ -48,7 +48,7 @@ public class MainApp extends Application {
@Override
public void init() throws Exception {
- logger.info("=============================[ Initializing AddressBook ]===========================");
+ logger.info("=============================[ Initializing MediTrack ]===========================");
super.init();
AppParameters appParameters = AppParameters.parse(getParameters());
@@ -57,8 +57,8 @@ public void init() throws Exception {
UserPrefsStorage userPrefsStorage = new JsonUserPrefsStorage(config.getUserPrefsFilePath());
UserPrefs userPrefs = initPrefs(userPrefsStorage);
- AddressBookStorage addressBookStorage = new JsonAddressBookStorage(userPrefs.getAddressBookFilePath());
- storage = new StorageManager(addressBookStorage, userPrefsStorage);
+ PatientListStorage patientListStorage = new JsonPatientListStorage(userPrefs.getPatientListFilePath());
+ storage = new StorageManager(patientListStorage, userPrefsStorage);
model = initModelManager(storage, userPrefs);
@@ -68,26 +68,26 @@ public void init() throws Exception {
}
/**
- * Returns a {@code ModelManager} with the data from {@code storage}'s address book and {@code userPrefs}.
- * The data from the sample address book will be used instead if {@code storage}'s address book is not found,
- * or an empty address book will be used instead if errors occur when reading {@code storage}'s address book.
+ * Returns a {@code ModelManager} with the data from {@code storage}'s patient list and {@code userPrefs}.
+ * The data from the sample patient list will be used instead if {@code storage}'s patient list is not found,
+ * or an empty patient list will be used instead if errors occur when reading {@code storage}'s patient list.
*/
private Model initModelManager(Storage storage, ReadOnlyUserPrefs userPrefs) {
- logger.info("Using data file : " + storage.getAddressBookFilePath());
+ logger.info("Using data file : " + storage.getPatientListFilePath());
- Optional addressBookOptional;
- ReadOnlyAddressBook initialData;
+ Optional patientListOptional;
+ ReadOnlyPatientList initialData;
try {
- addressBookOptional = storage.readAddressBook();
- if (!addressBookOptional.isPresent()) {
- logger.info("Creating a new data file " + storage.getAddressBookFilePath()
- + " populated with a sample AddressBook.");
+ patientListOptional = storage.readPatientList();
+ if (!patientListOptional.isPresent()) {
+ logger.info("Creating a new data file " + storage.getPatientListFilePath()
+ + " populated with a sample PatientList.");
}
- initialData = addressBookOptional.orElseGet(SampleDataUtil::getSampleAddressBook);
+ initialData = patientListOptional.orElseGet(SampleDataUtil::getSamplePatientList);
} catch (DataLoadingException e) {
- logger.warning("Data file at " + storage.getAddressBookFilePath() + " could not be loaded."
- + " Will be starting with an empty AddressBook.");
- initialData = new AddressBook();
+ logger.warning("Data file at " + storage.getPatientListFilePath() + " could not be loaded."
+ + " Will be starting with an empty PatientList.");
+ initialData = new PatientList();
}
return new ModelManager(initialData, userPrefs);
@@ -170,13 +170,13 @@ protected UserPrefs initPrefs(UserPrefsStorage storage) {
@Override
public void start(Stage primaryStage) {
- logger.info("Starting AddressBook " + MainApp.VERSION);
+ logger.info("Starting MediTrack " + MainApp.VERSION);
ui.start(primaryStage);
}
@Override
public void stop() {
- logger.info("============================ [ Stopping Address Book ] =============================");
+ logger.info("============================ [ Stopping MediTrack ] =============================");
try {
storage.saveUserPrefs(model.getUserPrefs());
} catch (IOException e) {
diff --git a/src/main/java/seedu/address/commons/core/LogsCenter.java b/src/main/java/seedu/address/commons/core/LogsCenter.java
index 8cf8e15a0f0..8132abad2b0 100644
--- a/src/main/java/seedu/address/commons/core/LogsCenter.java
+++ b/src/main/java/seedu/address/commons/core/LogsCenter.java
@@ -20,7 +20,7 @@
public class LogsCenter {
private static final int MAX_FILE_COUNT = 5;
private static final int MAX_FILE_SIZE_IN_BYTES = (int) (Math.pow(2, 20) * 5); // 5MB
- private static final String LOG_FILE = "addressbook.log";
+ private static final String LOG_FILE = "meditrack.log";
private static final Logger logger; // logger for this class
private static Logger baseLogger; // to be used as the parent of all other loggers created by this class.
private static Level currentLogLevel = Level.INFO;
@@ -75,11 +75,11 @@ private static void removeHandlers(Logger logger) {
}
/**
- * Creates a logger named 'ab3', containing a {@code ConsoleHandler} and a {@code FileHandler}.
+ * Creates a logger named 'base', containing a {@code ConsoleHandler} and a {@code FileHandler}.
* Sets it as the {@code baseLogger}, to be used as the parent logger of all other loggers.
*/
private static void setBaseLogger() {
- baseLogger = Logger.getLogger("ab3");
+ baseLogger = Logger.getLogger("meditrack");
baseLogger.setUseParentHandlers(false);
removeHandlers(baseLogger);
diff --git a/src/main/java/seedu/address/commons/util/FileUtil.java b/src/main/java/seedu/address/commons/util/FileUtil.java
index b1e2767cdd9..e38974eafa3 100644
--- a/src/main/java/seedu/address/commons/util/FileUtil.java
+++ b/src/main/java/seedu/address/commons/util/FileUtil.java
@@ -18,7 +18,7 @@ public static boolean isFileExists(Path file) {
}
/**
- * Returns true if {@code path} can be converted into a {@code Path} via {@link Paths#get(String)},
+ * Returns true if {@code path} can be converted into a {@code Path} via {@link Paths#get(String, String...)},
* otherwise returns false.
* @param path A string representing the file path. Cannot be null.
*/
diff --git a/src/main/java/seedu/address/logic/Logic.java b/src/main/java/seedu/address/logic/Logic.java
index 92cd8fa605a..3d4f23937c5 100644
--- a/src/main/java/seedu/address/logic/Logic.java
+++ b/src/main/java/seedu/address/logic/Logic.java
@@ -7,8 +7,8 @@
import seedu.address.logic.commands.CommandResult;
import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.ReadOnlyAddressBook;
-import seedu.address.model.person.Person;
+import seedu.address.model.ReadOnlyPatientList;
+import seedu.address.model.patient.Patient;
/**
* API of the Logic component
@@ -24,19 +24,19 @@ public interface Logic {
CommandResult execute(String commandText) throws CommandException, ParseException;
/**
- * Returns the AddressBook.
+ * Returns the PatientList.
*
- * @see seedu.address.model.Model#getAddressBook()
+ * @see seedu.address.model.Model#getPatientList()
*/
- ReadOnlyAddressBook getAddressBook();
+ ReadOnlyPatientList getPatientList();
- /** Returns an unmodifiable view of the filtered list of persons */
- ObservableList getFilteredPersonList();
+ /** Returns an unmodifiable view of the filtered list of patients */
+ ObservableList getFilteredPatientList();
/**
- * Returns the user prefs' address book file path.
+ * Returns the user prefs' patient list file path.
*/
- Path getAddressBookFilePath();
+ Path getPatientListFilePath();
/**
* Returns the user prefs' GUI settings.
diff --git a/src/main/java/seedu/address/logic/LogicManager.java b/src/main/java/seedu/address/logic/LogicManager.java
index 5aa3b91c7d0..4bd5bdd6cfc 100644
--- a/src/main/java/seedu/address/logic/LogicManager.java
+++ b/src/main/java/seedu/address/logic/LogicManager.java
@@ -11,11 +11,11 @@
import seedu.address.logic.commands.Command;
import seedu.address.logic.commands.CommandResult;
import seedu.address.logic.commands.exceptions.CommandException;
-import seedu.address.logic.parser.AddressBookParser;
+import seedu.address.logic.parser.InputParser;
import seedu.address.logic.parser.exceptions.ParseException;
import seedu.address.model.Model;
-import seedu.address.model.ReadOnlyAddressBook;
-import seedu.address.model.person.Person;
+import seedu.address.model.ReadOnlyPatientList;
+import seedu.address.model.patient.Patient;
import seedu.address.storage.Storage;
/**
@@ -31,7 +31,7 @@ public class LogicManager implements Logic {
private final Model model;
private final Storage storage;
- private final AddressBookParser addressBookParser;
+ private final InputParser inputParser;
/**
* Constructs a {@code LogicManager} with the given {@code Model} and {@code Storage}.
@@ -39,7 +39,7 @@ public class LogicManager implements Logic {
public LogicManager(Model model, Storage storage) {
this.model = model;
this.storage = storage;
- addressBookParser = new AddressBookParser();
+ inputParser = new InputParser();
}
@Override
@@ -47,11 +47,11 @@ public CommandResult execute(String commandText) throws CommandException, ParseE
logger.info("----------------[USER COMMAND][" + commandText + "]");
CommandResult commandResult;
- Command command = addressBookParser.parseCommand(commandText);
+ Command command = inputParser.parseCommand(commandText);
commandResult = command.execute(model);
try {
- storage.saveAddressBook(model.getAddressBook());
+ storage.savePatientList(model.getPatientList());
} catch (AccessDeniedException e) {
throw new CommandException(String.format(FILE_OPS_PERMISSION_ERROR_FORMAT, e.getMessage()), e);
} catch (IOException ioe) {
@@ -62,18 +62,18 @@ public CommandResult execute(String commandText) throws CommandException, ParseE
}
@Override
- public ReadOnlyAddressBook getAddressBook() {
- return model.getAddressBook();
+ public ReadOnlyPatientList getPatientList() {
+ return model.getPatientList();
}
@Override
- public ObservableList getFilteredPersonList() {
- return model.getFilteredPersonList();
+ public ObservableList getFilteredPatientList() {
+ return model.getFilteredPatientList();
}
@Override
- public Path getAddressBookFilePath() {
- return model.getAddressBookFilePath();
+ public Path getPatientListFilePath() {
+ return model.getPatientListFilePath();
}
@Override
diff --git a/src/main/java/seedu/address/logic/Messages.java b/src/main/java/seedu/address/logic/Messages.java
index ecd32c31b53..2fca3eec204 100644
--- a/src/main/java/seedu/address/logic/Messages.java
+++ b/src/main/java/seedu/address/logic/Messages.java
@@ -5,7 +5,7 @@
import java.util.stream.Stream;
import seedu.address.logic.parser.Prefix;
-import seedu.address.model.person.Person;
+import seedu.address.model.patient.Patient;
/**
* Container for user visible messages.
@@ -14,8 +14,8 @@ public class Messages {
public static final String MESSAGE_UNKNOWN_COMMAND = "Unknown command";
public static final String MESSAGE_INVALID_COMMAND_FORMAT = "Invalid command format! \n%1$s";
- public static final String MESSAGE_INVALID_PERSON_DISPLAYED_INDEX = "The person index provided is invalid";
- public static final String MESSAGE_PERSONS_LISTED_OVERVIEW = "%1$d persons listed!";
+ public static final String MESSAGE_INVALID_PATIENT_DISPLAYED_INDEX = "The patient index provided is invalid";
+ public static final String MESSAGE_PATIENTS_LISTED_OVERVIEW = "%1$d patients listed!";
public static final String MESSAGE_DUPLICATE_FIELDS =
"Multiple values specified for the following single-valued field(s): ";
@@ -32,19 +32,23 @@ public static String getErrorMessageForDuplicatePrefixes(Prefix... duplicatePref
}
/**
- * Formats the {@code person} for display to the user.
+ * Formats the {@code patient} for display to the user.
*/
- public static String format(Person person) {
+ public static String format(Patient patient) {
final StringBuilder builder = new StringBuilder();
- builder.append(person.getName())
+ builder.append(patient.getName())
.append("; Phone: ")
- .append(person.getPhone())
+ .append(patient.getPhone())
.append("; Email: ")
- .append(person.getEmail())
+ .append(patient.getEmail())
.append("; Address: ")
- .append(person.getAddress())
- .append("; Tags: ");
- person.getTags().forEach(builder::append);
+ .append(patient.getAddress())
+ .append("; Date Of birth: ")
+ .append(patient.getDateOfBirth())
+ .append("; Sex: ")
+ .append(patient.getSex())
+ .append("; Appointment: ")
+ .append(patient.getAppointment());
return builder.toString();
}
diff --git a/src/main/java/seedu/address/logic/commands/AddCommand.java b/src/main/java/seedu/address/logic/commands/AddCommand.java
index 5d7185a9680..3f02483db43 100644
--- a/src/main/java/seedu/address/logic/commands/AddCommand.java
+++ b/src/main/java/seedu/address/logic/commands/AddCommand.java
@@ -2,61 +2,63 @@
import static java.util.Objects.requireNonNull;
import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATEOFBIRTH;
import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_SEX;
import seedu.address.commons.util.ToStringBuilder;
import seedu.address.logic.Messages;
import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.model.Model;
-import seedu.address.model.person.Person;
+import seedu.address.model.patient.Patient;
/**
- * Adds a person to the address book.
+ * Adds a patient to the patient list.
*/
public class AddCommand extends Command {
public static final String COMMAND_WORD = "add";
- public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds a person to the address book. "
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Adds a patient to the list. "
+ "Parameters: "
+ PREFIX_NAME + "NAME "
+ PREFIX_PHONE + "PHONE "
+ PREFIX_EMAIL + "EMAIL "
+ PREFIX_ADDRESS + "ADDRESS "
- + "[" + PREFIX_TAG + "TAG]...\n"
+ + PREFIX_DATEOFBIRTH + "DATE OF BIRTH "
+ + PREFIX_SEX + "Sex \n"
+ "Example: " + COMMAND_WORD + " "
+ PREFIX_NAME + "John Doe "
+ PREFIX_PHONE + "98765432 "
+ PREFIX_EMAIL + "johnd@example.com "
+ PREFIX_ADDRESS + "311, Clementi Ave 2, #02-25 "
- + PREFIX_TAG + "friends "
- + PREFIX_TAG + "owesMoney";
+ + PREFIX_DATEOFBIRTH + "25/2/2024 "
+ + PREFIX_SEX + "Male";
- public static final String MESSAGE_SUCCESS = "New person added: %1$s";
- public static final String MESSAGE_DUPLICATE_PERSON = "This person already exists in the address book";
+ public static final String MESSAGE_SUCCESS = "New patient added: %1$s";
+ public static final String MESSAGE_DUPLICATE_PATIENT = "This patient already exists in the list";
- private final Person toAdd;
+ private final Patient toAdd;
/**
- * Creates an AddCommand to add the specified {@code Person}
+ * Creates an AddCommand to add the specified {@code Patient}
*/
- public AddCommand(Person person) {
- requireNonNull(person);
- toAdd = person;
+ public AddCommand(Patient patient) {
+ requireNonNull(patient);
+ toAdd = patient;
}
@Override
public CommandResult execute(Model model) throws CommandException {
requireNonNull(model);
- if (model.hasPerson(toAdd)) {
- throw new CommandException(MESSAGE_DUPLICATE_PERSON);
+ if (model.hasPatient(toAdd)) {
+ throw new CommandException(MESSAGE_DUPLICATE_PATIENT);
}
- model.addPerson(toAdd);
+ model.addPatient(toAdd);
return new CommandResult(String.format(MESSAGE_SUCCESS, Messages.format(toAdd)));
}
diff --git a/src/main/java/seedu/address/logic/commands/AddVisitCommand.java b/src/main/java/seedu/address/logic/commands/AddVisitCommand.java
new file mode 100644
index 00000000000..cb5bd6b40a8
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/AddVisitCommand.java
@@ -0,0 +1,156 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_CONDITION;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE_OF_VISIT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_SEVERITY;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PATIENTS;
+
+import java.util.List;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.commons.util.ToStringBuilder;
+import seedu.address.logic.Messages;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.patient.Name;
+import seedu.address.model.patient.Patient;
+import seedu.address.model.patient.Phone;
+import seedu.address.model.patient.Visit;
+
+/**
+ * Adds a visit to a Patient.
+ */
+public class AddVisitCommand extends Command {
+
+ public static final String COMMAND_WORD = "addv";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": adds a visit to the specified patient.\n"
+ + "Parameters: INDEX (must be a positive integer) "
+ + "[" + PREFIX_DATE_OF_VISIT + "DATE OF VISIT] "
+ + "[" + PREFIX_CONDITION + "CONDITION] "
+ + "[" + PREFIX_SEVERITY + "SEVERITY] \n"
+ + "OR "
+ + "[" + PREFIX_NAME + "NAME] "
+ + "[" + PREFIX_PHONE + "PHONE] "
+ + "[" + PREFIX_DATE_OF_VISIT + "DATE OF VISIT] "
+ + "[" + PREFIX_CONDITION + "CONDITION] "
+ + "[" + PREFIX_SEVERITY + "SEVERITY] \n"
+ + "Example: " + COMMAND_WORD + " 1 "
+ + PREFIX_DATE_OF_VISIT + "25/2/2024 "
+ + PREFIX_CONDITION + "Mild Fever "
+ + PREFIX_SEVERITY + "Low";
+
+ public static final String MESSAGE_SUCCESS = "New visit added";
+ public static final String MESSAGE_PATIENT_NOT_FOUND = "Could not find specified patient";
+ public static final String MESSAGE_DUPLICATE_VISIT = "Identical visit already exists for this patient";
+ private final Visit toAdd;
+ private final boolean useIndex;
+ private Index index;
+ private Name name;
+ private Phone phone;
+
+
+ /**
+ * Creates an add visit command from {@code index}.
+ */
+ public AddVisitCommand(Index index, Visit visit) {
+ requireAllNonNull(index, visit);
+
+ this.useIndex = true;
+ this.index = index;
+ this.toAdd = visit;
+ }
+
+ /**
+ * Creates an add visit command from {@code name} and {@code phone}.
+ */
+ public AddVisitCommand(Name name, Phone phone, Visit visit) {
+ requireAllNonNull(name, phone, visit);
+
+ this.useIndex = false;
+ this.name = name;
+ this.phone = phone;
+ this.toAdd = visit;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+
+ if (!hasPatient(model)) {
+ throw new CommandException(MESSAGE_PATIENT_NOT_FOUND);
+ }
+
+ Patient patient = getPatient(model);
+ if (patient.hasVisit(toAdd)) {
+ throw new CommandException(MESSAGE_DUPLICATE_VISIT);
+ }
+ patient.addVisit(toAdd);
+ model.updateFilteredPatientList(PREDICATE_SHOW_ALL_PATIENTS);
+
+ // Bandaid solution to fix UI not detecting visit changes.
+ model.deletePatient(patient);
+ model.addPatient(patient);
+
+ return new CommandResult(MESSAGE_SUCCESS);
+ }
+
+ private boolean hasPatient(Model model) {
+ if (useIndex) {
+ return true;
+ }
+ return model.hasPatient(name, phone);
+ }
+
+ private Patient getPatient(Model model) throws CommandException {
+ if (useIndex) {
+ return getPatientFromIndex(model);
+ } else {
+ return model.getPatient(name, phone);
+ }
+ }
+
+ private Patient getPatientFromIndex(Model model) throws CommandException {
+ List lastShownList = model.getFilteredPatientList();
+
+ if (index.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_PATIENT_DISPLAYED_INDEX);
+ }
+
+ return lastShownList.get(index.getZeroBased());
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof AddVisitCommand)) {
+ return false;
+ }
+
+ AddVisitCommand otherAddVisitCommand = (AddVisitCommand) other;
+ return toAdd.equals(otherAddVisitCommand.toAdd)
+ && useIndex == otherAddVisitCommand.useIndex
+ && index.equals(otherAddVisitCommand.index)
+ && name.equals(otherAddVisitCommand.name)
+ && phone.equals(otherAddVisitCommand.phone);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .add("toAdd", toAdd)
+ .add("useIndex", useIndex)
+ .add("index", index)
+ .add("name", name)
+ .add("phone", phone)
+ .toString();
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/ClearCommand.java b/src/main/java/seedu/address/logic/commands/ClearCommand.java
deleted file mode 100644
index 9c86b1fa6e4..00000000000
--- a/src/main/java/seedu/address/logic/commands/ClearCommand.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package seedu.address.logic.commands;
-
-import static java.util.Objects.requireNonNull;
-
-import seedu.address.model.AddressBook;
-import seedu.address.model.Model;
-
-/**
- * Clears the address book.
- */
-public class ClearCommand extends Command {
-
- public static final String COMMAND_WORD = "clear";
- public static final String MESSAGE_SUCCESS = "Address book has been cleared!";
-
-
- @Override
- public CommandResult execute(Model model) {
- requireNonNull(model);
- model.setAddressBook(new AddressBook());
- return new CommandResult(MESSAGE_SUCCESS);
- }
-}
diff --git a/src/main/java/seedu/address/logic/commands/DeleteAllCommand.java b/src/main/java/seedu/address/logic/commands/DeleteAllCommand.java
new file mode 100644
index 00000000000..6a74cf935c0
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/DeleteAllCommand.java
@@ -0,0 +1,29 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import seedu.address.model.Model;
+
+/**
+ * Deletes all entries in the patient list.
+ */
+public class DeleteAllCommand extends Command {
+
+ public static final String COMMAND_WORD = "delete-all";
+ public static final String CONFIRMATION =
+ "Are you sure you want to delete all?"
+ + "\nThis action is irreversible."
+ + "\nIf yes, enter ‘yes’. If not, simply enter 'no'.";
+
+ /**
+ * Executes the command and returns the result message.
+ *
+ * @param model {@code Model} which the command should operate on.
+ * @return feedback message of the operation result for display
+ */
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ return new CommandResult(CONFIRMATION);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/DeleteCommand.java b/src/main/java/seedu/address/logic/commands/DeleteByIndexCommand.java
similarity index 56%
rename from src/main/java/seedu/address/logic/commands/DeleteCommand.java
rename to src/main/java/seedu/address/logic/commands/DeleteByIndexCommand.java
index 1135ac19b74..dbc7b4bdbed 100644
--- a/src/main/java/seedu/address/logic/commands/DeleteCommand.java
+++ b/src/main/java/seedu/address/logic/commands/DeleteByIndexCommand.java
@@ -9,40 +9,39 @@
import seedu.address.logic.Messages;
import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.model.Model;
-import seedu.address.model.person.Person;
+import seedu.address.model.patient.Patient;
/**
- * Deletes a person identified using it's displayed index from the address book.
+ * Deletes a patient identified using it's displayed index from the patient list
*/
-public class DeleteCommand extends Command {
+public class DeleteByIndexCommand extends Command {
public static final String COMMAND_WORD = "delete";
public static final String MESSAGE_USAGE = COMMAND_WORD
- + ": Deletes the person identified by the index number used in the displayed person list.\n"
+ + ": Deletes the patient identified by the index number used in the displayed patient list.\n"
+ "Parameters: INDEX (must be a positive integer)\n"
+ "Example: " + COMMAND_WORD + " 1";
-
- public static final String MESSAGE_DELETE_PERSON_SUCCESS = "Deleted Person: %1$s";
+ public static final String MESSAGE_DELETE_PATIENT_SUCCESS = "Successfully deleted patient %1$s's data";
private final Index targetIndex;
- public DeleteCommand(Index targetIndex) {
+ public DeleteByIndexCommand(Index targetIndex) {
this.targetIndex = targetIndex;
}
@Override
public CommandResult execute(Model model) throws CommandException {
requireNonNull(model);
- List lastShownList = model.getFilteredPersonList();
+ List lastShownList = model.getFilteredPatientList();
if (targetIndex.getZeroBased() >= lastShownList.size()) {
- throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ throw new CommandException(Messages.MESSAGE_INVALID_PATIENT_DISPLAYED_INDEX);
}
- Person personToDelete = lastShownList.get(targetIndex.getZeroBased());
- model.deletePerson(personToDelete);
- return new CommandResult(String.format(MESSAGE_DELETE_PERSON_SUCCESS, Messages.format(personToDelete)));
+ Patient patientToDelete = lastShownList.get(targetIndex.getZeroBased());
+ model.deletePatient(patientToDelete);
+ return new CommandResult(String.format(MESSAGE_DELETE_PATIENT_SUCCESS, patientToDelete.getName()));
}
@Override
@@ -52,12 +51,12 @@ public boolean equals(Object other) {
}
// instanceof handles nulls
- if (!(other instanceof DeleteCommand)) {
+ if (!(other instanceof DeleteByIndexCommand)) {
return false;
}
- DeleteCommand otherDeleteCommand = (DeleteCommand) other;
- return targetIndex.equals(otherDeleteCommand.targetIndex);
+ DeleteByIndexCommand otherDeleteByIndexCommand = (DeleteByIndexCommand) other;
+ return targetIndex.equals(otherDeleteByIndexCommand.targetIndex);
}
@Override
diff --git a/src/main/java/seedu/address/logic/commands/DeleteByNamePhoneNumberCommand.java b/src/main/java/seedu/address/logic/commands/DeleteByNamePhoneNumberCommand.java
new file mode 100644
index 00000000000..718a5303770
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/DeleteByNamePhoneNumberCommand.java
@@ -0,0 +1,69 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.logging.Logger;
+
+import seedu.address.commons.core.LogsCenter;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.logic.parser.InputParser;
+import seedu.address.model.Model;
+import seedu.address.model.patient.Name;
+import seedu.address.model.patient.Patient;
+import seedu.address.model.patient.Phone;
+
+/**
+ * Deletes a patient identified using name and phone number.
+ */
+public class DeleteByNamePhoneNumberCommand extends Command {
+ public static final String COMMAND_WORD = "delete-p";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Deletes the patient identified by the specified name and phone number.\n"
+ + "Command format: delete-p n/ p/\n"
+ + "Example: " + COMMAND_WORD + " "
+ + "n/Eugene Hirose p/90807561";
+
+ public static final String DELETE_PATIENT_SUCCESS_MESSAGE = "Successfully deleted patient %1$s's data";
+ private static final Logger logger = LogsCenter.getLogger(InputParser.class);
+
+ private final Name name;
+ private final Phone phone;
+
+ /**
+ * Constructor for DeleteByNamePhoneNumberCommand.
+ *
+ * @param name Name of the patient to be deleted.
+ * @param phone Phone number of the patient to be deleted.
+ */
+ public DeleteByNamePhoneNumberCommand(Name name, Phone phone) {
+ this.name = name;
+ this.phone = phone;
+ }
+
+ /**
+ * Executes the command.
+ *
+ * @param model {@code Model} which the command should operate on.
+ * @return {@code CommandResult} of the command.
+ * @throws CommandException Exception thrown if the command fails.
+ */
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ try {
+ requireNonNull(model);
+
+ Patient patientToBeDeleted = model.getPatient(name, phone);
+
+ logger.fine("checkpoint");
+
+ model.deletePatient(patientToBeDeleted);
+
+ return new CommandResult(String.format(DELETE_PATIENT_SUCCESS_MESSAGE, patientToBeDeleted.getName()));
+ } catch (RuntimeException e) {
+ throw new CommandException("There is no patient with the specified name and phone number");
+ } catch (Exception e) {
+ throw new CommandException(e.getMessage());
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/DeleteVisitCommand.java b/src/main/java/seedu/address/logic/commands/DeleteVisitCommand.java
new file mode 100644
index 00000000000..ba07dcfe3a2
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/DeleteVisitCommand.java
@@ -0,0 +1,138 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PATIENTS;
+
+import java.util.List;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.commons.util.ToStringBuilder;
+import seedu.address.logic.Messages;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.patient.Name;
+import seedu.address.model.patient.Patient;
+import seedu.address.model.patient.Phone;
+
+/**
+ * Deletes the last visit from a Patient.
+ */
+public class DeleteVisitCommand extends Command {
+
+ public static final String COMMAND_WORD = "deletev";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": deletes the latest visit from the specified patient.\n"
+ + "Parameters: INDEX (must be a positive integer) \n"
+ + "OR "
+ + "[" + PREFIX_NAME + "NAME] "
+ + "[" + PREFIX_PHONE + "PHONE] \n"
+ + "Example: " + COMMAND_WORD + " 1";
+
+ public static final String MESSAGE_SUCCESS = "Visit deleted";
+ public static final String MESSAGE_PATIENT_NOT_FOUND = "Could not find specified patient";
+ public static final String MESSAGE_NO_VISIT = "This patient does not have a visit to delete";
+ private final boolean useIndex;
+ private Index index;
+ private Name name;
+ private Phone phone;
+
+
+ /**
+ * Creates a delete visit command from {@code index}.
+ */
+ public DeleteVisitCommand(Index index) {
+ requireNonNull(index);
+
+ this.useIndex = true;
+ this.index = index;
+ }
+
+ /**
+ * Creates a delete visit command from {@code name} and {@code phone}.
+ */
+ public DeleteVisitCommand(Name name, Phone phone) {
+ requireAllNonNull(name, phone);
+
+ this.useIndex = false;
+ this.name = name;
+ this.phone = phone;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+
+ if (!hasPatient(model)) {
+ throw new CommandException(MESSAGE_PATIENT_NOT_FOUND);
+ }
+
+ Patient patient = getPatient(model);
+ if (patient.getVisits().isEmpty()) {
+ throw new CommandException(MESSAGE_NO_VISIT);
+ }
+ patient.removeVisit(patient.getLatestVisit());
+ model.updateFilteredPatientList(PREDICATE_SHOW_ALL_PATIENTS);
+
+ // Bandaid solution to fix UI not detecting visit changes.
+ model.deletePatient(patient);
+ model.addPatient(patient);
+
+ return new CommandResult(MESSAGE_SUCCESS);
+ }
+
+ private boolean hasPatient(Model model) {
+ if (useIndex) {
+ return true;
+ }
+ return model.hasPatient(name, phone);
+ }
+
+ private Patient getPatient(Model model) throws CommandException {
+ if (useIndex) {
+ return getPatientFromIndex(model);
+ } else {
+ return model.getPatient(name, phone);
+ }
+ }
+
+ private Patient getPatientFromIndex(Model model) throws CommandException {
+ List lastShownList = model.getFilteredPatientList();
+
+ if (index.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_PATIENT_DISPLAYED_INDEX);
+ }
+
+ return lastShownList.get(index.getZeroBased());
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof DeleteVisitCommand)) {
+ return false;
+ }
+
+ DeleteVisitCommand otherDeleteVisitCommand = (DeleteVisitCommand) other;
+ return useIndex == otherDeleteVisitCommand.useIndex
+ && index.equals(otherDeleteVisitCommand.index)
+ && name.equals(otherDeleteVisitCommand.name)
+ && phone.equals(otherDeleteVisitCommand.phone);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .add("useIndex", useIndex)
+ .add("index", index)
+ .add("name", name)
+ .add("phone", phone)
+ .toString();
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/EditCommand.java b/src/main/java/seedu/address/logic/commands/EditCommand.java
index 4b581c7331e..41f2ca49a1e 100644
--- a/src/main/java/seedu/address/logic/commands/EditCommand.java
+++ b/src/main/java/seedu/address/logic/commands/EditCommand.java
@@ -2,18 +2,18 @@
import static java.util.Objects.requireNonNull;
import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_APPOINTMENT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATEOFBIRTH;
import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
-import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_SEX;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PATIENTS;
-import java.util.Collections;
-import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
-import java.util.Set;
+import java.util.function.Predicate;
import seedu.address.commons.core.index.Index;
import seedu.address.commons.util.CollectionUtil;
@@ -21,87 +21,121 @@
import seedu.address.logic.Messages;
import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.model.Model;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
+import seedu.address.model.patient.Address;
+import seedu.address.model.patient.Appointment;
+import seedu.address.model.patient.DateOfBirth;
+import seedu.address.model.patient.Email;
+import seedu.address.model.patient.Name;
+import seedu.address.model.patient.Patient;
+import seedu.address.model.patient.Phone;
+import seedu.address.model.patient.Sex;
/**
- * Edits the details of an existing person in the address book.
+ * Edits the details of an existing patient in the patient list.
*/
public class EditCommand extends Command {
public static final String COMMAND_WORD = "edit";
- public static final String MESSAGE_USAGE = COMMAND_WORD + ": Edits the details of the person identified "
- + "by the index number used in the displayed person list. "
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Edits the details of the patient identified "
+ + "by the index number used in the displayed patient list. "
+ "Existing values will be overwritten by the input values.\n"
+ "Parameters: INDEX (must be a positive integer) "
+ "[" + PREFIX_NAME + "NAME] "
+ "[" + PREFIX_PHONE + "PHONE] "
+ "[" + PREFIX_EMAIL + "EMAIL] "
+ "[" + PREFIX_ADDRESS + "ADDRESS] "
- + "[" + PREFIX_TAG + "TAG]...\n"
+ + "[" + PREFIX_DATEOFBIRTH + "DATEOFBIRTH] "
+ + "[" + PREFIX_SEX + "SEX] "
+ + "[" + PREFIX_APPOINTMENT + "APPOINTMENT] \n"
+ "Example: " + COMMAND_WORD + " 1 "
+ PREFIX_PHONE + "91234567 "
+ PREFIX_EMAIL + "johndoe@example.com";
- public static final String MESSAGE_EDIT_PERSON_SUCCESS = "Edited Person: %1$s";
+ public static final String MESSAGE_EDIT_PATIENT_SUCCESS = "Edited Patient: %1$s";
public static final String MESSAGE_NOT_EDITED = "At least one field to edit must be provided.";
- public static final String MESSAGE_DUPLICATE_PERSON = "This person already exists in the address book.";
+ public static final String MESSAGE_DUPLICATE_PATIENT = "This patient already exists in the list.";
- private final Index index;
- private final EditPersonDescriptor editPersonDescriptor;
+ private Index index;
+ private final EditPatientDescriptor editPatientDescriptor;
+ private Name name;
+ private Phone phone;
+ private final boolean useIndex;
/**
- * @param index of the person in the filtered person list to edit
- * @param editPersonDescriptor details to edit the person with
+ * @param index of the patient in the filtered patient list to edit
+ * @param editPatientDescriptor details to edit the patient with
*/
- public EditCommand(Index index, EditPersonDescriptor editPersonDescriptor) {
+ public EditCommand(Index index, EditPatientDescriptor editPatientDescriptor) {
requireNonNull(index);
- requireNonNull(editPersonDescriptor);
+ requireNonNull(editPatientDescriptor);
this.index = index;
- this.editPersonDescriptor = new EditPersonDescriptor(editPersonDescriptor);
+ this.editPatientDescriptor = new EditPatientDescriptor(editPatientDescriptor);
+ useIndex = true;
+ }
+
+ /**
+ * @param name name of the patient in the filtered patient list to edit
+ * @param phone phone number of the patient in the filtered patient list to edit
+ * @param editPatientDescriptor details to edit the patient with
+ */
+ public EditCommand(Name name, Phone phone, EditPatientDescriptor editPatientDescriptor) {
+ requireNonNull(name);
+ requireNonNull(phone);
+ requireNonNull(editPatientDescriptor);
+
+ this.name = name;
+ this.phone = phone;
+ this.editPatientDescriptor = new EditPatientDescriptor(editPatientDescriptor);
+ useIndex = false;
}
@Override
public CommandResult execute(Model model) throws CommandException {
requireNonNull(model);
- List lastShownList = model.getFilteredPersonList();
+ List lastShownList = model.getFilteredPatientList();
- if (index.getZeroBased() >= lastShownList.size()) {
- throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ if (useIndex && index.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_PATIENT_DISPLAYED_INDEX);
}
- Person personToEdit = lastShownList.get(index.getZeroBased());
- Person editedPerson = createEditedPerson(personToEdit, editPersonDescriptor);
+ Patient patientToEdit = null;
+ if (useIndex) {
+ patientToEdit = lastShownList.get(index.getZeroBased());
+ } else {
+ Predicate preodicate = patient -> patient.getName().equals(name)
+ && patient.getPhone().equals(phone);
+ patientToEdit = lastShownList.stream().filter(preodicate).findFirst().get();
+ }
+ Patient editedPatient = createEditedPatient(patientToEdit, editPatientDescriptor);
- if (!personToEdit.isSamePerson(editedPerson) && model.hasPerson(editedPerson)) {
- throw new CommandException(MESSAGE_DUPLICATE_PERSON);
+ if (!patientToEdit.isSamePatient(editedPatient) && model.hasPatient(editedPatient)) {
+ throw new CommandException(MESSAGE_DUPLICATE_PATIENT);
}
- model.setPerson(personToEdit, editedPerson);
- model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
- return new CommandResult(String.format(MESSAGE_EDIT_PERSON_SUCCESS, Messages.format(editedPerson)));
+ model.setPatient(patientToEdit, editedPatient);
+ model.updateFilteredPatientList(PREDICATE_SHOW_ALL_PATIENTS);
+ return new CommandResult(String.format(MESSAGE_EDIT_PATIENT_SUCCESS, Messages.format(editedPatient)));
}
/**
- * Creates and returns a {@code Person} with the details of {@code personToEdit}
- * edited with {@code editPersonDescriptor}.
+ * Creates and returns a {@code Patient} with the details of {@code patientToEdit}
+ * edited with {@code editPatientDescriptor}.
*/
- private static Person createEditedPerson(Person personToEdit, EditPersonDescriptor editPersonDescriptor) {
- assert personToEdit != null;
-
- Name updatedName = editPersonDescriptor.getName().orElse(personToEdit.getName());
- Phone updatedPhone = editPersonDescriptor.getPhone().orElse(personToEdit.getPhone());
- Email updatedEmail = editPersonDescriptor.getEmail().orElse(personToEdit.getEmail());
- Address updatedAddress = editPersonDescriptor.getAddress().orElse(personToEdit.getAddress());
- Set updatedTags = editPersonDescriptor.getTags().orElse(personToEdit.getTags());
-
- return new Person(updatedName, updatedPhone, updatedEmail, updatedAddress, updatedTags);
+ private static Patient createEditedPatient(Patient patientToEdit, EditPatientDescriptor editPatientDescriptor) {
+ assert patientToEdit != null;
+
+ Name updatedName = editPatientDescriptor.getName().orElse(patientToEdit.getName());
+ Phone updatedPhone = editPatientDescriptor.getPhone().orElse(patientToEdit.getPhone());
+ Email updatedEmail = editPatientDescriptor.getEmail().orElse(patientToEdit.getEmail());
+ Address updatedAddress = editPatientDescriptor.getAddress().orElse(patientToEdit.getAddress());
+ DateOfBirth updatedDateOfBirth = editPatientDescriptor.getDateOfBirth().orElse(patientToEdit.getDateOfBirth());
+ Sex updatedSex = editPatientDescriptor.getSex().orElse(patientToEdit.getSex());
+ Appointment updatedAppointment = editPatientDescriptor.getAppointment().orElse(patientToEdit.getAppointment());
+
+ return new Patient(updatedName, updatedPhone, updatedEmail, updatedAddress, updatedDateOfBirth, updatedSex,
+ updatedAppointment);
}
@Override
@@ -117,47 +151,50 @@ public boolean equals(Object other) {
EditCommand otherEditCommand = (EditCommand) other;
return index.equals(otherEditCommand.index)
- && editPersonDescriptor.equals(otherEditCommand.editPersonDescriptor);
+ && editPatientDescriptor.equals(otherEditCommand.editPatientDescriptor);
}
@Override
public String toString() {
return new ToStringBuilder(this)
.add("index", index)
- .add("editPersonDescriptor", editPersonDescriptor)
+ .add("editPatientDescriptor", editPatientDescriptor)
.toString();
}
/**
- * Stores the details to edit the person with. Each non-empty field value will replace the
- * corresponding field value of the person.
+ * Stores the details to edit the patient with. Each non-empty field value will replace the
+ * corresponding field value of the patient.
*/
- public static class EditPersonDescriptor {
+ public static class EditPatientDescriptor {
private Name name;
private Phone phone;
private Email email;
private Address address;
- private Set tags;
+ private DateOfBirth dateOfBirth;
+ private Sex sex;
+ private Appointment appointment;
- public EditPersonDescriptor() {}
+ public EditPatientDescriptor() {}
/**
* Copy constructor.
- * A defensive copy of {@code tags} is used internally.
*/
- public EditPersonDescriptor(EditPersonDescriptor toCopy) {
+ public EditPatientDescriptor(EditPatientDescriptor toCopy) {
setName(toCopy.name);
setPhone(toCopy.phone);
setEmail(toCopy.email);
setAddress(toCopy.address);
- setTags(toCopy.tags);
+ setDateOfBirth(toCopy.dateOfBirth);
+ setSex(toCopy.sex);
+ setAppointment(toCopy.appointment);
}
/**
* Returns true if at least one field is edited.
*/
public boolean isAnyFieldEdited() {
- return CollectionUtil.isAnyNonNull(name, phone, email, address, tags);
+ return CollectionUtil.isAnyNonNull(name, phone, email, address, dateOfBirth, sex, appointment);
}
public void setName(Name name) {
@@ -192,23 +229,29 @@ public Optional getAddress() {
return Optional.ofNullable(address);
}
- /**
- * Sets {@code tags} to this object's {@code tags}.
- * A defensive copy of {@code tags} is used internally.
- */
- public void setTags(Set tags) {
- this.tags = (tags != null) ? new HashSet<>(tags) : null;
+ public void setDateOfBirth(DateOfBirth dateOfBirth) {
+ this.dateOfBirth = dateOfBirth;
}
- /**
- * Returns an unmodifiable tag set, which throws {@code UnsupportedOperationException}
- * if modification is attempted.
- * Returns {@code Optional#empty()} if {@code tags} is null.
- */
- public Optional> getTags() {
- return (tags != null) ? Optional.of(Collections.unmodifiableSet(tags)) : Optional.empty();
+ public Optional getDateOfBirth() {
+ return Optional.ofNullable(dateOfBirth);
}
+ public void setSex(Sex sex) {
+ this.sex = sex;
+ }
+
+ public Optional getSex() {
+ return Optional.ofNullable(sex);
+ }
+
+ public void setAppointment(Appointment appointment) {
+ this.appointment = appointment;
+ }
+
+ public Optional getAppointment() {
+ return Optional.ofNullable(appointment);
+ }
@Override
public boolean equals(Object other) {
if (other == this) {
@@ -216,16 +259,18 @@ public boolean equals(Object other) {
}
// instanceof handles nulls
- if (!(other instanceof EditPersonDescriptor)) {
+ if (!(other instanceof EditPatientDescriptor)) {
return false;
}
- EditPersonDescriptor otherEditPersonDescriptor = (EditPersonDescriptor) other;
- return Objects.equals(name, otherEditPersonDescriptor.name)
- && Objects.equals(phone, otherEditPersonDescriptor.phone)
- && Objects.equals(email, otherEditPersonDescriptor.email)
- && Objects.equals(address, otherEditPersonDescriptor.address)
- && Objects.equals(tags, otherEditPersonDescriptor.tags);
+ EditPatientDescriptor otherEditPatientDescriptor = (EditPatientDescriptor) other;
+ return Objects.equals(name, otherEditPatientDescriptor.name)
+ && Objects.equals(phone, otherEditPatientDescriptor.phone)
+ && Objects.equals(email, otherEditPatientDescriptor.email)
+ && Objects.equals(address, otherEditPatientDescriptor.address)
+ && Objects.equals(dateOfBirth, otherEditPatientDescriptor.dateOfBirth)
+ && Objects.equals(sex, otherEditPatientDescriptor.sex)
+ && Objects.equals(appointment, otherEditPatientDescriptor.appointment);
}
@Override
@@ -235,7 +280,9 @@ public String toString() {
.add("phone", phone)
.add("email", email)
.add("address", address)
- .add("tags", tags)
+ .add("date of birth", dateOfBirth)
+ .add("sex", sex)
+ .add("appointment", appointment)
.toString();
}
}
diff --git a/src/main/java/seedu/address/logic/commands/EditVisitCommand.java b/src/main/java/seedu/address/logic/commands/EditVisitCommand.java
new file mode 100644
index 00000000000..006aea9b4d6
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/EditVisitCommand.java
@@ -0,0 +1,264 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_CONDITION;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE_OF_VISIT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_SEVERITY;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PATIENTS;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.commons.util.CollectionUtil;
+import seedu.address.commons.util.ToStringBuilder;
+import seedu.address.logic.Messages;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.patient.Condition;
+import seedu.address.model.patient.DateOfVisit;
+import seedu.address.model.patient.Name;
+import seedu.address.model.patient.Patient;
+import seedu.address.model.patient.Phone;
+import seedu.address.model.patient.Severity;
+import seedu.address.model.patient.Visit;
+
+/**
+ * Edits the latest visit from a Patient.
+ */
+public class EditVisitCommand extends Command {
+ public static final String COMMAND_WORD = "editv";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": edits the latest visit from the specified patient.\n"
+ + "Parameters: INDEX (must be a positive integer) "
+ + "[" + PREFIX_DATE_OF_VISIT + "DATE OF VISIT] "
+ + "[" + PREFIX_CONDITION + "CONDITION] "
+ + "[" + PREFIX_SEVERITY + "SEVERITY] \n"
+ + "OR "
+ + "[" + PREFIX_NAME + "NAME] "
+ + "[" + PREFIX_PHONE + "PHONE] "
+ + "[" + PREFIX_DATE_OF_VISIT + "DATE OF VISIT] "
+ + "[" + PREFIX_CONDITION + "CONDITION] "
+ + "[" + PREFIX_SEVERITY + "SEVERITY] \n"
+ + "Example: " + COMMAND_WORD + " 1 "
+ + PREFIX_DATE_OF_VISIT + "25/2/2024 "
+ + PREFIX_CONDITION + "High Fever "
+ + PREFIX_SEVERITY + "High";;
+
+ public static final String MESSAGE_SUCCESS = "Visit edited";
+ public static final String MESSAGE_PATIENT_NOT_FOUND = "Could not find specified patient";
+ public static final String MESSAGE_NOT_EDITED = "At least one field to edit must be provided.";
+ public static final String MESSAGE_NO_VISIT = "This patient does not have a visit to edit";
+ public static final String MESSAGE_DUPLICATE_VISIT = "Identical visit already exists for this patient";
+ private final EditVisitDescriptor editVisitDescriptor;
+ private final boolean useIndex;
+ private Index index;
+ private Name name;
+ private Phone phone;
+
+
+ /**
+ * Creates an edit visit command from {@code index}.
+ */
+ public EditVisitCommand(Index index, EditVisitDescriptor editVisitDescriptor) {
+ requireAllNonNull(index, editVisitDescriptor);
+
+ this.useIndex = true;
+ this.index = index;
+ this.editVisitDescriptor = editVisitDescriptor;
+ }
+
+ /**
+ * Creates an edit visit command from {@code name} and {@code phone}.
+ */
+ public EditVisitCommand(Name name, Phone phone, EditVisitDescriptor editVisitDescriptor) {
+ requireAllNonNull(name, phone, editVisitDescriptor);
+
+ this.useIndex = false;
+ this.name = name;
+ this.phone = phone;
+ this.editVisitDescriptor = editVisitDescriptor;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+
+ if (!hasPatient(model)) {
+ throw new CommandException(MESSAGE_PATIENT_NOT_FOUND);
+ }
+
+ Patient patient = getPatient(model);
+ if (patient.getVisits().isEmpty()) {
+ throw new CommandException(MESSAGE_NO_VISIT);
+ }
+
+ Visit visitToEdit = patient.getLatestVisit();
+ Visit editedVisit = createEditedVisit(visitToEdit, editVisitDescriptor);
+
+ if (!visitToEdit.equals(editedVisit) && patient.hasVisit(editedVisit)) {
+ throw new CommandException(MESSAGE_DUPLICATE_VISIT);
+ }
+
+ patient.setVisit(visitToEdit, editedVisit);
+ model.updateFilteredPatientList(PREDICATE_SHOW_ALL_PATIENTS);
+
+ // Bandaid solution to fix UI not detecting visit changes.
+ model.deletePatient(patient);
+ model.addPatient(patient);
+
+ return new CommandResult(MESSAGE_SUCCESS);
+ }
+
+ /**
+ * Creates and returns a {@code Visit} with the details of {@code visitToEdit}
+ * edited with {@code editVisitDescriptor}.
+ */
+ private static Visit createEditedVisit(Visit visitToEdit, EditVisitDescriptor editVisitDescriptor) {
+ assert visitToEdit != null;
+
+ Condition updatedCondition = editVisitDescriptor.getCondition().orElse(visitToEdit.getCondition());
+ Severity updatedSeverity = editVisitDescriptor.getSeverity().orElse(visitToEdit.getSeverity());
+ DateOfVisit updatedDateOfVisit = editVisitDescriptor.getDateOfVisit().orElse(visitToEdit.getDateOfVisit());
+
+ return new Visit(updatedCondition, updatedSeverity, updatedDateOfVisit);
+ }
+
+ private boolean hasPatient(Model model) {
+ if (useIndex) {
+ return true;
+ }
+ return model.hasPatient(name, phone);
+ }
+
+ private Patient getPatient(Model model) throws CommandException {
+ if (useIndex) {
+ return getPatientFromIndex(model);
+ } else {
+ return model.getPatient(name, phone);
+ }
+ }
+
+ private Patient getPatientFromIndex(Model model) throws CommandException {
+ List lastShownList = model.getFilteredPatientList();
+
+ if (index.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_PATIENT_DISPLAYED_INDEX);
+ }
+
+ return lastShownList.get(index.getZeroBased());
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof EditVisitCommand)) {
+ return false;
+ }
+
+ EditVisitCommand otherEditVisitCommand = (EditVisitCommand) other;
+ return useIndex == otherEditVisitCommand.useIndex
+ && editVisitDescriptor.equals(otherEditVisitCommand.editVisitDescriptor)
+ && index.equals(otherEditVisitCommand.index)
+ && name.equals(otherEditVisitCommand.name)
+ && phone.equals(otherEditVisitCommand.phone);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .add("editVisitDescriptor", editVisitDescriptor)
+ .add("useIndex", useIndex)
+ .add("index", index)
+ .add("name", name)
+ .add("phone", phone)
+ .toString();
+ }
+
+ /**
+ * Stores the details to edit the visit with. Each non-empty field value will replace the
+ * corresponding field value of the visit.
+ */
+ public static class EditVisitDescriptor {
+ private Condition condition;
+ private Severity severity;
+ private DateOfVisit dateOfVisit;
+
+ public EditVisitDescriptor() {};
+
+ /**
+ * Copy constructor.
+ */
+ public EditVisitDescriptor(EditVisitCommand.EditVisitDescriptor toCopy) {
+ setCondition(toCopy.condition);
+ setSeverity(toCopy.severity);
+ setDateOfVisit(toCopy.dateOfVisit);
+ }
+
+ /**
+ * Returns true if at least one field is edited.
+ */
+ public boolean isAnyFieldEdited() {
+ return CollectionUtil.isAnyNonNull(condition, severity, dateOfVisit);
+ }
+
+ public void setCondition(Condition condition) {
+ this.condition = condition;
+ }
+
+ public Optional getCondition() {
+ return Optional.ofNullable(condition);
+ }
+
+ public void setDateOfVisit(DateOfVisit dateOfVisit) {
+ this.dateOfVisit = dateOfVisit;
+ }
+
+ public Optional getDateOfVisit() {
+ return Optional.ofNullable(dateOfVisit);
+ }
+
+ public void setSeverity(Severity severity) {
+ this.severity = severity;
+ }
+
+ public Optional getSeverity() {
+ return Optional.ofNullable(severity);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof EditVisitCommand.EditVisitDescriptor)) {
+ return false;
+ }
+
+ EditVisitCommand.EditVisitDescriptor otherEditVisitDescriptor =
+ (EditVisitCommand.EditVisitDescriptor) other;
+ return Objects.equals(condition, otherEditVisitDescriptor.condition)
+ && Objects.equals(severity, otherEditVisitDescriptor.severity)
+ && Objects.equals(dateOfVisit, otherEditVisitDescriptor.dateOfVisit);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .add("condition", condition)
+ .add("severity", severity)
+ .add("dateOfVisit", dateOfVisit)
+ .toString();
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/ExitCommand.java b/src/main/java/seedu/address/logic/commands/ExitCommand.java
index 3dd85a8ba90..bee6f88d248 100644
--- a/src/main/java/seedu/address/logic/commands/ExitCommand.java
+++ b/src/main/java/seedu/address/logic/commands/ExitCommand.java
@@ -1,5 +1,7 @@
package seedu.address.logic.commands;
+import static java.util.Objects.requireNonNull;
+
import seedu.address.model.Model;
/**
@@ -9,11 +11,11 @@ public class ExitCommand extends Command {
public static final String COMMAND_WORD = "exit";
- public static final String MESSAGE_EXIT_ACKNOWLEDGEMENT = "Exiting Address Book as requested ...";
+ public static final String CONFIRMATION = "Would you like to exit the application? Enter 'yes' or 'no'.";
@Override
public CommandResult execute(Model model) {
- return new CommandResult(MESSAGE_EXIT_ACKNOWLEDGEMENT, false, true);
+ requireNonNull(model);
+ return new CommandResult(CONFIRMATION);
}
-
}
diff --git a/src/main/java/seedu/address/logic/commands/FindCommand.java b/src/main/java/seedu/address/logic/commands/FindCommand.java
index 72b9eddd3a7..9170a5839e9 100644
--- a/src/main/java/seedu/address/logic/commands/FindCommand.java
+++ b/src/main/java/seedu/address/logic/commands/FindCommand.java
@@ -1,37 +1,55 @@
package seedu.address.logic.commands;
import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
+
+import java.util.function.Predicate;
import seedu.address.commons.util.ToStringBuilder;
import seedu.address.logic.Messages;
import seedu.address.model.Model;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
+import seedu.address.model.patient.Patient;
+
/**
- * Finds and lists all persons in address book whose name contains any of the argument keywords.
- * Keyword matching is case insensitive.
+ * Finds and lists all patients whose name or phone number matches any of the argument inputs.
+ * Name matching is case insensitive.
*/
public class FindCommand extends Command {
public static final String COMMAND_WORD = "find";
- public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all persons whose names contain any of "
- + "the specified keywords (case-insensitive) and displays them as a list with index numbers.\n"
- + "Parameters: KEYWORD [MORE_KEYWORDS]...\n"
- + "Example: " + COMMAND_WORD + " alice bob charlie";
- private final NameContainsKeywordsPredicate predicate;
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all patients whose names or phone numbers "
+ + "matches any of the inputs (case-insensitive for names) and displays them as a list with index numbers.\n"
+ + "Parameters: "
+ + "[" + PREFIX_NAME + "KEYWORD] "
+ + "[" + PREFIX_PHONE + "PHONE] "
+ + "Example: " + COMMAND_WORD + " "
+ + PREFIX_NAME + "alice "
+ + PREFIX_PHONE + "91234567";
+
+
+ private final Predicate namePredicate;
+
+ private final Predicate phonePredicate;
- public FindCommand(NameContainsKeywordsPredicate predicate) {
- this.predicate = predicate;
+ /**
+ * @param namePredicate condition patient name must meet
+ * @param phonePredicate condition patient phone must meet
+ */
+ public FindCommand(Predicate namePredicate, Predicate phonePredicate) {
+ this.namePredicate = namePredicate;
+ this.phonePredicate = phonePredicate;
}
@Override
public CommandResult execute(Model model) {
requireNonNull(model);
- model.updateFilteredPersonList(predicate);
+ model.updateFilteredPatientList(namePredicate.and(phonePredicate));
return new CommandResult(
- String.format(Messages.MESSAGE_PERSONS_LISTED_OVERVIEW, model.getFilteredPersonList().size()));
+ String.format(Messages.MESSAGE_PATIENTS_LISTED_OVERVIEW, model.getFilteredPatientList().size()));
}
@Override
@@ -46,13 +64,15 @@ public boolean equals(Object other) {
}
FindCommand otherFindCommand = (FindCommand) other;
- return predicate.equals(otherFindCommand.predicate);
+ return namePredicate.equals(otherFindCommand.namePredicate)
+ && phonePredicate.equals(otherFindCommand.phonePredicate);
}
@Override
public String toString() {
return new ToStringBuilder(this)
- .add("predicate", predicate)
+ .add("namePredicate", namePredicate)
+ .add("phonePredicate", phonePredicate)
.toString();
}
}
diff --git a/src/main/java/seedu/address/logic/commands/ForceDeleteAllCommand.java b/src/main/java/seedu/address/logic/commands/ForceDeleteAllCommand.java
new file mode 100644
index 00000000000..7371c02a223
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/ForceDeleteAllCommand.java
@@ -0,0 +1,28 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import seedu.address.model.Model;
+import seedu.address.model.PatientList;
+
+/**
+ * Deletes all patients in the patient list forcefully.
+ */
+public class ForceDeleteAllCommand extends Command {
+ public static final String COMMAND_WORD = "delete-all-f";
+ public static final String MESSAGE_SUCCESS = "Successfully deleted all data";
+
+ /**
+ * Executes the command and returns the result message.
+ *
+ * @param model {@code Model} which the command should operate on.
+ * @return feedback message of the operation result for display
+ */
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+
+ model.setPatientList(new PatientList());
+ return new CommandResult(MESSAGE_SUCCESS);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/ForceExitCommand.java b/src/main/java/seedu/address/logic/commands/ForceExitCommand.java
new file mode 100644
index 00000000000..f2c8dafcc4a
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/ForceExitCommand.java
@@ -0,0 +1,17 @@
+package seedu.address.logic.commands;
+
+import seedu.address.model.Model;
+
+/**
+ * Forcefully terminates the program without confirmation check.
+ */
+public class ForceExitCommand extends Command {
+ public static final String COMMAND_WORD = "exit-f";
+
+ public static final String MESSAGE_EXIT_ACKNOWLEDGEMENT = "Exiting MediTrack as requested!";
+
+ @Override
+ public CommandResult execute(Model model) {
+ return new CommandResult(MESSAGE_EXIT_ACKNOWLEDGEMENT, false, true);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/HelpCommand.java b/src/main/java/seedu/address/logic/commands/HelpCommand.java
index bf824f91bd0..e08086c3ce0 100644
--- a/src/main/java/seedu/address/logic/commands/HelpCommand.java
+++ b/src/main/java/seedu/address/logic/commands/HelpCommand.java
@@ -9,13 +9,14 @@ public class HelpCommand extends Command {
public static final String COMMAND_WORD = "help";
- public static final String MESSAGE_USAGE = COMMAND_WORD + ": Shows program usage instructions.\n"
+ public static final String MESSAGE_USAGE = COMMAND_WORD + ": Shows the link to the user guide.\n"
+ "Example: " + COMMAND_WORD;
- public static final String SHOWING_HELP_MESSAGE = "Opened help window.";
+ public static final String RESULT_MESSAGE = "Successfully opened help window. "
+ + "\nAccess the user guide to see all the usable commands.";
@Override
public CommandResult execute(Model model) {
- return new CommandResult(SHOWING_HELP_MESSAGE, true, false);
+ return new CommandResult(RESULT_MESSAGE, true, false);
}
}
diff --git a/src/main/java/seedu/address/logic/commands/ListAlphabeticalCommand.java b/src/main/java/seedu/address/logic/commands/ListAlphabeticalCommand.java
new file mode 100644
index 00000000000..e97c10fd817
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/ListAlphabeticalCommand.java
@@ -0,0 +1,41 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PATIENTS;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+
+import seedu.address.model.Model;
+import seedu.address.model.patient.Patient;
+
+/**
+ * Lists all patients in the patient list alphabetically to the user.
+ */
+public class ListAlphabeticalCommand extends Command {
+
+ public static final String COMMAND_WORD = "list-a";
+
+ public static final String MESSAGE_SUCCESS = "Listed all patients in alphabetical order";
+
+
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ model.updateFilteredPatientList(PREDICATE_SHOW_ALL_PATIENTS);
+ List sortedList = new ArrayList();
+ sortedList.addAll(model.getFilteredPatientList());
+ Comparator comparator = (patient1, patient2) -> {
+ return patient1.getName().fullName.compareTo(patient2.getName().fullName);
+ };
+ sortedList.sort(comparator);
+ for (Patient patient : sortedList) {
+ model.deletePatient(patient);
+ }
+ for (Patient patient : sortedList) {
+ model.addPatient(patient);
+ }
+ return new CommandResult(MESSAGE_SUCCESS);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/ListByApptDateCommand.java b/src/main/java/seedu/address/logic/commands/ListByApptDateCommand.java
new file mode 100755
index 00000000000..5fd1845a97e
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/ListByApptDateCommand.java
@@ -0,0 +1,53 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PATIENTS;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.PatientList;
+import seedu.address.model.patient.Patient;
+
+/**
+ * Lists patient by appointment dates
+ */
+public class ListByApptDateCommand extends Command {
+
+ public static final String COMMAND_WORD = "list-by-date";
+
+ public static final String MESSAGE_SUCCESS = "Listed all patients by ascending appointment date";
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ model.updateFilteredPatientList(PREDICATE_SHOW_ALL_PATIENTS);
+ List sortedList = new ArrayList();
+ sortedList.addAll(model.getFilteredPatientList());
+ Comparator comparator = (patient1, patient2) -> {
+ if (null != patient1.getAppointment().appointment && null != patient2.getAppointment().appointment) {
+ return patient1.getAppointment().appointment.compareTo((patient2.getAppointment().appointment));
+ } else if (null != patient1.getAppointment().appointment && null == patient2.getAppointment().appointment) {
+ return 1;
+ } else if (null == patient1.getAppointment().appointment && null != patient2.getAppointment().appointment) {
+ return -1;
+ } else if (null == patient1.getAppointment().appointment && null == patient2.getAppointment().appointment) {
+ return 0;
+ }
+ return 0;
+ };
+ sortedList.sort(comparator);
+
+ for (Patient patient : sortedList) {
+ model.setPatientList(new PatientList());
+ //model.deletePatient(patient);
+ }
+ for (Patient patient : sortedList) {
+ model.addPatient(patient);
+ }
+ return new CommandResult(MESSAGE_SUCCESS);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/ListByDateCriteriaCommand.java b/src/main/java/seedu/address/logic/commands/ListByDateCriteriaCommand.java
new file mode 100755
index 00000000000..51c23aaaaf5
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/ListByDateCriteriaCommand.java
@@ -0,0 +1,46 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_APPOINTMENT;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PATIENTS;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.patient.ApptDateMatchesPredicate;
+import seedu.address.model.patient.Patient;
+
+/**
+ * Lists patient by appointment dates on or before given date
+ */
+public class ListByDateCriteriaCommand extends Command {
+
+ public static final String COMMAND_WORD = "list-until-date";
+
+ public static final String MESSAGE_SUCCESS = "Listed all patients with appointment date on or before date";
+
+ public static final String MESSAGE_USAGE = COMMAND_WORD
+ + ": Finds all patients with appointment date on or before date "
+ + "Parameters: "
+ + "[" + PREFIX_APPOINTMENT + "DATEOFAPPOINTMENT] "
+ + "Example: " + COMMAND_WORD + " "
+ + PREFIX_APPOINTMENT + "25/2/2024";
+
+ private final ApptDateMatchesPredicate apptDatePredicate;
+
+ public ListByDateCriteriaCommand(ApptDateMatchesPredicate apptDatePredicate) {
+ this.apptDatePredicate = apptDatePredicate;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ model.updateFilteredPatientList(PREDICATE_SHOW_ALL_PATIENTS);
+ List sortedList = new ArrayList();
+ model.updateFilteredPatientList(apptDatePredicate);
+
+ return new CommandResult(MESSAGE_SUCCESS);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/ListCommand.java b/src/main/java/seedu/address/logic/commands/ListCommand.java
index 84be6ad2596..5f0e91a2c4f 100644
--- a/src/main/java/seedu/address/logic/commands/ListCommand.java
+++ b/src/main/java/seedu/address/logic/commands/ListCommand.java
@@ -1,24 +1,24 @@
package seedu.address.logic.commands;
import static java.util.Objects.requireNonNull;
-import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PATIENTS;
import seedu.address.model.Model;
/**
- * Lists all persons in the address book to the user.
+ * Lists all patients in the patient list arbitrarily to the user.
*/
public class ListCommand extends Command {
public static final String COMMAND_WORD = "list";
- public static final String MESSAGE_SUCCESS = "Listed all persons";
+ public static final String MESSAGE_SUCCESS = "Listed all patients";
@Override
public CommandResult execute(Model model) {
requireNonNull(model);
- model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
+ model.updateFilteredPatientList(PREDICATE_SHOW_ALL_PATIENTS);
return new CommandResult(MESSAGE_SUCCESS);
}
}
diff --git a/src/main/java/seedu/address/logic/commands/NoCommand.java b/src/main/java/seedu/address/logic/commands/NoCommand.java
new file mode 100644
index 00000000000..635ff9ecc5a
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/NoCommand.java
@@ -0,0 +1,24 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import seedu.address.model.Model;
+
+/**
+ * No command, do nothing.
+ */
+public class NoCommand extends Command {
+ public static final String COMMAND_WORD = "no";
+
+ /**
+ * Executes the command and returns the result message.
+ *
+ * @param model {@code Model} which the command should operate on.
+ * @return feedback message of the operation result for display
+ */
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+ return new CommandResult("");
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/YesCommand.java b/src/main/java/seedu/address/logic/commands/YesCommand.java
new file mode 100644
index 00000000000..2dbb1b231dd
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/YesCommand.java
@@ -0,0 +1,49 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+
+import seedu.address.model.Model;
+import seedu.address.model.PatientList;
+
+/**
+ * Yes command for 'delete-all' command, force delete all entries.
+ */
+public class YesCommand extends Command {
+ public static final String COMMAND_WORD = "yes";
+ public static final String DELETE_MESSAGE_SUCCESS = "Successfully deleted all data";
+ public static final String EXIT_MESSAGE_SUCCESS = "Successfully exited the application";
+
+
+ private String previousCommand;
+
+ /**
+ * Constructor for YesCommand.
+ *
+ * @param previousCommand The previous command that was executed.
+ */
+ public YesCommand(String previousCommand) {
+ super();
+ this.previousCommand = previousCommand;
+ }
+
+ /**
+ * Executes the command and returns the result message.
+ *
+ * @param model {@code Model} which the command should operate on.
+ * @return feedback message of the operation result for display
+ */
+ @Override
+ public CommandResult execute(Model model) {
+ requireNonNull(model);
+
+ if (this.previousCommand.equals("delete-all")) {
+ model.setPatientList(new PatientList());
+
+ return new CommandResult(DELETE_MESSAGE_SUCCESS);
+ } else if (this.previousCommand.equals("exit")) {
+ return new CommandResult(EXIT_MESSAGE_SUCCESS, false, true);
+ } else {
+ return new CommandResult("");
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/exceptions/CommandException.java b/src/main/java/seedu/address/logic/commands/exceptions/CommandException.java
index a16bd14f2cd..f44c0c19186 100644
--- a/src/main/java/seedu/address/logic/commands/exceptions/CommandException.java
+++ b/src/main/java/seedu/address/logic/commands/exceptions/CommandException.java
@@ -1,5 +1,7 @@
package seedu.address.logic.commands.exceptions;
+import seedu.address.logic.commands.Command;
+
/**
* Represents an error which occurs during execution of a {@link Command}.
*/
diff --git a/src/main/java/seedu/address/logic/parser/AddCommandParser.java b/src/main/java/seedu/address/logic/parser/AddCommandParser.java
index 4ff1a97ed77..b5318e7dc16 100644
--- a/src/main/java/seedu/address/logic/parser/AddCommandParser.java
+++ b/src/main/java/seedu/address/logic/parser/AddCommandParser.java
@@ -2,22 +2,24 @@
import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATEOFBIRTH;
import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_SEX;
-import java.util.Set;
import java.util.stream.Stream;
import seedu.address.logic.commands.AddCommand;
import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
+import seedu.address.model.patient.Address;
+import seedu.address.model.patient.Appointment;
+import seedu.address.model.patient.DateOfBirth;
+import seedu.address.model.patient.Email;
+import seedu.address.model.patient.Name;
+import seedu.address.model.patient.Patient;
+import seedu.address.model.patient.Phone;
+import seedu.address.model.patient.Sex;
/**
* Parses input arguments and creates a new AddCommand object
@@ -31,23 +33,27 @@ public class AddCommandParser implements Parser {
*/
public AddCommand parse(String args) throws ParseException {
ArgumentMultimap argMultimap =
- ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_TAG);
+ ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS,
+ PREFIX_DATEOFBIRTH, PREFIX_SEX);
- if (!arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_ADDRESS, PREFIX_PHONE, PREFIX_EMAIL)
+ if (!arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_ADDRESS, PREFIX_PHONE, PREFIX_EMAIL,
+ PREFIX_DATEOFBIRTH, PREFIX_SEX)
|| !argMultimap.getPreamble().isEmpty()) {
throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE));
}
- argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS);
+ argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS,
+ PREFIX_DATEOFBIRTH, PREFIX_SEX);
Name name = ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get());
Phone phone = ParserUtil.parsePhone(argMultimap.getValue(PREFIX_PHONE).get());
Email email = ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get());
Address address = ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get());
- Set tagList = ParserUtil.parseTags(argMultimap.getAllValues(PREFIX_TAG));
+ DateOfBirth dateOfBirth = ParserUtil.parseDateOfBirth(argMultimap.getValue(PREFIX_DATEOFBIRTH).get());
+ Sex sex = ParserUtil.parseSex(argMultimap.getValue(PREFIX_SEX).get());
- Person person = new Person(name, phone, email, address, tagList);
+ Patient patient = new Patient(name, phone, email, address, dateOfBirth, sex, new Appointment(""));
- return new AddCommand(person);
+ return new AddCommand(patient);
}
/**
diff --git a/src/main/java/seedu/address/logic/parser/AddVisitCommandParser.java b/src/main/java/seedu/address/logic/parser/AddVisitCommandParser.java
new file mode 100644
index 00000000000..1e4fbb9b3d7
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/AddVisitCommandParser.java
@@ -0,0 +1,88 @@
+package seedu.address.logic.parser;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_CONDITION;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE_OF_VISIT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_SEVERITY;
+
+import java.util.stream.Stream;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.AddVisitCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.patient.Condition;
+import seedu.address.model.patient.DateOfVisit;
+import seedu.address.model.patient.Name;
+import seedu.address.model.patient.Phone;
+import seedu.address.model.patient.Severity;
+import seedu.address.model.patient.Visit;
+
+/**
+ * Parses input arguments and creates a new AddVisitCommand object
+ */
+public class AddVisitCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the AddVisitCommand
+ * and returns an AddVisitCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public AddVisitCommand parse(String args) throws ParseException {
+ requireNonNull(args);
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_DATE_OF_VISIT, PREFIX_CONDITION,
+ PREFIX_SEVERITY);
+
+ argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_NAME, PREFIX_PHONE, PREFIX_DATE_OF_VISIT, PREFIX_CONDITION,
+ PREFIX_SEVERITY);
+
+ if (!arePrefixesPresent(argMultimap, PREFIX_DATE_OF_VISIT, PREFIX_CONDITION, PREFIX_SEVERITY)) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddVisitCommand.MESSAGE_USAGE));
+ }
+
+ DateOfVisit dateOfVisit = ParserUtil.parseDateOfVisit(argMultimap.getValue(PREFIX_DATE_OF_VISIT).get());
+ Severity severity = ParserUtil.parseSeverity(argMultimap.getValue(PREFIX_SEVERITY).get());
+ Condition condition = ParserUtil.parseCondition(argMultimap.getValue(PREFIX_CONDITION).get());
+
+ Visit visit = new Visit(condition, severity, dateOfVisit);
+
+ if (!arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_PHONE) && !argMultimap.getPreamble().isEmpty()) {
+ return commandFromIndex(argMultimap.getPreamble(), visit);
+ } else if (argMultimap.getPreamble().isEmpty() && arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_PHONE)) {
+ return commandFromPrefixes(argMultimap.getValue(PREFIX_NAME).get(),
+ argMultimap.getValue(PREFIX_PHONE).get(), visit);
+ } else {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddVisitCommand.MESSAGE_USAGE));
+ }
+ }
+
+ /**
+ * Returns true if none of the prefixes contains empty {@code Optional} values in the given
+ * {@code ArgumentMultimap}.
+ */
+ private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) {
+ return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent());
+ }
+
+ private AddVisitCommand commandFromIndex(String arg, Visit visit) throws ParseException {
+ Index index;
+
+ try {
+ index = ParserUtil.parseIndex(arg);
+ } catch (ParseException pe) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddVisitCommand.MESSAGE_USAGE), pe);
+ }
+
+ return new AddVisitCommand(index, visit);
+ }
+
+ private AddVisitCommand commandFromPrefixes(String nameArg, String phoneArg, Visit visit) throws ParseException {
+ Name name = ParserUtil.parseName(nameArg);
+ Phone phone = ParserUtil.parsePhone(phoneArg);
+
+ return new AddVisitCommand(name, phone, visit);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/AddressBookParser.java b/src/main/java/seedu/address/logic/parser/AddressBookParser.java
deleted file mode 100644
index 3149ee07e0b..00000000000
--- a/src/main/java/seedu/address/logic/parser/AddressBookParser.java
+++ /dev/null
@@ -1,86 +0,0 @@
-package seedu.address.logic.parser;
-
-import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-import static seedu.address.logic.Messages.MESSAGE_UNKNOWN_COMMAND;
-
-import java.util.logging.Logger;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import seedu.address.commons.core.LogsCenter;
-import seedu.address.logic.commands.AddCommand;
-import seedu.address.logic.commands.ClearCommand;
-import seedu.address.logic.commands.Command;
-import seedu.address.logic.commands.DeleteCommand;
-import seedu.address.logic.commands.EditCommand;
-import seedu.address.logic.commands.ExitCommand;
-import seedu.address.logic.commands.FindCommand;
-import seedu.address.logic.commands.HelpCommand;
-import seedu.address.logic.commands.ListCommand;
-import seedu.address.logic.parser.exceptions.ParseException;
-
-/**
- * Parses user input.
- */
-public class AddressBookParser {
-
- /**
- * Used for initial separation of command word and args.
- */
- private static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?\\S+)(?.*)");
- private static final Logger logger = LogsCenter.getLogger(AddressBookParser.class);
-
- /**
- * Parses user input into command for execution.
- *
- * @param userInput full user input string
- * @return the command based on the user input
- * @throws ParseException if the user input does not conform the expected format
- */
- public Command parseCommand(String userInput) throws ParseException {
- final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput.trim());
- if (!matcher.matches()) {
- throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE));
- }
-
- final String commandWord = matcher.group("commandWord");
- final String arguments = matcher.group("arguments");
-
- // Note to developers: Change the log level in config.json to enable lower level (i.e., FINE, FINER and lower)
- // log messages such as the one below.
- // Lower level log messages are used sparingly to minimize noise in the code.
- logger.fine("Command word: " + commandWord + "; Arguments: " + arguments);
-
- switch (commandWord) {
-
- case AddCommand.COMMAND_WORD:
- return new AddCommandParser().parse(arguments);
-
- case EditCommand.COMMAND_WORD:
- return new EditCommandParser().parse(arguments);
-
- case DeleteCommand.COMMAND_WORD:
- return new DeleteCommandParser().parse(arguments);
-
- case ClearCommand.COMMAND_WORD:
- return new ClearCommand();
-
- case FindCommand.COMMAND_WORD:
- return new FindCommandParser().parse(arguments);
-
- case ListCommand.COMMAND_WORD:
- return new ListCommand();
-
- case ExitCommand.COMMAND_WORD:
- return new ExitCommand();
-
- case HelpCommand.COMMAND_WORD:
- return new HelpCommand();
-
- default:
- logger.finer("This user input caused a ParseException: " + userInput);
- throw new ParseException(MESSAGE_UNKNOWN_COMMAND);
- }
- }
-
-}
diff --git a/src/main/java/seedu/address/logic/parser/ArgumentMultimap.java b/src/main/java/seedu/address/logic/parser/ArgumentMultimap.java
index 21e26887a83..be60c391498 100644
--- a/src/main/java/seedu/address/logic/parser/ArgumentMultimap.java
+++ b/src/main/java/seedu/address/logic/parser/ArgumentMultimap.java
@@ -35,6 +35,13 @@ public void put(Prefix prefix, String argValue) {
argMultimap.put(prefix, argValues);
}
+ /**
+ * Returns true if {@code flag} exists.
+ */
+ public boolean hasFlag(Flag flag) {
+ return argMultimap.containsKey(flag);
+ }
+
/**
* Returns the last value of {@code prefix}.
*/
diff --git a/src/main/java/seedu/address/logic/parser/ArgumentTokenizer.java b/src/main/java/seedu/address/logic/parser/ArgumentTokenizer.java
index 5c9aebfa488..aceec2a8648 100644
--- a/src/main/java/seedu/address/logic/parser/ArgumentTokenizer.java
+++ b/src/main/java/seedu/address/logic/parser/ArgumentTokenizer.java
@@ -47,6 +47,16 @@ private static List findAllPrefixPositions(String argsString, Pr
private static List findPrefixPositions(String argsString, Prefix prefix) {
List positions = new ArrayList<>();
+ // Handle case for Flag
+ if (prefix instanceof Flag) {
+ Flag flag = (Flag) prefix;
+ int flagPosition = findFlagPosition(argsString, flag.toString());
+ PrefixPosition extendedFlag = new PrefixPosition(flag, flagPosition);
+ positions.add(extendedFlag);
+ return positions;
+ }
+
+
int prefixPosition = findPrefixPosition(argsString, prefix.getPrefix(), 0);
while (prefixPosition != -1) {
PrefixPosition extendedPrefix = new PrefixPosition(prefix, prefixPosition);
@@ -75,6 +85,15 @@ private static int findPrefixPosition(String argsString, String prefix, int from
: prefixIndex + 1; // +1 as offset for whitespace
}
+ /**
+ * Returns the index of the first occurrence of {@code Flag} in
+ * {@code argsString} starting from index {@code fromIndex}. Returns -1 if no
+ * such occurrence can be found.
+ */
+ private static int findFlagPosition(String argString, String flag) {
+ return argString.indexOf(flag);
+ }
+
/**
* Extracts prefixes and their argument values, and returns an {@code ArgumentMultimap} object that maps the
* extracted prefixes to their respective arguments. Prefixes are extracted based on their zero-based positions in
@@ -112,12 +131,17 @@ private static ArgumentMultimap extractArguments(String argsString, List 1;
+ return isInputFromat1 ? INPUTFORMAT1 : INPUTFORMAT2;
+ }
+
+ /**
+ * Converts the date into String output format.
+ *
+ * @return String date in output format.
+ */
+ public static String outputDateTime(LocalDate date) {
+ return date.format(OUTPUTFORMAT);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java b/src/main/java/seedu/address/logic/parser/DeleteByIndexCommandParser.java
similarity index 71%
rename from src/main/java/seedu/address/logic/parser/DeleteCommandParser.java
rename to src/main/java/seedu/address/logic/parser/DeleteByIndexCommandParser.java
index 3527fe76a3e..a95a466f760 100644
--- a/src/main/java/seedu/address/logic/parser/DeleteCommandParser.java
+++ b/src/main/java/seedu/address/logic/parser/DeleteByIndexCommandParser.java
@@ -3,27 +3,26 @@
import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import seedu.address.commons.core.index.Index;
-import seedu.address.logic.commands.DeleteCommand;
+import seedu.address.logic.commands.DeleteByIndexCommand;
import seedu.address.logic.parser.exceptions.ParseException;
/**
* Parses input arguments and creates a new DeleteCommand object
*/
-public class DeleteCommandParser implements Parser {
+public class DeleteByIndexCommandParser implements Parser {
/**
* Parses the given {@code String} of arguments in the context of the DeleteCommand
* and returns a DeleteCommand object for execution.
* @throws ParseException if the user input does not conform the expected format
*/
- public DeleteCommand parse(String args) throws ParseException {
+ public DeleteByIndexCommand parse(String args) throws ParseException {
try {
Index index = ParserUtil.parseIndex(args);
- return new DeleteCommand(index);
+ return new DeleteByIndexCommand(index);
} catch (ParseException pe) {
throw new ParseException(
- String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE), pe);
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteByIndexCommand.MESSAGE_USAGE), pe);
}
}
-
}
diff --git a/src/main/java/seedu/address/logic/parser/DeleteByNamePhoneNumberCommandParser.java b/src/main/java/seedu/address/logic/parser/DeleteByNamePhoneNumberCommandParser.java
new file mode 100644
index 00000000000..6cba61fa785
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/DeleteByNamePhoneNumberCommandParser.java
@@ -0,0 +1,58 @@
+package seedu.address.logic.parser;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
+
+import java.util.stream.Stream;
+
+import seedu.address.logic.commands.DeleteByNamePhoneNumberCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.patient.Name;
+import seedu.address.model.patient.Phone;
+
+/**
+ * Parses input arguments and creates a new DeleteByNamePhoneNumberCommand object.
+ */
+public class DeleteByNamePhoneNumberCommandParser implements Parser {
+ /**
+ * Parses the given argument String into a DeleteByNamePhoneNumberCommand.
+ *
+ * @param args String of arguments.
+ * @return DeleteByNamePhoneNumberCommand object.
+ * @throws ParseException Exception thrown if the user input does not conform the expected format.
+ */
+ public DeleteByNamePhoneNumberCommand parse(String args) throws ParseException {
+ requireNonNull(args);
+ ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE);
+ argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_NAME, PREFIX_PHONE);
+
+ if (!arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_PHONE) || !argMultimap.getPreamble().isEmpty()) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ DeleteByNamePhoneNumberCommand.MESSAGE_USAGE));
+ } else if (argMultimap.getPreamble().isEmpty() && arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_PHONE)) {
+ String nameArg = argMultimap.getValue(PREFIX_NAME).get();
+ String phoneArg = argMultimap.getValue(PREFIX_PHONE).get();
+
+ Name name = ParserUtil.parseName(nameArg);
+ Phone phone = ParserUtil.parsePhone(phoneArg);
+
+ return new DeleteByNamePhoneNumberCommand(name, phone);
+ } else {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteByNamePhoneNumberCommand.MESSAGE_USAGE));
+ }
+ }
+
+ /**
+ * Returns true if none of the prefixes contains empty {@code Optional} values in the given.
+ *
+ * @param argumentMultimap ArgumentMultimap object.
+ * @param prefixes Prefix objects.
+ * @return True if none of the prefixes contains empty {@code Optional} values in the given.
+ */
+ private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) {
+ return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent());
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/DeleteVisitCommandParser.java b/src/main/java/seedu/address/logic/parser/DeleteVisitCommandParser.java
new file mode 100644
index 00000000000..b30039f27e7
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/DeleteVisitCommandParser.java
@@ -0,0 +1,69 @@
+package seedu.address.logic.parser;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
+
+import java.util.stream.Stream;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.DeleteVisitCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.patient.Name;
+import seedu.address.model.patient.Phone;
+
+/**
+ * Parses input arguments and creates a new DeleteVisitCommand object
+ */
+public class DeleteVisitCommandParser implements Parser {
+ /**
+ * Parses the given {@code String} of arguments in the context of the DeleteVisitCommand
+ * and returns a DeleteVisitCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public DeleteVisitCommand parse(String args) throws ParseException {
+ requireNonNull(args);
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE);
+
+ argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_NAME, PREFIX_PHONE);
+
+ if (!arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_PHONE) && !argMultimap.getPreamble().isEmpty()) {
+ return commandFromIndex(argMultimap.getPreamble());
+ } else if (argMultimap.getPreamble().isEmpty() && arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_PHONE)) {
+ return commandFromPrefixes(argMultimap.getValue(PREFIX_NAME).get(),
+ argMultimap.getValue(PREFIX_PHONE).get());
+ } else {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteVisitCommand.MESSAGE_USAGE));
+ }
+ }
+
+ /**
+ * Returns true if none of the prefixes contains empty {@code Optional} values in the given
+ * {@code ArgumentMultimap}.
+ */
+ private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) {
+ return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent());
+ }
+
+ private DeleteVisitCommand commandFromIndex(String arg) throws ParseException {
+ Index index;
+
+ try {
+ index = ParserUtil.parseIndex(arg);
+ } catch (ParseException pe) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ DeleteVisitCommand.MESSAGE_USAGE), pe);
+ }
+
+ return new DeleteVisitCommand(index);
+ }
+
+ private DeleteVisitCommand commandFromPrefixes(String nameArg, String phoneArg) throws ParseException {
+ Name name = ParserUtil.parseName(nameArg);
+ Phone phone = ParserUtil.parsePhone(phoneArg);
+
+ return new DeleteVisitCommand(name, phone);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/EditCommandParser.java b/src/main/java/seedu/address/logic/parser/EditCommandParser.java
index 46b3309a78b..c605796dc5c 100644
--- a/src/main/java/seedu/address/logic/parser/EditCommandParser.java
+++ b/src/main/java/seedu/address/logic/parser/EditCommandParser.java
@@ -3,21 +3,21 @@
import static java.util.Objects.requireNonNull;
import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_APPOINTMENT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATEOFBIRTH;
import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_SEX;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Optional;
-import java.util.Set;
+import java.util.stream.Stream;
import seedu.address.commons.core.index.Index;
import seedu.address.logic.commands.EditCommand;
-import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
+import seedu.address.logic.commands.EditCommand.EditPatientDescriptor;
import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.tag.Tag;
+import seedu.address.model.patient.Name;
+import seedu.address.model.patient.Phone;
/**
* Parses input arguments and creates a new EditCommand object
@@ -31,8 +31,58 @@ public class EditCommandParser implements Parser {
*/
public EditCommand parse(String args) throws ParseException {
requireNonNull(args);
+
+ String[] splitMessages = args.trim().split(" ");
+ Boolean hasNamePrefix = false;
+ if (splitMessages[0].length() >= 2) {
+ hasNamePrefix = splitMessages[0].substring(0, 2).equals("n/");
+ }
+
+ if (hasNamePrefix) {
+ return parseStringWithNameAndPhone(splitMessages);
+ } else {
+ return parseStringWithIndex(args);
+ }
+ }
+
+ private EditCommand parseStringWithNameAndPhone(String[] splitMessages) throws ParseException {
+ String namePrefix = splitMessages[0].substring(2) + " ";
+ String phonePrefix = "";
+ String rest = " ";
+ Boolean isNameFilled = false;
+ Boolean isPhoneFilled = false;
+
+ for (int i = 1; i < splitMessages.length; i++) {
+ if (!isNameFilled && splitMessages[i].substring(0, 2).equals("p/") && !isPhoneFilled) {
+ isNameFilled = true;
+ phonePrefix = splitMessages[i].substring(2);
+ isPhoneFilled = true;
+ } else if (!isNameFilled && !splitMessages[i].substring(0, 2).equals("p/")) {
+ namePrefix += splitMessages[i] + " ";
+ } else {
+ rest += splitMessages[i] + " ";
+ }
+ }
+
ArgumentMultimap argMultimap =
- ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_TAG);
+ ArgumentTokenizer.tokenize(rest, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS,
+ PREFIX_DATEOFBIRTH, PREFIX_SEX, PREFIX_APPOINTMENT);
+
+ argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS,
+ PREFIX_DATEOFBIRTH, PREFIX_SEX, PREFIX_APPOINTMENT);
+
+ EditPatientDescriptor editPatientDescriptor = new EditPatientDescriptor();
+
+ setEditPatientDescriptor(editPatientDescriptor, argMultimap);
+
+ return new EditCommand(new Name(namePrefix.trim()), new Phone(phonePrefix.trim()), editPatientDescriptor);
+
+ }
+
+ private EditCommand parseStringWithIndex(String args) throws ParseException {
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS,
+ PREFIX_DATEOFBIRTH, PREFIX_SEX, PREFIX_APPOINTMENT);
Index index;
@@ -42,44 +92,52 @@ public EditCommand parse(String args) throws ParseException {
throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE), pe);
}
- argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS);
+ argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS,
+ PREFIX_DATEOFBIRTH, PREFIX_SEX, PREFIX_APPOINTMENT);
+
+ EditPatientDescriptor editPatientDescriptor = new EditPatientDescriptor();
- EditPersonDescriptor editPersonDescriptor = new EditPersonDescriptor();
+ setEditPatientDescriptor(editPatientDescriptor, argMultimap);
+ return new EditCommand(index, editPatientDescriptor);
+ }
+
+ private static void setEditPatientDescriptor(EditPatientDescriptor editPatientDescriptor,
+ ArgumentMultimap argMultimap) throws ParseException {
if (argMultimap.getValue(PREFIX_NAME).isPresent()) {
- editPersonDescriptor.setName(ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get()));
+ editPatientDescriptor.setName(ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get()));
}
if (argMultimap.getValue(PREFIX_PHONE).isPresent()) {
- editPersonDescriptor.setPhone(ParserUtil.parsePhone(argMultimap.getValue(PREFIX_PHONE).get()));
+ editPatientDescriptor.setPhone(ParserUtil.parsePhone(argMultimap.getValue(PREFIX_PHONE).get()));
}
if (argMultimap.getValue(PREFIX_EMAIL).isPresent()) {
- editPersonDescriptor.setEmail(ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get()));
+ editPatientDescriptor.setEmail(ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get()));
}
if (argMultimap.getValue(PREFIX_ADDRESS).isPresent()) {
- editPersonDescriptor.setAddress(ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get()));
+ editPatientDescriptor.setAddress(ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get()));
+ }
+ if (argMultimap.getValue(PREFIX_DATEOFBIRTH).isPresent()) {
+ editPatientDescriptor.setDateOfBirth(ParserUtil.parseDateOfBirth(argMultimap
+ .getValue(PREFIX_DATEOFBIRTH).get()));
+ }
+ if (argMultimap.getValue(PREFIX_SEX).isPresent()) {
+ editPatientDescriptor.setSex(ParserUtil.parseSex(argMultimap.getValue(PREFIX_SEX).get()));
+ }
+ if (argMultimap.getValue(PREFIX_APPOINTMENT).isPresent()) {
+ editPatientDescriptor.setAppointment(ParserUtil.parseAppointment(argMultimap
+ .getValue(PREFIX_APPOINTMENT).get()));
}
- parseTagsForEdit(argMultimap.getAllValues(PREFIX_TAG)).ifPresent(editPersonDescriptor::setTags);
- if (!editPersonDescriptor.isAnyFieldEdited()) {
+ if (!editPatientDescriptor.isAnyFieldEdited()) {
throw new ParseException(EditCommand.MESSAGE_NOT_EDITED);
}
-
- return new EditCommand(index, editPersonDescriptor);
}
/**
- * Parses {@code Collection tags} into a {@code Set} if {@code tags} is non-empty.
- * If {@code tags} contain only one element which is an empty string, it will be parsed into a
- * {@code Set} containing zero tags.
+ * Returns true if none of the prefixes contains empty {@code Optional} values in the given
+ * {@code ArgumentMultimap}.
*/
- private Optional> parseTagsForEdit(Collection tags) throws ParseException {
- assert tags != null;
-
- if (tags.isEmpty()) {
- return Optional.empty();
- }
- Collection tagSet = tags.size() == 1 && tags.contains("") ? Collections.emptySet() : tags;
- return Optional.of(ParserUtil.parseTags(tagSet));
+ private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) {
+ return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent());
}
-
}
diff --git a/src/main/java/seedu/address/logic/parser/EditVisitCommandParser.java b/src/main/java/seedu/address/logic/parser/EditVisitCommandParser.java
new file mode 100644
index 00000000000..4b14b9ea0de
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/EditVisitCommandParser.java
@@ -0,0 +1,93 @@
+package seedu.address.logic.parser;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_CONDITION;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATE_OF_VISIT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_SEVERITY;
+
+import java.util.stream.Stream;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.EditVisitCommand;
+import seedu.address.logic.commands.EditVisitCommand.EditVisitDescriptor;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.patient.Name;
+import seedu.address.model.patient.Phone;
+/**
+ * Parses input arguments and creates a new EditVisitCommand object
+ */
+public class EditVisitCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the EditVisitCommand
+ * and returns an EditVisitCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public EditVisitCommand parse(String args) throws ParseException {
+ requireNonNull(args);
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_DATE_OF_VISIT, PREFIX_CONDITION,
+ PREFIX_SEVERITY);
+
+ argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_NAME, PREFIX_PHONE, PREFIX_DATE_OF_VISIT, PREFIX_CONDITION,
+ PREFIX_SEVERITY);
+
+ EditVisitDescriptor editVisitDescriptor = new EditVisitDescriptor();
+
+ if (argMultimap.getValue(PREFIX_CONDITION).isPresent()) {
+ editVisitDescriptor.setCondition(ParserUtil.parseCondition(argMultimap.getValue(PREFIX_CONDITION).get()));
+ }
+ if (argMultimap.getValue(PREFIX_SEVERITY).isPresent()) {
+ editVisitDescriptor.setSeverity(ParserUtil.parseSeverity(argMultimap.getValue(PREFIX_SEVERITY).get()));
+ }
+ if (argMultimap.getValue(PREFIX_DATE_OF_VISIT).isPresent()) {
+ editVisitDescriptor.setDateOfVisit(
+ ParserUtil.parseDateOfVisit(argMultimap.getValue(PREFIX_DATE_OF_VISIT).get()));
+ }
+
+ if (!editVisitDescriptor.isAnyFieldEdited()) {
+ throw new ParseException(EditVisitCommand.MESSAGE_NOT_EDITED);
+ }
+
+ if (!arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_PHONE) && !argMultimap.getPreamble().isEmpty()) {
+ return commandFromIndex(argMultimap.getPreamble(), editVisitDescriptor);
+ } else if (argMultimap.getPreamble().isEmpty() && arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_PHONE)) {
+ return commandFromPrefixes(argMultimap.getValue(PREFIX_NAME).get(),
+ argMultimap.getValue(PREFIX_PHONE).get(), editVisitDescriptor);
+ } else {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditVisitCommand.MESSAGE_USAGE));
+ }
+ }
+
+ /**
+ * Returns true if none of the prefixes contains empty {@code Optional} values in the given
+ * {@code ArgumentMultimap}.
+ */
+ private static boolean arePrefixesPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) {
+ return Stream.of(prefixes).allMatch(prefix -> argumentMultimap.getValue(prefix).isPresent());
+ }
+
+ private EditVisitCommand commandFromIndex(String arg, EditVisitDescriptor editVisitDescriptor)
+ throws ParseException {
+ Index index;
+
+ try {
+ index = ParserUtil.parseIndex(arg);
+ } catch (ParseException pe) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditVisitCommand.MESSAGE_USAGE), pe);
+ }
+
+ return new EditVisitCommand(index, editVisitDescriptor);
+ }
+
+ private EditVisitCommand commandFromPrefixes(String nameArg, String phoneArg,
+ EditVisitDescriptor editVisitDescriptor) throws ParseException {
+ Name name = ParserUtil.parseName(nameArg);
+ Phone phone = ParserUtil.parsePhone(phoneArg);
+
+ return new EditVisitCommand(name, phone, editVisitDescriptor);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/FindCommandParser.java b/src/main/java/seedu/address/logic/parser/FindCommandParser.java
index 2867bde857b..d768ab8a25a 100644
--- a/src/main/java/seedu/address/logic/parser/FindCommandParser.java
+++ b/src/main/java/seedu/address/logic/parser/FindCommandParser.java
@@ -1,33 +1,74 @@
package seedu.address.logic.parser;
+import static java.util.Objects.requireNonNull;
import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PATIENTS;
import java.util.Arrays;
+import java.util.function.Predicate;
+import java.util.logging.Logger;
+import seedu.address.commons.core.LogsCenter;
import seedu.address.logic.commands.FindCommand;
import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
+import seedu.address.model.patient.NameContainsKeywordsPredicate;
+import seedu.address.model.patient.Patient;
+import seedu.address.model.patient.PhoneMatchesPredicate;
/**
* Parses input arguments and creates a new FindCommand object
*/
public class FindCommandParser implements Parser {
+ private final Logger logger = LogsCenter.getLogger(getClass());
+
/**
* Parses the given {@code String} of arguments in the context of the FindCommand
* and returns a FindCommand object for execution.
* @throws ParseException if the user input does not conform the expected format
*/
public FindCommand parse(String args) throws ParseException {
- String trimmedArgs = args.trim();
- if (trimmedArgs.isEmpty()) {
- throw new ParseException(
- String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE));
+ requireNonNull(args);
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE);
+
+ if (!argMultimap.getPreamble().equals("")) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE));
+ }
+
+ if (!argMultimap.getValue(PREFIX_NAME).isPresent() && !argMultimap.getValue(PREFIX_PHONE).isPresent()) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE));
+ }
+
+ argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_NAME, PREFIX_PHONE);
+
+ Predicate namePredicate;
+ Predicate phonePredicate;
+
+ if (argMultimap.getValue(PREFIX_NAME).isPresent()) {
+ String keyword = argMultimap.getValue(PREFIX_NAME).get().trim();
+ if (keyword.isEmpty()) {
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE));
+ }
+ String [] nameKeywords = keyword.split("\\s+");
+ namePredicate = new NameContainsKeywordsPredicate(Arrays.asList(nameKeywords));
+ } else {
+ namePredicate = PREDICATE_SHOW_ALL_PATIENTS;
+ }
+
+ if (argMultimap.getValue(PREFIX_PHONE).isPresent()) {
+ phonePredicate = new PhoneMatchesPredicate(ParserUtil.parsePhone(argMultimap.getValue(PREFIX_PHONE).get()));
+ } else {
+ phonePredicate = PREDICATE_SHOW_ALL_PATIENTS;
}
- String[] nameKeywords = trimmedArgs.split("\\s+");
+ logger.info("----------------[namePredicate][" + namePredicate + "]");
+ logger.info("----------------[phonePredicate][" + phonePredicate + "]");
- return new FindCommand(new NameContainsKeywordsPredicate(Arrays.asList(nameKeywords)));
+ return new FindCommand(namePredicate, phonePredicate);
}
}
diff --git a/src/main/java/seedu/address/logic/parser/Flag.java b/src/main/java/seedu/address/logic/parser/Flag.java
new file mode 100644
index 00000000000..ad9c9e0a14c
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/Flag.java
@@ -0,0 +1,11 @@
+package seedu.address.logic.parser;
+
+/**
+ * A flag that modifies the behaviour of a command, represented as a prefix with no arguments.
+ * E.g. '-a' in 'list -a'
+ */
+public class Flag extends Prefix {
+ public Flag(String flag) {
+ super(flag);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/InputParser.java b/src/main/java/seedu/address/logic/parser/InputParser.java
new file mode 100644
index 00000000000..8b964c8d030
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/InputParser.java
@@ -0,0 +1,166 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.Messages.MESSAGE_UNKNOWN_COMMAND;
+
+import java.util.logging.Logger;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import seedu.address.commons.core.LogsCenter;
+import seedu.address.logic.commands.AddCommand;
+import seedu.address.logic.commands.AddVisitCommand;
+import seedu.address.logic.commands.Command;
+import seedu.address.logic.commands.DeleteAllCommand;
+import seedu.address.logic.commands.DeleteByIndexCommand;
+import seedu.address.logic.commands.DeleteByNamePhoneNumberCommand;
+import seedu.address.logic.commands.DeleteVisitCommand;
+import seedu.address.logic.commands.EditCommand;
+import seedu.address.logic.commands.EditVisitCommand;
+import seedu.address.logic.commands.ExitCommand;
+import seedu.address.logic.commands.FindCommand;
+import seedu.address.logic.commands.ForceDeleteAllCommand;
+import seedu.address.logic.commands.ForceExitCommand;
+import seedu.address.logic.commands.HelpCommand;
+import seedu.address.logic.commands.ListAlphabeticalCommand;
+import seedu.address.logic.commands.ListByApptDateCommand;
+import seedu.address.logic.commands.ListByDateCriteriaCommand;
+import seedu.address.logic.commands.ListCommand;
+import seedu.address.logic.commands.NoCommand;
+import seedu.address.logic.commands.YesCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+
+/**
+ * Parses user input.
+ */
+public class InputParser {
+ private static final String DELETE_ALL_ERROR_MESSAGE =
+ "Please give either 'yes' or 'no' after 'delete-all' command!";
+ private static final String EXIT_ERROR_MESSAGE = "Please give either 'yes' or 'no' after 'exit' command!";
+
+ /**
+ * Used for initial separation of command word and args.
+ */
+ private static final Pattern BASIC_COMMAND_FORMAT = Pattern.compile("(?\\S+)(?.*)");
+ private static final Logger logger = LogsCenter.getLogger(InputParser.class);
+
+ private boolean isPreviousCommandDeleteAll = false; // To check if the previous command was "delete-all"
+ private boolean isPreviousCommandExit = false; // To check if the previous command was "exit"
+
+ /**
+ * Parses user input into command for execution.
+ *
+ * @param userInput full user input string
+ * @return the command based on the user input
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public Command parseCommand(String userInput) throws ParseException {
+ final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(userInput.trim());
+ if (!matcher.matches()) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE));
+ }
+
+ final String commandWord = matcher.group("commandWord");
+ final String arguments = matcher.group("arguments");
+
+ // Note to developers: Change the log level in config.json to enable lower level (i.e., FINE, FINER and lower)
+ // log messages such as the one below.
+ // Lower level log messages are used sparingly to minimize noise in the code.
+ logger.fine("Command word: " + commandWord + "; Arguments: " + arguments);
+
+ // Checking if the previous command was "delete-all"
+ if (isPreviousCommandDeleteAll) {
+ isPreviousCommandDeleteAll = false;
+
+ if (userInput.equals("yes")) {
+ return new YesCommand("delete-all");
+ } else if (userInput.equals("no")) {
+ return new NoCommand();
+ } else {
+ throw new ParseException(DELETE_ALL_ERROR_MESSAGE);
+ }
+ }
+
+ // Checking if the previous command was "exit"
+ if (isPreviousCommandExit) {
+ isPreviousCommandExit = false;
+
+ if (userInput.equals("yes")) {
+ return new YesCommand("exit");
+ } else if (userInput.equals("no")) {
+ return new NoCommand();
+ } else {
+ throw new ParseException(EXIT_ERROR_MESSAGE);
+ }
+ }
+
+ switch (commandWord) {
+
+ case AddCommand.COMMAND_WORD:
+ return new AddCommandParser().parse(arguments);
+
+ case AddVisitCommand.COMMAND_WORD:
+ return new AddVisitCommandParser().parse(arguments);
+
+ case EditCommand.COMMAND_WORD:
+ return new EditCommandParser().parse(arguments);
+
+ case EditVisitCommand.COMMAND_WORD:
+ return new EditVisitCommandParser().parse(arguments);
+
+ case DeleteByIndexCommand.COMMAND_WORD:
+ return new DeleteByIndexCommandParser().parse(arguments);
+
+ case DeleteAllCommand.COMMAND_WORD:
+ isPreviousCommandDeleteAll = true;
+ return new DeleteAllCommand();
+
+ case DeleteByNamePhoneNumberCommand.COMMAND_WORD:
+ return new DeleteByNamePhoneNumberCommandParser().parse(arguments);
+
+ case DeleteVisitCommand.COMMAND_WORD:
+ return new DeleteVisitCommandParser().parse(arguments);
+
+ case ForceDeleteAllCommand.COMMAND_WORD:
+ return new ForceDeleteAllCommand();
+
+ case FindCommand.COMMAND_WORD:
+ return new FindCommandParser().parse(arguments);
+
+ case ListCommand.COMMAND_WORD:
+ return new ListCommand();
+
+ case ListAlphabeticalCommand.COMMAND_WORD:
+ return new ListAlphabeticalCommand();
+
+ case ExitCommand.COMMAND_WORD:
+ isPreviousCommandExit = true;
+ return new ExitCommand();
+
+ case ForceExitCommand.COMMAND_WORD:
+ return new ForceExitCommand();
+
+ case HelpCommand.COMMAND_WORD:
+ return new HelpCommand();
+
+ case ListByApptDateCommand.COMMAND_WORD:
+ return new ListByApptDateCommand();
+
+ case ListByDateCriteriaCommand.COMMAND_WORD:
+ return new ListByDateCriteriaCommandParser().parse(arguments);
+
+ default:
+ logger.finer("This user input caused a ParseException: " + userInput);
+ throw new ParseException(MESSAGE_UNKNOWN_COMMAND);
+ }
+ }
+
+ /**
+ * Returns the error message for the delete-all command.
+ *
+ * @return The error message for the delete-all command.
+ */
+ public static String getDeleteAllErrorMessage() {
+ return DELETE_ALL_ERROR_MESSAGE;
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/ListByDateCriteriaCommandParser.java b/src/main/java/seedu/address/logic/parser/ListByDateCriteriaCommandParser.java
new file mode 100755
index 00000000000..758b1e7c40a
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/ListByDateCriteriaCommandParser.java
@@ -0,0 +1,39 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_APPOINTMENT;
+
+import java.time.LocalDate;
+import java.util.Optional;
+
+import seedu.address.logic.commands.ListByDateCriteriaCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.patient.ApptDateMatchesPredicate;
+
+/**
+ * Lists patient by appointment dates parser
+ */
+public class ListByDateCriteriaCommandParser implements Parser {
+
+ @Override
+ public ListByDateCriteriaCommand parse(String args) throws ParseException {
+
+ ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args, PREFIX_APPOINTMENT);
+
+ if (!argMultimap.getPreamble().equals("")) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ ListByDateCriteriaCommand.MESSAGE_USAGE));
+ }
+
+ if (Optional.empty().equals(argMultimap.getValue(PREFIX_APPOINTMENT))) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ ListByDateCriteriaCommand.MESSAGE_USAGE));
+ }
+
+ LocalDate dateOfVisit =
+ ParserUtil.parseAppointment(argMultimap.getValue(PREFIX_APPOINTMENT).get()).appointment;
+ ApptDateMatchesPredicate apptDatePredicate = new ApptDateMatchesPredicate(dateOfVisit);
+
+ return new ListByDateCriteriaCommand(apptDatePredicate);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/ParserUtil.java b/src/main/java/seedu/address/logic/parser/ParserUtil.java
index b117acb9c55..e1a4e33bee7 100644
--- a/src/main/java/seedu/address/logic/parser/ParserUtil.java
+++ b/src/main/java/seedu/address/logic/parser/ParserUtil.java
@@ -2,18 +2,19 @@
import static java.util.Objects.requireNonNull;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
-
import seedu.address.commons.core.index.Index;
import seedu.address.commons.util.StringUtil;
import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
+import seedu.address.model.patient.Address;
+import seedu.address.model.patient.Appointment;
+import seedu.address.model.patient.Condition;
+import seedu.address.model.patient.DateOfBirth;
+import seedu.address.model.patient.DateOfVisit;
+import seedu.address.model.patient.Email;
+import seedu.address.model.patient.Name;
+import seedu.address.model.patient.Phone;
+import seedu.address.model.patient.Severity;
+import seedu.address.model.patient.Sex;
/**
* Contains utility methods used for parsing strings in the various *Parser classes.
@@ -41,12 +42,15 @@ public static Index parseIndex(String oneBasedIndex) throws ParseException {
*
* @throws ParseException if the given {@code name} is invalid.
*/
- public static Name parseName(String name) throws ParseException {
- requireNonNull(name);
- String trimmedName = name.trim();
+ public static Name parseName(String stringToParse) throws ParseException {
+ requireNonNull(stringToParse);
+
+ String trimmedName = stringToParse.trim();
+
if (!Name.isValidName(trimmedName)) {
throw new ParseException(Name.MESSAGE_CONSTRAINTS);
}
+
return new Name(trimmedName);
}
@@ -56,12 +60,14 @@ public static Name parseName(String name) throws ParseException {
*
* @throws ParseException if the given {@code phone} is invalid.
*/
- public static Phone parsePhone(String phone) throws ParseException {
- requireNonNull(phone);
- String trimmedPhone = phone.trim();
+ public static Phone parsePhone(String stringToParse) throws ParseException {
+ requireNonNull(stringToParse);
+ String trimmedPhone = stringToParse.trim();
+
if (!Phone.isValidPhone(trimmedPhone)) {
throw new ParseException(Phone.MESSAGE_CONSTRAINTS);
}
+
return new Phone(trimmedPhone);
}
@@ -96,29 +102,92 @@ public static Email parseEmail(String email) throws ParseException {
}
/**
- * Parses a {@code String tag} into a {@code Tag}.
+ * Parses a {@code String dateOfBirth} into an {@code DateOfBirth}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @throws ParseException if the given {@code dateOfBirth} is invalid.
+ */
+ public static DateOfBirth parseDateOfBirth(String dateOfBirth) throws ParseException {
+ requireNonNull(dateOfBirth);
+ String trimmedDateOfBirth = dateOfBirth.trim();
+ if (!DateOfBirth.isValidDateOfBirth(trimmedDateOfBirth)) {
+ throw new ParseException(DateOfBirth.MESSAGE_CONSTRAINTS);
+ }
+ return new DateOfBirth(trimmedDateOfBirth);
+ }
+
+ /**
+ * Parses a {@code String sex} into an {@code Sex}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @throws ParseException if the given {@code Sex} is invalid.
+ */
+ public static Sex parseSex(String sex) throws ParseException {
+ requireNonNull(sex);
+ String trimmedSex = sex.trim();
+ if (!Sex.isValidSex(trimmedSex)) {
+ throw new ParseException(Sex.MESSAGE_CONSTRAINTS);
+ }
+ return new Sex(trimmedSex);
+ }
+
+ /**
+ * Parses a {@code String appointment} into an {@code Appointment}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @throws ParseException if the given {@code Appointment} is invalid.
+ */
+ public static Appointment parseAppointment(String appointment) throws ParseException {
+ requireNonNull(appointment);
+ String trimmedAppointment = appointment.trim();
+ if (!Appointment.isValidAppointment(trimmedAppointment)) {
+ throw new ParseException(Appointment.MESSAGE_CONSTRAINTS);
+ }
+ return new Appointment(trimmedAppointment);
+ }
+
+ /**
+ * Parses a {@code String dateOfVisit} into an {@code DateOfVisit}.
* Leading and trailing whitespaces will be trimmed.
*
- * @throws ParseException if the given {@code tag} is invalid.
+ * @throws ParseException if the given {@code dateOfVisit} is invalid.
*/
- public static Tag parseTag(String tag) throws ParseException {
- requireNonNull(tag);
- String trimmedTag = tag.trim();
- if (!Tag.isValidTagName(trimmedTag)) {
- throw new ParseException(Tag.MESSAGE_CONSTRAINTS);
+ public static DateOfVisit parseDateOfVisit(String dateOfVisit) throws ParseException {
+ requireNonNull(dateOfVisit);
+ String trimmedDateOfVisit = dateOfVisit.trim();
+ if (!DateOfVisit.isValidDateOfVisit(trimmedDateOfVisit)) {
+ throw new ParseException(DateOfVisit.MESSAGE_CONSTRAINTS);
}
- return new Tag(trimmedTag);
+ return new DateOfVisit(trimmedDateOfVisit);
}
/**
- * Parses {@code Collection tags} into a {@code Set}.
+ * Parses a {@code String severity} into an {@code Severity}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @throws ParseException if the given {@code Severity} is invalid.
+ */
+ public static Severity parseSeverity(String severity) throws ParseException {
+ requireNonNull(severity);
+ String trimmedSeverity = severity.trim();
+ if (!Severity.isValidSeverity(trimmedSeverity)) {
+ throw new ParseException(Severity.MESSAGE_CONSTRAINTS);
+ }
+ return new Severity(trimmedSeverity);
+ }
+
+ /**
+ * Parses a {@code String condition} into an {@code Condition}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @throws ParseException if the given {@code Condition} is invalid.
*/
- public static Set parseTags(Collection tags) throws ParseException {
- requireNonNull(tags);
- final Set tagSet = new HashSet<>();
- for (String tagName : tags) {
- tagSet.add(parseTag(tagName));
+ public static Condition parseCondition(String condition) throws ParseException {
+ requireNonNull(condition);
+ String trimmedCondition = condition.trim();
+ if (!Condition.isValidCondition(trimmedCondition)) {
+ throw new ParseException(Condition.MESSAGE_CONSTRAINTS);
}
- return tagSet;
+ return new Condition(trimmedCondition);
}
}
diff --git a/src/main/java/seedu/address/model/AddressBook.java b/src/main/java/seedu/address/model/AddressBook.java
deleted file mode 100644
index 73397161e84..00000000000
--- a/src/main/java/seedu/address/model/AddressBook.java
+++ /dev/null
@@ -1,130 +0,0 @@
-package seedu.address.model;
-
-import static java.util.Objects.requireNonNull;
-
-import java.util.List;
-
-import javafx.collections.ObservableList;
-import seedu.address.commons.util.ToStringBuilder;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.UniquePersonList;
-
-/**
- * Wraps all data at the address-book level
- * Duplicates are not allowed (by .isSamePerson comparison)
- */
-public class AddressBook implements ReadOnlyAddressBook {
-
- private final UniquePersonList persons;
-
- /*
- * The 'unusual' code block below is a non-static initialization block, sometimes used to avoid duplication
- * between constructors. See https://docs.oracle.com/javase/tutorial/java/javaOO/initial.html
- *
- * Note that non-static init blocks are not recommended to use. There are other ways to avoid duplication
- * among constructors.
- */
- {
- persons = new UniquePersonList();
- }
-
- public AddressBook() {}
-
- /**
- * Creates an AddressBook using the Persons in the {@code toBeCopied}
- */
- public AddressBook(ReadOnlyAddressBook toBeCopied) {
- this();
- resetData(toBeCopied);
- }
-
- //// list overwrite operations
-
- /**
- * Replaces the contents of the person list with {@code persons}.
- * {@code persons} must not contain duplicate persons.
- */
- public void setPersons(List persons) {
- this.persons.setPersons(persons);
- }
-
- /**
- * Resets the existing data of this {@code AddressBook} with {@code newData}.
- */
- public void resetData(ReadOnlyAddressBook newData) {
- requireNonNull(newData);
-
- setPersons(newData.getPersonList());
- }
-
- //// person-level operations
-
- /**
- * Returns true if a person with the same identity as {@code person} exists in the address book.
- */
- public boolean hasPerson(Person person) {
- requireNonNull(person);
- return persons.contains(person);
- }
-
- /**
- * Adds a person to the address book.
- * The person must not already exist in the address book.
- */
- public void addPerson(Person p) {
- persons.add(p);
- }
-
- /**
- * Replaces the given person {@code target} in the list with {@code editedPerson}.
- * {@code target} must exist in the address book.
- * The person identity of {@code editedPerson} must not be the same as another existing person in the address book.
- */
- public void setPerson(Person target, Person editedPerson) {
- requireNonNull(editedPerson);
-
- persons.setPerson(target, editedPerson);
- }
-
- /**
- * Removes {@code key} from this {@code AddressBook}.
- * {@code key} must exist in the address book.
- */
- public void removePerson(Person key) {
- persons.remove(key);
- }
-
- //// util methods
-
- @Override
- public String toString() {
- return new ToStringBuilder(this)
- .add("persons", persons)
- .toString();
- }
-
- @Override
- public ObservableList getPersonList() {
- return persons.asUnmodifiableObservableList();
- }
-
- @Override
- public boolean equals(Object other) {
- if (other == this) {
- return true;
- }
-
- // instanceof handles nulls
- if (!(other instanceof AddressBook)) {
- return false;
- }
-
- AddressBook otherAddressBook = (AddressBook) other;
- return persons.equals(otherAddressBook.persons);
- }
-
- @Override
- public int hashCode() {
- return persons.hashCode();
- }
-}
diff --git a/src/main/java/seedu/address/model/Model.java b/src/main/java/seedu/address/model/Model.java
index d54df471c1f..8980c823848 100644
--- a/src/main/java/seedu/address/model/Model.java
+++ b/src/main/java/seedu/address/model/Model.java
@@ -5,14 +5,16 @@
import javafx.collections.ObservableList;
import seedu.address.commons.core.GuiSettings;
-import seedu.address.model.person.Person;
+import seedu.address.model.patient.Name;
+import seedu.address.model.patient.Patient;
+import seedu.address.model.patient.Phone;
/**
* The API of the Model component.
*/
public interface Model {
/** {@code Predicate} that always evaluate to true */
- Predicate PREDICATE_SHOW_ALL_PERSONS = unused -> true;
+ Predicate PREDICATE_SHOW_ALL_PATIENTS = unused -> true;
/**
* Replaces user prefs data with the data in {@code userPrefs}.
@@ -35,53 +37,64 @@ public interface Model {
void setGuiSettings(GuiSettings guiSettings);
/**
- * Returns the user prefs' address book file path.
+ * Returns the user prefs' patient list file path.
*/
- Path getAddressBookFilePath();
+ Path getPatientListFilePath();
/**
- * Sets the user prefs' address book file path.
+ * Sets the user prefs' patient list file path.
*/
- void setAddressBookFilePath(Path addressBookFilePath);
+ void setPatientListFilePath(Path patientListFilePath);
/**
- * Replaces address book data with the data in {@code addressBook}.
+ * Replaces patient list data with the data in {@code patientList]}.
*/
- void setAddressBook(ReadOnlyAddressBook addressBook);
+ void setPatientList(ReadOnlyPatientList patientList);
- /** Returns the AddressBook */
- ReadOnlyAddressBook getAddressBook();
+ /** Returns the PatientList */
+ ReadOnlyPatientList getPatientList();
/**
- * Returns true if a person with the same identity as {@code person} exists in the address book.
+ * Returns true if a patient with the same identity as {@code patient} exists in the patient list.
*/
- boolean hasPerson(Person person);
+ boolean hasPatient(Patient patient);
/**
- * Deletes the given person.
- * The person must exist in the address book.
+ * Returns true if a patient with {@code name} and {@code phone} exists in the patient list.
*/
- void deletePerson(Person target);
+ boolean hasPatient(Name name, Phone phone);
/**
- * Adds the given person.
- * {@code person} must not already exist in the address book.
+ * Deletes the given patient.
+ * The patient must exist in the patient list.
*/
- void addPerson(Person person);
+ void deletePatient(Patient target);
/**
- * Replaces the given person {@code target} with {@code editedPerson}.
- * {@code target} must exist in the address book.
- * The person identity of {@code editedPerson} must not be the same as another existing person in the address book.
+ * Adds the given patient.
+ * {@code patient} must not already exist in the patient list.
*/
- void setPerson(Person target, Person editedPerson);
+ void addPatient(Patient patient);
- /** Returns an unmodifiable view of the filtered person list */
- ObservableList getFilteredPersonList();
+ /**
+ * Replaces the given patient {@code target} with {@code editedPatient}.
+ * {@code target} must exist in the patient list.
+ * The patient identity of {@code editedPatient} must not be the same as
+ * another existing patient in the patient list.
+ */
+ void setPatient(Patient target, Patient editedPatient);
+
+ /**
+ * Returns the patient with {@code name} and {@code phone} in the patient list.
+ */
+ Patient getPatient(Name name, Phone phone);
+
+ /** Returns an unmodifiable view of the filtered patient list */
+ ObservableList getFilteredPatientList();
/**
- * Updates the filter of the filtered person list to filter by the given {@code predicate}.
+ * Updates the filter of the filtered patient list to filter by the given {@code predicate}.
* @throws NullPointerException if {@code predicate} is null.
*/
- void updateFilteredPersonList(Predicate predicate);
+ void updateFilteredPatientList(Predicate predicate);
}
diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java
index 57bc563fde6..5000cfd3297 100644
--- a/src/main/java/seedu/address/model/ModelManager.java
+++ b/src/main/java/seedu/address/model/ModelManager.java
@@ -11,33 +11,35 @@
import javafx.collections.transformation.FilteredList;
import seedu.address.commons.core.GuiSettings;
import seedu.address.commons.core.LogsCenter;
-import seedu.address.model.person.Person;
+import seedu.address.model.patient.Name;
+import seedu.address.model.patient.Patient;
+import seedu.address.model.patient.Phone;
/**
- * Represents the in-memory model of the address book data.
+ * Represents the in-memory model of the patient list data.
*/
public class ModelManager implements Model {
private static final Logger logger = LogsCenter.getLogger(ModelManager.class);
- private final AddressBook addressBook;
+ private final PatientList patientList;
private final UserPrefs userPrefs;
- private final FilteredList filteredPersons;
+ private final FilteredList filteredPatients;
/**
- * Initializes a ModelManager with the given addressBook and userPrefs.
+ * Initializes a ModelManager with the given patientList and userPrefs.
*/
- public ModelManager(ReadOnlyAddressBook addressBook, ReadOnlyUserPrefs userPrefs) {
- requireAllNonNull(addressBook, userPrefs);
+ public ModelManager(ReadOnlyPatientList patientList, ReadOnlyUserPrefs userPrefs) {
+ requireAllNonNull(patientList, userPrefs);
- logger.fine("Initializing with address book: " + addressBook + " and user prefs " + userPrefs);
+ logger.fine("Initializing with patient list: " + patientList + " and user prefs " + userPrefs);
- this.addressBook = new AddressBook(addressBook);
+ this.patientList = new PatientList(patientList);
this.userPrefs = new UserPrefs(userPrefs);
- filteredPersons = new FilteredList<>(this.addressBook.getPersonList());
+ filteredPatients = new FilteredList<>(this.patientList.getPatientList());
}
public ModelManager() {
- this(new AddressBook(), new UserPrefs());
+ this(new PatientList(), new UserPrefs());
}
//=========== UserPrefs ==================================================================================
@@ -65,67 +67,77 @@ public void setGuiSettings(GuiSettings guiSettings) {
}
@Override
- public Path getAddressBookFilePath() {
- return userPrefs.getAddressBookFilePath();
+ public Path getPatientListFilePath() {
+ return userPrefs.getPatientListFilePath();
}
@Override
- public void setAddressBookFilePath(Path addressBookFilePath) {
- requireNonNull(addressBookFilePath);
- userPrefs.setAddressBookFilePath(addressBookFilePath);
+ public void setPatientListFilePath(Path patientListFilePath) {
+ requireNonNull(patientListFilePath);
+ userPrefs.setPatientListFilePath(patientListFilePath);
}
- //=========== AddressBook ================================================================================
+ //=========== PatientList ================================================================================
@Override
- public void setAddressBook(ReadOnlyAddressBook addressBook) {
- this.addressBook.resetData(addressBook);
+ public void setPatientList(ReadOnlyPatientList patientList) {
+ this.patientList.resetData(patientList);
}
@Override
- public ReadOnlyAddressBook getAddressBook() {
- return addressBook;
+ public ReadOnlyPatientList getPatientList() {
+ return patientList;
}
@Override
- public boolean hasPerson(Person person) {
- requireNonNull(person);
- return addressBook.hasPerson(person);
+ public boolean hasPatient(Patient patient) {
+ requireNonNull(patient);
+ return patientList.hasPatient(patient);
}
@Override
- public void deletePerson(Person target) {
- addressBook.removePerson(target);
+ public boolean hasPatient(Name name, Phone phone) {
+ requireAllNonNull(name, phone);
+ return patientList.hasPatient(name, phone);
}
@Override
- public void addPerson(Person person) {
- addressBook.addPerson(person);
- updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
+ public void deletePatient(Patient target) {
+ patientList.removePatient(target);
}
@Override
- public void setPerson(Person target, Person editedPerson) {
- requireAllNonNull(target, editedPerson);
+ public void addPatient(Patient patient) {
+ patientList.addPatient(patient);
+ updateFilteredPatientList(PREDICATE_SHOW_ALL_PATIENTS);
+ }
+
+ @Override
+ public void setPatient(Patient target, Patient editedPatient) {
+ requireAllNonNull(target, editedPatient);
- addressBook.setPerson(target, editedPerson);
+ patientList.setPatient(target, editedPatient);
+ }
+
+ @Override
+ public Patient getPatient(Name name, Phone phone) {
+ return patientList.getPatient(name, phone);
}
- //=========== Filtered Person List Accessors =============================================================
+ //=========== Filtered Patient List Accessors =============================================================
/**
- * Returns an unmodifiable view of the list of {@code Person} backed by the internal list of
- * {@code versionedAddressBook}
+ * Returns an unmodifiable view of the filtered list of {@code Patient}.
*/
@Override
- public ObservableList getFilteredPersonList() {
- return filteredPersons;
+ public ObservableList getFilteredPatientList() {
+ return filteredPatients;
}
@Override
- public void updateFilteredPersonList(Predicate predicate) {
+ public void updateFilteredPatientList(Predicate predicate) {
requireNonNull(predicate);
- filteredPersons.setPredicate(predicate);
+ filteredPatients.setPredicate(predicate);
}
@Override
@@ -140,9 +152,9 @@ public boolean equals(Object other) {
}
ModelManager otherModelManager = (ModelManager) other;
- return addressBook.equals(otherModelManager.addressBook)
+ return patientList.equals(otherModelManager.patientList)
&& userPrefs.equals(otherModelManager.userPrefs)
- && filteredPersons.equals(otherModelManager.filteredPersons);
+ && filteredPatients.equals(otherModelManager.filteredPatients);
}
}
diff --git a/src/main/java/seedu/address/model/PatientList.java b/src/main/java/seedu/address/model/PatientList.java
new file mode 100644
index 00000000000..7c98dbe6c95
--- /dev/null
+++ b/src/main/java/seedu/address/model/PatientList.java
@@ -0,0 +1,164 @@
+package seedu.address.model;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Predicate;
+
+import javafx.collections.ObservableList;
+import seedu.address.commons.util.ToStringBuilder;
+import seedu.address.model.patient.Name;
+import seedu.address.model.patient.Patient;
+import seedu.address.model.patient.Phone;
+import seedu.address.model.patient.UniquePatientList;
+import seedu.address.model.patient.exceptions.PatientNotFoundException;
+
+/**
+ * Wraps all data at the patient list level
+ * Duplicates are not allowed (by .isSamePatient comparison)
+ */
+public class PatientList implements ReadOnlyPatientList {
+
+ private final UniquePatientList patients;
+
+ /*
+ * The 'unusual' code block below is a non-static initialization block, sometimes used to avoid duplication
+ * between constructors. See https://docs.oracle.com/javase/tutorial/java/javaOO/initial.html
+ *
+ * Note that non-static init blocks are not recommended to use. There are other ways to avoid duplication
+ * among constructors.
+ */
+ {
+ patients = new UniquePatientList();
+ }
+
+ public PatientList() {}
+
+ /**
+ * Creates a PatientList using the Patients in the {@code toBeCopied}
+ */
+ public PatientList(ReadOnlyPatientList toBeCopied) {
+ this();
+ resetData(toBeCopied);
+ }
+
+ //// list overwrite operations
+
+ /**
+ * Replaces the contents of the patient list with {@code patients}.
+ * {@code patients} must not contain duplicate patients.
+ */
+ public void setPatients(List patients) {
+ this.patients.setPatients(patients);
+ }
+
+ /**
+ * Resets the existing data of this {@code PatientList} with {@code newData}.
+ */
+ public void resetData(ReadOnlyPatientList newData) {
+ requireNonNull(newData);
+
+ setPatients(newData.getPatientList());
+ }
+
+ //// patient-level operations
+
+ /**
+ * Returns true if a patient with the same identity as {@code patient} exists in the list.
+ */
+ public boolean hasPatient(Patient patient) {
+ requireNonNull(patient);
+ return patients.contains(patient);
+ }
+
+ /**
+ * Returns true if a patient with {@code name} and {@code phone} exists in the list.
+ */
+ public boolean hasPatient(Name name, Phone phone) {
+ requireNonNull(name);
+ requireNonNull(phone);
+ return getPatientOptional(name, phone).isPresent();
+ }
+
+ /**
+ * Adds a patient to the list.
+ * The patient must not already exist in the list.
+ */
+ public void addPatient(Patient p) {
+ patients.add(p);
+ }
+
+ /**
+ * Replaces the given patient {@code target} in the list with {@code editedPatient}.
+ * {@code target} must exist in the list.
+ * The patient identity of {@code editedPatient} must not be the same as another existing patient
+ * in the list.
+ */
+ public void setPatient(Patient target, Patient editedPatient) {
+ requireNonNull(editedPatient);
+
+ patients.setPatient(target, editedPatient);
+ }
+
+ /**
+ * Removes {@code key} from this {@code PatientList}.
+ * {@code key} must exist in the list.
+ */
+ public void removePatient(Patient key) {
+ patients.remove(key);
+ }
+
+ /**
+ * Returns a {@code Patient} in the patient list that matches the given {@code name} and {@code phone}.
+ */
+ public Patient getPatient(Name name, Phone phone) {
+ Optional patient = getPatientOptional(name, phone);
+ if (patient.isPresent()) {
+ return patient.get();
+ } else {
+ throw new PatientNotFoundException();
+ }
+ }
+
+
+
+ //// util methods
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .add("patients", patients)
+ .toString();
+ }
+
+ @Override
+ public ObservableList getPatientList() {
+ return patients.asUnmodifiableObservableList();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof PatientList)) {
+ return false;
+ }
+
+ PatientList otherPatientList = (PatientList) other;
+ return patients.equals(otherPatientList.patients);
+ }
+
+ @Override
+ public int hashCode() {
+ return patients.hashCode();
+ }
+
+ private Optional getPatientOptional(Name name, Phone phone) {
+ Predicate predicate = patient -> patient.getName().equals(name) && patient.getPhone().equals(phone);
+ return getPatientList().stream().filter(predicate).findFirst();
+ }
+}
diff --git a/src/main/java/seedu/address/model/ReadOnlyAddressBook.java b/src/main/java/seedu/address/model/ReadOnlyAddressBook.java
deleted file mode 100644
index 6ddc2cd9a29..00000000000
--- a/src/main/java/seedu/address/model/ReadOnlyAddressBook.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package seedu.address.model;
-
-import javafx.collections.ObservableList;
-import seedu.address.model.person.Person;
-
-/**
- * Unmodifiable view of an address book
- */
-public interface ReadOnlyAddressBook {
-
- /**
- * Returns an unmodifiable view of the persons list.
- * This list will not contain any duplicate persons.
- */
- ObservableList getPersonList();
-
-}
diff --git a/src/main/java/seedu/address/model/ReadOnlyPatientList.java b/src/main/java/seedu/address/model/ReadOnlyPatientList.java
new file mode 100644
index 00000000000..3e4cb88a033
--- /dev/null
+++ b/src/main/java/seedu/address/model/ReadOnlyPatientList.java
@@ -0,0 +1,17 @@
+package seedu.address.model;
+
+import javafx.collections.ObservableList;
+import seedu.address.model.patient.Patient;
+
+/**
+ * Unmodifiable view of a patient list
+ */
+public interface ReadOnlyPatientList {
+
+ /**
+ * Returns an unmodifiable view of the patient list.
+ * This list will not contain any duplicate patients.
+ */
+ ObservableList getPatientList();
+
+}
diff --git a/src/main/java/seedu/address/model/ReadOnlyUserPrefs.java b/src/main/java/seedu/address/model/ReadOnlyUserPrefs.java
index befd58a4c73..fc06fcfebfa 100644
--- a/src/main/java/seedu/address/model/ReadOnlyUserPrefs.java
+++ b/src/main/java/seedu/address/model/ReadOnlyUserPrefs.java
@@ -11,6 +11,6 @@ public interface ReadOnlyUserPrefs {
GuiSettings getGuiSettings();
- Path getAddressBookFilePath();
+ Path getPatientListFilePath();
}
diff --git a/src/main/java/seedu/address/model/UserPrefs.java b/src/main/java/seedu/address/model/UserPrefs.java
index 6be655fb4c7..5ae166d60c0 100644
--- a/src/main/java/seedu/address/model/UserPrefs.java
+++ b/src/main/java/seedu/address/model/UserPrefs.java
@@ -14,7 +14,7 @@
public class UserPrefs implements ReadOnlyUserPrefs {
private GuiSettings guiSettings = new GuiSettings();
- private Path addressBookFilePath = Paths.get("data" , "addressbook.json");
+ private Path patientListFilePath = Paths.get("data" , "patientlist.json");
/**
* Creates a {@code UserPrefs} with default values.
@@ -35,7 +35,7 @@ public UserPrefs(ReadOnlyUserPrefs userPrefs) {
public void resetData(ReadOnlyUserPrefs newUserPrefs) {
requireNonNull(newUserPrefs);
setGuiSettings(newUserPrefs.getGuiSettings());
- setAddressBookFilePath(newUserPrefs.getAddressBookFilePath());
+ setPatientListFilePath(newUserPrefs.getPatientListFilePath());
}
public GuiSettings getGuiSettings() {
@@ -47,13 +47,13 @@ public void setGuiSettings(GuiSettings guiSettings) {
this.guiSettings = guiSettings;
}
- public Path getAddressBookFilePath() {
- return addressBookFilePath;
+ public Path getPatientListFilePath() {
+ return patientListFilePath;
}
- public void setAddressBookFilePath(Path addressBookFilePath) {
- requireNonNull(addressBookFilePath);
- this.addressBookFilePath = addressBookFilePath;
+ public void setPatientListFilePath(Path patientListFilePath) {
+ requireNonNull(patientListFilePath);
+ this.patientListFilePath = patientListFilePath;
}
@Override
@@ -69,19 +69,19 @@ public boolean equals(Object other) {
UserPrefs otherUserPrefs = (UserPrefs) other;
return guiSettings.equals(otherUserPrefs.guiSettings)
- && addressBookFilePath.equals(otherUserPrefs.addressBookFilePath);
+ && patientListFilePath.equals(otherUserPrefs.patientListFilePath);
}
@Override
public int hashCode() {
- return Objects.hash(guiSettings, addressBookFilePath);
+ return Objects.hash(guiSettings, patientListFilePath);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Gui Settings : " + guiSettings);
- sb.append("\nLocal data file location : " + addressBookFilePath);
+ sb.append("\nLocal data file location : " + patientListFilePath);
return sb.toString();
}
diff --git a/src/main/java/seedu/address/model/person/Address.java b/src/main/java/seedu/address/model/patient/Address.java
similarity index 91%
rename from src/main/java/seedu/address/model/person/Address.java
rename to src/main/java/seedu/address/model/patient/Address.java
index 469a2cc9a1e..9ff9f9efdec 100644
--- a/src/main/java/seedu/address/model/person/Address.java
+++ b/src/main/java/seedu/address/model/patient/Address.java
@@ -1,10 +1,10 @@
-package seedu.address.model.person;
+package seedu.address.model.patient;
import static java.util.Objects.requireNonNull;
import static seedu.address.commons.util.AppUtil.checkArgument;
/**
- * Represents a Person's address in the address book.
+ * Represents a Patient's address in the list.
* Guarantees: immutable; is valid as declared in {@link #isValidAddress(String)}
*/
public class Address {
@@ -31,7 +31,7 @@ public Address(String address) {
}
/**
- * Returns true if a given string is a valid email.
+ * Returns true if a given string is a valid address.
*/
public static boolean isValidAddress(String test) {
return test.matches(VALIDATION_REGEX);
diff --git a/src/main/java/seedu/address/model/patient/Appointment.java b/src/main/java/seedu/address/model/patient/Appointment.java
new file mode 100644
index 00000000000..3d70ed0b34f
--- /dev/null
+++ b/src/main/java/seedu/address/model/patient/Appointment.java
@@ -0,0 +1,83 @@
+package seedu.address.model.patient;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.AppUtil.checkArgument;
+
+import java.time.LocalDate;
+
+import seedu.address.logic.parser.DateTimeParser;
+
+/**
+ * Represents a Patient's next appointment date
+ * Guarantees: immutable; is valid as declared in {@link #isValidAppointment(String)}
+ */
+public class Appointment {
+ public static final String MESSAGE_CONSTRAINTS =
+ "Appointment should only contain numeric values in dd/MM/yyyy or yyyy-MM-dd format, "
+ + "and it should not be left blank";
+
+ public final LocalDate appointment;
+
+ /**
+ * Constructs a {@code Appointment}
+ *
+ * @param appointment
+ */
+ public Appointment(String appointment) {
+ requireNonNull(appointment);
+ checkArgument(isValidAppointment(appointment), MESSAGE_CONSTRAINTS);
+ if (!appointment.isEmpty()) {
+ this.appointment = DateTimeParser.parseDateTime(appointment);
+ } else {
+ this.appointment = null;
+ }
+ }
+
+ /**
+ * Returns true if a given string is a valid appointment
+ */
+ public static boolean isValidAppointment(String test) {
+ if (test.isEmpty()) {
+ return true;
+ } else if (!test.isEmpty()) {
+ return DateTimeParser.parseDateTime(test) == null ? false : true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public String toString() {
+ if (appointment != null) {
+ return DateTimeParser.outputDateTime(appointment);
+ } else {
+ return "";
+ }
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ //instanceof handles nulls
+ if (!(other instanceof Appointment)) {
+ return false;
+ }
+
+ Appointment otherAppointment = (Appointment) other;
+ if (appointment == null && otherAppointment.appointment == null) {
+ return true;
+ }
+ if (appointment != null && otherAppointment.appointment != null) {
+ return appointment.equals(otherAppointment.appointment);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return appointment.hashCode();
+ }
+}
diff --git a/src/main/java/seedu/address/model/patient/ApptDateMatchesPredicate.java b/src/main/java/seedu/address/model/patient/ApptDateMatchesPredicate.java
new file mode 100755
index 00000000000..a2fa1375578
--- /dev/null
+++ b/src/main/java/seedu/address/model/patient/ApptDateMatchesPredicate.java
@@ -0,0 +1,46 @@
+package seedu.address.model.patient;
+
+import java.time.LocalDate;
+import java.util.function.Predicate;
+
+import seedu.address.commons.util.ToStringBuilder;
+
+/**
+ * Predicate for appointment date.
+ */
+public class ApptDateMatchesPredicate implements Predicate {
+ private final LocalDate apptDate;
+
+ public ApptDateMatchesPredicate(LocalDate apptDate) {
+ this.apptDate = apptDate;
+ }
+
+ @Override
+ public boolean test(Patient patient) {
+ LocalDate ptApptDate = patient.getAppointment().appointment;
+ if (ptApptDate == null) {
+ return false;
+ }
+ return ptApptDate.isBefore(this.apptDate) || ptApptDate.isEqual(this.apptDate);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof ApptDateMatchesPredicate)) {
+ return false;
+ }
+
+ ApptDateMatchesPredicate otherApptMatchesPredicate = (ApptDateMatchesPredicate) other;
+ return apptDate.equals(otherApptMatchesPredicate.apptDate);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this).add("appointment", apptDate).toString();
+ }
+}
diff --git a/src/main/java/seedu/address/model/patient/Condition.java b/src/main/java/seedu/address/model/patient/Condition.java
new file mode 100644
index 00000000000..a7cd565aa46
--- /dev/null
+++ b/src/main/java/seedu/address/model/patient/Condition.java
@@ -0,0 +1,65 @@
+package seedu.address.model.patient;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.AppUtil.checkArgument;
+
+/**
+ * Represents a Patient's condition for a visit.
+ * Guarantees: immutable; is valid as declared in {@link #isValidCondition(String)}
+ */
+public class Condition {
+
+ public static final String MESSAGE_CONSTRAINTS = "Condition can take any values, and it should not be blank";
+
+ /*
+ * The first character of the condition must not be a whitespace,
+ * otherwise " " (a blank string) becomes a valid input.
+ */
+ public static final String VALIDATION_REGEX = "[^\\s].*";
+
+ public final String value;
+
+ /**
+ * Constructs an {@code Condition}.
+ *
+ * @param condition A valid condition.
+ */
+ public Condition(String condition) {
+ requireNonNull(condition);
+ checkArgument(isValidCondition(condition), MESSAGE_CONSTRAINTS);
+ value = condition;
+ }
+
+ /**
+ * Returns true if a given string is a valid condition.
+ */
+ public static boolean isValidCondition(String test) {
+ return test.matches(VALIDATION_REGEX);
+ }
+
+ @Override
+ public String toString() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof Condition)) {
+ return false;
+ }
+
+ Condition otherCondition = (Condition) other;
+ return value.equals(otherCondition.value);
+ }
+
+ @Override
+ public int hashCode() {
+ return value.hashCode();
+ }
+
+}
diff --git a/src/main/java/seedu/address/model/patient/DateOfBirth.java b/src/main/java/seedu/address/model/patient/DateOfBirth.java
new file mode 100644
index 00000000000..958c5d966d8
--- /dev/null
+++ b/src/main/java/seedu/address/model/patient/DateOfBirth.java
@@ -0,0 +1,63 @@
+package seedu.address.model.patient;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.AppUtil.checkArgument;
+
+import java.time.LocalDate;
+
+import seedu.address.logic.parser.DateTimeParser;
+/**
+ * Represents a Patient's date of birth.
+ * Guarantees: immutable; is valid as declared in {@link #isValidDateOfBirth(String)}
+ */
+public class DateOfBirth {
+
+ public static final String MESSAGE_CONSTRAINTS =
+ "Date of birth should only contain numeric values in dd/MM/yyyy or yyyy-MM-dd format, and it should not "
+ + "be left blank";
+
+ public final LocalDate dateOfBirth;
+
+ /**
+ * Constructs a {@code DateOfBirth}.
+ *
+ * @param dateOfBirth A valid date of birth.
+ */
+ public DateOfBirth(String dateOfBirth) {
+ requireNonNull(dateOfBirth);
+ checkArgument(isValidDateOfBirth(dateOfBirth), MESSAGE_CONSTRAINTS);
+ this.dateOfBirth = DateTimeParser.parseDateTime(dateOfBirth);
+ }
+
+ /**
+ * Returns true if a given string is a valid date of birth.
+ */
+ public static boolean isValidDateOfBirth(String test) {
+ return DateTimeParser.parseDateTime(test) == null ? false : true;
+ }
+
+ @Override
+ public String toString() {
+ return DateTimeParser.outputDateTime(dateOfBirth);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof DateOfBirth)) {
+ return false;
+ }
+
+ DateOfBirth otherDateOfBirth = (DateOfBirth) other;
+ return dateOfBirth.equals(otherDateOfBirth.dateOfBirth);
+ }
+
+ @Override
+ public int hashCode() {
+ return dateOfBirth.hashCode();
+ }
+}
diff --git a/src/main/java/seedu/address/model/patient/DateOfVisit.java b/src/main/java/seedu/address/model/patient/DateOfVisit.java
new file mode 100644
index 00000000000..31ce656c037
--- /dev/null
+++ b/src/main/java/seedu/address/model/patient/DateOfVisit.java
@@ -0,0 +1,63 @@
+package seedu.address.model.patient;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.AppUtil.checkArgument;
+
+import java.time.LocalDate;
+
+import seedu.address.logic.parser.DateTimeParser;
+
+/**
+ * Represents a patient's date of visit.
+ * Guarantees: immutable; is valid as declared in {@link #isValidDateOfVisit(String)}
+ */
+public class DateOfVisit {
+ public static final String MESSAGE_CONSTRAINTS =
+ "Date of visit should only contain numeric values in dd/MM/yyyy or yyyy-MM-dd format, "
+ + "and it should not be left blank";
+
+ public final LocalDate dateOfVisit;
+
+ /**
+ * Constructs a {@code DateOfVisit}
+ *
+ * @param dateOfVisit
+ */
+ public DateOfVisit(String dateOfVisit) {
+ requireNonNull(dateOfVisit);
+ checkArgument(isValidDateOfVisit(dateOfVisit), MESSAGE_CONSTRAINTS);
+ this.dateOfVisit = DateTimeParser.parseDateTime(dateOfVisit);
+ }
+
+ /**
+ * Returns true if a given string is a valid date of visit
+ */
+ public static boolean isValidDateOfVisit(String test) {
+ return DateTimeParser.parseDateTime(test) == null ? false : true;
+ }
+
+ @Override
+ public String toString() {
+ return DateTimeParser.outputDateTime(dateOfVisit);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ //instanceof handles nulls
+ if (!(other instanceof DateOfVisit)) {
+ return false;
+ }
+
+ DateOfVisit otherDateOfVisit = (DateOfVisit) other;
+ return dateOfVisit.equals(otherDateOfVisit.dateOfVisit);
+ }
+
+ @Override
+ public int hashCode() {
+ return dateOfVisit.hashCode();
+ }
+}
diff --git a/src/main/java/seedu/address/model/person/Email.java b/src/main/java/seedu/address/model/patient/Email.java
similarity index 97%
rename from src/main/java/seedu/address/model/person/Email.java
rename to src/main/java/seedu/address/model/patient/Email.java
index c62e512bc29..993ca03115d 100644
--- a/src/main/java/seedu/address/model/person/Email.java
+++ b/src/main/java/seedu/address/model/patient/Email.java
@@ -1,10 +1,10 @@
-package seedu.address.model.person;
+package seedu.address.model.patient;
import static java.util.Objects.requireNonNull;
import static seedu.address.commons.util.AppUtil.checkArgument;
/**
- * Represents a Person's email in the address book.
+ * Represents a Patient's email in the list.
* Guarantees: immutable; is valid as declared in {@link #isValidEmail(String)}
*/
public class Email {
diff --git a/src/main/java/seedu/address/model/person/Name.java b/src/main/java/seedu/address/model/patient/Name.java
similarity index 80%
rename from src/main/java/seedu/address/model/person/Name.java
rename to src/main/java/seedu/address/model/patient/Name.java
index 173f15b9b00..899e17f37b8 100644
--- a/src/main/java/seedu/address/model/person/Name.java
+++ b/src/main/java/seedu/address/model/patient/Name.java
@@ -1,22 +1,23 @@
-package seedu.address.model.person;
+package seedu.address.model.patient;
import static java.util.Objects.requireNonNull;
import static seedu.address.commons.util.AppUtil.checkArgument;
/**
- * Represents a Person's name in the address book.
+ * Represents a Patient's name in the list.
* Guarantees: immutable; is valid as declared in {@link #isValidName(String)}
*/
public class Name {
public static final String MESSAGE_CONSTRAINTS =
- "Names should only contain alphanumeric characters and spaces, and it should not be blank";
+ "Names should not be blank, and can only contain letters or a special character (space, "
+ + "slash \nor dash) surrounded by letters.";
/*
* The first character of the address must not be a whitespace,
* otherwise " " (a blank string) becomes a valid input.
*/
- public static final String VALIDATION_REGEX = "[\\p{Alnum}][\\p{Alnum} ]*";
+ public static final String VALIDATION_REGEX = "[A-Za-z](([ -/\\\\][A-Za-z])|[A-Za-z])*";
public final String fullName;
diff --git a/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java b/src/main/java/seedu/address/model/patient/NameContainsKeywordsPredicate.java
similarity index 83%
rename from src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java
rename to src/main/java/seedu/address/model/patient/NameContainsKeywordsPredicate.java
index 62d19be2977..67229e64b6f 100644
--- a/src/main/java/seedu/address/model/person/NameContainsKeywordsPredicate.java
+++ b/src/main/java/seedu/address/model/patient/NameContainsKeywordsPredicate.java
@@ -1,4 +1,4 @@
-package seedu.address.model.person;
+package seedu.address.model.patient;
import java.util.List;
import java.util.function.Predicate;
@@ -7,9 +7,9 @@
import seedu.address.commons.util.ToStringBuilder;
/**
- * Tests that a {@code Person}'s {@code Name} matches any of the keywords given.
+ * Tests that a {@code Patient}'s {@code Name} matches any of the keywords given.
*/
-public class NameContainsKeywordsPredicate implements Predicate {
+public class NameContainsKeywordsPredicate implements Predicate {
private final List keywords;
public NameContainsKeywordsPredicate(List keywords) {
@@ -17,9 +17,9 @@ public NameContainsKeywordsPredicate(List keywords) {
}
@Override
- public boolean test(Person person) {
+ public boolean test(Patient patient) {
return keywords.stream()
- .anyMatch(keyword -> StringUtil.containsWordIgnoreCase(person.getName().fullName, keyword));
+ .anyMatch(keyword -> StringUtil.containsWordIgnoreCase(patient.getName().fullName, keyword));
}
@Override
diff --git a/src/main/java/seedu/address/model/patient/Patient.java b/src/main/java/seedu/address/model/patient/Patient.java
new file mode 100644
index 00000000000..4c2a5b989c1
--- /dev/null
+++ b/src/main/java/seedu/address/model/patient/Patient.java
@@ -0,0 +1,197 @@
+package seedu.address.model.patient;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
+
+import java.util.List;
+import java.util.Objects;
+
+import javafx.collections.ObservableList;
+import seedu.address.commons.util.ToStringBuilder;
+
+/**
+ * Represents a Patient in the list.
+ * Guarantees: details are present and not null, field values are validated, immutable.
+ */
+public class Patient {
+
+ // Identity fields
+ private final Name name;
+ private final Phone phone;
+ private final Email email;
+ private final DateOfBirth dateOfBirth;
+ private final Sex sex;
+
+ // Data fields
+ private final Address address;
+ private final Appointment appointment;
+ private final UniqueVisitList visits;
+
+ /*
+ * The 'unusual' code block below is a non-static initialization block, sometimes used to avoid duplication
+ * between constructors. See https://docs.oracle.com/javase/tutorial/java/javaOO/initial.html
+ *
+ * Note that non-static init blocks are not recommended to use. There are other ways to avoid duplication
+ * among constructors.
+ */
+ {
+ visits = new UniqueVisitList();
+ }
+
+ /**
+ * Every field must be present and not null.
+ */
+ public Patient(Name name, Phone phone, Email email, Address address, DateOfBirth dateOfBirth, Sex sex,
+ Appointment appointment) {
+ requireAllNonNull(name, phone, email, address, dateOfBirth, sex, appointment);
+ this.name = name;
+ this.phone = phone;
+ this.email = email;
+ this.address = address;
+ this.dateOfBirth = dateOfBirth;
+ this.sex = sex;
+ this.appointment = appointment;
+ }
+
+ public Name getName() {
+ return name;
+ }
+
+ public Phone getPhone() {
+ return phone;
+ }
+
+ public Email getEmail() {
+ return email;
+ }
+
+ public Address getAddress() {
+ return address;
+ }
+
+ public DateOfBirth getDateOfBirth() {
+ return dateOfBirth;
+ }
+
+ public Sex getSex() {
+ return sex;
+ }
+
+ public Appointment getAppointment() {
+ return appointment;
+ }
+
+ // Visit operations
+ public ObservableList getVisits() {
+ return visits.asUnmodifiableObservableList();
+ }
+
+ public Visit getLatestVisit() {
+ ObservableList visits = getVisits();
+ return visits.get(visits.size() - 1);
+ }
+
+ /**
+ * Replaces the list of visits with {@code visits}.
+ * {@code visits} must not contain duplicates.
+ */
+ public void setVisits(List visits) {
+ this.visits.setVisits(visits);
+ }
+
+ /**
+ * Returns true if a visit with the same fields as {@code visit} exists for this patient.
+ */
+ public boolean hasVisit(Visit visit) {
+ requireNonNull(visit);
+ return visits.contains(visit);
+ }
+
+ /**
+ * Adds a visit.
+ * The visit must not already exist.
+ */
+ public void addVisit(Visit v) {
+ visits.add(v);
+ }
+
+ /**
+ * Replaces the given visit {@code target} with {@code editedVisit}.
+ * {@code target} must exist.
+ * {@code editedVisit} must not exist.
+ */
+ public void setVisit(Visit target, Visit editedVisit) {
+ requireNonNull(editedVisit);
+
+ visits.setVisit(target, editedVisit);
+ }
+
+ /**
+ * Removes {@code visit} from this {@code Patient}.
+ * {@code visit} must exist.
+ */
+ public void removeVisit(Visit visit) {
+ visits.remove(visit);
+ }
+
+ /**
+ * Returns true if both patients have the same name.
+ * This defines a weaker notion of equality between two patients.
+ */
+ public boolean isSamePatient(Patient otherPatient) {
+ if (otherPatient == this) {
+ return true;
+ }
+
+ return otherPatient != null
+ && otherPatient.getName().equals(getName())
+ && otherPatient.getPhone().equals(getPhone());
+ }
+
+ /**
+ * Returns true if both patients have the same identity and data fields.
+ * This defines a stronger notion of equality between two patients.
+ */
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof Patient)) {
+ return false;
+ }
+
+ Patient otherPatient = (Patient) other;
+ return name.equals(otherPatient.name)
+ && phone.equals(otherPatient.phone)
+ && email.equals(otherPatient.email)
+ && address.equals(otherPatient.address)
+ && dateOfBirth.equals(otherPatient.dateOfBirth)
+ && sex.equals(otherPatient.sex)
+ && appointment.equals(otherPatient.appointment)
+ && visits.equals(otherPatient.visits);
+ }
+
+ @Override
+ public int hashCode() {
+ // use this method for custom fields hashing instead of implementing your own
+ return Objects.hash(name, phone, email, address, dateOfBirth, sex, appointment, visits);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .add("name", name)
+ .add("phone", phone)
+ .add("email", email)
+ .add("address", address)
+ .add("date of birth", dateOfBirth)
+ .add("sex", sex)
+ .add("appointment", appointment)
+ .add("visits", visits)
+ .toString();
+ }
+
+}
diff --git a/src/main/java/seedu/address/model/person/Phone.java b/src/main/java/seedu/address/model/patient/Phone.java
similarity index 93%
rename from src/main/java/seedu/address/model/person/Phone.java
rename to src/main/java/seedu/address/model/patient/Phone.java
index d733f63d739..08f74344f3e 100644
--- a/src/main/java/seedu/address/model/person/Phone.java
+++ b/src/main/java/seedu/address/model/patient/Phone.java
@@ -1,10 +1,10 @@
-package seedu.address.model.person;
+package seedu.address.model.patient;
import static java.util.Objects.requireNonNull;
import static seedu.address.commons.util.AppUtil.checkArgument;
/**
- * Represents a Person's phone number in the address book.
+ * Represents a Patient's phone number in the list.
* Guarantees: immutable; is valid as declared in {@link #isValidPhone(String)}
*/
public class Phone {
diff --git a/src/main/java/seedu/address/model/patient/PhoneMatchesPredicate.java b/src/main/java/seedu/address/model/patient/PhoneMatchesPredicate.java
new file mode 100644
index 00000000000..1b7f29fb773
--- /dev/null
+++ b/src/main/java/seedu/address/model/patient/PhoneMatchesPredicate.java
@@ -0,0 +1,44 @@
+package seedu.address.model.patient;
+
+import java.util.function.Predicate;
+
+import seedu.address.commons.util.ToStringBuilder;
+
+/**
+ * Tests that a {@code Patient}'s {@code Phone} matches the number given.
+ */
+public class PhoneMatchesPredicate implements Predicate {
+ private final Phone phone;
+
+ public PhoneMatchesPredicate(Phone phone) {
+ this.phone = phone;
+ }
+
+ @Override
+ public boolean test(Patient patient) {
+ if (patient == null) {
+ return false;
+ }
+ return patient.getPhone().equals(this.phone);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof PhoneMatchesPredicate)) {
+ return false;
+ }
+
+ PhoneMatchesPredicate otherPhoneMatchesPredicate = (PhoneMatchesPredicate) other;
+ return phone.equals(otherPhoneMatchesPredicate.phone);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this).add("phone", phone).toString();
+ }
+}
diff --git a/src/main/java/seedu/address/model/patient/Severity.java b/src/main/java/seedu/address/model/patient/Severity.java
new file mode 100644
index 00000000000..9e65a068e9d
--- /dev/null
+++ b/src/main/java/seedu/address/model/patient/Severity.java
@@ -0,0 +1,73 @@
+package seedu.address.model.patient;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.AppUtil.checkArgument;
+
+/**
+ * Represents the severity of a patient's visit.
+ * Guarantees: immutable; is valid as declared in {@link #isValidSeverity(String)}
+ */
+public class Severity {
+ public static final String MESSAGE_CONSTRAINTS = "Severity should only be High or Low";
+
+ public final SeverityOption severity;
+
+ /**
+ * Constructs a {@code Severity}.
+ *
+ * @param severity A valid severity.
+ */
+ public Severity(String severity) {
+ requireNonNull(severity);
+ checkArgument(isValidSeverity(severity), MESSAGE_CONSTRAINTS);
+ this.severity = assignSeverity(severity);
+ }
+
+ /**
+ * Returns true if a given string is a valid severity.
+ */
+ public static boolean isValidSeverity(String test) {
+ return test.equals("High") || test.equals("Low") ? true : false;
+ }
+
+ /**
+ * Assign one of SeverityOption, High or Low, depending on the severity input.
+ *
+ * @param severity severity input.
+ * @return one of SeverityOption
+ */
+ public SeverityOption assignSeverity(String severity) {
+ if (severity.equals("High")) {
+ return SeverityOption.HIGH;
+ } else if (severity.equals("Low")) {
+ return SeverityOption.LOW;
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return severity.getLabel();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof Severity)) {
+ return false;
+ }
+
+ Severity otherSeverity = (Severity) other;
+ return severity.equals(otherSeverity.severity);
+ }
+
+ @Override
+ public int hashCode() {
+ return severity.hashCode();
+ }
+}
diff --git a/src/main/java/seedu/address/model/patient/SeverityOption.java b/src/main/java/seedu/address/model/patient/SeverityOption.java
new file mode 100644
index 00000000000..de28c6b0449
--- /dev/null
+++ b/src/main/java/seedu/address/model/patient/SeverityOption.java
@@ -0,0 +1,19 @@
+package seedu.address.model.patient;
+
+/**
+ * Represents one of severity, High or Low.
+ */
+public enum SeverityOption {
+ HIGH("High"),
+ LOW("Low");
+
+ private final String label;
+
+ SeverityOption(String label) {
+ this.label = label;
+ }
+
+ public String getLabel() {
+ return label;
+ }
+}
diff --git a/src/main/java/seedu/address/model/patient/Sex.java b/src/main/java/seedu/address/model/patient/Sex.java
new file mode 100644
index 00000000000..bb837da40bd
--- /dev/null
+++ b/src/main/java/seedu/address/model/patient/Sex.java
@@ -0,0 +1,73 @@
+package seedu.address.model.patient;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.AppUtil.checkArgument;
+
+/**
+ * Represents a Patient's sex in the list.
+ * Guarantees: immutable; is valid as declared in {@link #isValidSex(String)}
+ */
+public class Sex {
+ public static final String MESSAGE_CONSTRAINTS = "Sex should only be Male or Female";
+
+ public final SexOption sex;
+
+ /**
+ * Constructus a {@code Sex}.
+ *
+ * @param sex A valid sex.
+ */
+ public Sex(String sex) {
+ requireNonNull(sex);
+ checkArgument(isValidSex(sex), MESSAGE_CONSTRAINTS);
+ this.sex = assignSex(sex);
+ }
+
+ /**
+ * Returns true if a given string is a valid sex.
+ */
+ public static boolean isValidSex(String test) {
+ return test.equals("Male") || test.equals("Female") ? true : false;
+ }
+
+ /**
+ * Assign one of SexOption, Male or Female, depending on the sex input.
+ *
+ * @param sex sex input.
+ * @return one of SexOption
+ */
+ public SexOption assignSex(String sex) {
+ if (sex.equals("Male")) {
+ return SexOption.MALE;
+ } else if (sex.equals("Female")) {
+ return SexOption.FEMALE;
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return sex.getLabel();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof Sex)) {
+ return false;
+ }
+
+ Sex otherSex = (Sex) other;
+ return sex.equals(otherSex.sex);
+ }
+
+ @Override
+ public int hashCode() {
+ return sex.hashCode();
+ }
+}
diff --git a/src/main/java/seedu/address/model/patient/SexOption.java b/src/main/java/seedu/address/model/patient/SexOption.java
new file mode 100644
index 00000000000..01da62dda0b
--- /dev/null
+++ b/src/main/java/seedu/address/model/patient/SexOption.java
@@ -0,0 +1,19 @@
+package seedu.address.model.patient;
+
+/**
+ * Represents one of sex, Male or Female.
+ */
+public enum SexOption {
+ MALE("Male"),
+ FEMALE("Female");
+
+ private final String label;
+
+ SexOption(String label) {
+ this.label = label;
+ }
+
+ public String getLabel() {
+ return label;
+ }
+}
diff --git a/src/main/java/seedu/address/model/patient/UniquePatientList.java b/src/main/java/seedu/address/model/patient/UniquePatientList.java
new file mode 100644
index 00000000000..ac1b39c2a15
--- /dev/null
+++ b/src/main/java/seedu/address/model/patient/UniquePatientList.java
@@ -0,0 +1,150 @@
+package seedu.address.model.patient;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
+
+import java.util.Iterator;
+import java.util.List;
+
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import seedu.address.model.patient.exceptions.DuplicatePatientException;
+import seedu.address.model.patient.exceptions.PatientNotFoundException;
+
+/**
+ * A list of patients that enforces uniqueness between its elements and does not allow nulls.
+ * A patient is considered unique by comparing using {@code Patient#isSamePatient(Patient)}. As such,
+ * adding and updating of patients uses Patient#isSamePatient(Patient) for equality to ensure that the patient
+ * being added or updated is unique in terms of identity in the UniquePatientList. However, the removal of a patient
+ * uses Patient#equals(Object) to ensure that the patient with exactly the same fields will be removed.
+ *
+ * Supports a minimal set of list operations.
+ *
+ * @see Patient#isSamePatient(Patient)
+ */
+public class UniquePatientList implements Iterable {
+
+ private final ObservableList internalList = FXCollections.observableArrayList();
+ private final ObservableList internalUnmodifiableList =
+ FXCollections.unmodifiableObservableList(internalList);
+
+ /**
+ * Returns true if the list contains an equivalent patient as the given argument.
+ */
+ public boolean contains(Patient toCheck) {
+ requireNonNull(toCheck);
+ return internalList.stream().anyMatch(toCheck::isSamePatient);
+ }
+
+ /**
+ * Adds a patient to the list.
+ * The patient must not already exist in the list.
+ */
+ public void add(Patient toAdd) {
+ requireNonNull(toAdd);
+ if (contains(toAdd)) {
+ throw new DuplicatePatientException();
+ }
+ internalList.add(toAdd);
+ }
+
+ /**
+ * Replaces the patient {@code target} in the list with {@code editedPatient}.
+ * {@code target} must exist in the list.
+ * The patient identity of {@code editedPatient} must not be the same as another existing patient in the list.
+ */
+ public void setPatient(Patient target, Patient editedPatient) {
+ requireAllNonNull(target, editedPatient);
+
+ int index = internalList.indexOf(target);
+ if (index == -1) {
+ throw new PatientNotFoundException();
+ }
+
+ if (!target.isSamePatient(editedPatient) && contains(editedPatient)) {
+ throw new DuplicatePatientException();
+ }
+
+ internalList.set(index, editedPatient);
+ }
+
+ /**
+ * Removes the equivalent patient from the list.
+ * The patient must exist in the list.
+ */
+ public void remove(Patient toRemove) {
+ requireNonNull(toRemove);
+ if (!internalList.remove(toRemove)) {
+ throw new PatientNotFoundException();
+ }
+ }
+
+ public void setPatients(UniquePatientList replacement) {
+ requireNonNull(replacement);
+ internalList.setAll(replacement.internalList);
+ }
+
+ /**
+ * Replaces the contents of this list with {@code patients}.
+ * {@code patients} must not contain duplicate patients.
+ */
+ public void setPatients(List patients) {
+ requireAllNonNull(patients);
+ if (!patientsAreUnique(patients)) {
+ throw new DuplicatePatientException();
+ }
+
+ internalList.setAll(patients);
+ }
+
+ /**
+ * Returns the backing list as an unmodifiable {@code ObservableList}.
+ */
+ public ObservableList asUnmodifiableObservableList() {
+ return internalUnmodifiableList;
+ }
+
+ @Override
+ public Iterator iterator() {
+ return internalList.iterator();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof UniquePatientList)) {
+ return false;
+ }
+
+ UniquePatientList otherUniquePatientList = (UniquePatientList) other;
+ return internalList.equals(otherUniquePatientList.internalList);
+ }
+
+ @Override
+ public int hashCode() {
+ return internalList.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return internalList.toString();
+ }
+
+ /**
+ * Returns true if {@code patients} contains only unique patients.
+ */
+ private boolean patientsAreUnique(List patients) {
+ for (int i = 0; i < patients.size() - 1; i++) {
+ for (int j = i + 1; j < patients.size(); j++) {
+ if (patients.get(i).isSamePatient(patients.get(j))) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+}
diff --git a/src/main/java/seedu/address/model/patient/UniqueVisitList.java b/src/main/java/seedu/address/model/patient/UniqueVisitList.java
new file mode 100644
index 00000000000..2f30b4a8117
--- /dev/null
+++ b/src/main/java/seedu/address/model/patient/UniqueVisitList.java
@@ -0,0 +1,146 @@
+package seedu.address.model.patient;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
+
+import java.util.Iterator;
+import java.util.List;
+
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import seedu.address.model.patient.exceptions.DuplicateVisitException;
+import seedu.address.model.patient.exceptions.VisitNotFoundException;
+
+/**
+ * A list of visits that enforces uniqueness between its elements and does not allow nulls.
+ * A visit is considered unique by comparing using {@code Visit#equals(Object)}.
+ *
+ * Supports a minimal set of list operations.
+ */
+public class UniqueVisitList implements Iterable {
+
+ private final ObservableList internalList = FXCollections.observableArrayList();
+ private final ObservableList internalUnmodifiableList =
+ FXCollections.unmodifiableObservableList(internalList);
+
+ /**
+ * Returns true if the list contains an equivalent visit as the given argument.
+ */
+ public boolean contains(Visit toCheck) {
+ requireNonNull(toCheck);
+ return internalList.stream().anyMatch(toCheck::equals);
+ }
+
+ /**
+ * Adds a visit to the end of the list.
+ * The visit must not already exist in the list.
+ */
+ public void add(Visit toAdd) {
+ requireNonNull(toAdd);
+ if (contains(toAdd)) {
+ throw new DuplicateVisitException();
+ }
+ internalList.add(toAdd);
+ }
+
+ /**
+ * Replaces the visit {@code target} in the list with {@code editedVisit}.
+ * {@code target} must exist in the list.
+ * {@code editedVisit} must not already be in the list.
+ */
+ public void setVisit(Visit target, Visit editedVisit) {
+ requireAllNonNull(target, editedVisit);
+
+ int index = internalList.indexOf(target);
+ if (index == -1) {
+ throw new VisitNotFoundException();
+ }
+
+ if (!target.equals(editedVisit) && contains(editedVisit)) {
+ throw new DuplicateVisitException();
+ }
+
+ internalList.set(index, editedVisit);
+ }
+
+ /**
+ * Removes the equivalent visit from the list.
+ * The visit must exist in the list.
+ */
+ public void remove(Visit toRemove) {
+ requireNonNull(toRemove);
+ if (!internalList.remove(toRemove)) {
+ throw new VisitNotFoundException();
+ }
+ }
+
+ public void setVisits(UniqueVisitList replacement) {
+ requireNonNull(replacement);
+ internalList.setAll(replacement.internalList);
+ }
+
+ /**
+ * Replaces the contents of this list with {@code visits}.
+ * {@code visits} must not contain duplicate patients.
+ */
+ public void setVisits(List visits) {
+ requireAllNonNull(visits);
+ if (!visitsAreUnique(visits)) {
+ throw new DuplicateVisitException();
+ }
+
+ internalList.setAll(visits);
+ }
+
+ /**
+ * Returns the backing list as an unmodifiable {@code ObservableList}.
+ */
+ public ObservableList asUnmodifiableObservableList() {
+ return internalUnmodifiableList;
+ }
+
+ @Override
+ public Iterator iterator() {
+ return internalList.iterator();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof UniqueVisitList)) {
+ return false;
+ }
+
+ UniqueVisitList otherUniqueVisitList = (UniqueVisitList) other;
+ return internalList.equals(otherUniqueVisitList.internalList);
+ }
+
+ @Override
+ public int hashCode() {
+ return internalList.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return internalList.toString();
+ }
+
+ /**
+ * Returns true if {@code visits} contains only unique visits.
+ */
+ private boolean visitsAreUnique(List visits) {
+ for (int i = 0; i < visits.size() - 1; i++) {
+ for (int j = i + 1; j < visits.size(); j++) {
+ if (visits.get(i).equals(visits.get(j))) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+}
+
diff --git a/src/main/java/seedu/address/model/patient/Visit.java b/src/main/java/seedu/address/model/patient/Visit.java
new file mode 100644
index 00000000000..b111f1b01c9
--- /dev/null
+++ b/src/main/java/seedu/address/model/patient/Visit.java
@@ -0,0 +1,72 @@
+package seedu.address.model.patient;
+
+import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
+
+import java.util.Objects;
+
+import seedu.address.commons.util.ToStringBuilder;
+
+/**
+ * Represents an instance of a Patient's visit.
+ * Guarantees: details are present and not null, field values are validated, immutable.
+ */
+public class Visit {
+
+ private final Condition condition;
+ private final Severity severity;
+ private final DateOfVisit dateOfVisit;
+
+ /**
+ * Every field must be present and not null.
+ */
+ public Visit(Condition condition, Severity severity, DateOfVisit dateOfVisit) {
+ requireAllNonNull(condition, severity, dateOfVisit);
+ this.condition = condition;
+ this.severity = severity;
+ this.dateOfVisit = dateOfVisit;
+ }
+
+ public Condition getCondition() {
+ return condition;
+ }
+
+ public Severity getSeverity() {
+ return severity;
+ }
+
+ public DateOfVisit getDateOfVisit() {
+ return dateOfVisit;
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .add("condition", condition)
+ .add("severity", severity)
+ .add("date of visit", dateOfVisit)
+ .toString();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof Visit)) {
+ return false;
+ }
+
+ Visit otherVisit = (Visit) other;
+ return condition.equals(otherVisit.condition)
+ && severity.equals(otherVisit.severity)
+ && dateOfVisit.equals(otherVisit.dateOfVisit);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(condition, severity, dateOfVisit);
+ }
+
+}
diff --git a/src/main/java/seedu/address/model/patient/exceptions/DuplicatePatientException.java b/src/main/java/seedu/address/model/patient/exceptions/DuplicatePatientException.java
new file mode 100644
index 00000000000..850a5b934f7
--- /dev/null
+++ b/src/main/java/seedu/address/model/patient/exceptions/DuplicatePatientException.java
@@ -0,0 +1,11 @@
+package seedu.address.model.patient.exceptions;
+
+/**
+ * Signals that the operation will result in duplicate Patients (Patients are considered duplicates if they have the
+ * same identity).
+ */
+public class DuplicatePatientException extends RuntimeException {
+ public DuplicatePatientException() {
+ super("Operation would result in duplicate patients");
+ }
+}
diff --git a/src/main/java/seedu/address/model/patient/exceptions/DuplicateVisitException.java b/src/main/java/seedu/address/model/patient/exceptions/DuplicateVisitException.java
new file mode 100644
index 00000000000..5a8e1c202ec
--- /dev/null
+++ b/src/main/java/seedu/address/model/patient/exceptions/DuplicateVisitException.java
@@ -0,0 +1,11 @@
+package seedu.address.model.patient.exceptions;
+
+/**
+ * Signals that the operation will result in duplicate Visits (Visits are considered duplicates if they have the
+ * same value in their fields).
+ */
+public class DuplicateVisitException extends RuntimeException {
+ public DuplicateVisitException() {
+ super("Operation would result in duplicate visits");
+ }
+}
diff --git a/src/main/java/seedu/address/model/patient/exceptions/PatientNotFoundException.java b/src/main/java/seedu/address/model/patient/exceptions/PatientNotFoundException.java
new file mode 100644
index 00000000000..681e9fe0af0
--- /dev/null
+++ b/src/main/java/seedu/address/model/patient/exceptions/PatientNotFoundException.java
@@ -0,0 +1,6 @@
+package seedu.address.model.patient.exceptions;
+
+/**
+ * Signals that the operation is unable to find the specified patient.
+ */
+public class PatientNotFoundException extends RuntimeException {}
diff --git a/src/main/java/seedu/address/model/patient/exceptions/VisitNotFoundException.java b/src/main/java/seedu/address/model/patient/exceptions/VisitNotFoundException.java
new file mode 100644
index 00000000000..ce56b834baa
--- /dev/null
+++ b/src/main/java/seedu/address/model/patient/exceptions/VisitNotFoundException.java
@@ -0,0 +1,6 @@
+package seedu.address.model.patient.exceptions;
+
+/**
+ * Signals that the operation is unable to find the specified visit.
+ */
+public class VisitNotFoundException extends RuntimeException {}
diff --git a/src/main/java/seedu/address/model/person/Person.java b/src/main/java/seedu/address/model/person/Person.java
deleted file mode 100644
index abe8c46b535..00000000000
--- a/src/main/java/seedu/address/model/person/Person.java
+++ /dev/null
@@ -1,117 +0,0 @@
-package seedu.address.model.person;
-
-import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Objects;
-import java.util.Set;
-
-import seedu.address.commons.util.ToStringBuilder;
-import seedu.address.model.tag.Tag;
-
-/**
- * Represents a Person in the address book.
- * Guarantees: details are present and not null, field values are validated, immutable.
- */
-public class Person {
-
- // Identity fields
- private final Name name;
- private final Phone phone;
- private final Email email;
-
- // Data fields
- private final Address address;
- private final Set tags = new HashSet<>();
-
- /**
- * Every field must be present and not null.
- */
- public Person(Name name, Phone phone, Email email, Address address, Set tags) {
- requireAllNonNull(name, phone, email, address, tags);
- this.name = name;
- this.phone = phone;
- this.email = email;
- this.address = address;
- this.tags.addAll(tags);
- }
-
- public Name getName() {
- return name;
- }
-
- public Phone getPhone() {
- return phone;
- }
-
- public Email getEmail() {
- return email;
- }
-
- public Address getAddress() {
- return address;
- }
-
- /**
- * Returns an immutable tag set, which throws {@code UnsupportedOperationException}
- * if modification is attempted.
- */
- public Set getTags() {
- return Collections.unmodifiableSet(tags);
- }
-
- /**
- * Returns true if both persons have the same name.
- * This defines a weaker notion of equality between two persons.
- */
- public boolean isSamePerson(Person otherPerson) {
- if (otherPerson == this) {
- return true;
- }
-
- return otherPerson != null
- && otherPerson.getName().equals(getName());
- }
-
- /**
- * Returns true if both persons have the same identity and data fields.
- * This defines a stronger notion of equality between two persons.
- */
- @Override
- public boolean equals(Object other) {
- if (other == this) {
- return true;
- }
-
- // instanceof handles nulls
- if (!(other instanceof Person)) {
- return false;
- }
-
- Person otherPerson = (Person) other;
- return name.equals(otherPerson.name)
- && phone.equals(otherPerson.phone)
- && email.equals(otherPerson.email)
- && address.equals(otherPerson.address)
- && tags.equals(otherPerson.tags);
- }
-
- @Override
- public int hashCode() {
- // use this method for custom fields hashing instead of implementing your own
- return Objects.hash(name, phone, email, address, tags);
- }
-
- @Override
- public String toString() {
- return new ToStringBuilder(this)
- .add("name", name)
- .add("phone", phone)
- .add("email", email)
- .add("address", address)
- .add("tags", tags)
- .toString();
- }
-
-}
diff --git a/src/main/java/seedu/address/model/person/UniquePersonList.java b/src/main/java/seedu/address/model/person/UniquePersonList.java
deleted file mode 100644
index cc0a68d79f9..00000000000
--- a/src/main/java/seedu/address/model/person/UniquePersonList.java
+++ /dev/null
@@ -1,150 +0,0 @@
-package seedu.address.model.person;
-
-import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
-
-import java.util.Iterator;
-import java.util.List;
-
-import javafx.collections.FXCollections;
-import javafx.collections.ObservableList;
-import seedu.address.model.person.exceptions.DuplicatePersonException;
-import seedu.address.model.person.exceptions.PersonNotFoundException;
-
-/**
- * A list of persons that enforces uniqueness between its elements and does not allow nulls.
- * A person is considered unique by comparing using {@code Person#isSamePerson(Person)}. As such, adding and updating of
- * persons uses Person#isSamePerson(Person) for equality so as to ensure that the person being added or updated is
- * unique in terms of identity in the UniquePersonList. However, the removal of a person uses Person#equals(Object) so
- * as to ensure that the person with exactly the same fields will be removed.
- *
- * Supports a minimal set of list operations.
- *
- * @see Person#isSamePerson(Person)
- */
-public class UniquePersonList implements Iterable {
-
- private final ObservableList internalList = FXCollections.observableArrayList();
- private final ObservableList internalUnmodifiableList =
- FXCollections.unmodifiableObservableList(internalList);
-
- /**
- * Returns true if the list contains an equivalent person as the given argument.
- */
- public boolean contains(Person toCheck) {
- requireNonNull(toCheck);
- return internalList.stream().anyMatch(toCheck::isSamePerson);
- }
-
- /**
- * Adds a person to the list.
- * The person must not already exist in the list.
- */
- public void add(Person toAdd) {
- requireNonNull(toAdd);
- if (contains(toAdd)) {
- throw new DuplicatePersonException();
- }
- internalList.add(toAdd);
- }
-
- /**
- * Replaces the person {@code target} in the list with {@code editedPerson}.
- * {@code target} must exist in the list.
- * The person identity of {@code editedPerson} must not be the same as another existing person in the list.
- */
- public void setPerson(Person target, Person editedPerson) {
- requireAllNonNull(target, editedPerson);
-
- int index = internalList.indexOf(target);
- if (index == -1) {
- throw new PersonNotFoundException();
- }
-
- if (!target.isSamePerson(editedPerson) && contains(editedPerson)) {
- throw new DuplicatePersonException();
- }
-
- internalList.set(index, editedPerson);
- }
-
- /**
- * Removes the equivalent person from the list.
- * The person must exist in the list.
- */
- public void remove(Person toRemove) {
- requireNonNull(toRemove);
- if (!internalList.remove(toRemove)) {
- throw new PersonNotFoundException();
- }
- }
-
- public void setPersons(UniquePersonList replacement) {
- requireNonNull(replacement);
- internalList.setAll(replacement.internalList);
- }
-
- /**
- * Replaces the contents of this list with {@code persons}.
- * {@code persons} must not contain duplicate persons.
- */
- public void setPersons(List persons) {
- requireAllNonNull(persons);
- if (!personsAreUnique(persons)) {
- throw new DuplicatePersonException();
- }
-
- internalList.setAll(persons);
- }
-
- /**
- * Returns the backing list as an unmodifiable {@code ObservableList}.
- */
- public ObservableList asUnmodifiableObservableList() {
- return internalUnmodifiableList;
- }
-
- @Override
- public Iterator iterator() {
- return internalList.iterator();
- }
-
- @Override
- public boolean equals(Object other) {
- if (other == this) {
- return true;
- }
-
- // instanceof handles nulls
- if (!(other instanceof UniquePersonList)) {
- return false;
- }
-
- UniquePersonList otherUniquePersonList = (UniquePersonList) other;
- return internalList.equals(otherUniquePersonList.internalList);
- }
-
- @Override
- public int hashCode() {
- return internalList.hashCode();
- }
-
- @Override
- public String toString() {
- return internalList.toString();
- }
-
- /**
- * Returns true if {@code persons} contains only unique persons.
- */
- private boolean personsAreUnique(List persons) {
- for (int i = 0; i < persons.size() - 1; i++) {
- for (int j = i + 1; j < persons.size(); j++) {
- if (persons.get(i).isSamePerson(persons.get(j))) {
- return false;
- }
- }
- }
- return true;
- }
-}
diff --git a/src/main/java/seedu/address/model/person/exceptions/DuplicatePersonException.java b/src/main/java/seedu/address/model/person/exceptions/DuplicatePersonException.java
deleted file mode 100644
index d7290f59442..00000000000
--- a/src/main/java/seedu/address/model/person/exceptions/DuplicatePersonException.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package seedu.address.model.person.exceptions;
-
-/**
- * Signals that the operation will result in duplicate Persons (Persons are considered duplicates if they have the same
- * identity).
- */
-public class DuplicatePersonException extends RuntimeException {
- public DuplicatePersonException() {
- super("Operation would result in duplicate persons");
- }
-}
diff --git a/src/main/java/seedu/address/model/person/exceptions/PersonNotFoundException.java b/src/main/java/seedu/address/model/person/exceptions/PersonNotFoundException.java
deleted file mode 100644
index fa764426ca7..00000000000
--- a/src/main/java/seedu/address/model/person/exceptions/PersonNotFoundException.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package seedu.address.model.person.exceptions;
-
-/**
- * Signals that the operation is unable to find the specified person.
- */
-public class PersonNotFoundException extends RuntimeException {}
diff --git a/src/main/java/seedu/address/model/tag/Tag.java b/src/main/java/seedu/address/model/tag/Tag.java
deleted file mode 100644
index f1a0d4e233b..00000000000
--- a/src/main/java/seedu/address/model/tag/Tag.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package seedu.address.model.tag;
-
-import static java.util.Objects.requireNonNull;
-import static seedu.address.commons.util.AppUtil.checkArgument;
-
-/**
- * Represents a Tag in the address book.
- * Guarantees: immutable; name is valid as declared in {@link #isValidTagName(String)}
- */
-public class Tag {
-
- public static final String MESSAGE_CONSTRAINTS = "Tags names should be alphanumeric";
- public static final String VALIDATION_REGEX = "\\p{Alnum}+";
-
- public final String tagName;
-
- /**
- * Constructs a {@code Tag}.
- *
- * @param tagName A valid tag name.
- */
- public Tag(String tagName) {
- requireNonNull(tagName);
- checkArgument(isValidTagName(tagName), MESSAGE_CONSTRAINTS);
- this.tagName = tagName;
- }
-
- /**
- * Returns true if a given string is a valid tag name.
- */
- public static boolean isValidTagName(String test) {
- return test.matches(VALIDATION_REGEX);
- }
-
- @Override
- public boolean equals(Object other) {
- if (other == this) {
- return true;
- }
-
- // instanceof handles nulls
- if (!(other instanceof Tag)) {
- return false;
- }
-
- Tag otherTag = (Tag) other;
- return tagName.equals(otherTag.tagName);
- }
-
- @Override
- public int hashCode() {
- return tagName.hashCode();
- }
-
- /**
- * Format state as text for viewing.
- */
- public String toString() {
- return '[' + tagName + ']';
- }
-
-}
diff --git a/src/main/java/seedu/address/model/util/SampleDataUtil.java b/src/main/java/seedu/address/model/util/SampleDataUtil.java
index 1806da4facf..9ab92663997 100644
--- a/src/main/java/seedu/address/model/util/SampleDataUtil.java
+++ b/src/main/java/seedu/address/model/util/SampleDataUtil.java
@@ -1,60 +1,48 @@
package seedu.address.model.util;
-import java.util.Arrays;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-import seedu.address.model.AddressBook;
-import seedu.address.model.ReadOnlyAddressBook;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
+import seedu.address.model.PatientList;
+import seedu.address.model.ReadOnlyPatientList;
+import seedu.address.model.patient.Address;
+import seedu.address.model.patient.Appointment;
+import seedu.address.model.patient.DateOfBirth;
+import seedu.address.model.patient.Email;
+import seedu.address.model.patient.Name;
+import seedu.address.model.patient.Patient;
+import seedu.address.model.patient.Phone;
+import seedu.address.model.patient.Sex;
/**
- * Contains utility methods for populating {@code AddressBook} with sample data.
+ * Contains utility methods for populating {@code PatientList} with sample data.
*/
public class SampleDataUtil {
- public static Person[] getSamplePersons() {
- return new Person[] {
- new Person(new Name("Alex Yeoh"), new Phone("87438807"), new Email("alexyeoh@example.com"),
+ public static Patient[] getSamplePatients() {
+ return new Patient[] {
+ new Patient(new Name("Alex Yeoh"), new Phone("87438807"), new Email("alexyeoh@example.com"),
new Address("Blk 30 Geylang Street 29, #06-40"),
- getTagSet("friends")),
- new Person(new Name("Bernice Yu"), new Phone("99272758"), new Email("berniceyu@example.com"),
+ new DateOfBirth("25/2/2024"), new Sex("Male"), new Appointment("")),
+ new Patient(new Name("Bernice Yu"), new Phone("99272758"), new Email("berniceyu@example.com"),
new Address("Blk 30 Lorong 3 Serangoon Gardens, #07-18"),
- getTagSet("colleagues", "friends")),
- new Person(new Name("Charlotte Oliveiro"), new Phone("93210283"), new Email("charlotte@example.com"),
+ new DateOfBirth("2024-2-25"), new Sex("Female"), new Appointment("2025-12-23")),
+ new Patient(new Name("Charlotte Oliveiro"), new Phone("93210283"), new Email("charlotte@example.com"),
new Address("Blk 11 Ang Mo Kio Street 74, #11-04"),
- getTagSet("neighbours")),
- new Person(new Name("David Li"), new Phone("91031282"), new Email("lidavid@example.com"),
+ new DateOfBirth("12/12/2024"), new Sex("Female"), new Appointment("")),
+ new Patient(new Name("David Li"), new Phone("91031282"), new Email("lidavid@example.com"),
new Address("Blk 436 Serangoon Gardens Street 26, #16-43"),
- getTagSet("family")),
- new Person(new Name("Irfan Ibrahim"), new Phone("92492021"), new Email("irfan@example.com"),
+ new DateOfBirth("25/2/2024"), new Sex("Male"), new Appointment("")),
+ new Patient(new Name("Irfan Ibrahim"), new Phone("92492021"), new Email("irfan@example.com"),
new Address("Blk 47 Tampines Street 20, #17-35"),
- getTagSet("classmates")),
- new Person(new Name("Roy Balakrishnan"), new Phone("92624417"), new Email("royb@example.com"),
+ new DateOfBirth("25/2/2024"), new Sex("Male"), new Appointment("25/2/2024")),
+ new Patient(new Name("Roy Balakrishnan"), new Phone("92624417"), new Email("royb@example.com"),
new Address("Blk 45 Aljunied Street 85, #11-31"),
- getTagSet("colleagues"))
+ new DateOfBirth("25/2/2024"), new Sex("Male"), new Appointment("")),
};
}
- public static ReadOnlyAddressBook getSampleAddressBook() {
- AddressBook sampleAb = new AddressBook();
- for (Person samplePerson : getSamplePersons()) {
- sampleAb.addPerson(samplePerson);
+ public static ReadOnlyPatientList getSamplePatientList() {
+ PatientList sampleList = new PatientList();
+ for (Patient samplePatient : getSamplePatients()) {
+ sampleList.addPatient(samplePatient);
}
- return sampleAb;
- }
-
- /**
- * Returns a tag set containing the list of strings given.
- */
- public static Set getTagSet(String... strings) {
- return Arrays.stream(strings)
- .map(Tag::new)
- .collect(Collectors.toSet());
+ return sampleList;
}
-
}
diff --git a/src/main/java/seedu/address/storage/AddressBookStorage.java b/src/main/java/seedu/address/storage/AddressBookStorage.java
deleted file mode 100644
index f2e015105ae..00000000000
--- a/src/main/java/seedu/address/storage/AddressBookStorage.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package seedu.address.storage;
-
-import java.io.IOException;
-import java.nio.file.Path;
-import java.util.Optional;
-
-import seedu.address.commons.exceptions.DataLoadingException;
-import seedu.address.model.ReadOnlyAddressBook;
-
-/**
- * Represents a storage for {@link seedu.address.model.AddressBook}.
- */
-public interface AddressBookStorage {
-
- /**
- * Returns the file path of the data file.
- */
- Path getAddressBookFilePath();
-
- /**
- * Returns AddressBook data as a {@link ReadOnlyAddressBook}.
- * Returns {@code Optional.empty()} if storage file is not found.
- *
- * @throws DataLoadingException if loading the data from storage failed.
- */
- Optional readAddressBook() throws DataLoadingException;
-
- /**
- * @see #getAddressBookFilePath()
- */
- Optional readAddressBook(Path filePath) throws DataLoadingException;
-
- /**
- * Saves the given {@link ReadOnlyAddressBook} to the storage.
- * @param addressBook cannot be null.
- * @throws IOException if there was any problem writing to the file.
- */
- void saveAddressBook(ReadOnlyAddressBook addressBook) throws IOException;
-
- /**
- * @see #saveAddressBook(ReadOnlyAddressBook)
- */
- void saveAddressBook(ReadOnlyAddressBook addressBook, Path filePath) throws IOException;
-
-}
diff --git a/src/main/java/seedu/address/storage/JsonAdaptedPatient.java b/src/main/java/seedu/address/storage/JsonAdaptedPatient.java
new file mode 100644
index 00000000000..de779a1e028
--- /dev/null
+++ b/src/main/java/seedu/address/storage/JsonAdaptedPatient.java
@@ -0,0 +1,147 @@
+package seedu.address.storage;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import seedu.address.commons.exceptions.IllegalValueException;
+import seedu.address.model.patient.Address;
+import seedu.address.model.patient.Appointment;
+import seedu.address.model.patient.DateOfBirth;
+import seedu.address.model.patient.Email;
+import seedu.address.model.patient.Name;
+import seedu.address.model.patient.Patient;
+import seedu.address.model.patient.Phone;
+import seedu.address.model.patient.Sex;
+import seedu.address.model.patient.Visit;
+
+/**
+ * Jackson-friendly version of {@link Patient}.
+ */
+class JsonAdaptedPatient {
+
+ public static final String MISSING_FIELD_MESSAGE_FORMAT = "Patient's %s field is missing!";
+ public static final String MESSAGE_DUPLICATE_VISIT = "Patient has duplicate visit(s).";
+
+ private final String name;
+ private final String phone;
+ private final String email;
+ private final String address;
+ private final String dateOfBirth;
+ private final String sex;
+ private final String appointment;
+ private final List visits = new ArrayList<>();
+
+ /**
+ * Constructs a {@code JsonAdaptedPatient} with the given patient details.
+ */
+ @JsonCreator
+ public JsonAdaptedPatient(@JsonProperty("name") String name, @JsonProperty("phone") String phone,
+ @JsonProperty("email") String email, @JsonProperty("address") String address,
+ @JsonProperty("date of birth") String dateOfBirth,
+ @JsonProperty("sex") String sex, @JsonProperty("appointment") String appointment,
+ @JsonProperty("visits") List visits) {
+ this.name = name;
+ this.phone = phone;
+ this.email = email;
+ this.address = address;
+ this.dateOfBirth = dateOfBirth;
+ this.sex = sex;
+ this.appointment = appointment;
+ this.visits.addAll(visits);
+ }
+
+ /**
+ * Converts a given {@code Patient} into this class for Jackson use.
+ */
+ public JsonAdaptedPatient(Patient source) {
+ name = source.getName().fullName;
+ phone = source.getPhone().value;
+ email = source.getEmail().value;
+ address = source.getAddress().value;
+ dateOfBirth = source.getDateOfBirth().dateOfBirth.toString();
+ sex = source.getSex().sex.getLabel();
+ appointment = source.getAppointment().appointment == null ? "" : source.getAppointment().appointment.toString();
+ visits.addAll(source.getVisits().stream().map(JsonAdaptedVisit::new).collect(Collectors.toList()));
+ }
+
+ /**
+ * Converts this Jackson-friendly adapted patient object into the model's {@code Patient} object.
+ *
+ * @throws IllegalValueException if there were any data constraints violated in the adapted patient.
+ */
+ public Patient toModelType() throws IllegalValueException {
+
+ if (name == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Name.class.getSimpleName()));
+ }
+ if (!Name.isValidName(name)) {
+ throw new IllegalValueException(Name.MESSAGE_CONSTRAINTS);
+ }
+ final Name modelName = new Name(name);
+
+ if (phone == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Phone.class.getSimpleName()));
+ }
+ if (!Phone.isValidPhone(phone)) {
+ throw new IllegalValueException(Phone.MESSAGE_CONSTRAINTS);
+ }
+ final Phone modelPhone = new Phone(phone);
+
+ if (email == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Email.class.getSimpleName()));
+ }
+ if (!Email.isValidEmail(email)) {
+ throw new IllegalValueException(Email.MESSAGE_CONSTRAINTS);
+ }
+ final Email modelEmail = new Email(email);
+
+ if (address == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Address.class.getSimpleName()));
+ }
+ if (!Address.isValidAddress(address)) {
+ throw new IllegalValueException(Address.MESSAGE_CONSTRAINTS);
+ }
+ final Address modelAddress = new Address(address);
+
+ if (dateOfBirth == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT,
+ DateOfBirth.class.getSimpleName()));
+ }
+ if (!DateOfBirth.isValidDateOfBirth(dateOfBirth)) {
+ throw new IllegalValueException(DateOfBirth.MESSAGE_CONSTRAINTS);
+ }
+ final DateOfBirth modelDateOfBirth = new DateOfBirth(dateOfBirth);
+
+ if (sex == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT,
+ Sex.class.getSimpleName()));
+ }
+ if (!Sex.isValidSex(sex)) {
+ throw new IllegalValueException(Sex.MESSAGE_CONSTRAINTS);
+ }
+ final Sex modelSex = new Sex(sex);
+
+ if (!Appointment.isValidAppointment(appointment)) {
+ throw new IllegalValueException(Appointment.MESSAGE_CONSTRAINTS);
+ }
+ final Appointment modelAppointment = new Appointment(appointment);
+
+ Patient patient = new Patient(modelName, modelPhone, modelEmail, modelAddress, modelDateOfBirth, modelSex,
+ modelAppointment);
+
+ for (JsonAdaptedVisit jsonAdaptedVisit : visits) {
+ Visit visit = jsonAdaptedVisit.toModelType();
+ if (patient.hasVisit(visit)) {
+ throw new IllegalValueException(MESSAGE_DUPLICATE_VISIT);
+ }
+ patient.addVisit(visit);
+ }
+
+ return patient;
+ }
+
+}
diff --git a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java b/src/main/java/seedu/address/storage/JsonAdaptedPerson.java
deleted file mode 100644
index bd1ca0f56c8..00000000000
--- a/src/main/java/seedu/address/storage/JsonAdaptedPerson.java
+++ /dev/null
@@ -1,109 +0,0 @@
-package seedu.address.storage;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
-import seedu.address.commons.exceptions.IllegalValueException;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
-
-/**
- * Jackson-friendly version of {@link Person}.
- */
-class JsonAdaptedPerson {
-
- public static final String MISSING_FIELD_MESSAGE_FORMAT = "Person's %s field is missing!";
-
- private final String name;
- private final String phone;
- private final String email;
- private final String address;
- private final List tags = new ArrayList<>();
-
- /**
- * Constructs a {@code JsonAdaptedPerson} with the given person details.
- */
- @JsonCreator
- public JsonAdaptedPerson(@JsonProperty("name") String name, @JsonProperty("phone") String phone,
- @JsonProperty("email") String email, @JsonProperty("address") String address,
- @JsonProperty("tags") List tags) {
- this.name = name;
- this.phone = phone;
- this.email = email;
- this.address = address;
- if (tags != null) {
- this.tags.addAll(tags);
- }
- }
-
- /**
- * Converts a given {@code Person} into this class for Jackson use.
- */
- public JsonAdaptedPerson(Person source) {
- name = source.getName().fullName;
- phone = source.getPhone().value;
- email = source.getEmail().value;
- address = source.getAddress().value;
- tags.addAll(source.getTags().stream()
- .map(JsonAdaptedTag::new)
- .collect(Collectors.toList()));
- }
-
- /**
- * Converts this Jackson-friendly adapted person object into the model's {@code Person} object.
- *
- * @throws IllegalValueException if there were any data constraints violated in the adapted person.
- */
- public Person toModelType() throws IllegalValueException {
- final List personTags = new ArrayList<>();
- for (JsonAdaptedTag tag : tags) {
- personTags.add(tag.toModelType());
- }
-
- if (name == null) {
- throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Name.class.getSimpleName()));
- }
- if (!Name.isValidName(name)) {
- throw new IllegalValueException(Name.MESSAGE_CONSTRAINTS);
- }
- final Name modelName = new Name(name);
-
- if (phone == null) {
- throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Phone.class.getSimpleName()));
- }
- if (!Phone.isValidPhone(phone)) {
- throw new IllegalValueException(Phone.MESSAGE_CONSTRAINTS);
- }
- final Phone modelPhone = new Phone(phone);
-
- if (email == null) {
- throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Email.class.getSimpleName()));
- }
- if (!Email.isValidEmail(email)) {
- throw new IllegalValueException(Email.MESSAGE_CONSTRAINTS);
- }
- final Email modelEmail = new Email(email);
-
- if (address == null) {
- throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT, Address.class.getSimpleName()));
- }
- if (!Address.isValidAddress(address)) {
- throw new IllegalValueException(Address.MESSAGE_CONSTRAINTS);
- }
- final Address modelAddress = new Address(address);
-
- final Set modelTags = new HashSet<>(personTags);
- return new Person(modelName, modelPhone, modelEmail, modelAddress, modelTags);
- }
-
-}
diff --git a/src/main/java/seedu/address/storage/JsonAdaptedTag.java b/src/main/java/seedu/address/storage/JsonAdaptedTag.java
deleted file mode 100644
index 0df22bdb754..00000000000
--- a/src/main/java/seedu/address/storage/JsonAdaptedTag.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package seedu.address.storage;
-
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonValue;
-
-import seedu.address.commons.exceptions.IllegalValueException;
-import seedu.address.model.tag.Tag;
-
-/**
- * Jackson-friendly version of {@link Tag}.
- */
-class JsonAdaptedTag {
-
- private final String tagName;
-
- /**
- * Constructs a {@code JsonAdaptedTag} with the given {@code tagName}.
- */
- @JsonCreator
- public JsonAdaptedTag(String tagName) {
- this.tagName = tagName;
- }
-
- /**
- * Converts a given {@code Tag} into this class for Jackson use.
- */
- public JsonAdaptedTag(Tag source) {
- tagName = source.tagName;
- }
-
- @JsonValue
- public String getTagName() {
- return tagName;
- }
-
- /**
- * Converts this Jackson-friendly adapted tag object into the model's {@code Tag} object.
- *
- * @throws IllegalValueException if there were any data constraints violated in the adapted tag.
- */
- public Tag toModelType() throws IllegalValueException {
- if (!Tag.isValidTagName(tagName)) {
- throw new IllegalValueException(Tag.MESSAGE_CONSTRAINTS);
- }
- return new Tag(tagName);
- }
-
-}
diff --git a/src/main/java/seedu/address/storage/JsonAdaptedVisit.java b/src/main/java/seedu/address/storage/JsonAdaptedVisit.java
new file mode 100644
index 00000000000..a6d97b42aa3
--- /dev/null
+++ b/src/main/java/seedu/address/storage/JsonAdaptedVisit.java
@@ -0,0 +1,82 @@
+package seedu.address.storage;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import seedu.address.commons.exceptions.IllegalValueException;
+import seedu.address.model.patient.Condition;
+import seedu.address.model.patient.DateOfVisit;
+import seedu.address.model.patient.Severity;
+import seedu.address.model.patient.Visit;
+
+/**
+ * Jackson-friendly version of {@link Visit}.
+ */
+class JsonAdaptedVisit {
+
+ public static final String MISSING_FIELD_MESSAGE_FORMAT = "Visit's %s field is missing!";
+
+ private final String condition;
+ private final String severity;
+ private final String dateOfVisit;
+
+ /**
+ * Constructs a {@code JsonAdaptedVisit} with the given visit details.
+ */
+ @JsonCreator
+ public JsonAdaptedVisit(@JsonProperty("condition") String condition, @JsonProperty("severity") String severity,
+ @JsonProperty("dateOfVisit") String dateOfVisit) {
+ this.condition = condition;
+ this.severity = severity;
+ this.dateOfVisit = dateOfVisit;
+ }
+
+ /**
+ * Converts a given {@code Visit} into this class for Jackson use.
+ */
+ public JsonAdaptedVisit(Visit source) {
+ condition = source.getCondition().value;
+ severity = source.getSeverity().severity.getLabel();
+ dateOfVisit = source.getDateOfVisit().dateOfVisit.toString();
+ }
+
+ /**
+ * Converts this Jackson-friendly adapted visit object into the model's {@code Visit} object.
+ *
+ * @throws IllegalValueException if there were any data constraints violated in the adapted visit.
+ */
+ public Visit toModelType() throws IllegalValueException {
+
+ if (condition == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT,
+ Condition.class.getSimpleName()));
+ }
+ if (!Condition.isValidCondition(condition)) {
+ throw new IllegalValueException(Condition.MESSAGE_CONSTRAINTS);
+ }
+ final Condition modelCondition = new Condition(condition);
+
+ if (severity == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT,
+ Severity.class.getSimpleName()));
+ }
+ if (!Severity.isValidSeverity(severity)) {
+ throw new IllegalValueException(Severity.MESSAGE_CONSTRAINTS);
+ }
+ final Severity modelSeverity = new Severity(severity);
+
+
+ if (dateOfVisit == null) {
+ throw new IllegalValueException(String.format(MISSING_FIELD_MESSAGE_FORMAT,
+ DateOfVisit.class.getSimpleName()));
+ }
+ if (!DateOfVisit.isValidDateOfVisit(dateOfVisit)) {
+ throw new IllegalValueException(DateOfVisit.MESSAGE_CONSTRAINTS);
+ }
+ final DateOfVisit modelDateOfVisit = new DateOfVisit(dateOfVisit);
+
+ return new Visit(modelCondition, modelSeverity, modelDateOfVisit);
+ }
+
+}
+
diff --git a/src/main/java/seedu/address/storage/JsonAddressBookStorage.java b/src/main/java/seedu/address/storage/JsonPatientListStorage.java
similarity index 56%
rename from src/main/java/seedu/address/storage/JsonAddressBookStorage.java
rename to src/main/java/seedu/address/storage/JsonPatientListStorage.java
index 41e06f264e1..7f071c62b52 100644
--- a/src/main/java/seedu/address/storage/JsonAddressBookStorage.java
+++ b/src/main/java/seedu/address/storage/JsonPatientListStorage.java
@@ -12,47 +12,47 @@
import seedu.address.commons.exceptions.IllegalValueException;
import seedu.address.commons.util.FileUtil;
import seedu.address.commons.util.JsonUtil;
-import seedu.address.model.ReadOnlyAddressBook;
+import seedu.address.model.ReadOnlyPatientList;
/**
- * A class to access AddressBook data stored as a json file on the hard disk.
+ * A class to access PatientList data stored as a json file on the hard disk.
*/
-public class JsonAddressBookStorage implements AddressBookStorage {
+public class JsonPatientListStorage implements PatientListStorage {
- private static final Logger logger = LogsCenter.getLogger(JsonAddressBookStorage.class);
+ private static final Logger logger = LogsCenter.getLogger(JsonPatientListStorage.class);
private Path filePath;
- public JsonAddressBookStorage(Path filePath) {
+ public JsonPatientListStorage(Path filePath) {
this.filePath = filePath;
}
- public Path getAddressBookFilePath() {
+ public Path getPatientListFilePath() {
return filePath;
}
@Override
- public Optional readAddressBook() throws DataLoadingException {
- return readAddressBook(filePath);
+ public Optional readPatientList() throws DataLoadingException {
+ return readPatientList(filePath);
}
/**
- * Similar to {@link #readAddressBook()}.
+ * Similar to {@link #readPatientList()}.
*
* @param filePath location of the data. Cannot be null.
* @throws DataLoadingException if loading the data from storage failed.
*/
- public Optional readAddressBook(Path filePath) throws DataLoadingException {
+ public Optional readPatientList(Path filePath) throws DataLoadingException {
requireNonNull(filePath);
- Optional jsonAddressBook = JsonUtil.readJsonFile(
- filePath, JsonSerializableAddressBook.class);
- if (!jsonAddressBook.isPresent()) {
+ Optional jsonPatientList = JsonUtil.readJsonFile(
+ filePath, JsonSerializablePatientList.class);
+ if (!jsonPatientList.isPresent()) {
return Optional.empty();
}
try {
- return Optional.of(jsonAddressBook.get().toModelType());
+ return Optional.of(jsonPatientList.get().toModelType());
} catch (IllegalValueException ive) {
logger.info("Illegal values found in " + filePath + ": " + ive.getMessage());
throw new DataLoadingException(ive);
@@ -60,21 +60,21 @@ public Optional readAddressBook(Path filePath) throws DataL
}
@Override
- public void saveAddressBook(ReadOnlyAddressBook addressBook) throws IOException {
- saveAddressBook(addressBook, filePath);
+ public void savePatientList(ReadOnlyPatientList patientList) throws IOException {
+ savePatientList(patientList, filePath);
}
/**
- * Similar to {@link #saveAddressBook(ReadOnlyAddressBook)}.
+ * Similar to {@link #savePatientList(ReadOnlyPatientList)}.
*
* @param filePath location of the data. Cannot be null.
*/
- public void saveAddressBook(ReadOnlyAddressBook addressBook, Path filePath) throws IOException {
- requireNonNull(addressBook);
+ public void savePatientList(ReadOnlyPatientList patientList, Path filePath) throws IOException {
+ requireNonNull(patientList);
requireNonNull(filePath);
FileUtil.createIfMissing(filePath);
- JsonUtil.saveJsonFile(new JsonSerializableAddressBook(addressBook), filePath);
+ JsonUtil.saveJsonFile(new JsonSerializablePatientList(patientList), filePath);
}
}
diff --git a/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java b/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java
deleted file mode 100644
index 5efd834091d..00000000000
--- a/src/main/java/seedu/address/storage/JsonSerializableAddressBook.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package seedu.address.storage;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.stream.Collectors;
-
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.annotation.JsonRootName;
-
-import seedu.address.commons.exceptions.IllegalValueException;
-import seedu.address.model.AddressBook;
-import seedu.address.model.ReadOnlyAddressBook;
-import seedu.address.model.person.Person;
-
-/**
- * An Immutable AddressBook that is serializable to JSON format.
- */
-@JsonRootName(value = "addressbook")
-class JsonSerializableAddressBook {
-
- public static final String MESSAGE_DUPLICATE_PERSON = "Persons list contains duplicate person(s).";
-
- private final List persons = new ArrayList<>();
-
- /**
- * Constructs a {@code JsonSerializableAddressBook} with the given persons.
- */
- @JsonCreator
- public JsonSerializableAddressBook(@JsonProperty("persons") List persons) {
- this.persons.addAll(persons);
- }
-
- /**
- * Converts a given {@code ReadOnlyAddressBook} into this class for Jackson use.
- *
- * @param source future changes to this will not affect the created {@code JsonSerializableAddressBook}.
- */
- public JsonSerializableAddressBook(ReadOnlyAddressBook source) {
- persons.addAll(source.getPersonList().stream().map(JsonAdaptedPerson::new).collect(Collectors.toList()));
- }
-
- /**
- * Converts this address book into the model's {@code AddressBook} object.
- *
- * @throws IllegalValueException if there were any data constraints violated.
- */
- public AddressBook toModelType() throws IllegalValueException {
- AddressBook addressBook = new AddressBook();
- for (JsonAdaptedPerson jsonAdaptedPerson : persons) {
- Person person = jsonAdaptedPerson.toModelType();
- if (addressBook.hasPerson(person)) {
- throw new IllegalValueException(MESSAGE_DUPLICATE_PERSON);
- }
- addressBook.addPerson(person);
- }
- return addressBook;
- }
-
-}
diff --git a/src/main/java/seedu/address/storage/JsonSerializablePatientList.java b/src/main/java/seedu/address/storage/JsonSerializablePatientList.java
new file mode 100644
index 00000000000..79c4cc4f76f
--- /dev/null
+++ b/src/main/java/seedu/address/storage/JsonSerializablePatientList.java
@@ -0,0 +1,60 @@
+package seedu.address.storage;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonRootName;
+
+import seedu.address.commons.exceptions.IllegalValueException;
+import seedu.address.model.PatientList;
+import seedu.address.model.ReadOnlyPatientList;
+import seedu.address.model.patient.Patient;
+
+/**
+ * An Immutable PatientList that is serializable to JSON format.
+ */
+@JsonRootName(value = "patientlist")
+class JsonSerializablePatientList {
+
+ public static final String MESSAGE_DUPLICATE_PATIENT = "Patient list contains duplicate patient(s).";
+
+ private final List patients = new ArrayList<>();
+
+ /**
+ * Constructs a {@code JsonSerializablePatientList} with the given patients.
+ */
+ @JsonCreator
+ public JsonSerializablePatientList(@JsonProperty("patients") List patients) {
+ this.patients.addAll(patients);
+ }
+
+ /**
+ * Converts a given {@code ReadOnlyPatientList} into this class for Jackson use.
+ *
+ * @param source future changes to this will not affect the created {@code JsonSerializablePatientList}.
+ */
+ public JsonSerializablePatientList(ReadOnlyPatientList source) {
+ patients.addAll(source.getPatientList().stream().map(JsonAdaptedPatient::new).collect(Collectors.toList()));
+ }
+
+ /**
+ * Converts this patient list into the model's {@code PatientList} object.
+ *
+ * @throws IllegalValueException if there were any data constraints violated.
+ */
+ public PatientList toModelType() throws IllegalValueException {
+ PatientList patientList = new PatientList();
+ for (JsonAdaptedPatient jsonAdaptedPatient : patients) {
+ Patient patient = jsonAdaptedPatient.toModelType();
+ if (patientList.hasPatient(patient)) {
+ throw new IllegalValueException(MESSAGE_DUPLICATE_PATIENT);
+ }
+ patientList.addPatient(patient);
+ }
+ return patientList;
+ }
+
+}
diff --git a/src/main/java/seedu/address/storage/PatientListStorage.java b/src/main/java/seedu/address/storage/PatientListStorage.java
new file mode 100644
index 00000000000..8123ca77cb6
--- /dev/null
+++ b/src/main/java/seedu/address/storage/PatientListStorage.java
@@ -0,0 +1,46 @@
+package seedu.address.storage;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Optional;
+
+import seedu.address.commons.exceptions.DataLoadingException;
+import seedu.address.model.PatientList;
+import seedu.address.model.ReadOnlyPatientList;
+
+/**
+ * Represents a storage for {@link PatientList}.
+ */
+public interface PatientListStorage {
+
+ /**
+ * Returns the file path of the data file.
+ */
+ Path getPatientListFilePath();
+
+ /**
+ * Returns PatientList data as a {@link ReadOnlyPatientList}.
+ * Returns {@code Optional.empty()} if storage file is not found.
+ *
+ * @throws DataLoadingException if loading the data from storage failed.
+ */
+ Optional readPatientList() throws DataLoadingException;
+
+ /**
+ * @see #getPatientListFilePath()
+ */
+ Optional readPatientList(Path filePath) throws DataLoadingException;
+
+ /**
+ * Saves the given {@link ReadOnlyPatientList} to the storage.
+ * @param patientList cannot be null.
+ * @throws IOException if there was any problem writing to the file.
+ */
+ void savePatientList(ReadOnlyPatientList patientList) throws IOException;
+
+ /**
+ * @see #savePatientList(ReadOnlyPatientList)
+ */
+ void savePatientList(ReadOnlyPatientList patientList, Path filePath) throws IOException;
+
+}
diff --git a/src/main/java/seedu/address/storage/Storage.java b/src/main/java/seedu/address/storage/Storage.java
index 9fba0c7a1d6..3bda1d9ae5d 100644
--- a/src/main/java/seedu/address/storage/Storage.java
+++ b/src/main/java/seedu/address/storage/Storage.java
@@ -5,14 +5,14 @@
import java.util.Optional;
import seedu.address.commons.exceptions.DataLoadingException;
-import seedu.address.model.ReadOnlyAddressBook;
+import seedu.address.model.ReadOnlyPatientList;
import seedu.address.model.ReadOnlyUserPrefs;
import seedu.address.model.UserPrefs;
/**
* API of the Storage component
*/
-public interface Storage extends AddressBookStorage, UserPrefsStorage {
+public interface Storage extends PatientListStorage, UserPrefsStorage {
@Override
Optional readUserPrefs() throws DataLoadingException;
@@ -21,12 +21,12 @@ public interface Storage extends AddressBookStorage, UserPrefsStorage {
void saveUserPrefs(ReadOnlyUserPrefs userPrefs) throws IOException;
@Override
- Path getAddressBookFilePath();
+ Path getPatientListFilePath();
@Override
- Optional readAddressBook() throws DataLoadingException;
+ Optional readPatientList() throws DataLoadingException;
@Override
- void saveAddressBook(ReadOnlyAddressBook addressBook) throws IOException;
+ void savePatientList(ReadOnlyPatientList patientList) throws IOException;
}
diff --git a/src/main/java/seedu/address/storage/StorageManager.java b/src/main/java/seedu/address/storage/StorageManager.java
index 8b84a9024d5..c448396ac39 100644
--- a/src/main/java/seedu/address/storage/StorageManager.java
+++ b/src/main/java/seedu/address/storage/StorageManager.java
@@ -7,24 +7,24 @@
import seedu.address.commons.core.LogsCenter;
import seedu.address.commons.exceptions.DataLoadingException;
-import seedu.address.model.ReadOnlyAddressBook;
+import seedu.address.model.ReadOnlyPatientList;
import seedu.address.model.ReadOnlyUserPrefs;
import seedu.address.model.UserPrefs;
/**
- * Manages storage of AddressBook data in local storage.
+ * Manages storage of PatientList data in local storage.
*/
public class StorageManager implements Storage {
private static final Logger logger = LogsCenter.getLogger(StorageManager.class);
- private AddressBookStorage addressBookStorage;
+ private PatientListStorage patientListStorage;
private UserPrefsStorage userPrefsStorage;
/**
- * Creates a {@code StorageManager} with the given {@code AddressBookStorage} and {@code UserPrefStorage}.
+ * Creates a {@code StorageManager} with the given {@code PatientListStorage} and {@code UserPrefStorage}.
*/
- public StorageManager(AddressBookStorage addressBookStorage, UserPrefsStorage userPrefsStorage) {
- this.addressBookStorage = addressBookStorage;
+ public StorageManager(PatientListStorage patientListStorage, UserPrefsStorage userPrefsStorage) {
+ this.patientListStorage = patientListStorage;
this.userPrefsStorage = userPrefsStorage;
}
@@ -46,33 +46,33 @@ public void saveUserPrefs(ReadOnlyUserPrefs userPrefs) throws IOException {
}
- // ================ AddressBook methods ==============================
+ // ================ PatientList methods ==============================
@Override
- public Path getAddressBookFilePath() {
- return addressBookStorage.getAddressBookFilePath();
+ public Path getPatientListFilePath() {
+ return patientListStorage.getPatientListFilePath();
}
@Override
- public Optional readAddressBook() throws DataLoadingException {
- return readAddressBook(addressBookStorage.getAddressBookFilePath());
+ public Optional readPatientList() throws DataLoadingException {
+ return readPatientList(patientListStorage.getPatientListFilePath());
}
@Override
- public Optional readAddressBook(Path filePath) throws DataLoadingException {
+ public Optional readPatientList(Path filePath) throws DataLoadingException {
logger.fine("Attempting to read data from file: " + filePath);
- return addressBookStorage.readAddressBook(filePath);
+ return patientListStorage.readPatientList(filePath);
}
@Override
- public void saveAddressBook(ReadOnlyAddressBook addressBook) throws IOException {
- saveAddressBook(addressBook, addressBookStorage.getAddressBookFilePath());
+ public void savePatientList(ReadOnlyPatientList patientList) throws IOException {
+ savePatientList(patientList, patientListStorage.getPatientListFilePath());
}
@Override
- public void saveAddressBook(ReadOnlyAddressBook addressBook, Path filePath) throws IOException {
+ public void savePatientList(ReadOnlyPatientList patientList, Path filePath) throws IOException {
logger.fine("Attempting to write to data file: " + filePath);
- addressBookStorage.saveAddressBook(addressBook, filePath);
+ patientListStorage.savePatientList(patientList, filePath);
}
}
diff --git a/src/main/java/seedu/address/ui/HelpWindow.java b/src/main/java/seedu/address/ui/HelpWindow.java
index 3f16b2fcf26..0e29812868b 100644
--- a/src/main/java/seedu/address/ui/HelpWindow.java
+++ b/src/main/java/seedu/address/ui/HelpWindow.java
@@ -15,7 +15,7 @@
*/
public class HelpWindow extends UiPart {
- public static final String USERGUIDE_URL = "https://se-education.org/addressbook-level3/UserGuide.html";
+ public static final String USERGUIDE_URL = "https://ay2324s2-cs2103t-t14-2.github.io/tp/UserGuide.html";
public static final String HELP_MESSAGE = "Refer to the user guide: " + USERGUIDE_URL;
private static final Logger logger = LogsCenter.getLogger(HelpWindow.class);
diff --git a/src/main/java/seedu/address/ui/MainWindow.java b/src/main/java/seedu/address/ui/MainWindow.java
index 79e74ef37c0..9c9b0f39846 100644
--- a/src/main/java/seedu/address/ui/MainWindow.java
+++ b/src/main/java/seedu/address/ui/MainWindow.java
@@ -31,7 +31,7 @@ public class MainWindow extends UiPart {
private Logic logic;
// Independent Ui parts residing in this Ui container
- private PersonListPanel personListPanel;
+ private PatientListPanel patientListPanel;
private ResultDisplay resultDisplay;
private HelpWindow helpWindow;
@@ -42,7 +42,7 @@ public class MainWindow extends UiPart {
private MenuItem helpMenuItem;
@FXML
- private StackPane personListPanelPlaceholder;
+ private StackPane patientListPanelPlaceholder;
@FXML
private StackPane resultDisplayPlaceholder;
@@ -110,13 +110,13 @@ private void setAccelerator(MenuItem menuItem, KeyCombination keyCombination) {
* Fills up all the placeholders of this window.
*/
void fillInnerParts() {
- personListPanel = new PersonListPanel(logic.getFilteredPersonList());
- personListPanelPlaceholder.getChildren().add(personListPanel.getRoot());
+ patientListPanel = new PatientListPanel(logic.getFilteredPatientList());
+ patientListPanelPlaceholder.getChildren().add(patientListPanel.getRoot());
resultDisplay = new ResultDisplay();
resultDisplayPlaceholder.getChildren().add(resultDisplay.getRoot());
- StatusBarFooter statusBarFooter = new StatusBarFooter(logic.getAddressBookFilePath());
+ StatusBarFooter statusBarFooter = new StatusBarFooter(logic.getPatientListFilePath());
statusbarPlaceholder.getChildren().add(statusBarFooter.getRoot());
CommandBox commandBox = new CommandBox(this::executeCommand);
@@ -163,8 +163,8 @@ private void handleExit() {
primaryStage.hide();
}
- public PersonListPanel getPersonListPanel() {
- return personListPanel;
+ public PatientListPanel getPatientListPanel() {
+ return patientListPanel;
}
/**
diff --git a/src/main/java/seedu/address/ui/PatientCard.java b/src/main/java/seedu/address/ui/PatientCard.java
new file mode 100644
index 00000000000..1ab36e3384d
--- /dev/null
+++ b/src/main/java/seedu/address/ui/PatientCard.java
@@ -0,0 +1,87 @@
+package seedu.address.ui;
+
+import javafx.fxml.FXML;
+import javafx.scene.control.Label;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Region;
+import seedu.address.model.patient.Patient;
+import seedu.address.model.patient.Visit;
+
+/**
+ * A UI component that displays information of a {@code Patient}.
+ */
+public class PatientCard extends UiPart {
+
+ private static final String FXML = "PatientListCard.fxml";
+
+ /**
+ * Note: Certain keywords such as "location" and "resources" are reserved keywords in JavaFX.
+ * As a consequence, UI elements' variable names cannot be set to such keywords
+ * or an exception will be thrown by JavaFX during runtime.
+ */
+
+ public final Patient patient;
+
+ @FXML
+ private HBox cardPane;
+ @FXML
+ private Label name;
+ @FXML
+ private Label id;
+ @FXML
+ private Label phone;
+ @FXML
+ private Label address;
+ @FXML
+ private Label email;
+ @FXML
+ private Label dateOfBirth;
+ @FXML
+ private Label sex;
+ @FXML
+ private Label appointment;
+ @FXML
+ private Label visit;
+ @FXML
+ private Label hasLatestVisit;
+ @FXML
+ private Label dateOfVisit;
+ @FXML
+ private Label condition;
+ @FXML
+ private Label severity;
+
+ /**
+ * Creates a {@code PatientCard} with the given {@code Patient} and index to display.
+ */
+ public PatientCard(Patient patient, int displayedIndex) {
+ super(FXML);
+ this.patient = patient;
+ id.setText(displayedIndex + ". ");
+ name.setText(patient.getName().fullName);
+ phone.setText(patient.getPhone().value);
+ address.setText(patient.getAddress().value);
+ email.setText(patient.getEmail().value);
+ dateOfBirth.setText(patient.getDateOfBirth().toString());
+ sex.setText(patient.getSex().toString());
+
+ if (patient.getAppointment().appointment == null) {
+ appointment.setText("");
+ } else {
+ appointment.setText("Next appointment: " + patient.getAppointment().toString());
+ }
+
+ if (!patient.getVisits().isEmpty()) {
+ Visit latest = patient.getLatestVisit();
+ hasLatestVisit.setText("");
+ dateOfVisit.setText("Date: " + latest.getDateOfVisit().toString());
+ condition.setText("Condition: " + latest.getCondition().value);
+ severity.setText("Severity: " + latest.getSeverity().toString());
+ } else {
+ hasLatestVisit.setText("None");
+ dateOfVisit.setText("");
+ condition.setText("");
+ severity.setText("");
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/ui/PatientListPanel.java b/src/main/java/seedu/address/ui/PatientListPanel.java
new file mode 100644
index 00000000000..ab8e85c9289
--- /dev/null
+++ b/src/main/java/seedu/address/ui/PatientListPanel.java
@@ -0,0 +1,49 @@
+package seedu.address.ui;
+
+import java.util.logging.Logger;
+
+import javafx.collections.ObservableList;
+import javafx.fxml.FXML;
+import javafx.scene.control.ListCell;
+import javafx.scene.control.ListView;
+import javafx.scene.layout.Region;
+import seedu.address.commons.core.LogsCenter;
+import seedu.address.model.patient.Patient;
+
+/**
+ * Panel containing the list of patients.
+ */
+public class PatientListPanel extends UiPart {
+ private static final String FXML = "PatientListPanel.fxml";
+ private final Logger logger = LogsCenter.getLogger(PatientListPanel.class);
+
+ @FXML
+ private ListView patientListView;
+
+ /**
+ * Creates a {@code PatientListPanel} with the given {@code ObservableList}.
+ */
+ public PatientListPanel(ObservableList patientList) {
+ super(FXML);
+ patientListView.setItems(patientList);
+ patientListView.setCellFactory(listView -> new PatientListViewCell());
+ }
+
+ /**
+ * Custom {@code ListCell} that displays the graphics of a {@code Patient} using a {@code PatientCard}.
+ */
+ class PatientListViewCell extends ListCell {
+ @Override
+ protected void updateItem(Patient patient, boolean empty) {
+ super.updateItem(patient, empty);
+
+ if (empty || patient == null) {
+ setGraphic(null);
+ setText(null);
+ } else {
+ setGraphic(new PatientCard(patient, getIndex() + 1).getRoot());
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/seedu/address/ui/PersonCard.java b/src/main/java/seedu/address/ui/PersonCard.java
deleted file mode 100644
index 094c42cda82..00000000000
--- a/src/main/java/seedu/address/ui/PersonCard.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package seedu.address.ui;
-
-import java.util.Comparator;
-
-import javafx.fxml.FXML;
-import javafx.scene.control.Label;
-import javafx.scene.layout.FlowPane;
-import javafx.scene.layout.HBox;
-import javafx.scene.layout.Region;
-import seedu.address.model.person.Person;
-
-/**
- * An UI component that displays information of a {@code Person}.
- */
-public class PersonCard extends UiPart {
-
- private static final String FXML = "PersonListCard.fxml";
-
- /**
- * Note: Certain keywords such as "location" and "resources" are reserved keywords in JavaFX.
- * As a consequence, UI elements' variable names cannot be set to such keywords
- * or an exception will be thrown by JavaFX during runtime.
- *
- * @see The issue on AddressBook level 4
- */
-
- public final Person person;
-
- @FXML
- private HBox cardPane;
- @FXML
- private Label name;
- @FXML
- private Label id;
- @FXML
- private Label phone;
- @FXML
- private Label address;
- @FXML
- private Label email;
- @FXML
- private FlowPane tags;
-
- /**
- * Creates a {@code PersonCode} with the given {@code Person} and index to display.
- */
- public PersonCard(Person person, int displayedIndex) {
- super(FXML);
- this.person = person;
- id.setText(displayedIndex + ". ");
- name.setText(person.getName().fullName);
- phone.setText(person.getPhone().value);
- address.setText(person.getAddress().value);
- email.setText(person.getEmail().value);
- person.getTags().stream()
- .sorted(Comparator.comparing(tag -> tag.tagName))
- .forEach(tag -> tags.getChildren().add(new Label(tag.tagName)));
- }
-}
diff --git a/src/main/java/seedu/address/ui/PersonListPanel.java b/src/main/java/seedu/address/ui/PersonListPanel.java
deleted file mode 100644
index f4c501a897b..00000000000
--- a/src/main/java/seedu/address/ui/PersonListPanel.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package seedu.address.ui;
-
-import java.util.logging.Logger;
-
-import javafx.collections.ObservableList;
-import javafx.fxml.FXML;
-import javafx.scene.control.ListCell;
-import javafx.scene.control.ListView;
-import javafx.scene.layout.Region;
-import seedu.address.commons.core.LogsCenter;
-import seedu.address.model.person.Person;
-
-/**
- * Panel containing the list of persons.
- */
-public class PersonListPanel extends UiPart {
- private static final String FXML = "PersonListPanel.fxml";
- private final Logger logger = LogsCenter.getLogger(PersonListPanel.class);
-
- @FXML
- private ListView personListView;
-
- /**
- * Creates a {@code PersonListPanel} with the given {@code ObservableList}.
- */
- public PersonListPanel(ObservableList personList) {
- super(FXML);
- personListView.setItems(personList);
- personListView.setCellFactory(listView -> new PersonListViewCell());
- }
-
- /**
- * Custom {@code ListCell} that displays the graphics of a {@code Person} using a {@code PersonCard}.
- */
- class PersonListViewCell extends ListCell {
- @Override
- protected void updateItem(Person person, boolean empty) {
- super.updateItem(person, empty);
-
- if (empty || person == null) {
- setGraphic(null);
- setText(null);
- } else {
- setGraphic(new PersonCard(person, getIndex() + 1).getRoot());
- }
- }
- }
-
-}
diff --git a/src/main/java/seedu/address/ui/UiManager.java b/src/main/java/seedu/address/ui/UiManager.java
index fdf024138bc..e676a7bc4f1 100644
--- a/src/main/java/seedu/address/ui/UiManager.java
+++ b/src/main/java/seedu/address/ui/UiManager.java
@@ -84,5 +84,4 @@ private void showFatalErrorDialogAndShutdown(String title, Throwable e) {
Platform.exit();
System.exit(1);
}
-
}
diff --git a/src/main/resources/view/DarkTheme.css b/src/main/resources/view/DarkTheme.css
index 36e6b001cd8..e279af5f3a8 100644
--- a/src/main/resources/view/DarkTheme.css
+++ b/src/main/resources/view/DarkTheme.css
@@ -328,7 +328,7 @@
-fx-text-fill: white;
}
-#filterField, #personListPanel, #personWebpage {
+#filterField, #patientListPanel, #personWebpage {
-fx-effect: innershadow(gaussian, black, 10, 0, 0, 0);
}
diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml
index 7778f666a0a..fa0e20f3e2c 100644
--- a/src/main/resources/view/MainWindow.fxml
+++ b/src/main/resources/view/MainWindow.fxml
@@ -12,7 +12,7 @@
+ title="MediTrack" minWidth="450" minHeight="600" onCloseRequest="#handleExit">
@@ -46,11 +46,11 @@
-
+
-
+
diff --git a/src/main/resources/view/PersonListCard.fxml b/src/main/resources/view/PatientListCard.fxml
similarity index 56%
rename from src/main/resources/view/PersonListCard.fxml
rename to src/main/resources/view/PatientListCard.fxml
index f5e812e25e6..7f8b299d642 100644
--- a/src/main/resources/view/PersonListCard.fxml
+++ b/src/main/resources/view/PatientListCard.fxml
@@ -3,7 +3,6 @@
-
@@ -14,7 +13,7 @@
-
+
@@ -27,10 +26,25 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/view/PersonListPanel.fxml b/src/main/resources/view/PatientListPanel.fxml
similarity index 77%
rename from src/main/resources/view/PersonListPanel.fxml
rename to src/main/resources/view/PatientListPanel.fxml
index a1bb6bbace8..6e1109d4058 100644
--- a/src/main/resources/view/PersonListPanel.fxml
+++ b/src/main/resources/view/PatientListPanel.fxml
@@ -4,5 +4,5 @@
-
+
diff --git a/src/test/data/JsonAddressBookStorageTest/invalidAndValidPersonAddressBook.json b/src/test/data/JsonAddressBookStorageTest/invalidAndValidPersonAddressBook.json
deleted file mode 100644
index 6a4d2b7181c..00000000000
--- a/src/test/data/JsonAddressBookStorageTest/invalidAndValidPersonAddressBook.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "persons": [ {
- "name": "Valid Person",
- "phone": "9482424",
- "email": "hans@example.com",
- "address": "4th street"
- }, {
- "name": "Person With Invalid Phone Field",
- "phone": "948asdf2424",
- "email": "hans@example.com",
- "address": "4th street"
- } ]
-}
diff --git a/src/test/data/JsonAddressBookStorageTest/invalidPersonAddressBook.json b/src/test/data/JsonAddressBookStorageTest/invalidPersonAddressBook.json
deleted file mode 100644
index ccd21f7d1a9..00000000000
--- a/src/test/data/JsonAddressBookStorageTest/invalidPersonAddressBook.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "persons": [ {
- "name": "Person with invalid name field: Ha!ns Mu@ster",
- "phone": "9482424",
- "email": "hans@example.com",
- "address": "4th street"
- } ]
-}
diff --git a/src/test/data/JsonPatientListStorageTest/invalidAndValidPatientAddressBook.json b/src/test/data/JsonPatientListStorageTest/invalidAndValidPatientAddressBook.json
new file mode 100644
index 00000000000..fc3275ae5a5
--- /dev/null
+++ b/src/test/data/JsonPatientListStorageTest/invalidAndValidPatientAddressBook.json
@@ -0,0 +1,21 @@
+{
+ "patients": [ {
+ "name": "Valid Person",
+ "phone": "9482424",
+ "email": "hans@example.com",
+ "address": "4th street",
+ "dateOfBirth" : "2024-02-25",
+ "sex": "Female",
+ "appointment": "",
+ "visits" : [ ]
+ }, {
+ "name": "Person With Invalid Phone Field",
+ "phone": "948asdf2424",
+ "email": "hans@example.com",
+ "address": "4th street",
+ "dateOfBirth" : "2024-02-25",
+ "sex": "Female",
+ "appointment": "",
+ "visits" : [ ]
+ } ]
+}
diff --git a/src/test/data/JsonPatientListStorageTest/invalidPatientAddressBook.json b/src/test/data/JsonPatientListStorageTest/invalidPatientAddressBook.json
new file mode 100644
index 00000000000..5a4adfca21b
--- /dev/null
+++ b/src/test/data/JsonPatientListStorageTest/invalidPatientAddressBook.json
@@ -0,0 +1,11 @@
+{
+ "patients": [ {
+ "name": "Person with invalid name field Hans Mu@ster",
+ "phone": "9482424",
+ "email": "hans@example.com",
+ "address": "4th street",
+ "sex": "Female",
+ "dateOfBirth" : "2024-02-25",
+ "visits" : [ ]
+ } ]
+}
diff --git a/src/test/data/JsonAddressBookStorageTest/notJsonFormatAddressBook.json b/src/test/data/JsonPatientListStorageTest/notJsonFormatAddressBook.json
similarity index 100%
rename from src/test/data/JsonAddressBookStorageTest/notJsonFormatAddressBook.json
rename to src/test/data/JsonPatientListStorageTest/notJsonFormatAddressBook.json
diff --git a/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json b/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json
deleted file mode 100644
index ad3f135ae42..00000000000
--- a/src/test/data/JsonSerializableAddressBookTest/invalidPersonAddressBook.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "persons": [ {
- "name": "Hans Muster",
- "phone": "9482424",
- "email": "invalid@email!3e",
- "address": "4th street"
- } ]
-}
diff --git a/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json b/src/test/data/JsonSerializablePatientListTest/duplicatePatientAddressBook.json
similarity index 50%
rename from src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json
rename to src/test/data/JsonSerializablePatientListTest/duplicatePatientAddressBook.json
index a7427fe7aa2..a70a2e42e07 100644
--- a/src/test/data/JsonSerializableAddressBookTest/duplicatePersonAddressBook.json
+++ b/src/test/data/JsonSerializablePatientListTest/duplicatePatientAddressBook.json
@@ -1,14 +1,21 @@
{
- "persons": [ {
+ "patients": [ {
"name": "Alice Pauline",
"phone": "94351253",
"email": "alice@example.com",
"address": "123, Jurong West Ave 6, #08-111",
- "tags": [ "friends" ]
+ "dateOfBirth" : "2024-12-2",
+ "sex" : "Female",
+ "appointment": "",
+ "visits" : [ ]
}, {
"name": "Alice Pauline",
"phone": "94351253",
"email": "pauline@example.com",
- "address": "4th street"
+ "address": "4th street",
+ "dateOfBirth" : "2032-06-23",
+ "sex" : "Female",
+ "appointment": "",
+ "visits" : [ ]
} ]
}
diff --git a/src/test/data/JsonSerializablePatientListTest/invalidPatientAddressBook.json b/src/test/data/JsonSerializablePatientListTest/invalidPatientAddressBook.json
new file mode 100644
index 00000000000..7366af5ad3e
--- /dev/null
+++ b/src/test/data/JsonSerializablePatientListTest/invalidPatientAddressBook.json
@@ -0,0 +1,11 @@
+{
+ "patients": [ {
+ "name": "Hans Muster",
+ "phone": "9482424",
+ "email": "invalid@email!3e",
+ "address": "4th street",
+ "sex": "Male",
+ "dateOfBirth" : "2024-02-25",
+ "visits" : [ ]
+ } ]
+}
diff --git a/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json b/src/test/data/JsonSerializablePatientListTest/typicalPatientAddressBook.json
similarity index 59%
rename from src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json
rename to src/test/data/JsonSerializablePatientListTest/typicalPatientAddressBook.json
index 72262099d35..096da2880c0 100644
--- a/src/test/data/JsonSerializableAddressBookTest/typicalPersonsAddressBook.json
+++ b/src/test/data/JsonSerializablePatientListTest/typicalPatientAddressBook.json
@@ -1,46 +1,67 @@
{
"_comment": "AddressBook save file which contains the same Person values as in TypicalPersons#getTypicalAddressBook()",
- "persons" : [ {
+ "patients" : [ {
"name" : "Alice Pauline",
"phone" : "94351253",
"email" : "alice@example.com",
"address" : "123, Jurong West Ave 6, #08-111",
- "tags" : [ "friends" ]
+ "dateOfBirth" : "2024-2-25",
+ "sex" : "Female",
+ "appointment": "2025-2-25",
+ "visits" : [ ]
}, {
"name" : "Benson Meier",
"phone" : "98765432",
"email" : "johnd@example.com",
"address" : "311, Clementi Ave 2, #02-25",
- "tags" : [ "owesMoney", "friends" ]
+ "dateOfBirth" : "2024-2-25",
+ "sex" : "Male",
+ "appointment": "",
+ "visits" : [ ]
}, {
"name" : "Carl Kurz",
"phone" : "95352563",
"email" : "heinz@example.com",
"address" : "wall street",
- "tags" : [ ]
+ "dateOfBirth" : "2032-06-23",
+ "sex" : "Male",
+ "appointment": "2026-12-2",
+ "visits" : [ ]
}, {
"name" : "Daniel Meier",
"phone" : "87652533",
"email" : "cornelia@example.com",
"address" : "10th street",
- "tags" : [ "friends" ]
+ "dateOfBirth" : "2028-11-28",
+ "sex" : "Male",
+ "appointment": "",
+ "visits" : [ ]
}, {
"name" : "Elle Meyer",
"phone" : "9482224",
"email" : "werner@example.com",
"address" : "michegan ave",
- "tags" : [ ]
+ "dateOfBirth" : "2024-01-01",
+ "sex" : "Male",
+ "appointment": "",
+ "visits" : [ ]
}, {
"name" : "Fiona Kunz",
"phone" : "9482427",
"email" : "lydia@example.com",
"address" : "little tokyo",
- "tags" : [ ]
+ "dateOfBirth" : "2024-06-25",
+ "sex" : "Female",
+ "appointment": "2192-5-12",
+ "visits" : [ ]
}, {
"name" : "George Best",
"phone" : "9482442",
"email" : "anna@example.com",
"address" : "4th street",
- "tags" : [ ]
+ "dateOfBirth" : "2024-02-25",
+ "sex" : "Male",
+ "appointment": "",
+ "visits" : [ ]
} ]
}
diff --git a/src/test/data/JsonUserPrefsStorageTest/ExtraValuesUserPref.json b/src/test/data/JsonUserPrefsStorageTest/ExtraValuesUserPref.json
index 1037548a9cd..626618c26e5 100644
--- a/src/test/data/JsonUserPrefsStorageTest/ExtraValuesUserPref.json
+++ b/src/test/data/JsonUserPrefsStorageTest/ExtraValuesUserPref.json
@@ -9,5 +9,5 @@
"z" : 99
}
},
- "addressBookFilePath" : "addressbook.json"
+ "patientListFilePath" : "patientlist.json"
}
diff --git a/src/test/data/JsonUserPrefsStorageTest/TypicalUserPref.json b/src/test/data/JsonUserPrefsStorageTest/TypicalUserPref.json
index b819bed900a..d7748a3f0bb 100644
--- a/src/test/data/JsonUserPrefsStorageTest/TypicalUserPref.json
+++ b/src/test/data/JsonUserPrefsStorageTest/TypicalUserPref.json
@@ -7,5 +7,5 @@
"y" : 100
}
},
- "addressBookFilePath" : "addressbook.json"
+ "patientListFilePath" : "patientlist.json"
}
diff --git a/src/test/java/seedu/address/logic/LogicManagerTest.java b/src/test/java/seedu/address/logic/LogicManagerTest.java
index baf8ce336a2..71eb69f92dc 100644
--- a/src/test/java/seedu/address/logic/LogicManagerTest.java
+++ b/src/test/java/seedu/address/logic/LogicManagerTest.java
@@ -1,14 +1,16 @@
package seedu.address.logic;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static seedu.address.logic.Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX;
+import static seedu.address.logic.Messages.MESSAGE_INVALID_PATIENT_DISPLAYED_INDEX;
import static seedu.address.logic.Messages.MESSAGE_UNKNOWN_COMMAND;
import static seedu.address.logic.commands.CommandTestUtil.ADDRESS_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.DATEOFBIRTH_DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.EMAIL_DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.NAME_DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.PHONE_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.SEX_DESC_AMY;
import static seedu.address.testutil.Assert.assertThrows;
-import static seedu.address.testutil.TypicalPersons.AMY;
+import static seedu.address.testutil.TypicalPatients.AMY;
import java.io.IOException;
import java.nio.file.AccessDeniedException;
@@ -25,13 +27,13 @@
import seedu.address.logic.parser.exceptions.ParseException;
import seedu.address.model.Model;
import seedu.address.model.ModelManager;
-import seedu.address.model.ReadOnlyAddressBook;
+import seedu.address.model.ReadOnlyPatientList;
import seedu.address.model.UserPrefs;
-import seedu.address.model.person.Person;
-import seedu.address.storage.JsonAddressBookStorage;
+import seedu.address.model.patient.Patient;
+import seedu.address.storage.JsonPatientListStorage;
import seedu.address.storage.JsonUserPrefsStorage;
import seedu.address.storage.StorageManager;
-import seedu.address.testutil.PersonBuilder;
+import seedu.address.testutil.PatientBuilder;
public class LogicManagerTest {
private static final IOException DUMMY_IO_EXCEPTION = new IOException("dummy IO exception");
@@ -45,8 +47,8 @@ public class LogicManagerTest {
@BeforeEach
public void setUp() {
- JsonAddressBookStorage addressBookStorage =
- new JsonAddressBookStorage(temporaryFolder.resolve("addressBook.json"));
+ JsonPatientListStorage addressBookStorage =
+ new JsonPatientListStorage(temporaryFolder.resolve("addressBook.json"));
JsonUserPrefsStorage userPrefsStorage = new JsonUserPrefsStorage(temporaryFolder.resolve("userPrefs.json"));
StorageManager storage = new StorageManager(addressBookStorage, userPrefsStorage);
logic = new LogicManager(model, storage);
@@ -61,7 +63,7 @@ public void execute_invalidCommandFormat_throwsParseException() {
@Test
public void execute_commandExecutionError_throwsCommandException() {
String deleteCommand = "delete 9";
- assertCommandException(deleteCommand, MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ assertCommandException(deleteCommand, MESSAGE_INVALID_PATIENT_DISPLAYED_INDEX);
}
@Test
@@ -83,8 +85,8 @@ public void execute_storageThrowsAdException_throwsCommandException() {
}
@Test
- public void getFilteredPersonList_modifyList_throwsUnsupportedOperationException() {
- assertThrows(UnsupportedOperationException.class, () -> logic.getFilteredPersonList().remove(0));
+ public void getFilteredPatientList_modifyList_throwsUnsupportedOperationException() {
+ assertThrows(UnsupportedOperationException.class, () -> logic.getFilteredPatientList().remove(0));
}
/**
@@ -123,7 +125,7 @@ private void assertCommandException(String inputCommand, String expectedMessage)
*/
private void assertCommandFailure(String inputCommand, Class extends Throwable> expectedException,
String expectedMessage) {
- Model expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs());
+ Model expectedModel = new ModelManager(model.getPatientList(), new UserPrefs());
assertCommandFailure(inputCommand, expectedException, expectedMessage, expectedModel);
}
@@ -149,10 +151,10 @@ private void assertCommandFailure(String inputCommand, Class extends Throwable
private void assertCommandFailureForExceptionFromStorage(IOException e, String expectedMessage) {
Path prefPath = temporaryFolder.resolve("ExceptionUserPrefs.json");
- // Inject LogicManager with an AddressBookStorage that throws the IOException e when saving
- JsonAddressBookStorage addressBookStorage = new JsonAddressBookStorage(prefPath) {
+ // Inject LogicManager with an PatientListStorage that throws the IOException e when saving
+ JsonPatientListStorage addressBookStorage = new JsonPatientListStorage(prefPath) {
@Override
- public void saveAddressBook(ReadOnlyAddressBook addressBook, Path filePath)
+ public void savePatientList(ReadOnlyPatientList patientList, Path filePath)
throws IOException {
throw e;
}
@@ -166,10 +168,10 @@ public void saveAddressBook(ReadOnlyAddressBook addressBook, Path filePath)
// Triggers the saveAddressBook method by executing an add command
String addCommand = AddCommand.COMMAND_WORD + NAME_DESC_AMY + PHONE_DESC_AMY
- + EMAIL_DESC_AMY + ADDRESS_DESC_AMY;
- Person expectedPerson = new PersonBuilder(AMY).withTags().build();
+ + EMAIL_DESC_AMY + ADDRESS_DESC_AMY + DATEOFBIRTH_DESC_AMY + SEX_DESC_AMY;
+ Patient expectedPatient = new PatientBuilder(AMY).build();
ModelManager expectedModel = new ModelManager();
- expectedModel.addPerson(expectedPerson);
+ expectedModel.addPatient(expectedPatient);
assertCommandFailure(addCommand, CommandException.class, expectedMessage, expectedModel);
}
}
diff --git a/src/test/java/seedu/address/logic/commands/AddCommandIntegrationTest.java b/src/test/java/seedu/address/logic/commands/AddCommandIntegrationTest.java
index 162a0c86031..3cb4b28ec69 100644
--- a/src/test/java/seedu/address/logic/commands/AddCommandIntegrationTest.java
+++ b/src/test/java/seedu/address/logic/commands/AddCommandIntegrationTest.java
@@ -2,7 +2,7 @@
import static seedu.address.logic.commands.CommandTestUtil.assertCommandFailure;
import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
-import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
+import static seedu.address.testutil.TypicalPatients.getTypicalAddressBook;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -11,8 +11,8 @@
import seedu.address.model.Model;
import seedu.address.model.ModelManager;
import seedu.address.model.UserPrefs;
-import seedu.address.model.person.Person;
-import seedu.address.testutil.PersonBuilder;
+import seedu.address.model.patient.Patient;
+import seedu.address.testutil.PatientBuilder;
/**
* Contains integration tests (interaction with the Model) for {@code AddCommand}.
@@ -27,22 +27,22 @@ public void setUp() {
}
@Test
- public void execute_newPerson_success() {
- Person validPerson = new PersonBuilder().build();
+ public void execute_newPatient_success() {
+ Patient validPatient = new PatientBuilder().build();
- Model expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs());
- expectedModel.addPerson(validPerson);
+ Model expectedModel = new ModelManager(model.getPatientList(), new UserPrefs());
+ expectedModel.addPatient(validPatient);
- assertCommandSuccess(new AddCommand(validPerson), model,
- String.format(AddCommand.MESSAGE_SUCCESS, Messages.format(validPerson)),
+ assertCommandSuccess(new AddCommand(validPatient), model,
+ String.format(AddCommand.MESSAGE_SUCCESS, Messages.format(validPatient)),
expectedModel);
}
@Test
- public void execute_duplicatePerson_throwsCommandException() {
- Person personInList = model.getAddressBook().getPersonList().get(0);
- assertCommandFailure(new AddCommand(personInList), model,
- AddCommand.MESSAGE_DUPLICATE_PERSON);
+ public void execute_duplicatePatient_throwsCommandException() {
+ Patient patientInList = model.getPatientList().getPatientList().get(0);
+ assertCommandFailure(new AddCommand(patientInList), model,
+ AddCommand.MESSAGE_DUPLICATE_PATIENT);
}
}
diff --git a/src/test/java/seedu/address/logic/commands/AddCommandTest.java b/src/test/java/seedu/address/logic/commands/AddCommandTest.java
index 90e8253f48e..c13144df605 100644
--- a/src/test/java/seedu/address/logic/commands/AddCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/AddCommandTest.java
@@ -5,7 +5,7 @@
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static seedu.address.testutil.Assert.assertThrows;
-import static seedu.address.testutil.TypicalPersons.ALICE;
+import static seedu.address.testutil.TypicalPatients.ALICE;
import java.nio.file.Path;
import java.util.ArrayList;
@@ -18,45 +18,47 @@
import seedu.address.commons.core.GuiSettings;
import seedu.address.logic.Messages;
import seedu.address.logic.commands.exceptions.CommandException;
-import seedu.address.model.AddressBook;
import seedu.address.model.Model;
-import seedu.address.model.ReadOnlyAddressBook;
+import seedu.address.model.PatientList;
+import seedu.address.model.ReadOnlyPatientList;
import seedu.address.model.ReadOnlyUserPrefs;
-import seedu.address.model.person.Person;
-import seedu.address.testutil.PersonBuilder;
+import seedu.address.model.patient.Name;
+import seedu.address.model.patient.Patient;
+import seedu.address.model.patient.Phone;
+import seedu.address.testutil.PatientBuilder;
public class AddCommandTest {
@Test
- public void constructor_nullPerson_throwsNullPointerException() {
+ public void constructor_nullPatient_throwsNullPointerException() {
assertThrows(NullPointerException.class, () -> new AddCommand(null));
}
@Test
- public void execute_personAcceptedByModel_addSuccessful() throws Exception {
- ModelStubAcceptingPersonAdded modelStub = new ModelStubAcceptingPersonAdded();
- Person validPerson = new PersonBuilder().build();
+ public void execute_patientAcceptedByModel_addSuccessful() throws Exception {
+ ModelStubAcceptingPatientAdded modelStub = new ModelStubAcceptingPatientAdded();
+ Patient validPatient = new PatientBuilder().build();
- CommandResult commandResult = new AddCommand(validPerson).execute(modelStub);
+ CommandResult commandResult = new AddCommand(validPatient).execute(modelStub);
- assertEquals(String.format(AddCommand.MESSAGE_SUCCESS, Messages.format(validPerson)),
+ assertEquals(String.format(AddCommand.MESSAGE_SUCCESS, Messages.format(validPatient)),
commandResult.getFeedbackToUser());
- assertEquals(Arrays.asList(validPerson), modelStub.personsAdded);
+ assertEquals(Arrays.asList(validPatient), modelStub.patientsAdded);
}
@Test
- public void execute_duplicatePerson_throwsCommandException() {
- Person validPerson = new PersonBuilder().build();
- AddCommand addCommand = new AddCommand(validPerson);
- ModelStub modelStub = new ModelStubWithPerson(validPerson);
+ public void execute_duplicatePatient_throwsCommandException() {
+ Patient validPatient = new PatientBuilder().build();
+ AddCommand addCommand = new AddCommand(validPatient);
+ ModelStub modelStub = new ModelStubWithPatient(validPatient);
- assertThrows(CommandException.class, AddCommand.MESSAGE_DUPLICATE_PERSON, () -> addCommand.execute(modelStub));
+ assertThrows(CommandException.class, AddCommand.MESSAGE_DUPLICATE_PATIENT, () -> addCommand.execute(modelStub));
}
@Test
public void equals() {
- Person alice = new PersonBuilder().withName("Alice").build();
- Person bob = new PersonBuilder().withName("Bob").build();
+ Patient alice = new PatientBuilder().withName("Alice").build();
+ Patient bob = new PatientBuilder().withName("Bob").build();
AddCommand addAliceCommand = new AddCommand(alice);
AddCommand addBobCommand = new AddCommand(bob);
@@ -73,7 +75,7 @@ public void equals() {
// null -> returns false
assertFalse(addAliceCommand.equals(null));
- // different person -> returns false
+ // different patient -> returns false
assertFalse(addAliceCommand.equals(addBobCommand));
}
@@ -109,95 +111,105 @@ public void setGuiSettings(GuiSettings guiSettings) {
}
@Override
- public Path getAddressBookFilePath() {
+ public Path getPatientListFilePath() {
throw new AssertionError("This method should not be called.");
}
@Override
- public void setAddressBookFilePath(Path addressBookFilePath) {
+ public void setPatientListFilePath(Path patientListFilePath) {
throw new AssertionError("This method should not be called.");
}
@Override
- public void addPerson(Person person) {
+ public void addPatient(Patient patient) {
throw new AssertionError("This method should not be called.");
}
@Override
- public void setAddressBook(ReadOnlyAddressBook newData) {
+ public void setPatientList(ReadOnlyPatientList newData) {
throw new AssertionError("This method should not be called.");
}
@Override
- public ReadOnlyAddressBook getAddressBook() {
+ public ReadOnlyPatientList getPatientList() {
throw new AssertionError("This method should not be called.");
}
@Override
- public boolean hasPerson(Person person) {
+ public boolean hasPatient(Patient patient) {
throw new AssertionError("This method should not be called.");
}
@Override
- public void deletePerson(Person target) {
+ public boolean hasPatient(Name name, Phone phone) {
+ throw new AssertionError("This method should not be called");
+ }
+
+ @Override
+ public void deletePatient(Patient target) {
throw new AssertionError("This method should not be called.");
}
@Override
- public void setPerson(Person target, Person editedPerson) {
+ public void setPatient(Patient target, Patient editedPatient) {
throw new AssertionError("This method should not be called.");
}
@Override
- public ObservableList getFilteredPersonList() {
+ public ObservableList getFilteredPatientList() {
throw new AssertionError("This method should not be called.");
}
@Override
- public void updateFilteredPersonList(Predicate predicate) {
+ public void updateFilteredPatientList(Predicate predicate) {
throw new AssertionError("This method should not be called.");
}
+
+ @Override
+ public Patient getPatient(Name name, Phone phone) {
+ throw new AssertionError("This method should not be called");
+ }
}
/**
- * A Model stub that contains a single person.
+ * A Model stub that contains a single patient.
*/
- private class ModelStubWithPerson extends ModelStub {
- private final Person person;
+ private class ModelStubWithPatient extends ModelStub {
+ private final Patient patient;
- ModelStubWithPerson(Person person) {
- requireNonNull(person);
- this.person = person;
+ ModelStubWithPatient(Patient patient) {
+ requireNonNull(patient);
+ this.patient = patient;
}
@Override
- public boolean hasPerson(Person person) {
- requireNonNull(person);
- return this.person.isSamePerson(person);
+ public boolean hasPatient(Patient patient) {
+ requireNonNull(patient);
+ return this.patient.isSamePatient(patient);
}
}
/**
- * A Model stub that always accept the person being added.
+ * A Model stub that always accept the patient being added.
*/
- private class ModelStubAcceptingPersonAdded extends ModelStub {
- final ArrayList personsAdded = new ArrayList<>();
+ private class ModelStubAcceptingPatientAdded extends ModelStub {
+ final ArrayList patientsAdded = new ArrayList<>();
@Override
- public boolean hasPerson(Person person) {
- requireNonNull(person);
- return personsAdded.stream().anyMatch(person::isSamePerson);
+ public boolean hasPatient(Patient patient) {
+ requireNonNull(patient);
+ return patientsAdded.stream().anyMatch(patient::isSamePatient);
}
@Override
- public void addPerson(Person person) {
- requireNonNull(person);
- personsAdded.add(person);
+ public void addPatient(Patient patient) {
+ requireNonNull(patient);
+ patientsAdded.add(patient);
}
@Override
- public ReadOnlyAddressBook getAddressBook() {
- return new AddressBook();
+ public ReadOnlyPatientList getPatientList() {
+ return new PatientList();
}
}
diff --git a/src/test/java/seedu/address/logic/commands/AddVisitCommandTest.java b/src/test/java/seedu/address/logic/commands/AddVisitCommandTest.java
new file mode 100644
index 00000000000..15e6c511dc3
--- /dev/null
+++ b/src/test/java/seedu/address/logic/commands/AddVisitCommandTest.java
@@ -0,0 +1,80 @@
+package seedu.address.logic.commands;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.testutil.Assert.assertThrows;
+import static seedu.address.testutil.TypicalPatients.getTypicalAddressBook;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.Messages;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.ModelManager;
+import seedu.address.model.PatientList;
+import seedu.address.model.UserPrefs;
+import seedu.address.model.patient.Name;
+import seedu.address.model.patient.Patient;
+import seedu.address.model.patient.Phone;
+import seedu.address.model.patient.Visit;
+import seedu.address.testutil.PatientBuilder;
+import seedu.address.testutil.VisitBuilder;
+
+
+public class AddVisitCommandTest {
+ private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+ private Index validIndex = Index.fromOneBased(model.getFilteredPatientList().size());
+ private Index invalidIndex = Index.fromOneBased(model.getFilteredPatientList().size() + 1);
+ private Visit testVisit = new VisitBuilder().build();
+ private Name testName = new Name("Bob");
+ private Phone testPhone = new Phone("98765432");
+ @Test
+ public void constructor_nullParameters_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> new AddVisitCommand(validIndex, null));
+ assertThrows(NullPointerException.class, () -> new AddVisitCommand(null, testVisit));
+ assertThrows(NullPointerException.class, () -> new AddVisitCommand(null, testPhone, testVisit));
+ assertThrows(NullPointerException.class, () -> new AddVisitCommand(testName, null, testVisit));
+ assertThrows(NullPointerException.class, () -> new AddVisitCommand(testName, testPhone, null));
+ }
+
+ @Test
+ public void execute_invalidIndex_throwsCommandException() {
+ AddVisitCommand command = new AddVisitCommand(invalidIndex, testVisit);
+ assertThrows(CommandException.class, Messages.MESSAGE_INVALID_PATIENT_DISPLAYED_INDEX, ()
+ -> command.execute(model));
+ }
+
+ @Test
+ public void execute_invalidPatient_throwsCommandException() {
+ Model model = new ModelManager(new PatientList(), new UserPrefs());
+ Patient testPatient = new PatientBuilder().build();
+ AddVisitCommand command = new AddVisitCommand(testPatient.getName(), testPatient.getPhone(), testVisit);
+ assertThrows(CommandException.class, AddVisitCommand.MESSAGE_PATIENT_NOT_FOUND, () -> command.execute(model));
+ }
+
+ @Test
+ public void execute_duplicateVisit_throwsCommandException() {
+ Model model = new ModelManager(new PatientList(), new UserPrefs());
+ Patient testPatient = new PatientBuilder().build();
+ testPatient.addVisit(testVisit);
+ model.addPatient(testPatient);
+ AddVisitCommand command = new AddVisitCommand(testPatient.getName(), testPatient.getPhone(), testVisit);
+ assertThrows(CommandException.class, AddVisitCommand.MESSAGE_DUPLICATE_VISIT, () -> command.execute(model));
+ AddVisitCommand alternateCommand = new AddVisitCommand(Index.fromOneBased(1), testVisit);
+ assertThrows(CommandException.class, AddVisitCommand.MESSAGE_DUPLICATE_VISIT, ()
+ -> alternateCommand.execute(model));
+ }
+
+ @Test
+ public void execute_validVisit_addSuccessful() throws Exception {
+ Model model = new ModelManager(new PatientList(), new UserPrefs());
+ Patient testPatient = new PatientBuilder().build();
+ model.addPatient(testPatient);
+ AddVisitCommand command = new AddVisitCommand(testPatient.getName(), testPatient.getPhone(), testVisit);
+ CommandResult commandResult = command.execute(model);
+
+ assertEquals(AddVisitCommand.MESSAGE_SUCCESS, commandResult.getFeedbackToUser());
+ assertTrue(testPatient.hasVisit(testVisit));
+ }
+}
diff --git a/src/test/java/seedu/address/logic/commands/CommandTestUtil.java b/src/test/java/seedu/address/logic/commands/CommandTestUtil.java
index 643a1d08069..c3122532af1 100644
--- a/src/test/java/seedu/address/logic/commands/CommandTestUtil.java
+++ b/src/test/java/seedu/address/logic/commands/CommandTestUtil.java
@@ -3,10 +3,12 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_APPOINTMENT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATEOFBIRTH;
import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_SEX;
import static seedu.address.testutil.Assert.assertThrows;
import java.util.ArrayList;
@@ -15,11 +17,11 @@
import seedu.address.commons.core.index.Index;
import seedu.address.logic.commands.exceptions.CommandException;
-import seedu.address.model.AddressBook;
import seedu.address.model.Model;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
-import seedu.address.model.person.Person;
-import seedu.address.testutil.EditPersonDescriptorBuilder;
+import seedu.address.model.PatientList;
+import seedu.address.model.patient.NameContainsKeywordsPredicate;
+import seedu.address.model.patient.Patient;
+import seedu.address.testutil.EditPatientDescriptorBuilder;
/**
* Contains helper methods for testing commands.
@@ -34,8 +36,12 @@ public class CommandTestUtil {
public static final String VALID_EMAIL_BOB = "bob@example.com";
public static final String VALID_ADDRESS_AMY = "Block 312, Amy Street 1";
public static final String VALID_ADDRESS_BOB = "Block 123, Bobby Street 3";
- public static final String VALID_TAG_HUSBAND = "husband";
- public static final String VALID_TAG_FRIEND = "friend";
+ public static final String VALID_DATEOFBIRTH_AMY = "1/12/2024";
+ public static final String VALID_DATEOFBIRTH_BOB = "2024-1-3";
+ public static final String VALID_SEX_AMY = "Female";
+ public static final String VALID_SEX_BOB = "Male";
+ public static final String VALID_APPOINTMENT_AMY = "";
+ public static final String VALID_APPOINTMENT_BOB = "2025-2-4";
public static final String NAME_DESC_AMY = " " + PREFIX_NAME + VALID_NAME_AMY;
public static final String NAME_DESC_BOB = " " + PREFIX_NAME + VALID_NAME_BOB;
@@ -45,28 +51,37 @@ public class CommandTestUtil {
public static final String EMAIL_DESC_BOB = " " + PREFIX_EMAIL + VALID_EMAIL_BOB;
public static final String ADDRESS_DESC_AMY = " " + PREFIX_ADDRESS + VALID_ADDRESS_AMY;
public static final String ADDRESS_DESC_BOB = " " + PREFIX_ADDRESS + VALID_ADDRESS_BOB;
- public static final String TAG_DESC_FRIEND = " " + PREFIX_TAG + VALID_TAG_FRIEND;
- public static final String TAG_DESC_HUSBAND = " " + PREFIX_TAG + VALID_TAG_HUSBAND;
+ public static final String DATEOFBIRTH_DESC_AMY = " " + PREFIX_DATEOFBIRTH + VALID_DATEOFBIRTH_AMY;
+ public static final String DATEOFBIRTH_DESC_BOB = " " + PREFIX_DATEOFBIRTH + VALID_DATEOFBIRTH_BOB;
+ public static final String SEX_DESC_AMY = " " + PREFIX_SEX + VALID_SEX_AMY;
+ public static final String SEX_DESC_BOB = " " + PREFIX_SEX + VALID_SEX_BOB;
+ public static final String APPOINTMENT_DESC_AMY = " " + PREFIX_APPOINTMENT + VALID_APPOINTMENT_AMY;
+ public static final String APPOINTMENT_DESC_BOB = " " + PREFIX_APPOINTMENT + VALID_APPOINTMENT_BOB;
public static final String INVALID_NAME_DESC = " " + PREFIX_NAME + "James&"; // '&' not allowed in names
public static final String INVALID_PHONE_DESC = " " + PREFIX_PHONE + "911a"; // 'a' not allowed in phones
public static final String INVALID_EMAIL_DESC = " " + PREFIX_EMAIL + "bob!yahoo"; // missing '@' symbol
public static final String INVALID_ADDRESS_DESC = " " + PREFIX_ADDRESS; // empty string not allowed for addresses
- public static final String INVALID_TAG_DESC = " " + PREFIX_TAG + "hubby*"; // '*' not allowed in tags
+ public static final String INVALID_DATEOFBIRTH_DESC = " " + PREFIX_DATEOFBIRTH; // empty string not allowed for
+ // date of birth
+ public static final String INVALID_SEX_DESC = " " + PREFIX_SEX + "Others";
+ public static final String INVALID_APPOINTMENT_DESC = " " + PREFIX_APPOINTMENT;
public static final String PREAMBLE_WHITESPACE = "\t \r \n";
public static final String PREAMBLE_NON_EMPTY = "NonEmptyPreamble";
- public static final EditCommand.EditPersonDescriptor DESC_AMY;
- public static final EditCommand.EditPersonDescriptor DESC_BOB;
+ public static final EditCommand.EditPatientDescriptor DESC_AMY;
+ public static final EditCommand.EditPatientDescriptor DESC_BOB;
static {
- DESC_AMY = new EditPersonDescriptorBuilder().withName(VALID_NAME_AMY)
+ DESC_AMY = new EditPatientDescriptorBuilder().withName(VALID_NAME_AMY)
.withPhone(VALID_PHONE_AMY).withEmail(VALID_EMAIL_AMY).withAddress(VALID_ADDRESS_AMY)
- .withTags(VALID_TAG_FRIEND).build();
- DESC_BOB = new EditPersonDescriptorBuilder().withName(VALID_NAME_BOB)
+ .withDateOfBirth(VALID_DATEOFBIRTH_AMY).withSex(VALID_SEX_AMY).withAppointment(VALID_APPOINTMENT_AMY)
+ .build();
+ DESC_BOB = new EditPatientDescriptorBuilder().withName(VALID_NAME_BOB)
.withPhone(VALID_PHONE_BOB).withEmail(VALID_EMAIL_BOB).withAddress(VALID_ADDRESS_BOB)
- .withTags(VALID_TAG_HUSBAND, VALID_TAG_FRIEND).build();
+ .withDateOfBirth(VALID_DATEOFBIRTH_BOB).withSex(VALID_SEX_BOB)
+ .withAppointment(VALID_APPOINTMENT_BOB).build();
}
/**
@@ -75,7 +90,7 @@ public class CommandTestUtil {
* - the {@code actualModel} matches {@code expectedModel}
*/
public static void assertCommandSuccess(Command command, Model actualModel, CommandResult expectedCommandResult,
- Model expectedModel) {
+ Model expectedModel) {
try {
CommandResult result = command.execute(actualModel);
assertEquals(expectedCommandResult, result);
@@ -99,30 +114,30 @@ public static void assertCommandSuccess(Command command, Model actualModel, Stri
* Executes the given {@code command}, confirms that
* - a {@code CommandException} is thrown
* - the CommandException message matches {@code expectedMessage}
- * - the address book, filtered person list and selected person in {@code actualModel} remain unchanged
+ * - the address book, filtered patient list and selected patient in {@code actualModel} remain unchanged
*/
public static void assertCommandFailure(Command command, Model actualModel, String expectedMessage) {
// we are unable to defensively copy the model for comparison later, so we can
// only do so by copying its components.
- AddressBook expectedAddressBook = new AddressBook(actualModel.getAddressBook());
- List expectedFilteredList = new ArrayList<>(actualModel.getFilteredPersonList());
+ PatientList expectedPatientList = new PatientList(actualModel.getPatientList());
+ List expectedFilteredList = new ArrayList<>(actualModel.getFilteredPatientList());
assertThrows(CommandException.class, expectedMessage, () -> command.execute(actualModel));
- assertEquals(expectedAddressBook, actualModel.getAddressBook());
- assertEquals(expectedFilteredList, actualModel.getFilteredPersonList());
+ assertEquals(expectedPatientList, actualModel.getPatientList());
+ assertEquals(expectedFilteredList, actualModel.getFilteredPatientList());
}
/**
- * Updates {@code model}'s filtered list to show only the person at the given {@code targetIndex} in the
+ * Updates {@code model}'s filtered list to show only the patient at the given {@code targetIndex} in the
* {@code model}'s address book.
*/
- public static void showPersonAtIndex(Model model, Index targetIndex) {
- assertTrue(targetIndex.getZeroBased() < model.getFilteredPersonList().size());
+ public static void showPatientAtIndex(Model model, Index targetIndex) {
+ assertTrue(targetIndex.getZeroBased() < model.getFilteredPatientList().size());
- Person person = model.getFilteredPersonList().get(targetIndex.getZeroBased());
- final String[] splitName = person.getName().fullName.split("\\s+");
- model.updateFilteredPersonList(new NameContainsKeywordsPredicate(Arrays.asList(splitName[0])));
+ Patient patient = model.getFilteredPatientList().get(targetIndex.getZeroBased());
+ final String[] splitName = patient.getName().fullName.split("\\s+");
+ model.updateFilteredPatientList(new NameContainsKeywordsPredicate(Arrays.asList(splitName[0])));
- assertEquals(1, model.getFilteredPersonList().size());
+ assertEquals(1, model.getFilteredPatientList().size());
}
}
diff --git a/src/test/java/seedu/address/logic/commands/DeleteByIndexCommandTest.java b/src/test/java/seedu/address/logic/commands/DeleteByIndexCommandTest.java
new file mode 100644
index 00000000000..0c3e2179566
--- /dev/null
+++ b/src/test/java/seedu/address/logic/commands/DeleteByIndexCommandTest.java
@@ -0,0 +1,87 @@
+package seedu.address.logic.commands;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.logic.commands.CommandTestUtil.assertCommandFailure;
+import static seedu.address.logic.commands.CommandTestUtil.showPatientAtIndex;
+import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PATIENT;
+import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND_PATIENT;
+import static seedu.address.testutil.TypicalPatients.getTypicalAddressBook;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.Messages;
+import seedu.address.model.Model;
+import seedu.address.model.ModelManager;
+import seedu.address.model.UserPrefs;
+
+/**
+ * Contains integration tests (interaction with the Model) and unit tests for
+ * {@code DeleteCommand}.
+ */
+public class DeleteByIndexCommandTest {
+
+ private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+
+ @Test
+ public void execute_invalidIndexUnfilteredList_throwsCommandException() {
+ Index outOfBoundIndex = Index.fromOneBased(model.getFilteredPatientList().size() + 1);
+ DeleteByIndexCommand deleteByIndexCommand = new DeleteByIndexCommand(outOfBoundIndex);
+
+ assertCommandFailure(deleteByIndexCommand, model, Messages.MESSAGE_INVALID_PATIENT_DISPLAYED_INDEX);
+ }
+
+ @Test
+ public void execute_invalidIndexFilteredList_throwsCommandException() {
+ showPatientAtIndex(model, INDEX_FIRST_PATIENT);
+
+ Index outOfBoundIndex = INDEX_SECOND_PATIENT;
+ // ensures that outOfBoundIndex is still in bounds of address book list
+ assertTrue(outOfBoundIndex.getZeroBased() < model.getPatientList().getPatientList().size());
+
+ DeleteByIndexCommand deleteByIndexCommand = new DeleteByIndexCommand(outOfBoundIndex);
+
+ assertCommandFailure(deleteByIndexCommand, model, Messages.MESSAGE_INVALID_PATIENT_DISPLAYED_INDEX);
+ }
+
+ @Test
+ public void equals() {
+ DeleteByIndexCommand deleteFirstCommand = new DeleteByIndexCommand(INDEX_FIRST_PATIENT);
+ DeleteByIndexCommand deleteSecondCommand = new DeleteByIndexCommand(INDEX_SECOND_PATIENT);
+
+ // same object -> returns true
+ assertTrue(deleteFirstCommand.equals(deleteFirstCommand));
+
+ // same values -> returns true
+ DeleteByIndexCommand deleteFirstCommandCopy = new DeleteByIndexCommand(INDEX_FIRST_PATIENT);
+ assertTrue(deleteFirstCommand.equals(deleteFirstCommandCopy));
+
+ // different types -> returns false
+ assertFalse(deleteFirstCommand.equals(1));
+
+ // null -> returns false
+ assertFalse(deleteFirstCommand.equals(null));
+
+ // different patient -> returns false
+ assertFalse(deleteFirstCommand.equals(deleteSecondCommand));
+ }
+
+ @Test
+ public void toStringMethod() {
+ Index targetIndex = Index.fromOneBased(1);
+ DeleteByIndexCommand deleteByIndexCommand = new DeleteByIndexCommand(targetIndex);
+ String expected = DeleteByIndexCommand.class.getCanonicalName() + "{targetIndex=" + targetIndex + "}";
+ assertEquals(expected, deleteByIndexCommand.toString());
+ }
+
+ /**
+ * Updates {@code model}'s filtered list to show no one.
+ */
+ private void showNoPatient(Model model) {
+ model.updateFilteredPatientList(p -> false);
+
+ assertTrue(model.getFilteredPatientList().isEmpty());
+ }
+}
diff --git a/src/test/java/seedu/address/logic/commands/DeleteCommandTest.java b/src/test/java/seedu/address/logic/commands/DeleteCommandTest.java
deleted file mode 100644
index b6f332eabca..00000000000
--- a/src/test/java/seedu/address/logic/commands/DeleteCommandTest.java
+++ /dev/null
@@ -1,120 +0,0 @@
-package seedu.address.logic.commands;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static seedu.address.logic.commands.CommandTestUtil.assertCommandFailure;
-import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
-import static seedu.address.logic.commands.CommandTestUtil.showPersonAtIndex;
-import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
-import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND_PERSON;
-import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
-
-import org.junit.jupiter.api.Test;
-
-import seedu.address.commons.core.index.Index;
-import seedu.address.logic.Messages;
-import seedu.address.model.Model;
-import seedu.address.model.ModelManager;
-import seedu.address.model.UserPrefs;
-import seedu.address.model.person.Person;
-
-/**
- * Contains integration tests (interaction with the Model) and unit tests for
- * {@code DeleteCommand}.
- */
-public class DeleteCommandTest {
-
- private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
-
- @Test
- public void execute_validIndexUnfilteredList_success() {
- Person personToDelete = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased());
- DeleteCommand deleteCommand = new DeleteCommand(INDEX_FIRST_PERSON);
-
- String expectedMessage = String.format(DeleteCommand.MESSAGE_DELETE_PERSON_SUCCESS,
- Messages.format(personToDelete));
-
- ModelManager expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs());
- expectedModel.deletePerson(personToDelete);
-
- assertCommandSuccess(deleteCommand, model, expectedMessage, expectedModel);
- }
-
- @Test
- public void execute_invalidIndexUnfilteredList_throwsCommandException() {
- Index outOfBoundIndex = Index.fromOneBased(model.getFilteredPersonList().size() + 1);
- DeleteCommand deleteCommand = new DeleteCommand(outOfBoundIndex);
-
- assertCommandFailure(deleteCommand, model, Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
- }
-
- @Test
- public void execute_validIndexFilteredList_success() {
- showPersonAtIndex(model, INDEX_FIRST_PERSON);
-
- Person personToDelete = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased());
- DeleteCommand deleteCommand = new DeleteCommand(INDEX_FIRST_PERSON);
-
- String expectedMessage = String.format(DeleteCommand.MESSAGE_DELETE_PERSON_SUCCESS,
- Messages.format(personToDelete));
-
- Model expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs());
- expectedModel.deletePerson(personToDelete);
- showNoPerson(expectedModel);
-
- assertCommandSuccess(deleteCommand, model, expectedMessage, expectedModel);
- }
-
- @Test
- public void execute_invalidIndexFilteredList_throwsCommandException() {
- showPersonAtIndex(model, INDEX_FIRST_PERSON);
-
- Index outOfBoundIndex = INDEX_SECOND_PERSON;
- // ensures that outOfBoundIndex is still in bounds of address book list
- assertTrue(outOfBoundIndex.getZeroBased() < model.getAddressBook().getPersonList().size());
-
- DeleteCommand deleteCommand = new DeleteCommand(outOfBoundIndex);
-
- assertCommandFailure(deleteCommand, model, Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
- }
-
- @Test
- public void equals() {
- DeleteCommand deleteFirstCommand = new DeleteCommand(INDEX_FIRST_PERSON);
- DeleteCommand deleteSecondCommand = new DeleteCommand(INDEX_SECOND_PERSON);
-
- // same object -> returns true
- assertTrue(deleteFirstCommand.equals(deleteFirstCommand));
-
- // same values -> returns true
- DeleteCommand deleteFirstCommandCopy = new DeleteCommand(INDEX_FIRST_PERSON);
- assertTrue(deleteFirstCommand.equals(deleteFirstCommandCopy));
-
- // different types -> returns false
- assertFalse(deleteFirstCommand.equals(1));
-
- // null -> returns false
- assertFalse(deleteFirstCommand.equals(null));
-
- // different person -> returns false
- assertFalse(deleteFirstCommand.equals(deleteSecondCommand));
- }
-
- @Test
- public void toStringMethod() {
- Index targetIndex = Index.fromOneBased(1);
- DeleteCommand deleteCommand = new DeleteCommand(targetIndex);
- String expected = DeleteCommand.class.getCanonicalName() + "{targetIndex=" + targetIndex + "}";
- assertEquals(expected, deleteCommand.toString());
- }
-
- /**
- * Updates {@code model}'s filtered list to show no one.
- */
- private void showNoPerson(Model model) {
- model.updateFilteredPersonList(p -> false);
-
- assertTrue(model.getFilteredPersonList().isEmpty());
- }
-}
diff --git a/src/test/java/seedu/address/logic/commands/DeleteVisitCommandTest.java b/src/test/java/seedu/address/logic/commands/DeleteVisitCommandTest.java
new file mode 100644
index 00000000000..2e3b7e08297
--- /dev/null
+++ b/src/test/java/seedu/address/logic/commands/DeleteVisitCommandTest.java
@@ -0,0 +1,82 @@
+package seedu.address.logic.commands;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.testutil.Assert.assertThrows;
+import static seedu.address.testutil.TypicalPatients.getTypicalAddressBook;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.Messages;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.ModelManager;
+import seedu.address.model.PatientList;
+import seedu.address.model.UserPrefs;
+import seedu.address.model.patient.Name;
+import seedu.address.model.patient.Patient;
+import seedu.address.model.patient.Phone;
+import seedu.address.model.patient.Visit;
+import seedu.address.testutil.PatientBuilder;
+import seedu.address.testutil.VisitBuilder;
+
+public class DeleteVisitCommandTest {
+
+ private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+ private Index validIndex = Index.fromOneBased(model.getFilteredPatientList().size());
+ private Index invalidIndex = Index.fromOneBased(model.getFilteredPatientList().size() + 1);
+ private Visit testVisit = new VisitBuilder().build();
+ private Name testName = new Name("Bob");
+ private Phone testPhone = new Phone("98765432");
+
+ @Test
+ public void constructor_nullParameters_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> new DeleteVisitCommand(testName, null));
+ assertThrows(NullPointerException.class, () -> new DeleteVisitCommand(null, testPhone));
+ assertThrows(NullPointerException.class, () -> new DeleteVisitCommand(null));
+ }
+
+ @Test
+ public void execute_invalidIndex_throwsCommandException() {
+ DeleteVisitCommand command = new DeleteVisitCommand(invalidIndex);
+ assertThrows(CommandException.class, Messages.MESSAGE_INVALID_PATIENT_DISPLAYED_INDEX, ()
+ -> command.execute(model));
+ }
+
+ @Test
+ public void execute_invalidPatient_throwsCommandException() {
+ Model model = new ModelManager(new PatientList(), new UserPrefs());
+ Patient testPatient = new PatientBuilder().build();
+ DeleteVisitCommand command = new DeleteVisitCommand(testPatient.getName(), testPatient.getPhone());
+ assertThrows(CommandException.class, DeleteVisitCommand.MESSAGE_PATIENT_NOT_FOUND, ()
+ -> command.execute(model));
+ }
+
+ @Test
+ public void execute_noVisit_throwsCommandException() {
+ Model model = new ModelManager(new PatientList(), new UserPrefs());
+ Patient testPatient = new PatientBuilder().build();
+ model.addPatient(testPatient);
+ DeleteVisitCommand command = new DeleteVisitCommand(testPatient.getName(), testPatient.getPhone());
+ assertThrows(CommandException.class, DeleteVisitCommand.MESSAGE_NO_VISIT, () -> command.execute(model));
+ DeleteVisitCommand alternateCommand = new DeleteVisitCommand(Index.fromOneBased(1));
+ assertThrows(CommandException.class, DeleteVisitCommand.MESSAGE_NO_VISIT, ()
+ -> alternateCommand.execute(model));
+ }
+
+ @Test
+ public void execute_validVisit_addSuccessful() throws Exception {
+ Model model = new ModelManager(new PatientList(), new UserPrefs());
+ Patient testPatient = new PatientBuilder().build();
+ testPatient.addVisit(testVisit);
+ model.addPatient(testPatient);
+ DeleteVisitCommand command = new DeleteVisitCommand(testPatient.getName(), testPatient.getPhone());
+ CommandResult commandResult = command.execute(model);
+
+ assertEquals(DeleteVisitCommand.MESSAGE_SUCCESS, commandResult.getFeedbackToUser());
+ assertFalse(testPatient.hasVisit(testVisit));
+ assertTrue(testPatient.getVisits().isEmpty());
+ }
+}
diff --git a/src/test/java/seedu/address/logic/commands/EditCommandTest.java b/src/test/java/seedu/address/logic/commands/EditCommandTest.java
index 469dd97daa7..9ec4c9b444b 100644
--- a/src/test/java/seedu/address/logic/commands/EditCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/EditCommandTest.java
@@ -7,26 +7,25 @@
import static seedu.address.logic.commands.CommandTestUtil.DESC_BOB;
import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_BOB;
import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
import static seedu.address.logic.commands.CommandTestUtil.assertCommandFailure;
import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
-import static seedu.address.logic.commands.CommandTestUtil.showPersonAtIndex;
-import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
-import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND_PERSON;
-import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
+import static seedu.address.logic.commands.CommandTestUtil.showPatientAtIndex;
+import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PATIENT;
+import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND_PATIENT;
+import static seedu.address.testutil.TypicalPatients.getTypicalAddressBook;
import org.junit.jupiter.api.Test;
import seedu.address.commons.core.index.Index;
import seedu.address.logic.Messages;
-import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
-import seedu.address.model.AddressBook;
+import seedu.address.logic.commands.EditCommand.EditPatientDescriptor;
import seedu.address.model.Model;
import seedu.address.model.ModelManager;
+import seedu.address.model.PatientList;
import seedu.address.model.UserPrefs;
-import seedu.address.model.person.Person;
-import seedu.address.testutil.EditPersonDescriptorBuilder;
-import seedu.address.testutil.PersonBuilder;
+import seedu.address.model.patient.Patient;
+import seedu.address.testutil.EditPatientDescriptorBuilder;
+import seedu.address.testutil.PatientBuilder;
/**
* Contains integration tests (interaction with the Model) and unit tests for EditCommand.
@@ -37,96 +36,101 @@ public class EditCommandTest {
@Test
public void execute_allFieldsSpecifiedUnfilteredList_success() {
- Person editedPerson = new PersonBuilder().build();
- EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder(editedPerson).build();
- EditCommand editCommand = new EditCommand(INDEX_FIRST_PERSON, descriptor);
+ Patient editedPatient = new PatientBuilder().build();
+ EditPatientDescriptor descriptor = new EditPatientDescriptorBuilder(editedPatient).build();
+ System.out.println(descriptor);
+ EditCommand editCommand = new EditCommand(INDEX_FIRST_PATIENT, descriptor);
- String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_PERSON_SUCCESS, Messages.format(editedPerson));
+ String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_PATIENT_SUCCESS,
+ Messages.format(editedPatient));
- Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), new UserPrefs());
- expectedModel.setPerson(model.getFilteredPersonList().get(0), editedPerson);
+ Model expectedModel = new ModelManager(new PatientList(model.getPatientList()), new UserPrefs());
+ expectedModel.setPatient(model.getFilteredPatientList().get(0), editedPatient);
assertCommandSuccess(editCommand, model, expectedMessage, expectedModel);
}
@Test
public void execute_someFieldsSpecifiedUnfilteredList_success() {
- Index indexLastPerson = Index.fromOneBased(model.getFilteredPersonList().size());
- Person lastPerson = model.getFilteredPersonList().get(indexLastPerson.getZeroBased());
+ Index indexLastPerson = Index.fromOneBased(model.getFilteredPatientList().size());
+ Patient lastPatient = model.getFilteredPatientList().get(indexLastPerson.getZeroBased());
- PersonBuilder personInList = new PersonBuilder(lastPerson);
- Person editedPerson = personInList.withName(VALID_NAME_BOB).withPhone(VALID_PHONE_BOB)
- .withTags(VALID_TAG_HUSBAND).build();
+ PatientBuilder personInList = new PatientBuilder(lastPatient);
+ Patient editedPatient = personInList.withName(VALID_NAME_BOB).withPhone(VALID_PHONE_BOB)
+ .build();
- EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withName(VALID_NAME_BOB)
- .withPhone(VALID_PHONE_BOB).withTags(VALID_TAG_HUSBAND).build();
+ EditPatientDescriptor descriptor = new EditPatientDescriptorBuilder().withName(VALID_NAME_BOB)
+ .withPhone(VALID_PHONE_BOB).build();
EditCommand editCommand = new EditCommand(indexLastPerson, descriptor);
- String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_PERSON_SUCCESS, Messages.format(editedPerson));
+ String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_PATIENT_SUCCESS,
+ Messages.format(editedPatient));
- Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), new UserPrefs());
- expectedModel.setPerson(lastPerson, editedPerson);
+ Model expectedModel = new ModelManager(new PatientList(model.getPatientList()), new UserPrefs());
+ expectedModel.setPatient(lastPatient, editedPatient);
assertCommandSuccess(editCommand, model, expectedMessage, expectedModel);
}
@Test
public void execute_noFieldSpecifiedUnfilteredList_success() {
- EditCommand editCommand = new EditCommand(INDEX_FIRST_PERSON, new EditPersonDescriptor());
- Person editedPerson = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased());
+ EditCommand editCommand = new EditCommand(INDEX_FIRST_PATIENT, new EditPatientDescriptor());
+ Patient editedPatient = model.getFilteredPatientList().get(INDEX_FIRST_PATIENT.getZeroBased());
- String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_PERSON_SUCCESS, Messages.format(editedPerson));
+ String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_PATIENT_SUCCESS,
+ Messages.format(editedPatient));
- Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), new UserPrefs());
+ Model expectedModel = new ModelManager(new PatientList(model.getPatientList()), new UserPrefs());
assertCommandSuccess(editCommand, model, expectedMessage, expectedModel);
}
@Test
public void execute_filteredList_success() {
- showPersonAtIndex(model, INDEX_FIRST_PERSON);
+ showPatientAtIndex(model, INDEX_FIRST_PATIENT);
- Person personInFilteredList = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased());
- Person editedPerson = new PersonBuilder(personInFilteredList).withName(VALID_NAME_BOB).build();
- EditCommand editCommand = new EditCommand(INDEX_FIRST_PERSON,
- new EditPersonDescriptorBuilder().withName(VALID_NAME_BOB).build());
+ Patient patientInFilteredList = model.getFilteredPatientList().get(INDEX_FIRST_PATIENT.getZeroBased());
+ Patient editedPatient = new PatientBuilder(patientInFilteredList).withName(VALID_NAME_BOB).build();
+ EditCommand editCommand = new EditCommand(INDEX_FIRST_PATIENT,
+ new EditPatientDescriptorBuilder().withName(VALID_NAME_BOB).build());
- String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_PERSON_SUCCESS, Messages.format(editedPerson));
+ String expectedMessage = String.format(EditCommand.MESSAGE_EDIT_PATIENT_SUCCESS,
+ Messages.format(editedPatient));
- Model expectedModel = new ModelManager(new AddressBook(model.getAddressBook()), new UserPrefs());
- expectedModel.setPerson(model.getFilteredPersonList().get(0), editedPerson);
+ Model expectedModel = new ModelManager(new PatientList(model.getPatientList()), new UserPrefs());
+ expectedModel.setPatient(model.getFilteredPatientList().get(0), editedPatient);
assertCommandSuccess(editCommand, model, expectedMessage, expectedModel);
}
@Test
- public void execute_duplicatePersonUnfilteredList_failure() {
- Person firstPerson = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased());
- EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder(firstPerson).build();
- EditCommand editCommand = new EditCommand(INDEX_SECOND_PERSON, descriptor);
+ public void execute_duplicatePatientUnfilteredList_failure() {
+ Patient firstPatient = model.getFilteredPatientList().get(INDEX_FIRST_PATIENT.getZeroBased());
+ EditPatientDescriptor descriptor = new EditPatientDescriptorBuilder(firstPatient).build();
+ EditCommand editCommand = new EditCommand(INDEX_SECOND_PATIENT, descriptor);
- assertCommandFailure(editCommand, model, EditCommand.MESSAGE_DUPLICATE_PERSON);
+ assertCommandFailure(editCommand, model, EditCommand.MESSAGE_DUPLICATE_PATIENT);
}
@Test
- public void execute_duplicatePersonFilteredList_failure() {
- showPersonAtIndex(model, INDEX_FIRST_PERSON);
+ public void execute_duplicatePatientFilteredList_failure() {
+ showPatientAtIndex(model, INDEX_FIRST_PATIENT);
- // edit person in filtered list into a duplicate in address book
- Person personInList = model.getAddressBook().getPersonList().get(INDEX_SECOND_PERSON.getZeroBased());
- EditCommand editCommand = new EditCommand(INDEX_FIRST_PERSON,
- new EditPersonDescriptorBuilder(personInList).build());
+ // edit patient in filtered list into a duplicate in address book
+ Patient patientInList = model.getPatientList().getPatientList().get(INDEX_SECOND_PATIENT.getZeroBased());
+ EditCommand editCommand = new EditCommand(INDEX_FIRST_PATIENT,
+ new EditPatientDescriptorBuilder(patientInList).build());
- assertCommandFailure(editCommand, model, EditCommand.MESSAGE_DUPLICATE_PERSON);
+ assertCommandFailure(editCommand, model, EditCommand.MESSAGE_DUPLICATE_PATIENT);
}
@Test
- public void execute_invalidPersonIndexUnfilteredList_failure() {
- Index outOfBoundIndex = Index.fromOneBased(model.getFilteredPersonList().size() + 1);
- EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withName(VALID_NAME_BOB).build();
+ public void execute_invalidPatientIndexUnfilteredList_failure() {
+ Index outOfBoundIndex = Index.fromOneBased(model.getFilteredPatientList().size() + 1);
+ EditPatientDescriptor descriptor = new EditPatientDescriptorBuilder().withName(VALID_NAME_BOB).build();
EditCommand editCommand = new EditCommand(outOfBoundIndex, descriptor);
- assertCommandFailure(editCommand, model, Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ assertCommandFailure(editCommand, model, Messages.MESSAGE_INVALID_PATIENT_DISPLAYED_INDEX);
}
/**
@@ -134,25 +138,25 @@ public void execute_invalidPersonIndexUnfilteredList_failure() {
* but smaller than size of address book
*/
@Test
- public void execute_invalidPersonIndexFilteredList_failure() {
- showPersonAtIndex(model, INDEX_FIRST_PERSON);
- Index outOfBoundIndex = INDEX_SECOND_PERSON;
+ public void execute_invalidPatientIndexFilteredList_failure() {
+ showPatientAtIndex(model, INDEX_FIRST_PATIENT);
+ Index outOfBoundIndex = INDEX_SECOND_PATIENT;
// ensures that outOfBoundIndex is still in bounds of address book list
- assertTrue(outOfBoundIndex.getZeroBased() < model.getAddressBook().getPersonList().size());
+ assertTrue(outOfBoundIndex.getZeroBased() < model.getPatientList().getPatientList().size());
EditCommand editCommand = new EditCommand(outOfBoundIndex,
- new EditPersonDescriptorBuilder().withName(VALID_NAME_BOB).build());
+ new EditPatientDescriptorBuilder().withName(VALID_NAME_BOB).build());
- assertCommandFailure(editCommand, model, Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ assertCommandFailure(editCommand, model, Messages.MESSAGE_INVALID_PATIENT_DISPLAYED_INDEX);
}
@Test
public void equals() {
- final EditCommand standardCommand = new EditCommand(INDEX_FIRST_PERSON, DESC_AMY);
+ final EditCommand standardCommand = new EditCommand(INDEX_FIRST_PATIENT, DESC_AMY);
// same values -> returns true
- EditPersonDescriptor copyDescriptor = new EditPersonDescriptor(DESC_AMY);
- EditCommand commandWithSameValues = new EditCommand(INDEX_FIRST_PERSON, copyDescriptor);
+ EditPatientDescriptor copyDescriptor = new EditPatientDescriptor(DESC_AMY);
+ EditCommand commandWithSameValues = new EditCommand(INDEX_FIRST_PATIENT, copyDescriptor);
assertTrue(standardCommand.equals(commandWithSameValues));
// same object -> returns true
@@ -162,21 +166,21 @@ public void equals() {
assertFalse(standardCommand.equals(null));
// different types -> returns false
- assertFalse(standardCommand.equals(new ClearCommand()));
+ assertFalse(standardCommand.equals(new DeleteAllCommand()));
// different index -> returns false
- assertFalse(standardCommand.equals(new EditCommand(INDEX_SECOND_PERSON, DESC_AMY)));
+ assertFalse(standardCommand.equals(new EditCommand(INDEX_SECOND_PATIENT, DESC_AMY)));
// different descriptor -> returns false
- assertFalse(standardCommand.equals(new EditCommand(INDEX_FIRST_PERSON, DESC_BOB)));
+ assertFalse(standardCommand.equals(new EditCommand(INDEX_FIRST_PATIENT, DESC_BOB)));
}
@Test
public void toStringMethod() {
Index index = Index.fromOneBased(1);
- EditPersonDescriptor editPersonDescriptor = new EditPersonDescriptor();
+ EditPatientDescriptor editPersonDescriptor = new EditPatientDescriptor();
EditCommand editCommand = new EditCommand(index, editPersonDescriptor);
- String expected = EditCommand.class.getCanonicalName() + "{index=" + index + ", editPersonDescriptor="
+ String expected = EditCommand.class.getCanonicalName() + "{index=" + index + ", editPatientDescriptor="
+ editPersonDescriptor + "}";
assertEquals(expected, editCommand.toString());
}
diff --git a/src/test/java/seedu/address/logic/commands/EditPersonDescriptorTest.java b/src/test/java/seedu/address/logic/commands/EditPatientDescriptorTest.java
similarity index 62%
rename from src/test/java/seedu/address/logic/commands/EditPersonDescriptorTest.java
rename to src/test/java/seedu/address/logic/commands/EditPatientDescriptorTest.java
index b17c1f3d5c2..1a65cf2c3b8 100644
--- a/src/test/java/seedu/address/logic/commands/EditPersonDescriptorTest.java
+++ b/src/test/java/seedu/address/logic/commands/EditPatientDescriptorTest.java
@@ -9,19 +9,20 @@
import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_BOB;
import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_BOB;
import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
import org.junit.jupiter.api.Test;
-import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
-import seedu.address.testutil.EditPersonDescriptorBuilder;
+import seedu.address.logic.commands.EditCommand.EditPatientDescriptor;
+import seedu.address.testutil.EditPatientDescriptorBuilder;
-public class EditPersonDescriptorTest {
+public class EditPatientDescriptorTest {
@Test
public void equals() {
// same values -> returns true
- EditPersonDescriptor descriptorWithSameValues = new EditPersonDescriptor(DESC_AMY);
+ EditPatientDescriptor descriptorWithSameValues = new EditPatientDescriptor(DESC_AMY);
+ System.out.println(DESC_AMY);
+ System.out.println(descriptorWithSameValues);
assertTrue(DESC_AMY.equals(descriptorWithSameValues));
// same object -> returns true
@@ -37,35 +38,33 @@ public void equals() {
assertFalse(DESC_AMY.equals(DESC_BOB));
// different name -> returns false
- EditPersonDescriptor editedAmy = new EditPersonDescriptorBuilder(DESC_AMY).withName(VALID_NAME_BOB).build();
+ EditPatientDescriptor editedAmy = new EditPatientDescriptorBuilder(DESC_AMY).withName(VALID_NAME_BOB).build();
assertFalse(DESC_AMY.equals(editedAmy));
// different phone -> returns false
- editedAmy = new EditPersonDescriptorBuilder(DESC_AMY).withPhone(VALID_PHONE_BOB).build();
+ editedAmy = new EditPatientDescriptorBuilder(DESC_AMY).withPhone(VALID_PHONE_BOB).build();
assertFalse(DESC_AMY.equals(editedAmy));
// different email -> returns false
- editedAmy = new EditPersonDescriptorBuilder(DESC_AMY).withEmail(VALID_EMAIL_BOB).build();
+ editedAmy = new EditPatientDescriptorBuilder(DESC_AMY).withEmail(VALID_EMAIL_BOB).build();
assertFalse(DESC_AMY.equals(editedAmy));
// different address -> returns false
- editedAmy = new EditPersonDescriptorBuilder(DESC_AMY).withAddress(VALID_ADDRESS_BOB).build();
- assertFalse(DESC_AMY.equals(editedAmy));
-
- // different tags -> returns false
- editedAmy = new EditPersonDescriptorBuilder(DESC_AMY).withTags(VALID_TAG_HUSBAND).build();
+ editedAmy = new EditPatientDescriptorBuilder(DESC_AMY).withAddress(VALID_ADDRESS_BOB).build();
assertFalse(DESC_AMY.equals(editedAmy));
}
@Test
public void toStringMethod() {
- EditPersonDescriptor editPersonDescriptor = new EditPersonDescriptor();
- String expected = EditPersonDescriptor.class.getCanonicalName() + "{name="
+ EditPatientDescriptor editPersonDescriptor = new EditPatientDescriptor();
+ String expected = EditPatientDescriptor.class.getCanonicalName() + "{name="
+ editPersonDescriptor.getName().orElse(null) + ", phone="
+ editPersonDescriptor.getPhone().orElse(null) + ", email="
+ editPersonDescriptor.getEmail().orElse(null) + ", address="
- + editPersonDescriptor.getAddress().orElse(null) + ", tags="
- + editPersonDescriptor.getTags().orElse(null) + "}";
+ + editPersonDescriptor.getAddress().orElse(null) + ", date of birth="
+ + editPersonDescriptor.getDateOfBirth().orElse(null) + ", sex="
+ + editPersonDescriptor.getSex().orElse(null) + ", appointment="
+ + editPersonDescriptor.getAppointment().orElse(null) + "}";
assertEquals(expected, editPersonDescriptor.toString());
}
}
diff --git a/src/test/java/seedu/address/logic/commands/EditVisitCommandTest.java b/src/test/java/seedu/address/logic/commands/EditVisitCommandTest.java
new file mode 100644
index 00000000000..9017095dbc7
--- /dev/null
+++ b/src/test/java/seedu/address/logic/commands/EditVisitCommandTest.java
@@ -0,0 +1,123 @@
+package seedu.address.logic.commands;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.testutil.Assert.assertThrows;
+import static seedu.address.testutil.TypicalPatients.getTypicalAddressBook;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.Messages;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.ModelManager;
+import seedu.address.model.PatientList;
+import seedu.address.model.UserPrefs;
+import seedu.address.model.patient.Name;
+import seedu.address.model.patient.Patient;
+import seedu.address.model.patient.Phone;
+import seedu.address.model.patient.Visit;
+import seedu.address.testutil.EditVisitDescriptorBuilder;
+import seedu.address.testutil.PatientBuilder;
+import seedu.address.testutil.VisitBuilder;
+
+public class EditVisitCommandTest {
+
+ private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
+ private Index validIndex = Index.fromOneBased(model.getFilteredPatientList().size());
+ private Index invalidIndex = Index.fromOneBased(model.getFilteredPatientList().size() + 1);
+ private Visit testVisit = new VisitBuilder().build();
+ private EditVisitCommand.EditVisitDescriptor testEditVisitDescriptor =
+ new EditVisitDescriptorBuilder(testVisit).build();
+ private Name testName = new Name("Bob");
+ private Phone testPhone = new Phone("98765432");
+
+ @Test
+ public void constructor_nullParameters_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> new EditVisitCommand(validIndex, null));
+ assertThrows(NullPointerException.class, () -> new EditVisitCommand(null, testEditVisitDescriptor));
+ assertThrows(NullPointerException.class, () -> new EditVisitCommand(null, testPhone,
+ testEditVisitDescriptor));
+ assertThrows(NullPointerException.class, () -> new EditVisitCommand(testName, null,
+ testEditVisitDescriptor));
+ assertThrows(NullPointerException.class, () -> new EditVisitCommand(testName, testPhone, null));
+ }
+
+ @Test
+ public void execute_invalidIndex_throwsCommandException() {
+ EditVisitCommand command = new EditVisitCommand(invalidIndex, testEditVisitDescriptor);
+ assertThrows(CommandException.class, Messages.MESSAGE_INVALID_PATIENT_DISPLAYED_INDEX, ()
+ -> command.execute(model));
+ }
+
+ @Test
+ public void execute_invalidPatient_throwsCommandException() {
+ Model model = new ModelManager(new PatientList(), new UserPrefs());
+ Patient testPatient = new PatientBuilder().build();
+ EditVisitCommand command = new EditVisitCommand(testPatient.getName(), testPatient.getPhone(),
+ testEditVisitDescriptor);
+ assertThrows(CommandException.class, EditVisitCommand.MESSAGE_PATIENT_NOT_FOUND, () -> command.execute(model));
+ }
+
+ @Test
+ public void execute_noVisit_throwsCommandException() {
+ Model model = new ModelManager(new PatientList(), new UserPrefs());
+ Patient testPatient = new PatientBuilder().build();
+ model.addPatient(testPatient);
+ EditVisitCommand command = new EditVisitCommand(testPatient.getName(), testPatient.getPhone(),
+ testEditVisitDescriptor);
+ assertThrows(CommandException.class, EditVisitCommand.MESSAGE_NO_VISIT, () -> command.execute(model));
+ EditVisitCommand alternateCommand = new EditVisitCommand(Index.fromOneBased(1),
+ testEditVisitDescriptor);
+ assertThrows(CommandException.class, EditVisitCommand.MESSAGE_NO_VISIT, () -> alternateCommand.execute(model));
+ }
+
+ @Test
+ public void execute_duplicateVisit_throwsCommandException() {
+ Model model = new ModelManager(new PatientList(), new UserPrefs());
+ Patient testPatient = new PatientBuilder().build();
+ testPatient.addVisit(testVisit);
+ Visit visitToEdit = new VisitBuilder().withCondition("toEdit").withSeverity("Low").build();
+ testPatient.addVisit(visitToEdit);
+ model.addPatient(testPatient);
+ EditVisitCommand command = new EditVisitCommand(testPatient.getName(), testPatient.getPhone(),
+ testEditVisitDescriptor);
+ assertThrows(CommandException.class, EditVisitCommand.MESSAGE_DUPLICATE_VISIT, () -> command.execute(model));
+ EditVisitCommand alternateCommand = new EditVisitCommand(Index.fromOneBased(1),
+ testEditVisitDescriptor);
+ assertThrows(CommandException.class, EditVisitCommand.MESSAGE_DUPLICATE_VISIT, ()
+ -> alternateCommand.execute(model));
+ }
+
+ @Test
+ public void execute_unchangedVisit_editSuccessful() throws Exception {
+ Model model = new ModelManager(new PatientList(), new UserPrefs());
+ Patient testPatient = new PatientBuilder().build();
+ testPatient.addVisit(testVisit);
+ model.addPatient(testPatient);
+ EditVisitCommand command = new EditVisitCommand(testPatient.getName(), testPatient.getPhone(),
+ testEditVisitDescriptor);
+ assertEquals(EditVisitCommand.MESSAGE_SUCCESS, command.execute(model).getFeedbackToUser());
+ assertTrue(testPatient.hasVisit(testVisit));
+ }
+
+ @Test
+ public void execute_validVisit_addSuccessful() throws Exception {
+ Model model = new ModelManager(new PatientList(), new UserPrefs());
+ Patient testPatient = new PatientBuilder().build();
+ Visit visitToBeEdited = new VisitBuilder().withDateOfVisit("1/1/2001").withSeverity("Low")
+ .withCondition("toBeEdited").build();
+ Visit visitToEdit = new VisitBuilder().withDateOfVisit("2/2/2002").withSeverity("High")
+ .withCondition("toEdit").build();
+ EditVisitCommand.EditVisitDescriptor descriptor = new EditVisitDescriptorBuilder(visitToEdit).build();
+ testPatient.addVisit(visitToBeEdited);
+ model.addPatient(testPatient);
+ EditVisitCommand command = new EditVisitCommand(testPatient.getName(), testPatient.getPhone(), descriptor);
+ CommandResult commandResult = command.execute(model);
+ assertEquals(EditVisitCommand.MESSAGE_SUCCESS, commandResult.getFeedbackToUser());
+ assertTrue(testPatient.hasVisit(visitToEdit));
+ assertFalse(testPatient.hasVisit(visitToBeEdited));
+ }
+}
diff --git a/src/test/java/seedu/address/logic/commands/FindCommandTest.java b/src/test/java/seedu/address/logic/commands/FindCommandTest.java
index b8b7dbba91a..ccd42c8ba3a 100644
--- a/src/test/java/seedu/address/logic/commands/FindCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/FindCommandTest.java
@@ -3,12 +3,14 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static seedu.address.logic.Messages.MESSAGE_PERSONS_LISTED_OVERVIEW;
+import static seedu.address.logic.Messages.MESSAGE_PATIENTS_LISTED_OVERVIEW;
import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
-import static seedu.address.testutil.TypicalPersons.CARL;
-import static seedu.address.testutil.TypicalPersons.ELLE;
-import static seedu.address.testutil.TypicalPersons.FIONA;
-import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PATIENTS;
+import static seedu.address.testutil.TypicalPatients.ALICE;
+import static seedu.address.testutil.TypicalPatients.CARL;
+import static seedu.address.testutil.TypicalPatients.ELLE;
+import static seedu.address.testutil.TypicalPatients.FIONA;
+import static seedu.address.testutil.TypicalPatients.getTypicalAddressBook;
import java.util.Arrays;
import java.util.Collections;
@@ -18,7 +20,9 @@
import seedu.address.model.Model;
import seedu.address.model.ModelManager;
import seedu.address.model.UserPrefs;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
+import seedu.address.model.patient.NameContainsKeywordsPredicate;
+import seedu.address.model.patient.Phone;
+import seedu.address.model.patient.PhoneMatchesPredicate;
/**
* Contains integration tests (interaction with the Model) for {@code FindCommand}.
@@ -33,15 +37,18 @@ public void equals() {
new NameContainsKeywordsPredicate(Collections.singletonList("first"));
NameContainsKeywordsPredicate secondPredicate =
new NameContainsKeywordsPredicate(Collections.singletonList("second"));
+ PhoneMatchesPredicate thirdPredicate =
+ new PhoneMatchesPredicate(new Phone("99999999"));
- FindCommand findFirstCommand = new FindCommand(firstPredicate);
- FindCommand findSecondCommand = new FindCommand(secondPredicate);
+ FindCommand findFirstCommand = new FindCommand(firstPredicate, PREDICATE_SHOW_ALL_PATIENTS);
+ FindCommand findSecondCommand = new FindCommand(secondPredicate, PREDICATE_SHOW_ALL_PATIENTS);
+ FindCommand findThirdCommand = new FindCommand(thirdPredicate, PREDICATE_SHOW_ALL_PATIENTS);
// same object -> returns true
assertTrue(findFirstCommand.equals(findFirstCommand));
// same values -> returns true
- FindCommand findFirstCommandCopy = new FindCommand(firstPredicate);
+ FindCommand findFirstCommandCopy = new FindCommand(firstPredicate, PREDICATE_SHOW_ALL_PATIENTS);
assertTrue(findFirstCommand.equals(findFirstCommandCopy));
// different types -> returns false
@@ -50,42 +57,83 @@ public void equals() {
// null -> returns false
assertFalse(findFirstCommand.equals(null));
- // different person -> returns false
+ // different name -> returns false
assertFalse(findFirstCommand.equals(findSecondCommand));
+ assertFalse(findFirstCommand.equals(findThirdCommand));
}
@Test
- public void execute_zeroKeywords_noPersonFound() {
- String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 0);
- NameContainsKeywordsPredicate predicate = preparePredicate(" ");
- FindCommand command = new FindCommand(predicate);
- expectedModel.updateFilteredPersonList(predicate);
+ public void execute_zeroKeywords_noPatientFound() {
+ String expectedMessage = String.format(MESSAGE_PATIENTS_LISTED_OVERVIEW, 0);
+ NameContainsKeywordsPredicate namePredicate = prepareNamePredicate(" ");
+ FindCommand command = new FindCommand(namePredicate, PREDICATE_SHOW_ALL_PATIENTS);
+ expectedModel.updateFilteredPatientList(namePredicate);
assertCommandSuccess(command, model, expectedMessage, expectedModel);
- assertEquals(Collections.emptyList(), model.getFilteredPersonList());
+ assertEquals(Collections.emptyList(), model.getFilteredPatientList());
}
@Test
- public void execute_multipleKeywords_multiplePersonsFound() {
- String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 3);
- NameContainsKeywordsPredicate predicate = preparePredicate("Kurz Elle Kunz");
- FindCommand command = new FindCommand(predicate);
- expectedModel.updateFilteredPersonList(predicate);
+ public void execute_multipleKeywords_multiplePatientsFound() {
+ String expectedMessage = String.format(MESSAGE_PATIENTS_LISTED_OVERVIEW, 3);
+ NameContainsKeywordsPredicate namePredicate = prepareNamePredicate("Kurz Elle Kunz");
+ FindCommand command = new FindCommand(namePredicate, PREDICATE_SHOW_ALL_PATIENTS);
+ expectedModel.updateFilteredPatientList(namePredicate);
assertCommandSuccess(command, model, expectedMessage, expectedModel);
- assertEquals(Arrays.asList(CARL, ELLE, FIONA), model.getFilteredPersonList());
+ assertEquals(Arrays.asList(CARL, ELLE, FIONA), model.getFilteredPatientList());
+ }
+
+ @Test
+ public void execute_phoneNotFound_noPatientFound() {
+ String expectedMessage = String.format(MESSAGE_PATIENTS_LISTED_OVERVIEW, 0);
+ PhoneMatchesPredicate phoneMatchesPredicate = preparePhonePredicate("999");
+ FindCommand command = new FindCommand(PREDICATE_SHOW_ALL_PATIENTS, phoneMatchesPredicate);
+ expectedModel.updateFilteredPatientList(phoneMatchesPredicate);
+ assertCommandSuccess(command, model, expectedMessage, expectedModel);
+ assertEquals(Collections.emptyList(), model.getFilteredPatientList());
+ }
+
+ @Test
+ public void execute_phonePredicate_onePatientFound() {
+ String expectedMessage = String.format(MESSAGE_PATIENTS_LISTED_OVERVIEW, 1);
+ PhoneMatchesPredicate phoneMatchesPredicate = preparePhonePredicate("94351253");
+ FindCommand command = new FindCommand(PREDICATE_SHOW_ALL_PATIENTS, phoneMatchesPredicate);
+ expectedModel.updateFilteredPatientList(phoneMatchesPredicate);
+ assertCommandSuccess(command, model, expectedMessage, expectedModel);
+ assertEquals(Arrays.asList(ALICE), model.getFilteredPatientList());
+ }
+
+ @Test
+ public void execute_nameAndPhonePredicate_onePatientFound() {
+ String expectedMessage = String.format(MESSAGE_PATIENTS_LISTED_OVERVIEW, 1);
+ NameContainsKeywordsPredicate namePredicate = prepareNamePredicate("Alice");
+ PhoneMatchesPredicate phoneMatchesPredicate = preparePhonePredicate("94351253");
+ FindCommand command = new FindCommand(namePredicate, phoneMatchesPredicate);
+ expectedModel.updateFilteredPatientList(namePredicate.and(phoneMatchesPredicate));
+ assertCommandSuccess(command, model, expectedMessage, expectedModel);
+ assertEquals(Arrays.asList(ALICE), model.getFilteredPatientList());
}
@Test
public void toStringMethod() {
- NameContainsKeywordsPredicate predicate = new NameContainsKeywordsPredicate(Arrays.asList("keyword"));
- FindCommand findCommand = new FindCommand(predicate);
- String expected = FindCommand.class.getCanonicalName() + "{predicate=" + predicate + "}";
+ NameContainsKeywordsPredicate namePredicate = prepareNamePredicate("name");
+ PhoneMatchesPredicate phonePredicate = preparePhonePredicate("12345678");
+ FindCommand findCommand = new FindCommand(namePredicate, phonePredicate);
+ String expected = FindCommand.class.getCanonicalName() + "{namePredicate=" + namePredicate + ", "
+ + "phonePredicate=" + phonePredicate + "}";
assertEquals(expected, findCommand.toString());
}
/**
* Parses {@code userInput} into a {@code NameContainsKeywordsPredicate}.
*/
- private NameContainsKeywordsPredicate preparePredicate(String userInput) {
+ private NameContainsKeywordsPredicate prepareNamePredicate(String userInput) {
return new NameContainsKeywordsPredicate(Arrays.asList(userInput.split("\\s+")));
}
+
+ /**
+ * Parses {@code userInput} into a {@code PhoneMatchesPredicate}.
+ */
+ private PhoneMatchesPredicate preparePhonePredicate(String userInput) {
+ return new PhoneMatchesPredicate(new Phone(userInput));
+ }
}
diff --git a/src/test/java/seedu/address/logic/commands/ClearCommandTest.java b/src/test/java/seedu/address/logic/commands/ForceDeleteAllCommandTest.java
similarity index 51%
rename from src/test/java/seedu/address/logic/commands/ClearCommandTest.java
rename to src/test/java/seedu/address/logic/commands/ForceDeleteAllCommandTest.java
index 80d9110c03a..f9be7fe0678 100644
--- a/src/test/java/seedu/address/logic/commands/ClearCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/ForceDeleteAllCommandTest.java
@@ -1,32 +1,39 @@
package seedu.address.logic.commands;
import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
-import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
+import static seedu.address.testutil.TypicalPatients.getTypicalAddressBook;
import org.junit.jupiter.api.Test;
-import seedu.address.model.AddressBook;
import seedu.address.model.Model;
import seedu.address.model.ModelManager;
+import seedu.address.model.PatientList;
import seedu.address.model.UserPrefs;
-public class ClearCommandTest {
-
+/**
+ * Contains integration and unit tests for DeleteAllCommand.
+ */
+public class ForceDeleteAllCommandTest {
+ /**
+ * Tests when PatientList is empty.
+ */
@Test
public void execute_emptyAddressBook_success() {
Model model = new ModelManager();
Model expectedModel = new ModelManager();
- assertCommandSuccess(new ClearCommand(), model, ClearCommand.MESSAGE_SUCCESS, expectedModel);
+ assertCommandSuccess(new ForceDeleteAllCommand(), model, ForceDeleteAllCommand.MESSAGE_SUCCESS, expectedModel);
}
+ /**
+ * Tests when PatientList is not empty.
+ */
@Test
public void execute_nonEmptyAddressBook_success() {
Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
Model expectedModel = new ModelManager(getTypicalAddressBook(), new UserPrefs());
- expectedModel.setAddressBook(new AddressBook());
+ expectedModel.setPatientList(new PatientList());
- assertCommandSuccess(new ClearCommand(), model, ClearCommand.MESSAGE_SUCCESS, expectedModel);
+ assertCommandSuccess(new ForceDeleteAllCommand(), model, ForceDeleteAllCommand.MESSAGE_SUCCESS, expectedModel);
}
-
}
diff --git a/src/test/java/seedu/address/logic/commands/ExitCommandTest.java b/src/test/java/seedu/address/logic/commands/ForceExitCommandTest.java
similarity index 69%
rename from src/test/java/seedu/address/logic/commands/ExitCommandTest.java
rename to src/test/java/seedu/address/logic/commands/ForceExitCommandTest.java
index 9533c473875..5dbc70fef81 100644
--- a/src/test/java/seedu/address/logic/commands/ExitCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/ForceExitCommandTest.java
@@ -1,20 +1,20 @@
package seedu.address.logic.commands;
import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
-import static seedu.address.logic.commands.ExitCommand.MESSAGE_EXIT_ACKNOWLEDGEMENT;
+import static seedu.address.logic.commands.ForceExitCommand.MESSAGE_EXIT_ACKNOWLEDGEMENT;
import org.junit.jupiter.api.Test;
import seedu.address.model.Model;
import seedu.address.model.ModelManager;
-public class ExitCommandTest {
+public class ForceExitCommandTest {
private Model model = new ModelManager();
private Model expectedModel = new ModelManager();
@Test
public void execute_exit_success() {
CommandResult expectedCommandResult = new CommandResult(MESSAGE_EXIT_ACKNOWLEDGEMENT, false, true);
- assertCommandSuccess(new ExitCommand(), model, expectedCommandResult, expectedModel);
+ assertCommandSuccess(new ForceExitCommand(), model, expectedCommandResult, expectedModel);
}
}
diff --git a/src/test/java/seedu/address/logic/commands/HelpCommandTest.java b/src/test/java/seedu/address/logic/commands/HelpCommandTest.java
index 4904fc4352e..47d67da4452 100644
--- a/src/test/java/seedu/address/logic/commands/HelpCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/HelpCommandTest.java
@@ -1,7 +1,7 @@
package seedu.address.logic.commands;
import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
-import static seedu.address.logic.commands.HelpCommand.SHOWING_HELP_MESSAGE;
+import static seedu.address.logic.commands.HelpCommand.RESULT_MESSAGE;
import org.junit.jupiter.api.Test;
@@ -14,7 +14,7 @@ public class HelpCommandTest {
@Test
public void execute_help_success() {
- CommandResult expectedCommandResult = new CommandResult(SHOWING_HELP_MESSAGE, true, false);
+ CommandResult expectedCommandResult = new CommandResult(RESULT_MESSAGE, true, false);
assertCommandSuccess(new HelpCommand(), model, expectedCommandResult, expectedModel);
}
}
diff --git a/src/test/java/seedu/address/logic/commands/ListAlphabeticalCommandTest.java b/src/test/java/seedu/address/logic/commands/ListAlphabeticalCommandTest.java
new file mode 100755
index 00000000000..d8bd33ef6cc
--- /dev/null
+++ b/src/test/java/seedu/address/logic/commands/ListAlphabeticalCommandTest.java
@@ -0,0 +1,55 @@
+package seedu.address.logic.commands;
+
+import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
+import static seedu.address.logic.commands.CommandTestUtil.showPatientAtIndex;
+import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PATIENT;
+import static seedu.address.testutil.TypicalPatients.ALICE;
+import static seedu.address.testutil.TypicalPatients.BENSON;
+import static seedu.address.testutil.TypicalPatients.CARL;
+import static seedu.address.testutil.TypicalPatients.DANIEL;
+import static seedu.address.testutil.TypicalPatients.ELLE;
+import static seedu.address.testutil.TypicalPatients.FIONA;
+import static seedu.address.testutil.TypicalPatients.GEORGE;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import seedu.address.model.Model;
+import seedu.address.model.ModelManager;
+import seedu.address.model.PatientList;
+import seedu.address.model.UserPrefs;
+import seedu.address.model.patient.Patient;
+
+
+
+/**
+ * Contains integration tests (interaction with the Model) and unit tests for ListAlphabeticalCommand.
+ */
+public class ListAlphabeticalCommandTest {
+ private Model model;
+ private Model expectedModel;
+
+ @BeforeEach
+ public void setUp() {
+ List patientList = new ArrayList<>(Arrays.asList(GEORGE, CARL, DANIEL, ALICE, FIONA, BENSON, ELLE));
+ List expectedPatientList =
+ new ArrayList<>(Arrays.asList(ALICE, BENSON, CARL, DANIEL, ELLE, FIONA, GEORGE));
+ PatientList patients = new PatientList();
+ patients.setPatients(patientList);
+ model = new ModelManager(patients, new UserPrefs());
+ PatientList expectedPatients = new PatientList();
+ expectedPatients.setPatients(expectedPatientList);
+ expectedModel = new ModelManager(expectedPatients, new UserPrefs());
+ }
+
+ @Test
+ void testExecute() {
+ showPatientAtIndex(model, INDEX_FIRST_PATIENT);
+ assertCommandSuccess(new ListAlphabeticalCommand(), model,
+ ListAlphabeticalCommand.MESSAGE_SUCCESS, expectedModel);
+ }
+}
diff --git a/src/test/java/seedu/address/logic/commands/ListByApptDateCommandTest.java b/src/test/java/seedu/address/logic/commands/ListByApptDateCommandTest.java
new file mode 100755
index 00000000000..3a37513101e
--- /dev/null
+++ b/src/test/java/seedu/address/logic/commands/ListByApptDateCommandTest.java
@@ -0,0 +1,61 @@
+package seedu.address.logic.commands;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static seedu.address.testutil.TypicalPatients.ALICE;
+import static seedu.address.testutil.TypicalPatients.BENSON;
+import static seedu.address.testutil.TypicalPatients.CARL;
+import static seedu.address.testutil.TypicalPatients.DANIEL;
+import static seedu.address.testutil.TypicalPatients.ELLE;
+import static seedu.address.testutil.TypicalPatients.FIONA;
+import static seedu.address.testutil.TypicalPatients.GEORGE;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.ModelManager;
+import seedu.address.model.PatientList;
+import seedu.address.model.UserPrefs;
+import seedu.address.model.patient.Patient;
+
+
+/**
+ * Contains integration tests (interaction with the Model) and unit tests for ListCommand.
+ */
+public class ListByApptDateCommandTest {
+
+ private Model model;
+ private Model expectedModel;
+
+
+ @Test
+ void testExecute() {
+ List patientList = new ArrayList<>(
+ Arrays.asList(GEORGE, CARL, DANIEL, ALICE, FIONA, BENSON, ELLE));
+ List expectedPatientList = new ArrayList<>(
+ Arrays.asList(BENSON, DANIEL, ELLE, GEORGE, ALICE, CARL, FIONA));
+ PatientList patients = new PatientList();
+ patients.setPatients(patientList);
+ model = new ModelManager(patients, new UserPrefs());
+ PatientList expectedPatients = new PatientList();
+ expectedPatients.setPatients(expectedPatientList);
+ expectedModel = new ModelManager(expectedPatients, new UserPrefs());
+
+ //String expectedMessage = String.format(ListByApptDateCommand.MESSAGE_SUCCESS, 0);
+ ListByApptDateCommand command = new ListByApptDateCommand();
+ //model.updateFilteredPatientList(PREDICATE_SHOW_ALL_PATIENTS);
+ try {
+ CommandResult commandResult = command.execute(model);
+ assertEquals(commandResult, new CommandResult(ListByApptDateCommand.MESSAGE_SUCCESS));
+ //assertEquals(expectedPatientList, new ArrayList(model.getFilteredPatientList()));
+ } catch (CommandException e) {
+ throw new RuntimeException(e);
+ }
+ //assertCommandSuccess(command, model, expectedMessage, expectedModel);
+ //assertEquals(expectedPatientList, model.getFilteredPatientList());
+ }
+}
diff --git a/src/test/java/seedu/address/logic/commands/ListByDateCriteriaCommandTest.java b/src/test/java/seedu/address/logic/commands/ListByDateCriteriaCommandTest.java
new file mode 100755
index 00000000000..bd5458ff59f
--- /dev/null
+++ b/src/test/java/seedu/address/logic/commands/ListByDateCriteriaCommandTest.java
@@ -0,0 +1,65 @@
+package seedu.address.logic.commands;
+
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static seedu.address.testutil.TypicalPatients.ALICE;
+import static seedu.address.testutil.TypicalPatients.BENSON;
+import static seedu.address.testutil.TypicalPatients.CARL;
+import static seedu.address.testutil.TypicalPatients.DANIEL;
+import static seedu.address.testutil.TypicalPatients.ELLE;
+import static seedu.address.testutil.TypicalPatients.FIONA;
+import static seedu.address.testutil.TypicalPatients.GEORGE;
+
+import java.time.LocalDate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.logic.parser.ParserUtil;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.Model;
+import seedu.address.model.ModelManager;
+import seedu.address.model.PatientList;
+import seedu.address.model.UserPrefs;
+import seedu.address.model.patient.ApptDateMatchesPredicate;
+import seedu.address.model.patient.Patient;
+
+
+/**
+ * Contains integration tests (interaction with the Model) and unit tests for ListCommand.
+ */
+public class ListByDateCriteriaCommandTest {
+ private Model model;
+ private Model expectedModel;
+
+ @Test
+ void testExecute() {
+ List patientList = new ArrayList<>(
+ Arrays.asList(GEORGE, CARL, DANIEL, ALICE, FIONA, BENSON, ELLE));
+ List expectedPatientList = new ArrayList<>(
+ Arrays.asList(BENSON, DANIEL, ELLE, GEORGE, ALICE, CARL, FIONA));
+ PatientList patients = new PatientList();
+ patients.setPatients(patientList);
+ model = new ModelManager(patients, new UserPrefs());
+ PatientList expectedPatients = new PatientList();
+ expectedPatients.setPatients(expectedPatientList);
+ expectedModel = new ModelManager(expectedPatients, new UserPrefs());
+
+ try {
+ LocalDate apptDate = ParserUtil.parseAppointment("27/2/2025").appointment;
+ ApptDateMatchesPredicate predicate = new ApptDateMatchesPredicate(apptDate);
+ ListByDateCriteriaCommand command = new ListByDateCriteriaCommand(predicate);
+ CommandResult commandResult = null;
+ commandResult = command.execute(model);
+ assertEquals(commandResult, new CommandResult(ListByDateCriteriaCommand.MESSAGE_SUCCESS));
+ //assertEquals(expectedPatientList, new ArrayList(model.getFilteredPatientList()));
+ } catch (CommandException e) {
+ throw new RuntimeException(e);
+ } catch (ParseException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/src/test/java/seedu/address/logic/commands/ListCommandTest.java b/src/test/java/seedu/address/logic/commands/ListCommandTest.java
index 435ff1f7275..c87004882dc 100644
--- a/src/test/java/seedu/address/logic/commands/ListCommandTest.java
+++ b/src/test/java/seedu/address/logic/commands/ListCommandTest.java
@@ -1,9 +1,9 @@
package seedu.address.logic.commands;
import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
-import static seedu.address.logic.commands.CommandTestUtil.showPersonAtIndex;
-import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
-import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
+import static seedu.address.logic.commands.CommandTestUtil.showPatientAtIndex;
+import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PATIENT;
+import static seedu.address.testutil.TypicalPatients.getTypicalAddressBook;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -23,7 +23,7 @@ public class ListCommandTest {
@BeforeEach
public void setUp() {
model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
- expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs());
+ expectedModel = new ModelManager(model.getPatientList(), new UserPrefs());
}
@Test
@@ -33,7 +33,7 @@ public void execute_listIsNotFiltered_showsSameList() {
@Test
public void execute_listIsFiltered_showsEverything() {
- showPersonAtIndex(model, INDEX_FIRST_PERSON);
+ showPatientAtIndex(model, INDEX_FIRST_PATIENT);
assertCommandSuccess(new ListCommand(), model, ListCommand.MESSAGE_SUCCESS, expectedModel);
}
}
diff --git a/src/test/java/seedu/address/logic/parser/AddCommandParserTest.java b/src/test/java/seedu/address/logic/parser/AddCommandParserTest.java
index 5bc11d3cdaa..0723af0f07f 100644
--- a/src/test/java/seedu/address/logic/parser/AddCommandParserTest.java
+++ b/src/test/java/seedu/address/logic/parser/AddCommandParserTest.java
@@ -3,72 +3,80 @@
import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static seedu.address.logic.commands.CommandTestUtil.ADDRESS_DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.ADDRESS_DESC_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.DATEOFBIRTH_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.DATEOFBIRTH_DESC_BOB;
import static seedu.address.logic.commands.CommandTestUtil.EMAIL_DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.EMAIL_DESC_BOB;
import static seedu.address.logic.commands.CommandTestUtil.INVALID_ADDRESS_DESC;
+import static seedu.address.logic.commands.CommandTestUtil.INVALID_DATEOFBIRTH_DESC;
import static seedu.address.logic.commands.CommandTestUtil.INVALID_EMAIL_DESC;
import static seedu.address.logic.commands.CommandTestUtil.INVALID_NAME_DESC;
import static seedu.address.logic.commands.CommandTestUtil.INVALID_PHONE_DESC;
-import static seedu.address.logic.commands.CommandTestUtil.INVALID_TAG_DESC;
+import static seedu.address.logic.commands.CommandTestUtil.INVALID_SEX_DESC;
import static seedu.address.logic.commands.CommandTestUtil.NAME_DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.NAME_DESC_BOB;
import static seedu.address.logic.commands.CommandTestUtil.PHONE_DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.PHONE_DESC_BOB;
import static seedu.address.logic.commands.CommandTestUtil.PREAMBLE_NON_EMPTY;
import static seedu.address.logic.commands.CommandTestUtil.PREAMBLE_WHITESPACE;
-import static seedu.address.logic.commands.CommandTestUtil.TAG_DESC_FRIEND;
-import static seedu.address.logic.commands.CommandTestUtil.TAG_DESC_HUSBAND;
+import static seedu.address.logic.commands.CommandTestUtil.SEX_DESC_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.SEX_DESC_BOB;
import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_DATEOFBIRTH_BOB;
import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_BOB;
import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_BOB;
import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_FRIEND;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_SEX_BOB;
import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATEOFBIRTH;
import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_SEX;
import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure;
import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess;
-import static seedu.address.testutil.TypicalPersons.AMY;
-import static seedu.address.testutil.TypicalPersons.BOB;
+import static seedu.address.testutil.TypicalPatients.AMY;
+import static seedu.address.testutil.TypicalPatients.BOB;
import org.junit.jupiter.api.Test;
import seedu.address.logic.Messages;
import seedu.address.logic.commands.AddCommand;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
-import seedu.address.testutil.PersonBuilder;
+import seedu.address.model.patient.Address;
+import seedu.address.model.patient.DateOfBirth;
+import seedu.address.model.patient.Email;
+import seedu.address.model.patient.Name;
+import seedu.address.model.patient.Patient;
+import seedu.address.model.patient.Phone;
+import seedu.address.model.patient.Sex;
+import seedu.address.testutil.PatientBuilder;
+
public class AddCommandParserTest {
private AddCommandParser parser = new AddCommandParser();
@Test
public void parse_allFieldsPresent_success() {
- Person expectedPerson = new PersonBuilder(BOB).withTags(VALID_TAG_FRIEND).build();
+ Patient expectedPatient = new PatientBuilder(BOB).withAppointment("").build();
// whitespace only preamble
assertParseSuccess(parser, PREAMBLE_WHITESPACE + NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB
- + ADDRESS_DESC_BOB + TAG_DESC_FRIEND, new AddCommand(expectedPerson));
+ + ADDRESS_DESC_BOB + DATEOFBIRTH_DESC_BOB + SEX_DESC_BOB, new AddCommand(expectedPatient));
// multiple tags - all accepted
- Person expectedPersonMultipleTags = new PersonBuilder(BOB).withTags(VALID_TAG_FRIEND, VALID_TAG_HUSBAND)
+ Patient expectedPatientMultipleTags = new PatientBuilder(BOB).withAppointment("")
.build();
assertParseSuccess(parser,
- NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB + TAG_DESC_HUSBAND + TAG_DESC_FRIEND,
- new AddCommand(expectedPersonMultipleTags));
+ NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB + DATEOFBIRTH_DESC_BOB
+ + SEX_DESC_BOB,
+ new AddCommand(expectedPatientMultipleTags));
}
@Test
public void parse_repeatedNonTagValue_failure() {
String validExpectedPersonString = NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB
- + ADDRESS_DESC_BOB + TAG_DESC_FRIEND;
+ + ADDRESS_DESC_BOB + DATEOFBIRTH_DESC_BOB + SEX_DESC_BOB;
// multiple names
assertParseFailure(parser, NAME_DESC_AMY + validExpectedPersonString,
@@ -86,11 +94,20 @@ public void parse_repeatedNonTagValue_failure() {
assertParseFailure(parser, ADDRESS_DESC_AMY + validExpectedPersonString,
Messages.getErrorMessageForDuplicatePrefixes(PREFIX_ADDRESS));
+ // multiple date of birth
+ assertParseFailure(parser, DATEOFBIRTH_DESC_AMY + validExpectedPersonString,
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_DATEOFBIRTH));
+
+ // multiple sex
+ assertParseFailure(parser, SEX_DESC_AMY + validExpectedPersonString,
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_SEX));
+
// multiple fields repeated
assertParseFailure(parser,
validExpectedPersonString + PHONE_DESC_AMY + EMAIL_DESC_AMY + NAME_DESC_AMY + ADDRESS_DESC_AMY
- + validExpectedPersonString,
- Messages.getErrorMessageForDuplicatePrefixes(PREFIX_NAME, PREFIX_ADDRESS, PREFIX_EMAIL, PREFIX_PHONE));
+ + DATEOFBIRTH_DESC_AMY + SEX_DESC_AMY + validExpectedPersonString,
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_NAME, PREFIX_ADDRESS, PREFIX_EMAIL, PREFIX_PHONE,
+ PREFIX_DATEOFBIRTH, PREFIX_SEX));
// invalid value followed by valid value
@@ -110,6 +127,14 @@ public void parse_repeatedNonTagValue_failure() {
assertParseFailure(parser, INVALID_ADDRESS_DESC + validExpectedPersonString,
Messages.getErrorMessageForDuplicatePrefixes(PREFIX_ADDRESS));
+ // invalid date of birth
+ assertParseFailure(parser, INVALID_DATEOFBIRTH_DESC + validExpectedPersonString,
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_DATEOFBIRTH));
+
+ // invalid sex
+ assertParseFailure(parser, INVALID_SEX_DESC + validExpectedPersonString,
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_SEX));
+
// valid value followed by invalid value
// invalid name
@@ -127,14 +152,24 @@ public void parse_repeatedNonTagValue_failure() {
// invalid address
assertParseFailure(parser, validExpectedPersonString + INVALID_ADDRESS_DESC,
Messages.getErrorMessageForDuplicatePrefixes(PREFIX_ADDRESS));
+
+ // invalid date of birth
+ assertParseFailure(parser, validExpectedPersonString + INVALID_DATEOFBIRTH_DESC,
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_DATEOFBIRTH));
+
+ // invalid sex
+ assertParseFailure(parser, validExpectedPersonString + INVALID_SEX_DESC,
+ Messages.getErrorMessageForDuplicatePrefixes(PREFIX_SEX));
}
@Test
public void parse_optionalFieldsMissing_success() {
// zero tags
- Person expectedPerson = new PersonBuilder(AMY).withTags().build();
- assertParseSuccess(parser, NAME_DESC_AMY + PHONE_DESC_AMY + EMAIL_DESC_AMY + ADDRESS_DESC_AMY,
- new AddCommand(expectedPerson));
+ Patient expectedPatient = new PatientBuilder(AMY).build();
+ System.out.println(expectedPatient);
+ assertParseSuccess(parser, NAME_DESC_AMY + PHONE_DESC_AMY + EMAIL_DESC_AMY + ADDRESS_DESC_AMY
+ + DATEOFBIRTH_DESC_AMY + SEX_DESC_AMY,
+ new AddCommand(expectedPatient));
}
@Test
@@ -142,23 +177,38 @@ public void parse_compulsoryFieldMissing_failure() {
String expectedMessage = String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE);
// missing name prefix
- assertParseFailure(parser, VALID_NAME_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB,
+ assertParseFailure(parser, VALID_NAME_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB
+ + DATEOFBIRTH_DESC_BOB + SEX_DESC_BOB,
expectedMessage);
// missing phone prefix
- assertParseFailure(parser, NAME_DESC_BOB + VALID_PHONE_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB,
+ assertParseFailure(parser, NAME_DESC_BOB + VALID_PHONE_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB
+ + DATEOFBIRTH_DESC_BOB + SEX_DESC_BOB,
expectedMessage);
// missing email prefix
- assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + VALID_EMAIL_BOB + ADDRESS_DESC_BOB,
+ assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + VALID_EMAIL_BOB + ADDRESS_DESC_BOB
+ + DATEOFBIRTH_DESC_BOB + SEX_DESC_BOB,
expectedMessage);
// missing address prefix
- assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + VALID_ADDRESS_BOB,
+ assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + VALID_ADDRESS_BOB
+ + DATEOFBIRTH_DESC_BOB + SEX_DESC_BOB,
+ expectedMessage);
+
+ // missing date of birth prefix
+ assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB
+ + VALID_DATEOFBIRTH_BOB + SEX_DESC_BOB,
+ expectedMessage);
+
+ // missing sex prefix
+ assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB
+ + DATEOFBIRTH_DESC_BOB + VALID_SEX_BOB,
expectedMessage);
// all prefixes missing
- assertParseFailure(parser, VALID_NAME_BOB + VALID_PHONE_BOB + VALID_EMAIL_BOB + VALID_ADDRESS_BOB,
+ assertParseFailure(parser, VALID_NAME_BOB + VALID_PHONE_BOB + VALID_EMAIL_BOB + VALID_ADDRESS_BOB
+ + VALID_DATEOFBIRTH_BOB + VALID_SEX_BOB,
expectedMessage);
}
@@ -166,31 +216,42 @@ public void parse_compulsoryFieldMissing_failure() {
public void parse_invalidValue_failure() {
// invalid name
assertParseFailure(parser, INVALID_NAME_DESC + PHONE_DESC_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB
- + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, Name.MESSAGE_CONSTRAINTS);
+ + DATEOFBIRTH_DESC_BOB + SEX_DESC_BOB,
+ Name.MESSAGE_CONSTRAINTS);
// invalid phone
assertParseFailure(parser, NAME_DESC_BOB + INVALID_PHONE_DESC + EMAIL_DESC_BOB + ADDRESS_DESC_BOB
- + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, Phone.MESSAGE_CONSTRAINTS);
+ + DATEOFBIRTH_DESC_BOB + SEX_DESC_BOB,
+ Phone.MESSAGE_CONSTRAINTS);
// invalid email
assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + INVALID_EMAIL_DESC + ADDRESS_DESC_BOB
- + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, Email.MESSAGE_CONSTRAINTS);
+ + DATEOFBIRTH_DESC_BOB + SEX_DESC_BOB,
+ Email.MESSAGE_CONSTRAINTS);
// invalid address
assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + INVALID_ADDRESS_DESC
- + TAG_DESC_HUSBAND + TAG_DESC_FRIEND, Address.MESSAGE_CONSTRAINTS);
+ + DATEOFBIRTH_DESC_BOB + SEX_DESC_BOB,
+ Address.MESSAGE_CONSTRAINTS);
+
+ // invalid date of birth
+ assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB
+ + INVALID_DATEOFBIRTH_DESC + SEX_DESC_BOB,
+ DateOfBirth.MESSAGE_CONSTRAINTS);
- // invalid tag
+ // invalid sex
assertParseFailure(parser, NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB + ADDRESS_DESC_BOB
- + INVALID_TAG_DESC + VALID_TAG_FRIEND, Tag.MESSAGE_CONSTRAINTS);
+ + DATEOFBIRTH_DESC_BOB + INVALID_SEX_DESC,
+ Sex.MESSAGE_CONSTRAINTS);
// two invalid values, only first invalid value reported
- assertParseFailure(parser, INVALID_NAME_DESC + PHONE_DESC_BOB + EMAIL_DESC_BOB + INVALID_ADDRESS_DESC,
+ assertParseFailure(parser, INVALID_NAME_DESC + PHONE_DESC_BOB + EMAIL_DESC_BOB + INVALID_ADDRESS_DESC
+ + DATEOFBIRTH_DESC_BOB + SEX_DESC_BOB,
Name.MESSAGE_CONSTRAINTS);
// non-empty preamble
assertParseFailure(parser, PREAMBLE_NON_EMPTY + NAME_DESC_BOB + PHONE_DESC_BOB + EMAIL_DESC_BOB
- + ADDRESS_DESC_BOB + TAG_DESC_HUSBAND + TAG_DESC_FRIEND,
+ + ADDRESS_DESC_BOB + DATEOFBIRTH_DESC_BOB + SEX_DESC_BOB,
String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE));
}
}
diff --git a/src/test/java/seedu/address/logic/parser/AddVisitCommandParserTest.java b/src/test/java/seedu/address/logic/parser/AddVisitCommandParserTest.java
new file mode 100644
index 00000000000..fc7b81596ce
--- /dev/null
+++ b/src/test/java/seedu/address/logic/parser/AddVisitCommandParserTest.java
@@ -0,0 +1,38 @@
+package seedu.address.logic.parser;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.logic.commands.AddVisitCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.patient.Visit;
+import seedu.address.testutil.VisitBuilder;
+
+public class AddVisitCommandParserTest {
+ private AddVisitCommandParser parser = new AddVisitCommandParser();
+
+ @Test
+ public void parse_invalidArg_throwsParseException() {
+ assertParseFailure(parser, " ", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ AddVisitCommand.MESSAGE_USAGE));
+ assertParseFailure(parser, "n/name n/anothername", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ AddVisitCommand.MESSAGE_USAGE));
+ assertParseFailure(parser, "n/name p/phone c/condition v/High",
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddVisitCommand.MESSAGE_USAGE));
+ }
+
+
+ @Test
+ public void parse_validArgs_returnsAddVisitCommand() throws ParseException {
+ Visit testVisit = new VisitBuilder().build();
+ AddVisitCommand actualCommandWithoutindex =
+ parser.parse(" n/Alice p/99999999 d/2025-2-25 v/Low c/Fever");
+ assertTrue(actualCommandWithoutindex instanceof AddVisitCommand);
+ AddVisitCommand actualCommandWithindex =
+ parser.parse(" 1 d/25/2/2025 v/Low c/Fever");
+ assertTrue(actualCommandWithindex instanceof AddVisitCommand);
+ }
+}
diff --git a/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java b/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java
deleted file mode 100644
index 5a1ab3dbc0c..00000000000
--- a/src/test/java/seedu/address/logic/parser/AddressBookParserTest.java
+++ /dev/null
@@ -1,101 +0,0 @@
-package seedu.address.logic.parser;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
-import static seedu.address.logic.Messages.MESSAGE_UNKNOWN_COMMAND;
-import static seedu.address.testutil.Assert.assertThrows;
-import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.stream.Collectors;
-
-import org.junit.jupiter.api.Test;
-
-import seedu.address.logic.commands.AddCommand;
-import seedu.address.logic.commands.ClearCommand;
-import seedu.address.logic.commands.DeleteCommand;
-import seedu.address.logic.commands.EditCommand;
-import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
-import seedu.address.logic.commands.ExitCommand;
-import seedu.address.logic.commands.FindCommand;
-import seedu.address.logic.commands.HelpCommand;
-import seedu.address.logic.commands.ListCommand;
-import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
-import seedu.address.model.person.Person;
-import seedu.address.testutil.EditPersonDescriptorBuilder;
-import seedu.address.testutil.PersonBuilder;
-import seedu.address.testutil.PersonUtil;
-
-public class AddressBookParserTest {
-
- private final AddressBookParser parser = new AddressBookParser();
-
- @Test
- public void parseCommand_add() throws Exception {
- Person person = new PersonBuilder().build();
- AddCommand command = (AddCommand) parser.parseCommand(PersonUtil.getAddCommand(person));
- assertEquals(new AddCommand(person), command);
- }
-
- @Test
- public void parseCommand_clear() throws Exception {
- assertTrue(parser.parseCommand(ClearCommand.COMMAND_WORD) instanceof ClearCommand);
- assertTrue(parser.parseCommand(ClearCommand.COMMAND_WORD + " 3") instanceof ClearCommand);
- }
-
- @Test
- public void parseCommand_delete() throws Exception {
- DeleteCommand command = (DeleteCommand) parser.parseCommand(
- DeleteCommand.COMMAND_WORD + " " + INDEX_FIRST_PERSON.getOneBased());
- assertEquals(new DeleteCommand(INDEX_FIRST_PERSON), command);
- }
-
- @Test
- public void parseCommand_edit() throws Exception {
- Person person = new PersonBuilder().build();
- EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder(person).build();
- EditCommand command = (EditCommand) parser.parseCommand(EditCommand.COMMAND_WORD + " "
- + INDEX_FIRST_PERSON.getOneBased() + " " + PersonUtil.getEditPersonDescriptorDetails(descriptor));
- assertEquals(new EditCommand(INDEX_FIRST_PERSON, descriptor), command);
- }
-
- @Test
- public void parseCommand_exit() throws Exception {
- assertTrue(parser.parseCommand(ExitCommand.COMMAND_WORD) instanceof ExitCommand);
- assertTrue(parser.parseCommand(ExitCommand.COMMAND_WORD + " 3") instanceof ExitCommand);
- }
-
- @Test
- public void parseCommand_find() throws Exception {
- List keywords = Arrays.asList("foo", "bar", "baz");
- FindCommand command = (FindCommand) parser.parseCommand(
- FindCommand.COMMAND_WORD + " " + keywords.stream().collect(Collectors.joining(" ")));
- assertEquals(new FindCommand(new NameContainsKeywordsPredicate(keywords)), command);
- }
-
- @Test
- public void parseCommand_help() throws Exception {
- assertTrue(parser.parseCommand(HelpCommand.COMMAND_WORD) instanceof HelpCommand);
- assertTrue(parser.parseCommand(HelpCommand.COMMAND_WORD + " 3") instanceof HelpCommand);
- }
-
- @Test
- public void parseCommand_list() throws Exception {
- assertTrue(parser.parseCommand(ListCommand.COMMAND_WORD) instanceof ListCommand);
- assertTrue(parser.parseCommand(ListCommand.COMMAND_WORD + " 3") instanceof ListCommand);
- }
-
- @Test
- public void parseCommand_unrecognisedInput_throwsParseException() {
- assertThrows(ParseException.class, String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE), ()
- -> parser.parseCommand(""));
- }
-
- @Test
- public void parseCommand_unknownCommand_throwsParseException() {
- assertThrows(ParseException.class, MESSAGE_UNKNOWN_COMMAND, () -> parser.parseCommand("unknownCommand"));
- }
-}
diff --git a/src/test/java/seedu/address/logic/parser/DateTimeParserTest.java b/src/test/java/seedu/address/logic/parser/DateTimeParserTest.java
new file mode 100644
index 00000000000..2705e7a4f03
--- /dev/null
+++ b/src/test/java/seedu/address/logic/parser/DateTimeParserTest.java
@@ -0,0 +1,40 @@
+package seedu.address.logic.parser;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+
+import org.junit.jupiter.api.Test;
+
+public class DateTimeParserTest {
+ @Test
+ public void parseDateTime() {
+ // invalid date string
+ assertEquals(DateTimeParser.parseDateTime(""), null);
+ assertEquals(DateTimeParser.parseDateTime(" "), null);
+ assertEquals(DateTimeParser.parseDateTime("wdalsjdaj"), null);
+ assertEquals(DateTimeParser.parseDateTime("12/2024"), null);
+ assertEquals(DateTimeParser.parseDateTime("245/2/2024"), null);
+ assertEquals(DateTimeParser.parseDateTime("25/24/2024"), null);
+ assertEquals(DateTimeParser.parseDateTime("25/2/22"), null);
+
+ // valid date string
+ assertEquals(DateTimeParser.parseDateTime("25/2/2024"),
+ LocalDate.parse("25/2/2024", DateTimeFormatter.ofPattern("d/M/yyyy")));
+ assertEquals(DateTimeParser.parseDateTime("2024-2-24"), LocalDate.parse("2024-2-24",
+ DateTimeFormatter.ofPattern("yyyy-M-d")));
+ }
+
+ @Test
+ public void outputDateTime() {
+ assertEquals(
+ DateTimeParser.outputDateTime(
+ LocalDate.parse("25/2/2024", DateTimeFormatter.ofPattern("d/M/yyyy"))),
+ "2024-2-25");
+ assertEquals(
+ DateTimeParser.outputDateTime(
+ LocalDate.parse("2024-2-24", DateTimeFormatter.ofPattern("yyyy-M-d"))),
+ "2024-2-24");
+ }
+}
diff --git a/src/test/java/seedu/address/logic/parser/DeleteCommandParserTest.java b/src/test/java/seedu/address/logic/parser/DeleteByIndexCommandParserTest.java
similarity index 68%
rename from src/test/java/seedu/address/logic/parser/DeleteCommandParserTest.java
rename to src/test/java/seedu/address/logic/parser/DeleteByIndexCommandParserTest.java
index 6a40e14a649..96cd02b1a05 100644
--- a/src/test/java/seedu/address/logic/parser/DeleteCommandParserTest.java
+++ b/src/test/java/seedu/address/logic/parser/DeleteByIndexCommandParserTest.java
@@ -3,11 +3,11 @@
import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure;
import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess;
-import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
+import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PATIENT;
import org.junit.jupiter.api.Test;
-import seedu.address.logic.commands.DeleteCommand;
+import seedu.address.logic.commands.DeleteByIndexCommand;
/**
* As we are only doing white-box testing, our test cases do not cover path variations
@@ -16,17 +16,18 @@
* The path variation for those two cases occur inside the ParserUtil, and
* therefore should be covered by the ParserUtilTest.
*/
-public class DeleteCommandParserTest {
+public class DeleteByIndexCommandParserTest {
- private DeleteCommandParser parser = new DeleteCommandParser();
+ private DeleteByIndexCommandParser parser = new DeleteByIndexCommandParser();
@Test
public void parse_validArgs_returnsDeleteCommand() {
- assertParseSuccess(parser, "1", new DeleteCommand(INDEX_FIRST_PERSON));
+ assertParseSuccess(parser, "1", new DeleteByIndexCommand(INDEX_FIRST_PATIENT));
}
@Test
public void parse_invalidArgs_throwsParseException() {
- assertParseFailure(parser, "a", String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteCommand.MESSAGE_USAGE));
+ assertParseFailure(parser, "a",
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteByIndexCommand.MESSAGE_USAGE));
}
}
diff --git a/src/test/java/seedu/address/logic/parser/DeleteVisitCommandParserTest.java b/src/test/java/seedu/address/logic/parser/DeleteVisitCommandParserTest.java
new file mode 100644
index 00000000000..e254d06a561
--- /dev/null
+++ b/src/test/java/seedu/address/logic/parser/DeleteVisitCommandParserTest.java
@@ -0,0 +1,38 @@
+package seedu.address.logic.parser;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.logic.commands.DeleteVisitCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.patient.Visit;
+import seedu.address.testutil.VisitBuilder;
+
+public class DeleteVisitCommandParserTest {
+ private DeleteVisitCommandParser parser = new DeleteVisitCommandParser();
+
+ @Test
+ public void parse_invalidArg_throwsParseException() {
+ assertParseFailure(parser, " ", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ DeleteVisitCommand.MESSAGE_USAGE));
+ assertParseFailure(parser, "n/name n/anothername", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ DeleteVisitCommand.MESSAGE_USAGE));
+ assertParseFailure(parser, "n/name",
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, DeleteVisitCommand.MESSAGE_USAGE));
+ }
+
+
+ @Test
+ public void parse_validArgs_returnsDeleteVisitCommand() throws ParseException {
+ Visit testVisit = new VisitBuilder().build();
+ DeleteVisitCommand actualCommandWithoutindex =
+ parser.parse(" n/Alice p/99999999");
+ assertTrue(actualCommandWithoutindex instanceof DeleteVisitCommand);
+ DeleteVisitCommand actualCommandWithindex =
+ parser.parse(" 1 ");
+ assertTrue(actualCommandWithindex instanceof DeleteVisitCommand);
+ }
+}
diff --git a/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java b/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java
index cc7175172d4..05444207f0a 100644
--- a/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java
+++ b/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java
@@ -9,46 +9,37 @@
import static seedu.address.logic.commands.CommandTestUtil.INVALID_EMAIL_DESC;
import static seedu.address.logic.commands.CommandTestUtil.INVALID_NAME_DESC;
import static seedu.address.logic.commands.CommandTestUtil.INVALID_PHONE_DESC;
-import static seedu.address.logic.commands.CommandTestUtil.INVALID_TAG_DESC;
import static seedu.address.logic.commands.CommandTestUtil.NAME_DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.PHONE_DESC_AMY;
import static seedu.address.logic.commands.CommandTestUtil.PHONE_DESC_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.TAG_DESC_FRIEND;
-import static seedu.address.logic.commands.CommandTestUtil.TAG_DESC_HUSBAND;
import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_AMY;
import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_AMY;
import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_AMY;
import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_AMY;
import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_FRIEND;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure;
import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess;
-import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
-import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND_PERSON;
-import static seedu.address.testutil.TypicalIndexes.INDEX_THIRD_PERSON;
+import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PATIENT;
+import static seedu.address.testutil.TypicalIndexes.INDEX_SECOND_PATIENT;
+import static seedu.address.testutil.TypicalIndexes.INDEX_THIRD_PATIENT;
import org.junit.jupiter.api.Test;
import seedu.address.commons.core.index.Index;
import seedu.address.logic.Messages;
import seedu.address.logic.commands.EditCommand;
-import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
-import seedu.address.testutil.EditPersonDescriptorBuilder;
+import seedu.address.logic.commands.EditCommand.EditPatientDescriptor;
+import seedu.address.model.patient.Address;
+import seedu.address.model.patient.Email;
+import seedu.address.model.patient.Name;
+import seedu.address.model.patient.Phone;
+import seedu.address.testutil.EditPatientDescriptorBuilder;
public class EditCommandParserTest {
- private static final String TAG_EMPTY = " " + PREFIX_TAG;
-
private static final String MESSAGE_INVALID_FORMAT =
String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE);
@@ -87,16 +78,11 @@ public void parse_invalidValue_failure() {
assertParseFailure(parser, "1" + INVALID_PHONE_DESC, Phone.MESSAGE_CONSTRAINTS); // invalid phone
assertParseFailure(parser, "1" + INVALID_EMAIL_DESC, Email.MESSAGE_CONSTRAINTS); // invalid email
assertParseFailure(parser, "1" + INVALID_ADDRESS_DESC, Address.MESSAGE_CONSTRAINTS); // invalid address
- assertParseFailure(parser, "1" + INVALID_TAG_DESC, Tag.MESSAGE_CONSTRAINTS); // invalid tag
// invalid phone followed by valid email
assertParseFailure(parser, "1" + INVALID_PHONE_DESC + EMAIL_DESC_AMY, Phone.MESSAGE_CONSTRAINTS);
- // while parsing {@code PREFIX_TAG} alone will reset the tags of the {@code Person} being edited,
- // parsing it together with a valid tag results in error
- assertParseFailure(parser, "1" + TAG_DESC_FRIEND + TAG_DESC_HUSBAND + TAG_EMPTY, Tag.MESSAGE_CONSTRAINTS);
- assertParseFailure(parser, "1" + TAG_DESC_FRIEND + TAG_EMPTY + TAG_DESC_HUSBAND, Tag.MESSAGE_CONSTRAINTS);
- assertParseFailure(parser, "1" + TAG_EMPTY + TAG_DESC_FRIEND + TAG_DESC_HUSBAND, Tag.MESSAGE_CONSTRAINTS);
+ // while parsing {@code PREFIX_TAG} alone will reset the tags of the {@code Patient} being edited,
// multiple invalid values, but only the first invalid value is captured
assertParseFailure(parser, "1" + INVALID_NAME_DESC + INVALID_EMAIL_DESC + VALID_ADDRESS_AMY + VALID_PHONE_AMY,
@@ -105,13 +91,13 @@ public void parse_invalidValue_failure() {
@Test
public void parse_allFieldsSpecified_success() {
- Index targetIndex = INDEX_SECOND_PERSON;
- String userInput = targetIndex.getOneBased() + PHONE_DESC_BOB + TAG_DESC_HUSBAND
- + EMAIL_DESC_AMY + ADDRESS_DESC_AMY + NAME_DESC_AMY + TAG_DESC_FRIEND;
+ Index targetIndex = INDEX_SECOND_PATIENT;
+ String userInput = targetIndex.getOneBased() + PHONE_DESC_BOB
+ + EMAIL_DESC_AMY + ADDRESS_DESC_AMY + NAME_DESC_AMY;
- EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withName(VALID_NAME_AMY)
+ EditPatientDescriptor descriptor = new EditPatientDescriptorBuilder().withName(VALID_NAME_AMY)
.withPhone(VALID_PHONE_BOB).withEmail(VALID_EMAIL_AMY).withAddress(VALID_ADDRESS_AMY)
- .withTags(VALID_TAG_HUSBAND, VALID_TAG_FRIEND).build();
+ .build();
EditCommand expectedCommand = new EditCommand(targetIndex, descriptor);
assertParseSuccess(parser, userInput, expectedCommand);
@@ -119,10 +105,10 @@ public void parse_allFieldsSpecified_success() {
@Test
public void parse_someFieldsSpecified_success() {
- Index targetIndex = INDEX_FIRST_PERSON;
+ Index targetIndex = INDEX_FIRST_PATIENT;
String userInput = targetIndex.getOneBased() + PHONE_DESC_BOB + EMAIL_DESC_AMY;
- EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withPhone(VALID_PHONE_BOB)
+ EditPatientDescriptor descriptor = new EditPatientDescriptorBuilder().withPhone(VALID_PHONE_BOB)
.withEmail(VALID_EMAIL_AMY).build();
EditCommand expectedCommand = new EditCommand(targetIndex, descriptor);
@@ -132,33 +118,27 @@ public void parse_someFieldsSpecified_success() {
@Test
public void parse_oneFieldSpecified_success() {
// name
- Index targetIndex = INDEX_THIRD_PERSON;
+ Index targetIndex = INDEX_THIRD_PATIENT;
String userInput = targetIndex.getOneBased() + NAME_DESC_AMY;
- EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withName(VALID_NAME_AMY).build();
+ EditPatientDescriptor descriptor = new EditPatientDescriptorBuilder().withName(VALID_NAME_AMY).build();
EditCommand expectedCommand = new EditCommand(targetIndex, descriptor);
assertParseSuccess(parser, userInput, expectedCommand);
// phone
userInput = targetIndex.getOneBased() + PHONE_DESC_AMY;
- descriptor = new EditPersonDescriptorBuilder().withPhone(VALID_PHONE_AMY).build();
+ descriptor = new EditPatientDescriptorBuilder().withPhone(VALID_PHONE_AMY).build();
expectedCommand = new EditCommand(targetIndex, descriptor);
assertParseSuccess(parser, userInput, expectedCommand);
// email
userInput = targetIndex.getOneBased() + EMAIL_DESC_AMY;
- descriptor = new EditPersonDescriptorBuilder().withEmail(VALID_EMAIL_AMY).build();
+ descriptor = new EditPatientDescriptorBuilder().withEmail(VALID_EMAIL_AMY).build();
expectedCommand = new EditCommand(targetIndex, descriptor);
assertParseSuccess(parser, userInput, expectedCommand);
// address
userInput = targetIndex.getOneBased() + ADDRESS_DESC_AMY;
- descriptor = new EditPersonDescriptorBuilder().withAddress(VALID_ADDRESS_AMY).build();
- expectedCommand = new EditCommand(targetIndex, descriptor);
- assertParseSuccess(parser, userInput, expectedCommand);
-
- // tags
- userInput = targetIndex.getOneBased() + TAG_DESC_FRIEND;
- descriptor = new EditPersonDescriptorBuilder().withTags(VALID_TAG_FRIEND).build();
+ descriptor = new EditPatientDescriptorBuilder().withAddress(VALID_ADDRESS_AMY).build();
expectedCommand = new EditCommand(targetIndex, descriptor);
assertParseSuccess(parser, userInput, expectedCommand);
}
@@ -169,7 +149,7 @@ public void parse_multipleRepeatedFields_failure() {
// AddCommandParserTest#parse_repeatedNonTagValue_failure()
// valid followed by invalid
- Index targetIndex = INDEX_FIRST_PERSON;
+ Index targetIndex = INDEX_FIRST_PATIENT;
String userInput = targetIndex.getOneBased() + INVALID_PHONE_DESC + PHONE_DESC_BOB;
assertParseFailure(parser, userInput, Messages.getErrorMessageForDuplicatePrefixes(PREFIX_PHONE));
@@ -181,8 +161,8 @@ public void parse_multipleRepeatedFields_failure() {
// mulltiple valid fields repeated
userInput = targetIndex.getOneBased() + PHONE_DESC_AMY + ADDRESS_DESC_AMY + EMAIL_DESC_AMY
- + TAG_DESC_FRIEND + PHONE_DESC_AMY + ADDRESS_DESC_AMY + EMAIL_DESC_AMY + TAG_DESC_FRIEND
- + PHONE_DESC_BOB + ADDRESS_DESC_BOB + EMAIL_DESC_BOB + TAG_DESC_HUSBAND;
+ + PHONE_DESC_AMY + ADDRESS_DESC_AMY + EMAIL_DESC_AMY
+ + PHONE_DESC_BOB + ADDRESS_DESC_BOB + EMAIL_DESC_BOB;
assertParseFailure(parser, userInput,
Messages.getErrorMessageForDuplicatePrefixes(PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS));
@@ -194,15 +174,4 @@ public void parse_multipleRepeatedFields_failure() {
assertParseFailure(parser, userInput,
Messages.getErrorMessageForDuplicatePrefixes(PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS));
}
-
- @Test
- public void parse_resetTags_success() {
- Index targetIndex = INDEX_THIRD_PERSON;
- String userInput = targetIndex.getOneBased() + TAG_EMPTY;
-
- EditPersonDescriptor descriptor = new EditPersonDescriptorBuilder().withTags().build();
- EditCommand expectedCommand = new EditCommand(targetIndex, descriptor);
-
- assertParseSuccess(parser, userInput, expectedCommand);
- }
}
diff --git a/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java.rej b/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java.rej
new file mode 100644
index 00000000000..b3484542244
--- /dev/null
+++ b/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java.rej
@@ -0,0 +1,18 @@
+diff a/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java b/src/test/java/seedu/address/logic/parser/EditCommandParserTest.java (rejected hunks)
+@@ -3,13 +3,16 @@
+ import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+ import static seedu.address.logic.commands.CommandTestUtil.ADDRESS_DESC_AMY;
+ import static seedu.address.logic.commands.CommandTestUtil.ADDRESS_DESC_BOB;
++import static seedu.address.logic.commands.CommandTestUtil.DATEOFBIRTH_DESC_AMY;
+ import static seedu.address.logic.commands.CommandTestUtil.EMAIL_DESC_AMY;
+ import static seedu.address.logic.commands.CommandTestUtil.EMAIL_DESC_BOB;
+ import static seedu.address.logic.commands.CommandTestUtil.INVALID_ADDRESS_DESC;
+ import static seedu.address.logic.commands.CommandTestUtil.INVALID_EMAIL_DESC;
+ import static seedu.address.logic.commands.CommandTestUtil.INVALID_NAME_DESC;
+ import static seedu.address.logic.commands.CommandTestUtil.INVALID_PHONE_DESC;
++import static seedu.address.logic.commands.CommandTestUtil.INVALID_SEX_DESC;
+ import static seedu.address.logic.commands.CommandTestUtil.NAME_DESC_AMY;
++import static seedu.address.logic.commands.CommandTestUtil.NAME_DESC_BOB;
+ import static seedu.address.logic.commands.CommandTestUtil.PHONE_DESC_AMY;
+ import static seedu.address.logic.commands.CommandTestUtil.PHONE_DESC_BOB;
+ import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_AMY;
diff --git a/src/test/java/seedu/address/logic/parser/EditVisitCommandParserTest.java b/src/test/java/seedu/address/logic/parser/EditVisitCommandParserTest.java
new file mode 100644
index 00000000000..2e2937c3f0b
--- /dev/null
+++ b/src/test/java/seedu/address/logic/parser/EditVisitCommandParserTest.java
@@ -0,0 +1,36 @@
+package seedu.address.logic.parser;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.logic.commands.EditVisitCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.patient.Visit;
+import seedu.address.testutil.VisitBuilder;
+
+public class EditVisitCommandParserTest {
+ private EditVisitCommandParser parser = new EditVisitCommandParser();
+
+ @Test
+ public void parse_invalidArg_throwsParseException() {
+ assertParseFailure(parser, " ", EditVisitCommand.MESSAGE_NOT_EDITED);
+ assertParseFailure(parser, "n/name n/anothername", EditVisitCommand.MESSAGE_NOT_EDITED);
+ assertParseFailure(parser, "1 n/name p/phone c/condition v/High",
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditVisitCommand.MESSAGE_USAGE));
+ }
+
+
+ @Test
+ public void parse_validArgs_returnsEditVisitCommand() throws ParseException {
+ Visit testVisit = new VisitBuilder().build();
+ EditVisitCommand actualCommandWithoutindex =
+ parser.parse(" n/Alice p/99999999 d/2025-2-25 v/High c/Fever");
+ assertTrue(actualCommandWithoutindex instanceof EditVisitCommand);
+ EditVisitCommand actualCommandWithindex =
+ parser.parse(" 1 d/25/2/2025 v/High c/Fever");
+ assertTrue(actualCommandWithindex instanceof EditVisitCommand);
+ }
+}
diff --git a/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java b/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java
index d92e64d12f9..28a1eb54ec7 100644
--- a/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java
+++ b/src/test/java/seedu/address/logic/parser/FindCommandParserTest.java
@@ -3,32 +3,50 @@
import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static seedu.address.logic.parser.CommandParserTestUtil.assertParseFailure;
import static seedu.address.logic.parser.CommandParserTestUtil.assertParseSuccess;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PATIENTS;
-import java.util.Arrays;
+import java.util.List;
import org.junit.jupiter.api.Test;
import seedu.address.logic.commands.FindCommand;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
+import seedu.address.model.patient.NameContainsKeywordsPredicate;
+import seedu.address.model.patient.Phone;
+import seedu.address.model.patient.PhoneMatchesPredicate;
public class FindCommandParserTest {
private FindCommandParser parser = new FindCommandParser();
@Test
- public void parse_emptyArg_throwsParseException() {
- assertParseFailure(parser, " ", String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE));
+ public void parse_invalidArg_throwsParseException() {
+ assertParseFailure(parser, " ", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ FindCommand.MESSAGE_USAGE));
+ assertParseFailure(parser, "1 n/name", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ FindCommand.MESSAGE_USAGE));
+ assertParseFailure(parser, "n/ p/", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ FindCommand.MESSAGE_USAGE));
+ assertParseFailure(parser, "name", String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ FindCommand.MESSAGE_USAGE));
}
+
@Test
public void parse_validArgs_returnsFindCommand() {
- // no leading and trailing whitespaces
FindCommand expectedFindCommand =
- new FindCommand(new NameContainsKeywordsPredicate(Arrays.asList("Alice", "Bob")));
- assertParseSuccess(parser, "Alice Bob", expectedFindCommand);
-
- // multiple whitespaces between keywords
- assertParseSuccess(parser, " \n Alice \n \t Bob \t", expectedFindCommand);
+ new FindCommand(new NameContainsKeywordsPredicate(List.of("Alice")),
+ new PhoneMatchesPredicate(new Phone("99999999")));
+ assertParseSuccess(parser, " n/Alice p/99999999", expectedFindCommand);
+ assertParseSuccess(parser, " \n n/Alice \n \t p/99999999 \t", expectedFindCommand);
+
+ expectedFindCommand =
+ new FindCommand(new NameContainsKeywordsPredicate(List.of("Alice")),
+ PREDICATE_SHOW_ALL_PATIENTS);
+ assertParseSuccess(parser, " n/Alice", expectedFindCommand);
+
+ expectedFindCommand =
+ new FindCommand(PREDICATE_SHOW_ALL_PATIENTS,
+ new PhoneMatchesPredicate(new Phone("99999999")));
+ assertParseSuccess(parser, " p/99999999", expectedFindCommand);
}
-
}
diff --git a/src/test/java/seedu/address/logic/parser/ParserUtilTest.java b/src/test/java/seedu/address/logic/parser/ParserUtilTest.java
index 4256788b1a7..2d5a2a6b3cf 100644
--- a/src/test/java/seedu/address/logic/parser/ParserUtilTest.java
+++ b/src/test/java/seedu/address/logic/parser/ParserUtilTest.java
@@ -1,38 +1,28 @@
package seedu.address.logic.parser;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
import static seedu.address.logic.parser.ParserUtil.MESSAGE_INVALID_INDEX;
import static seedu.address.testutil.Assert.assertThrows;
-import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
+import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PATIENT;
import org.junit.jupiter.api.Test;
import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
+import seedu.address.model.patient.Address;
+import seedu.address.model.patient.Email;
+import seedu.address.model.patient.Name;
+import seedu.address.model.patient.Phone;
public class ParserUtilTest {
private static final String INVALID_NAME = "R@chel";
private static final String INVALID_PHONE = "+651234";
private static final String INVALID_ADDRESS = " ";
private static final String INVALID_EMAIL = "example.com";
- private static final String INVALID_TAG = "#friend";
private static final String VALID_NAME = "Rachel Walker";
private static final String VALID_PHONE = "123456";
private static final String VALID_ADDRESS = "123 Main Street #0505";
private static final String VALID_EMAIL = "rachel@example.com";
- private static final String VALID_TAG_1 = "friend";
- private static final String VALID_TAG_2 = "neighbour";
private static final String WHITESPACE = " \t\r\n";
@@ -50,10 +40,10 @@ public void parseIndex_outOfRangeInput_throwsParseException() {
@Test
public void parseIndex_validInput_success() throws Exception {
// No whitespaces
- assertEquals(INDEX_FIRST_PERSON, ParserUtil.parseIndex("1"));
+ assertEquals(INDEX_FIRST_PATIENT, ParserUtil.parseIndex("1"));
// Leading and trailing whitespaces
- assertEquals(INDEX_FIRST_PERSON, ParserUtil.parseIndex(" 1 "));
+ assertEquals(INDEX_FIRST_PATIENT, ParserUtil.parseIndex(" 1 "));
}
@Test
@@ -147,50 +137,4 @@ public void parseEmail_validValueWithWhitespace_returnsTrimmedEmail() throws Exc
Email expectedEmail = new Email(VALID_EMAIL);
assertEquals(expectedEmail, ParserUtil.parseEmail(emailWithWhitespace));
}
-
- @Test
- public void parseTag_null_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> ParserUtil.parseTag(null));
- }
-
- @Test
- public void parseTag_invalidValue_throwsParseException() {
- assertThrows(ParseException.class, () -> ParserUtil.parseTag(INVALID_TAG));
- }
-
- @Test
- public void parseTag_validValueWithoutWhitespace_returnsTag() throws Exception {
- Tag expectedTag = new Tag(VALID_TAG_1);
- assertEquals(expectedTag, ParserUtil.parseTag(VALID_TAG_1));
- }
-
- @Test
- public void parseTag_validValueWithWhitespace_returnsTrimmedTag() throws Exception {
- String tagWithWhitespace = WHITESPACE + VALID_TAG_1 + WHITESPACE;
- Tag expectedTag = new Tag(VALID_TAG_1);
- assertEquals(expectedTag, ParserUtil.parseTag(tagWithWhitespace));
- }
-
- @Test
- public void parseTags_null_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> ParserUtil.parseTags(null));
- }
-
- @Test
- public void parseTags_collectionWithInvalidTags_throwsParseException() {
- assertThrows(ParseException.class, () -> ParserUtil.parseTags(Arrays.asList(VALID_TAG_1, INVALID_TAG)));
- }
-
- @Test
- public void parseTags_emptyCollection_returnsEmptySet() throws Exception {
- assertTrue(ParserUtil.parseTags(Collections.emptyList()).isEmpty());
- }
-
- @Test
- public void parseTags_collectionWithValidTags_returnsTagSet() throws Exception {
- Set actualTagSet = ParserUtil.parseTags(Arrays.asList(VALID_TAG_1, VALID_TAG_2));
- Set expectedTagSet = new HashSet(Arrays.asList(new Tag(VALID_TAG_1), new Tag(VALID_TAG_2)));
-
- assertEquals(expectedTagSet, actualTagSet);
- }
}
diff --git a/src/test/java/seedu/address/logic/parser/PatientListParserTest.java b/src/test/java/seedu/address/logic/parser/PatientListParserTest.java
new file mode 100644
index 00000000000..44739763209
--- /dev/null
+++ b/src/test/java/seedu/address/logic/parser/PatientListParserTest.java
@@ -0,0 +1,125 @@
+package seedu.address.logic.parser;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.Messages.MESSAGE_UNKNOWN_COMMAND;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PATIENTS;
+import static seedu.address.testutil.Assert.assertThrows;
+import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PATIENT;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.logic.commands.AddCommand;
+import seedu.address.logic.commands.DeleteAllCommand;
+import seedu.address.logic.commands.DeleteByIndexCommand;
+import seedu.address.logic.commands.EditCommand;
+import seedu.address.logic.commands.EditCommand.EditPatientDescriptor;
+import seedu.address.logic.commands.FindCommand;
+import seedu.address.logic.commands.ForceDeleteAllCommand;
+import seedu.address.logic.commands.ForceExitCommand;
+import seedu.address.logic.commands.HelpCommand;
+import seedu.address.logic.commands.ListCommand;
+import seedu.address.logic.commands.NoCommand;
+import seedu.address.logic.commands.YesCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.patient.NameContainsKeywordsPredicate;
+import seedu.address.model.patient.Patient;
+import seedu.address.testutil.EditPatientDescriptorBuilder;
+import seedu.address.testutil.PatientBuilder;
+import seedu.address.testutil.PatientUtil;
+
+public class PatientListParserTest {
+
+ private final InputParser parser = new InputParser();
+
+ @Test
+ public void parseCommand_add() throws Exception {
+ Patient patient = new PatientBuilder().build();
+ System.out.println(patient);
+ System.out.println(PatientUtil.getAddCommand(patient));
+ AddCommand command = (AddCommand) parser.parseCommand(PatientUtil.getAddCommand(patient));
+ assertEquals(new AddCommand(patient), command);
+ }
+
+ /**
+ * Test for the delete-all command.
+ *
+ * @throws Exception Exception thrown by the parseCommand method.
+ */
+ @Test
+ public void parseCommand_deleteAll() throws Exception {
+ assertTrue(parser.parseCommand(DeleteAllCommand.COMMAND_WORD) instanceof DeleteAllCommand);
+ assertTrue(parser.parseCommand(YesCommand.COMMAND_WORD) instanceof YesCommand);
+
+ assertTrue(parser.parseCommand(DeleteAllCommand.COMMAND_WORD) instanceof DeleteAllCommand);
+ assertTrue(parser.parseCommand(NoCommand.COMMAND_WORD) instanceof NoCommand);
+
+ assertTrue(parser.parseCommand(DeleteAllCommand.COMMAND_WORD) instanceof DeleteAllCommand);
+ assertThrows(ParseException.class, InputParser.getDeleteAllErrorMessage(), ()
+ -> parser.parseCommand(EditCommand.COMMAND_WORD));
+ }
+
+ @Test
+ public void parseCommand_forceDeleteAll() throws Exception {
+ assertTrue(parser.parseCommand(ForceDeleteAllCommand.COMMAND_WORD) instanceof ForceDeleteAllCommand);
+ }
+
+ @Test
+ public void parseCommand_delete() throws Exception {
+ DeleteByIndexCommand command = (DeleteByIndexCommand) parser.parseCommand(
+ DeleteByIndexCommand.COMMAND_WORD + " " + INDEX_FIRST_PATIENT.getOneBased());
+ assertEquals(new DeleteByIndexCommand(INDEX_FIRST_PATIENT), command);
+ }
+
+ @Test
+ public void parseCommand_edit() throws Exception {
+ Patient patient = new PatientBuilder().build();
+ EditPatientDescriptor descriptor = new EditPatientDescriptorBuilder(patient).build();
+ EditCommand command = (EditCommand) parser.parseCommand(EditCommand.COMMAND_WORD + " "
+ + INDEX_FIRST_PATIENT.getOneBased() + " " + PatientUtil.getEditPatientDescriptorDetails(descriptor));
+ assertEquals(new EditCommand(INDEX_FIRST_PATIENT, descriptor), command);
+ }
+
+ @Test
+ public void parseCommand_forceExit() throws Exception {
+ assertTrue(parser.parseCommand(ForceExitCommand.COMMAND_WORD) instanceof ForceExitCommand);
+ assertTrue(parser.parseCommand(ForceExitCommand.COMMAND_WORD + " 3") instanceof ForceExitCommand);
+ }
+
+ @Test
+ public void parseCommand_find() throws Exception {
+ List keywords = Arrays.asList("foo", "bar", "baz");
+ FindCommand command = (FindCommand) parser.parseCommand(
+ FindCommand.COMMAND_WORD + " n/" + keywords.stream().collect(Collectors.joining(" ")));
+ assertEquals(new FindCommand(new NameContainsKeywordsPredicate(keywords),
+ PREDICATE_SHOW_ALL_PATIENTS), command);
+ }
+
+ @Test
+ public void parseCommand_help() throws Exception {
+ assertTrue(parser.parseCommand(HelpCommand.COMMAND_WORD) instanceof HelpCommand);
+ assertTrue(parser.parseCommand(HelpCommand.COMMAND_WORD + " 3") instanceof HelpCommand);
+ }
+
+ @Test
+ public void parseCommand_list() throws Exception {
+ assertTrue(parser.parseCommand(ListCommand.COMMAND_WORD) instanceof ListCommand);
+ assertTrue(parser.parseCommand(ListCommand.COMMAND_WORD + " 3") instanceof ListCommand);
+ }
+
+ @Test
+ public void parseCommand_unrecognisedInput_throwsParseException() {
+ assertThrows(ParseException.class, String.format(MESSAGE_INVALID_COMMAND_FORMAT, HelpCommand.MESSAGE_USAGE), ()
+ -> parser.parseCommand(""));
+ }
+
+ @Test
+ public void parseCommand_unknownCommand_throwsParseException() {
+ assertThrows(ParseException.class, MESSAGE_UNKNOWN_COMMAND, () -> parser.parseCommand("unknownCommand"));
+ }
+}
diff --git a/src/test/java/seedu/address/model/AddressBookTest.java b/src/test/java/seedu/address/model/AddressBookTest.java
deleted file mode 100644
index 68c8c5ba4d5..00000000000
--- a/src/test/java/seedu/address/model/AddressBookTest.java
+++ /dev/null
@@ -1,108 +0,0 @@
-package seedu.address.model;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
-import static seedu.address.testutil.Assert.assertThrows;
-import static seedu.address.testutil.TypicalPersons.ALICE;
-import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-
-import org.junit.jupiter.api.Test;
-
-import javafx.collections.FXCollections;
-import javafx.collections.ObservableList;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.exceptions.DuplicatePersonException;
-import seedu.address.testutil.PersonBuilder;
-
-public class AddressBookTest {
-
- private final AddressBook addressBook = new AddressBook();
-
- @Test
- public void constructor() {
- assertEquals(Collections.emptyList(), addressBook.getPersonList());
- }
-
- @Test
- public void resetData_null_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> addressBook.resetData(null));
- }
-
- @Test
- public void resetData_withValidReadOnlyAddressBook_replacesData() {
- AddressBook newData = getTypicalAddressBook();
- addressBook.resetData(newData);
- assertEquals(newData, addressBook);
- }
-
- @Test
- public void resetData_withDuplicatePersons_throwsDuplicatePersonException() {
- // Two persons with the same identity fields
- Person editedAlice = new PersonBuilder(ALICE).withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_HUSBAND)
- .build();
- List newPersons = Arrays.asList(ALICE, editedAlice);
- AddressBookStub newData = new AddressBookStub(newPersons);
-
- assertThrows(DuplicatePersonException.class, () -> addressBook.resetData(newData));
- }
-
- @Test
- public void hasPerson_nullPerson_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> addressBook.hasPerson(null));
- }
-
- @Test
- public void hasPerson_personNotInAddressBook_returnsFalse() {
- assertFalse(addressBook.hasPerson(ALICE));
- }
-
- @Test
- public void hasPerson_personInAddressBook_returnsTrue() {
- addressBook.addPerson(ALICE);
- assertTrue(addressBook.hasPerson(ALICE));
- }
-
- @Test
- public void hasPerson_personWithSameIdentityFieldsInAddressBook_returnsTrue() {
- addressBook.addPerson(ALICE);
- Person editedAlice = new PersonBuilder(ALICE).withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_HUSBAND)
- .build();
- assertTrue(addressBook.hasPerson(editedAlice));
- }
-
- @Test
- public void getPersonList_modifyList_throwsUnsupportedOperationException() {
- assertThrows(UnsupportedOperationException.class, () -> addressBook.getPersonList().remove(0));
- }
-
- @Test
- public void toStringMethod() {
- String expected = AddressBook.class.getCanonicalName() + "{persons=" + addressBook.getPersonList() + "}";
- assertEquals(expected, addressBook.toString());
- }
-
- /**
- * A stub ReadOnlyAddressBook whose persons list can violate interface constraints.
- */
- private static class AddressBookStub implements ReadOnlyAddressBook {
- private final ObservableList persons = FXCollections.observableArrayList();
-
- AddressBookStub(Collection persons) {
- this.persons.setAll(persons);
- }
-
- @Override
- public ObservableList getPersonList() {
- return persons;
- }
- }
-
-}
diff --git a/src/test/java/seedu/address/model/ModelManagerTest.java b/src/test/java/seedu/address/model/ModelManagerTest.java
index 2cf1418d116..217db8e8154 100644
--- a/src/test/java/seedu/address/model/ModelManagerTest.java
+++ b/src/test/java/seedu/address/model/ModelManagerTest.java
@@ -3,10 +3,10 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PATIENTS;
import static seedu.address.testutil.Assert.assertThrows;
-import static seedu.address.testutil.TypicalPersons.ALICE;
-import static seedu.address.testutil.TypicalPersons.BENSON;
+import static seedu.address.testutil.TypicalPatients.ALICE;
+import static seedu.address.testutil.TypicalPatients.BENSON;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -15,7 +15,7 @@
import org.junit.jupiter.api.Test;
import seedu.address.commons.core.GuiSettings;
-import seedu.address.model.person.NameContainsKeywordsPredicate;
+import seedu.address.model.patient.NameContainsKeywordsPredicate;
import seedu.address.testutil.AddressBookBuilder;
public class ModelManagerTest {
@@ -26,7 +26,7 @@ public class ModelManagerTest {
public void constructor() {
assertEquals(new UserPrefs(), modelManager.getUserPrefs());
assertEquals(new GuiSettings(), modelManager.getGuiSettings());
- assertEquals(new AddressBook(), new AddressBook(modelManager.getAddressBook()));
+ assertEquals(new PatientList(), new PatientList(modelManager.getPatientList()));
}
@Test
@@ -37,14 +37,14 @@ public void setUserPrefs_nullUserPrefs_throwsNullPointerException() {
@Test
public void setUserPrefs_validUserPrefs_copiesUserPrefs() {
UserPrefs userPrefs = new UserPrefs();
- userPrefs.setAddressBookFilePath(Paths.get("address/book/file/path"));
+ userPrefs.setPatientListFilePath(Paths.get("address/book/file/path"));
userPrefs.setGuiSettings(new GuiSettings(1, 2, 3, 4));
modelManager.setUserPrefs(userPrefs);
assertEquals(userPrefs, modelManager.getUserPrefs());
// Modifying userPrefs should not modify modelManager's userPrefs
UserPrefs oldUserPrefs = new UserPrefs(userPrefs);
- userPrefs.setAddressBookFilePath(Paths.get("new/address/book/file/path"));
+ userPrefs.setPatientListFilePath(Paths.get("new/address/book/file/path"));
assertEquals(oldUserPrefs, modelManager.getUserPrefs());
}
@@ -62,46 +62,46 @@ public void setGuiSettings_validGuiSettings_setsGuiSettings() {
@Test
public void setAddressBookFilePath_nullPath_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> modelManager.setAddressBookFilePath(null));
+ assertThrows(NullPointerException.class, () -> modelManager.setPatientListFilePath(null));
}
@Test
public void setAddressBookFilePath_validPath_setsAddressBookFilePath() {
Path path = Paths.get("address/book/file/path");
- modelManager.setAddressBookFilePath(path);
- assertEquals(path, modelManager.getAddressBookFilePath());
+ modelManager.setPatientListFilePath(path);
+ assertEquals(path, modelManager.getPatientListFilePath());
}
@Test
- public void hasPerson_nullPerson_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> modelManager.hasPerson(null));
+ public void hasPatient_nullPatient_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> modelManager.hasPatient(null));
}
@Test
- public void hasPerson_personNotInAddressBook_returnsFalse() {
- assertFalse(modelManager.hasPerson(ALICE));
+ public void hasPatient_patientNotInAddressBook_returnsFalse() {
+ assertFalse(modelManager.hasPatient(ALICE));
}
@Test
- public void hasPerson_personInAddressBook_returnsTrue() {
- modelManager.addPerson(ALICE);
- assertTrue(modelManager.hasPerson(ALICE));
+ public void hasPatient_patientInAddressBook_returnsTrue() {
+ modelManager.addPatient(ALICE);
+ assertTrue(modelManager.hasPatient(ALICE));
}
@Test
- public void getFilteredPersonList_modifyList_throwsUnsupportedOperationException() {
- assertThrows(UnsupportedOperationException.class, () -> modelManager.getFilteredPersonList().remove(0));
+ public void getFilteredPatientList_modifyList_throwsUnsupportedOperationException() {
+ assertThrows(UnsupportedOperationException.class, () -> modelManager.getFilteredPatientList().remove(0));
}
@Test
public void equals() {
- AddressBook addressBook = new AddressBookBuilder().withPerson(ALICE).withPerson(BENSON).build();
- AddressBook differentAddressBook = new AddressBook();
+ PatientList patientList = new AddressBookBuilder().withPatient(ALICE).withPatient(BENSON).build();
+ PatientList differentPatientList = new PatientList();
UserPrefs userPrefs = new UserPrefs();
// same values -> returns true
- modelManager = new ModelManager(addressBook, userPrefs);
- ModelManager modelManagerCopy = new ModelManager(addressBook, userPrefs);
+ modelManager = new ModelManager(patientList, userPrefs);
+ ModelManager modelManagerCopy = new ModelManager(patientList, userPrefs);
assertTrue(modelManager.equals(modelManagerCopy));
// same object -> returns true
@@ -113,20 +113,20 @@ public void equals() {
// different types -> returns false
assertFalse(modelManager.equals(5));
- // different addressBook -> returns false
- assertFalse(modelManager.equals(new ModelManager(differentAddressBook, userPrefs)));
+ // different patientList -> returns false
+ assertFalse(modelManager.equals(new ModelManager(differentPatientList, userPrefs)));
// different filteredList -> returns false
String[] keywords = ALICE.getName().fullName.split("\\s+");
- modelManager.updateFilteredPersonList(new NameContainsKeywordsPredicate(Arrays.asList(keywords)));
- assertFalse(modelManager.equals(new ModelManager(addressBook, userPrefs)));
+ modelManager.updateFilteredPatientList(new NameContainsKeywordsPredicate(Arrays.asList(keywords)));
+ assertFalse(modelManager.equals(new ModelManager(patientList, userPrefs)));
// resets modelManager to initial state for upcoming tests
- modelManager.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
+ modelManager.updateFilteredPatientList(PREDICATE_SHOW_ALL_PATIENTS);
// different userPrefs -> returns false
UserPrefs differentUserPrefs = new UserPrefs();
- differentUserPrefs.setAddressBookFilePath(Paths.get("differentFilePath"));
- assertFalse(modelManager.equals(new ModelManager(addressBook, differentUserPrefs)));
+ differentUserPrefs.setPatientListFilePath(Paths.get("differentFilePath"));
+ assertFalse(modelManager.equals(new ModelManager(patientList, differentUserPrefs)));
}
}
diff --git a/src/test/java/seedu/address/model/PatientListTest.java b/src/test/java/seedu/address/model/PatientListTest.java
new file mode 100644
index 00000000000..ebb95620b54
--- /dev/null
+++ b/src/test/java/seedu/address/model/PatientListTest.java
@@ -0,0 +1,107 @@
+package seedu.address.model;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
+import static seedu.address.testutil.Assert.assertThrows;
+import static seedu.address.testutil.TypicalPatients.ALICE;
+import static seedu.address.testutil.TypicalPatients.getTypicalAddressBook;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import seedu.address.model.patient.Patient;
+import seedu.address.model.patient.exceptions.DuplicatePatientException;
+import seedu.address.testutil.PatientBuilder;
+
+public class PatientListTest {
+
+ private final PatientList patientList = new PatientList();
+
+ @Test
+ public void constructor() {
+ assertEquals(Collections.emptyList(), patientList.getPatientList());
+ }
+
+ @Test
+ public void resetData_null_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> patientList.resetData(null));
+ }
+
+ @Test
+ public void resetData_withValidReadOnlyAddressBook_replacesData() {
+ PatientList newData = getTypicalAddressBook();
+ patientList.resetData(newData);
+ assertEquals(newData, patientList);
+ }
+
+ @Test
+ public void resetData_withDuplicatePatients_throwsDuplicatePatientException() {
+ // Two patients with the same identity fields
+ Patient editedAlice = new PatientBuilder(ALICE).withAddress(VALID_ADDRESS_BOB)
+ .build();
+ List newPatients = Arrays.asList(ALICE, editedAlice);
+ AddressBookStub newData = new AddressBookStub(newPatients);
+
+ assertThrows(DuplicatePatientException.class, () -> patientList.resetData(newData));
+ }
+
+ @Test
+ public void hasPatient_nullPatient_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> patientList.hasPatient(null));
+ }
+
+ @Test
+ public void hasPatient_patientNotInAddressBook_returnsFalse() {
+ assertFalse(patientList.hasPatient(ALICE));
+ }
+
+ @Test
+ public void hasPatient_patientInAddressBook_returnsTrue() {
+ patientList.addPatient(ALICE);
+ assertTrue(patientList.hasPatient(ALICE));
+ }
+
+ @Test
+ public void hasPatient_patientWithSameIdentityFieldsInAddressBook_returnsTrue() {
+ patientList.addPatient(ALICE);
+ Patient editedAlice = new PatientBuilder(ALICE).withAddress(VALID_ADDRESS_BOB)
+ .build();
+ assertTrue(patientList.hasPatient(editedAlice));
+ }
+
+ @Test
+ public void getPatientList_modifyList_throwsUnsupportedOperationException() {
+ assertThrows(UnsupportedOperationException.class, () -> patientList.getPatientList().remove(0));
+ }
+
+ @Test
+ public void toStringMethod() {
+ String expected = PatientList.class.getCanonicalName() + "{patients=" + patientList.getPatientList() + "}";
+ assertEquals(expected, patientList.toString());
+ }
+
+ /**
+ * A stub ReadOnlyPatientList whose patients list can violate interface constraints.
+ */
+ private static class AddressBookStub implements ReadOnlyPatientList {
+ private final ObservableList patients = FXCollections.observableArrayList();
+
+ AddressBookStub(Collection patients) {
+ this.patients.setAll(patients);
+ }
+
+ @Override
+ public ObservableList getPatientList() {
+ return patients;
+ }
+ }
+
+}
diff --git a/src/test/java/seedu/address/model/UserPrefsTest.java b/src/test/java/seedu/address/model/UserPrefsTest.java
index b1307a70d52..7f20a4b43ac 100644
--- a/src/test/java/seedu/address/model/UserPrefsTest.java
+++ b/src/test/java/seedu/address/model/UserPrefsTest.java
@@ -15,7 +15,7 @@ public void setGuiSettings_nullGuiSettings_throwsNullPointerException() {
@Test
public void setAddressBookFilePath_nullPath_throwsNullPointerException() {
UserPrefs userPrefs = new UserPrefs();
- assertThrows(NullPointerException.class, () -> userPrefs.setAddressBookFilePath(null));
+ assertThrows(NullPointerException.class, () -> userPrefs.setPatientListFilePath(null));
}
}
diff --git a/src/test/java/seedu/address/model/person/AddressTest.java b/src/test/java/seedu/address/model/patient/AddressTest.java
similarity index 97%
rename from src/test/java/seedu/address/model/person/AddressTest.java
rename to src/test/java/seedu/address/model/patient/AddressTest.java
index 314885eca26..3717c09c109 100644
--- a/src/test/java/seedu/address/model/person/AddressTest.java
+++ b/src/test/java/seedu/address/model/patient/AddressTest.java
@@ -1,4 +1,4 @@
-package seedu.address.model.person;
+package seedu.address.model.patient;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
diff --git a/src/test/java/seedu/address/model/patient/AppointmentTest.java b/src/test/java/seedu/address/model/patient/AppointmentTest.java
new file mode 100644
index 00000000000..2aa90f81ba3
--- /dev/null
+++ b/src/test/java/seedu/address/model/patient/AppointmentTest.java
@@ -0,0 +1,65 @@
+package seedu.address.model.patient;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.testutil.Assert.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+public class AppointmentTest {
+ @Test
+ public void constructor_null_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> new Appointment(null));
+ }
+
+ @Test
+ public void constructor_invalidAppointment_throwsIllegalArgumentException() {
+ String invalidAppointment = "wdasfsdf";
+ assertThrows(IllegalArgumentException.class, () -> new Appointment(invalidAppointment));
+ }
+
+ @Test
+ public void isValidAppointment() {
+ // invalid appointment
+ assertFalse(Appointment.isValidAppointment(" ")); // spaces only
+ assertFalse(Appointment.isValidAppointment("wdalsjdaj")); // random string
+ assertFalse(Appointment.isValidAppointment("12/2024")); // without date
+ assertFalse(Appointment.isValidAppointment("245/2/2024")); // invalid date
+ assertFalse(Appointment.isValidAppointment("25/24/2024")); // invalid month
+ assertFalse(Appointment.isValidAppointment("25/2/22")); // invalid year
+
+ // valid appointment
+ assertTrue(Appointment.isValidAppointment("")); // empty string
+ assertTrue(Appointment.isValidAppointment("25/2/2024")); // valid first input foramt
+ assertTrue(Appointment.isValidAppointment("2024-2-24")); // valid second input format
+ }
+
+ @Test
+ public void equals() {
+ Appointment appointment = new Appointment("2024-2-5");
+
+ // same values -> returns true
+ assertTrue(appointment.equals(new Appointment("2024-2-5")));
+
+ // same values -> returns true
+ assertTrue(appointment.equals(new Appointment("2024-02-05")));
+
+ // another acceptable input format -> returns true
+ assertTrue(appointment.equals(new Appointment("5/2/2024")));
+
+ //another acceptable input format -> returns true
+ assertTrue(appointment.equals(new Appointment("05/02/2024")));
+
+ // same object -> returns true
+ assertTrue(appointment.equals(appointment));
+
+ // null -> returns false
+ assertFalse(appointment.equals(null));
+
+ // different types -> returns false
+ assertFalse(appointment.equals(5.0f));
+
+ // different values -> returns false
+ assertFalse(appointment.equals(new Appointment("2026-12-5")));
+ }
+}
diff --git a/src/test/java/seedu/address/model/patient/ApptDateMatchesPredicateTest.java b/src/test/java/seedu/address/model/patient/ApptDateMatchesPredicateTest.java
new file mode 100755
index 00000000000..97841612276
--- /dev/null
+++ b/src/test/java/seedu/address/model/patient/ApptDateMatchesPredicateTest.java
@@ -0,0 +1,60 @@
+package seedu.address.model.patient;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.time.LocalDate;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.logic.parser.ParserUtil;
+import seedu.address.logic.parser.exceptions.ParseException;
+
+
+class ApptDateMatchesPredicateTest {
+
+
+ @Test
+ void testEquals() {
+ String firstApptDate = "01/02/2024";
+ LocalDate firstAppt = null;
+ String firstApptDate2 = "01/02/2024";
+ LocalDate firstAppt2 = null;
+
+ String secondApptDate = "2024-2-1";
+ LocalDate secondAppt = null;
+ try {
+ firstAppt = ParserUtil.parseAppointment(firstApptDate).appointment;
+ firstAppt2 = ParserUtil.parseAppointment(firstApptDate2).appointment;
+ secondAppt = ParserUtil.parseAppointment(secondApptDate).appointment;
+ } catch (ParseException e) {
+ throw new RuntimeException(e);
+ }
+
+ ApptDateMatchesPredicate firstPredicate = new ApptDateMatchesPredicate(firstAppt);
+ ApptDateMatchesPredicate firstPredicate2 = new ApptDateMatchesPredicate(firstAppt2);
+ ApptDateMatchesPredicate secondPredicate = new ApptDateMatchesPredicate(secondAppt);
+ assertTrue(firstPredicate.equals(firstPredicate2));
+ assertTrue(firstPredicate.equals(secondPredicate));
+ assertTrue(firstPredicate2.equals(secondPredicate));
+ }
+
+ @Test
+ void testNotEquals() {
+ String firstApptDate = "01/02/2024";
+ LocalDate firstAppt = null;
+
+ String secondApptDate = "01/01/2024";
+ LocalDate secondAppt = null;
+ try {
+ firstAppt = ParserUtil.parseAppointment(firstApptDate).appointment;
+ secondAppt = ParserUtil.parseAppointment(secondApptDate).appointment;
+ } catch (ParseException e) {
+ throw new RuntimeException(e);
+ }
+
+ ApptDateMatchesPredicate firstPredicate = new ApptDateMatchesPredicate(firstAppt);
+ ApptDateMatchesPredicate secondPredicate = new ApptDateMatchesPredicate(secondAppt);
+ assertFalse(firstPredicate.equals(secondPredicate));
+ }
+}
diff --git a/src/test/java/seedu/address/model/patient/ConditionTest.java b/src/test/java/seedu/address/model/patient/ConditionTest.java
new file mode 100644
index 00000000000..4f5acaa314c
--- /dev/null
+++ b/src/test/java/seedu/address/model/patient/ConditionTest.java
@@ -0,0 +1,55 @@
+package seedu.address.model.patient;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.testutil.Assert.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+public class ConditionTest {
+ @Test
+ public void constructor_null_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> new Condition(null));
+ }
+
+ @Test
+ public void constructor_invalidCondition_throwsIllegalArgumentException() {
+ String invalidCondition = "";
+ assertThrows(IllegalArgumentException.class, () -> new Condition(invalidCondition));
+ }
+
+ @Test
+ public void isValidCondition() {
+ // null Condition
+ assertThrows(NullPointerException.class, () -> Condition.isValidCondition(null));
+
+ // invalid Condition
+ assertFalse(Condition.isValidCondition("")); // empty string
+ assertFalse(Condition.isValidCondition(" ")); // spaces only
+
+ // valid Condition
+ assertTrue(Condition.isValidCondition("Fever"));
+ assertTrue(Condition.isValidCondition("F")); // one character
+ assertTrue(Condition.isValidCondition("Pneumonoultramicroscopicsilicovolcanoconiosis")); // long Condition
+ }
+
+ @Test
+ public void equals() {
+ Condition condition = new Condition("Valid Condition");
+
+ // same values -> returns true
+ assertTrue(condition.equals(new Condition("Valid Condition")));
+
+ // same object -> returns true
+ assertTrue(condition.equals(condition));
+
+ // null -> returns false
+ assertFalse(condition.equals(null));
+
+ // different types -> returns false
+ assertFalse(condition.equals(5.0f));
+
+ // different values -> returns false
+ assertFalse(condition.equals(new Condition("Other Valid Condition")));
+ }
+}
diff --git a/src/test/java/seedu/address/model/patient/DateOfBirthTest.java b/src/test/java/seedu/address/model/patient/DateOfBirthTest.java
new file mode 100644
index 00000000000..66cf9083d4f
--- /dev/null
+++ b/src/test/java/seedu/address/model/patient/DateOfBirthTest.java
@@ -0,0 +1,68 @@
+package seedu.address.model.patient;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.testutil.Assert.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+public class DateOfBirthTest {
+ @Test
+ public void constructor_null_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> new DateOfBirth(null));
+ }
+
+ @Test
+ public void constuctor_invalidDateOfBirth_throwsIllegalArgumentException() {
+ String invalidDateOfBirth = "";
+ assertThrows(IllegalArgumentException.class, () -> new DateOfBirth(invalidDateOfBirth));
+ }
+
+ @Test
+ public void isValidDateOfBirth() {
+ // null date of birth
+ assertThrows(NullPointerException.class, () -> DateOfBirth.isValidDateOfBirth(null));
+
+ // invalid date of birth
+ assertFalse(DateOfBirth.isValidDateOfBirth("")); // empty string
+ assertFalse(DateOfBirth.isValidDateOfBirth(" ")); // spaces only
+ assertFalse(DateOfBirth.isValidDateOfBirth("wdalsjdaj")); // random string
+ assertFalse(DateOfBirth.isValidDateOfBirth("12/2024")); // without date
+ assertFalse(DateOfBirth.isValidDateOfBirth("245/2/2024")); // invalid date
+ assertFalse(DateOfBirth.isValidDateOfBirth("25/24/2024")); // invalid month
+ assertFalse(DateOfBirth.isValidDateOfBirth("25/2/22")); // invalid year
+
+ // valid date of birth
+ assertTrue(DateOfBirth.isValidDateOfBirth("25/2/2024")); // valid first input foramt
+ assertTrue(DateOfBirth.isValidDateOfBirth("2024-2-24")); // valid second input format
+ }
+
+ @Test
+ public void equals() {
+ DateOfBirth dateOfBirth = new DateOfBirth("2024-2-5");
+
+ // same values -> returns true
+ assertTrue(dateOfBirth.equals(new DateOfBirth("2024-2-5")));
+
+ // same values -> returns true
+ assertTrue(dateOfBirth.equals(new DateOfBirth("2024-02-05")));
+
+ // another acceptable input format -> returns true
+ assertTrue(dateOfBirth.equals(new DateOfBirth("5/2/2024")));
+
+ //another acceptable input format -> returns true
+ assertTrue(dateOfBirth.equals(new DateOfBirth("05/02/2024")));
+
+ // same object -> returns true
+ assertTrue(dateOfBirth.equals(dateOfBirth));
+
+ // null -> returns false
+ assertFalse(dateOfBirth.equals(null));
+
+ // different types -> returns false
+ assertFalse(dateOfBirth.equals(5.0f));
+
+ // different values -> returns false
+ assertFalse(dateOfBirth.equals(new DateOfBirth("2026-12-5")));
+ }
+}
diff --git a/src/test/java/seedu/address/model/patient/DateOfVisitTest.java b/src/test/java/seedu/address/model/patient/DateOfVisitTest.java
new file mode 100644
index 00000000000..081796c130a
--- /dev/null
+++ b/src/test/java/seedu/address/model/patient/DateOfVisitTest.java
@@ -0,0 +1,68 @@
+package seedu.address.model.patient;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.testutil.Assert.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+public class DateOfVisitTest {
+ @Test
+ public void constructor_null_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> new DateOfVisit(null));
+ }
+
+ @Test
+ public void constuctor_invalidDateOfVisit_throwsIllegalArgumentException() {
+ String invalidDateOfVisit = "";
+ assertThrows(IllegalArgumentException.class, () -> new DateOfVisit(invalidDateOfVisit));
+ }
+
+ @Test
+ public void isValidDateOfVisit() {
+ // null date of visit
+ assertThrows(NullPointerException.class, () -> DateOfVisit.isValidDateOfVisit(null));
+
+ // invalid date of visit
+ assertFalse(DateOfVisit.isValidDateOfVisit("")); // empty string
+ assertFalse(DateOfVisit.isValidDateOfVisit(" ")); // spaces only
+ assertFalse(DateOfVisit.isValidDateOfVisit("wdalsjdaj")); // random string
+ assertFalse(DateOfVisit.isValidDateOfVisit("12/2024")); // without date
+ assertFalse(DateOfVisit.isValidDateOfVisit("245/2/2024")); // invalid date
+ assertFalse(DateOfVisit.isValidDateOfVisit("25/24/2024")); // invalid month
+ assertFalse(DateOfVisit.isValidDateOfVisit("25/2/22")); // invalid year
+
+ // valid date of visit
+ assertTrue(DateOfVisit.isValidDateOfVisit("25/2/2024")); // valid first input foramt
+ assertTrue(DateOfVisit.isValidDateOfVisit("2024-2-24")); // valid second input format
+ }
+
+ @Test
+ public void equals() {
+ DateOfVisit dateOfVisit = new DateOfVisit("2024-2-5");
+
+ // same values -> returns true
+ assertTrue(dateOfVisit.equals(new DateOfVisit("2024-2-5")));
+
+ // same values -> returns true
+ assertTrue(dateOfVisit.equals(new DateOfVisit("2024-02-05")));
+
+ // another acceptable input format -> returns true
+ assertTrue(dateOfVisit.equals(new DateOfVisit("5/2/2024")));
+
+ //another acceptable input format -> returns true
+ assertTrue(dateOfVisit.equals(new DateOfVisit("05/02/2024")));
+
+ // same object -> returns true
+ assertTrue(dateOfVisit.equals(dateOfVisit));
+
+ // null -> returns false
+ assertFalse(dateOfVisit.equals(null));
+
+ // different types -> returns false
+ assertFalse(dateOfVisit.equals(5.0f));
+
+ // different values -> returns false
+ assertFalse(dateOfVisit.equals(new DateOfVisit("2026-12-5")));
+ }
+}
diff --git a/src/test/java/seedu/address/model/person/EmailTest.java b/src/test/java/seedu/address/model/patient/EmailTest.java
similarity index 99%
rename from src/test/java/seedu/address/model/person/EmailTest.java
rename to src/test/java/seedu/address/model/patient/EmailTest.java
index f08cdff0a64..eff4692d045 100644
--- a/src/test/java/seedu/address/model/person/EmailTest.java
+++ b/src/test/java/seedu/address/model/patient/EmailTest.java
@@ -1,4 +1,4 @@
-package seedu.address.model.person;
+package seedu.address.model.patient;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
diff --git a/src/test/java/seedu/address/model/person/NameContainsKeywordsPredicateTest.java b/src/test/java/seedu/address/model/patient/NameContainsKeywordsPredicateTest.java
similarity index 80%
rename from src/test/java/seedu/address/model/person/NameContainsKeywordsPredicateTest.java
rename to src/test/java/seedu/address/model/patient/NameContainsKeywordsPredicateTest.java
index 6b3fd90ade7..e15e4001a33 100644
--- a/src/test/java/seedu/address/model/person/NameContainsKeywordsPredicateTest.java
+++ b/src/test/java/seedu/address/model/patient/NameContainsKeywordsPredicateTest.java
@@ -1,4 +1,4 @@
-package seedu.address.model.person;
+package seedu.address.model.patient;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -10,7 +10,7 @@
import org.junit.jupiter.api.Test;
-import seedu.address.testutil.PersonBuilder;
+import seedu.address.testutil.PatientBuilder;
public class NameContainsKeywordsPredicateTest {
@@ -35,7 +35,7 @@ public void equals() {
// null -> returns false
assertFalse(firstPredicate.equals(null));
- // different person -> returns false
+ // different patient -> returns false
assertFalse(firstPredicate.equals(secondPredicate));
}
@@ -43,34 +43,34 @@ public void equals() {
public void test_nameContainsKeywords_returnsTrue() {
// One keyword
NameContainsKeywordsPredicate predicate = new NameContainsKeywordsPredicate(Collections.singletonList("Alice"));
- assertTrue(predicate.test(new PersonBuilder().withName("Alice Bob").build()));
+ assertTrue(predicate.test(new PatientBuilder().withName("Alice Bob").build()));
// Multiple keywords
predicate = new NameContainsKeywordsPredicate(Arrays.asList("Alice", "Bob"));
- assertTrue(predicate.test(new PersonBuilder().withName("Alice Bob").build()));
+ assertTrue(predicate.test(new PatientBuilder().withName("Alice Bob").build()));
// Only one matching keyword
predicate = new NameContainsKeywordsPredicate(Arrays.asList("Bob", "Carol"));
- assertTrue(predicate.test(new PersonBuilder().withName("Alice Carol").build()));
+ assertTrue(predicate.test(new PatientBuilder().withName("Alice Carol").build()));
// Mixed-case keywords
predicate = new NameContainsKeywordsPredicate(Arrays.asList("aLIce", "bOB"));
- assertTrue(predicate.test(new PersonBuilder().withName("Alice Bob").build()));
+ assertTrue(predicate.test(new PatientBuilder().withName("Alice Bob").build()));
}
@Test
public void test_nameDoesNotContainKeywords_returnsFalse() {
// Zero keywords
NameContainsKeywordsPredicate predicate = new NameContainsKeywordsPredicate(Collections.emptyList());
- assertFalse(predicate.test(new PersonBuilder().withName("Alice").build()));
+ assertFalse(predicate.test(new PatientBuilder().withName("Alice").build()));
// Non-matching keyword
predicate = new NameContainsKeywordsPredicate(Arrays.asList("Carol"));
- assertFalse(predicate.test(new PersonBuilder().withName("Alice Bob").build()));
+ assertFalse(predicate.test(new PatientBuilder().withName("Alice Bob").build()));
// Keywords match phone, email and address, but does not match name
predicate = new NameContainsKeywordsPredicate(Arrays.asList("12345", "alice@email.com", "Main", "Street"));
- assertFalse(predicate.test(new PersonBuilder().withName("Alice").withPhone("12345")
+ assertFalse(predicate.test(new PatientBuilder().withName("Alice").withPhone("12345")
.withEmail("alice@email.com").withAddress("Main Street").build()));
}
diff --git a/src/test/java/seedu/address/model/person/NameTest.java b/src/test/java/seedu/address/model/patient/NameTest.java
similarity index 81%
rename from src/test/java/seedu/address/model/person/NameTest.java
rename to src/test/java/seedu/address/model/patient/NameTest.java
index 94e3dd726bd..1e848b17545 100644
--- a/src/test/java/seedu/address/model/person/NameTest.java
+++ b/src/test/java/seedu/address/model/patient/NameTest.java
@@ -1,4 +1,4 @@
-package seedu.address.model.person;
+package seedu.address.model.patient;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -27,15 +27,14 @@ public void isValidName() {
// invalid name
assertFalse(Name.isValidName("")); // empty string
assertFalse(Name.isValidName(" ")); // spaces only
- assertFalse(Name.isValidName("^")); // only non-alphanumeric characters
- assertFalse(Name.isValidName("peter*")); // contains non-alphanumeric characters
+ assertFalse(Name.isValidName("^")); // only non-alphabets
+ assertFalse(Name.isValidName("peter*")); // contains disallowed character
// valid name
assertTrue(Name.isValidName("peter jack")); // alphabets only
- assertTrue(Name.isValidName("12345")); // numbers only
- assertTrue(Name.isValidName("peter the 2nd")); // alphanumeric characters
+ assertTrue(Name.isValidName("peter-jack")); // - between alphabets
assertTrue(Name.isValidName("Capital Tan")); // with capital letters
- assertTrue(Name.isValidName("David Roger Jackson Ray Jr 2nd")); // long names
+ assertTrue(Name.isValidName("David Roger Jackson Ray Jr The Almighty")); // long names
}
@Test
diff --git a/src/test/java/seedu/address/model/patient/PatientTest.java b/src/test/java/seedu/address/model/patient/PatientTest.java
new file mode 100644
index 00000000000..67bc971e12e
--- /dev/null
+++ b/src/test/java/seedu/address/model/patient/PatientTest.java
@@ -0,0 +1,101 @@
+package seedu.address.model.patient;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_DATEOFBIRTH_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_SEX_BOB;
+import static seedu.address.testutil.TypicalPatients.ALICE;
+import static seedu.address.testutil.TypicalPatients.BOB;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.testutil.PatientBuilder;
+
+public class PatientTest {
+
+
+ @Test
+ public void isSamePatient() {
+ // same object -> returns true
+ assertTrue(ALICE.isSamePatient(ALICE));
+
+ // null -> returns false
+ assertFalse(ALICE.isSamePatient(null));
+
+ // same name and phone number, all other attributes different -> returns true
+ Patient editedAlice = new PatientBuilder(ALICE).withEmail(VALID_EMAIL_BOB)
+ .withAddress(VALID_ADDRESS_BOB).withDateOfBirth(VALID_DATEOFBIRTH_BOB).build();
+ assertTrue(ALICE.isSamePatient(editedAlice));
+
+ // different name, all other attributes same -> returns false
+ editedAlice = new PatientBuilder(ALICE).withName(VALID_NAME_BOB).build();
+ assertFalse(ALICE.isSamePatient(editedAlice));
+
+ // name differs in case, all other attributes same -> returns false
+ Patient editedBob = new PatientBuilder(BOB).withName(VALID_NAME_BOB.toLowerCase()).build();
+ assertFalse(BOB.isSamePatient(editedBob));
+
+ // different phone number and different name, all other attributes same -> returns false
+ editedBob = new PatientBuilder(BOB).withName(VALID_NAME_AMY).withPhone(VALID_PHONE_AMY).build();
+ assertFalse(BOB.isSamePatient(editedBob));
+ }
+
+ @Test
+ public void equals() {
+ // same values -> returns true
+ Patient aliceCopy = new PatientBuilder(ALICE).build();
+ assertTrue(ALICE.equals(aliceCopy));
+
+ // same object -> returns true
+ assertTrue(ALICE.equals(ALICE));
+
+ // null -> returns false
+ assertFalse(ALICE.equals(null));
+
+ // different type -> returns false
+ assertFalse(ALICE.equals(5));
+
+ // different patient -> returns false
+ assertFalse(ALICE.equals(BOB));
+
+ // different name -> returns false
+ Patient editedAlice = new PatientBuilder(ALICE).withName(VALID_NAME_BOB).build();
+ assertFalse(ALICE.equals(editedAlice));
+
+ // different phone -> returns false
+ editedAlice = new PatientBuilder(ALICE).withPhone(VALID_PHONE_BOB).build();
+ assertFalse(ALICE.equals(editedAlice));
+
+ // different email -> returns false
+ editedAlice = new PatientBuilder(ALICE).withEmail(VALID_EMAIL_BOB).build();
+ assertFalse(ALICE.equals(editedAlice));
+
+ // different address -> returns false
+ editedAlice = new PatientBuilder(ALICE).withAddress(VALID_ADDRESS_BOB).build();
+ assertFalse(ALICE.equals(editedAlice));
+
+ // different date of birth -> returns false
+ editedAlice = new PatientBuilder(ALICE).withDateOfBirth(VALID_DATEOFBIRTH_BOB).build();
+ assertFalse(ALICE.equals(editedAlice));
+
+ // different sex -> returns false
+ editedAlice = new PatientBuilder(ALICE).withSex(VALID_SEX_BOB).build();
+ assertFalse(ALICE.equals(editedAlice));
+ }
+
+ @Test
+ public void toStringMethod() {
+ String expected = Patient.class.getCanonicalName() + "{name=" + ALICE.getName() + ", phone=" + ALICE.getPhone()
+ + ", email=" + ALICE.getEmail() + ", address=" + ALICE.getAddress() + ", date of birth="
+ + ALICE.getDateOfBirth() + ", sex=" + ALICE.getSex() + ", appointment=" + ALICE.getAppointment()
+ + ", visits=" + ALICE.getVisits() + "}";
+ assertEquals(expected, ALICE.toString());
+ }
+}
diff --git a/src/test/java/seedu/address/model/patient/PhoneMatchesPredicateTest.java b/src/test/java/seedu/address/model/patient/PhoneMatchesPredicateTest.java
new file mode 100644
index 00000000000..1e5aa8358d9
--- /dev/null
+++ b/src/test/java/seedu/address/model/patient/PhoneMatchesPredicateTest.java
@@ -0,0 +1,69 @@
+package seedu.address.model.patient;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.testutil.PatientBuilder;
+
+public class PhoneMatchesPredicateTest {
+
+ @Test
+ public void equals() {
+ String firstPhoneString = "99999999";
+ Phone firstPhone = new Phone(firstPhoneString);
+
+ String secondPhoneString = "88888888";
+ Phone secondPhone = new Phone(secondPhoneString);
+
+ PhoneMatchesPredicate firstPredicate = new PhoneMatchesPredicate(firstPhone);
+ PhoneMatchesPredicate secondPredicate = new PhoneMatchesPredicate(secondPhone);
+
+ // same object -> returns true
+ assertTrue(firstPredicate.equals(firstPredicate));
+
+ // same values -> returns true
+ String firstPhoneStringCopy = "99999999";
+ Phone firstPhoneCopy = new Phone(firstPhoneStringCopy);
+ PhoneMatchesPredicate firstPredicateCopy = new PhoneMatchesPredicate(firstPhoneCopy);
+ assertTrue(firstPredicate.equals(firstPredicateCopy));
+
+ // different types -> returns false
+ assertFalse(firstPredicate.equals(1));
+
+ // null -> returns false
+ assertFalse(firstPredicate.equals(null));
+
+ // different person -> returns false
+ assertFalse(firstPredicate.equals(secondPredicate));
+ }
+
+ @Test
+ public void test_phoneMatches_returnsTrue() {
+ String phoneNumber = "98765432";
+ PhoneMatchesPredicate predicate = new PhoneMatchesPredicate(new Phone(phoneNumber));
+ assertTrue(predicate.test(new PatientBuilder().withPhone(phoneNumber).build()));
+ }
+
+ @Test
+ public void test_phoneDoesNotMatch_returnsFalse() {
+ // Null check
+ String phoneNumber = "98765432";
+ PhoneMatchesPredicate predicate = new PhoneMatchesPredicate(new Phone(phoneNumber));
+ assertFalse(predicate.test(null));
+
+ // Non-matching phones
+ assertFalse(predicate.test(new PatientBuilder().withPhone("99999999").build()));
+ }
+
+ @Test
+ public void toStringMethod() {
+ Phone phone = new Phone("99999999");
+ PhoneMatchesPredicate predicate = new PhoneMatchesPredicate(phone);
+
+ String expected = PhoneMatchesPredicate.class.getCanonicalName() + "{phone=" + phone + "}";
+ assertEquals(expected, predicate.toString());
+ }
+}
diff --git a/src/test/java/seedu/address/model/person/PhoneTest.java b/src/test/java/seedu/address/model/patient/PhoneTest.java
similarity index 98%
rename from src/test/java/seedu/address/model/person/PhoneTest.java
rename to src/test/java/seedu/address/model/patient/PhoneTest.java
index deaaa5ba190..3c3630b7a1c 100644
--- a/src/test/java/seedu/address/model/person/PhoneTest.java
+++ b/src/test/java/seedu/address/model/patient/PhoneTest.java
@@ -1,4 +1,4 @@
-package seedu.address.model.person;
+package seedu.address.model.patient;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
diff --git a/src/test/java/seedu/address/model/patient/SeverityTest.java b/src/test/java/seedu/address/model/patient/SeverityTest.java
new file mode 100644
index 00000000000..af721cce2e7
--- /dev/null
+++ b/src/test/java/seedu/address/model/patient/SeverityTest.java
@@ -0,0 +1,56 @@
+package seedu.address.model.patient;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.testutil.Assert.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+public class SeverityTest {
+ @Test
+ public void constructor_null_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> new Severity(null));
+ }
+
+ @Test
+ public void constructor_invalidSeverity_throwsIllegalArgumentException() {
+ String invalidSeverity = "";
+ assertThrows(IllegalArgumentException.class, () -> new Severity(invalidSeverity));
+ }
+
+ @Test
+ public void isValidSeverity() {
+ // null Severity
+ assertThrows(NullPointerException.class, () -> Severity.isValidSeverity(null));
+
+ // invalid Severity
+ assertFalse(Severity.isValidSeverity("")); // empty string
+ assertFalse(Severity.isValidSeverity(" ")); // spaces only
+ assertFalse(Severity.isValidSeverity("akldjkldf")); // random string
+ assertFalse(Severity.isValidSeverity("LOW")); // similar to valid string
+
+ // valid Severity
+ assertTrue(Severity.isValidSeverity("Low"));
+ assertTrue(Severity.isValidSeverity("High"));
+ }
+
+ @Test
+ public void equals() {
+ Severity severity = new Severity("High");
+
+ // same values -> returns true
+ assertTrue(severity.equals(new Severity("High")));
+
+ // same object -> returns true
+ assertTrue(severity.equals(severity));
+
+ // null -> returns false
+ assertFalse(severity.equals(null));
+
+ // different types -> returns false
+ assertFalse(severity.equals(5.0f));
+
+ // different values -> returns false
+ assertFalse(severity.equals(new Severity("Low")));
+ }
+}
diff --git a/src/test/java/seedu/address/model/patient/SexTest.java b/src/test/java/seedu/address/model/patient/SexTest.java
new file mode 100644
index 00000000000..7d3aab52e41
--- /dev/null
+++ b/src/test/java/seedu/address/model/patient/SexTest.java
@@ -0,0 +1,56 @@
+package seedu.address.model.patient;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.testutil.Assert.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+public class SexTest {
+ @Test
+ public void constructor_null_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> new Sex(null));
+ }
+
+ @Test
+ public void constructor_invalidSex_throwsIllegalArgumentException() {
+ String invalidSex = "";
+ assertThrows(IllegalArgumentException.class, () -> new Sex(invalidSex));
+ }
+
+ @Test
+ public void isValidSex() {
+ // null sex
+ assertThrows(NullPointerException.class, () -> Sex.isValidSex(null));
+
+ // invalid sex
+ assertFalse(Sex.isValidSex("")); // empty string
+ assertFalse(Sex.isValidSex(" ")); // spaces only
+ assertFalse(Sex.isValidSex("akldjkldf")); // random string
+ assertFalse(Sex.isValidSex("Malet")); // similar to valid string
+
+ // valid sex
+ assertTrue(Sex.isValidSex("Male"));
+ assertTrue(Sex.isValidSex("Female"));
+ }
+
+ @Test
+ public void equals() {
+ Sex sex = new Sex("Male");
+
+ // same values -> returns true
+ assertTrue(sex.equals(new Sex("Male")));
+
+ // same object -> returns true
+ assertTrue(sex.equals(sex));
+
+ // null -> returns false
+ assertFalse(sex.equals(null));
+
+ // different types -> returns false
+ assertFalse(sex.equals(5.0f));
+
+ // different values -> returns false
+ assertFalse(sex.equals(new Sex("Female")));
+ }
+}
diff --git a/src/test/java/seedu/address/model/patient/UniquePatientListTest.java b/src/test/java/seedu/address/model/patient/UniquePatientListTest.java
new file mode 100644
index 00000000000..39fc07623ff
--- /dev/null
+++ b/src/test/java/seedu/address/model/patient/UniquePatientListTest.java
@@ -0,0 +1,174 @@
+package seedu.address.model.patient;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
+import static seedu.address.testutil.Assert.assertThrows;
+import static seedu.address.testutil.TypicalPatients.ALICE;
+import static seedu.address.testutil.TypicalPatients.BOB;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.model.patient.exceptions.DuplicatePatientException;
+import seedu.address.model.patient.exceptions.PatientNotFoundException;
+import seedu.address.testutil.PatientBuilder;
+
+public class UniquePatientListTest {
+
+ private final UniquePatientList uniquePatientList = new UniquePatientList();
+
+ @Test
+ public void contains_nullPatient_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> uniquePatientList.contains(null));
+ }
+
+ @Test
+ public void contains_patientNotInList_returnsFalse() {
+ assertFalse(uniquePatientList.contains(ALICE));
+ }
+
+ @Test
+ public void contains_patientInList_returnsTrue() {
+ uniquePatientList.add(ALICE);
+ assertTrue(uniquePatientList.contains(ALICE));
+ }
+
+ @Test
+ public void contains_patientWithSameIdentityFieldsInList_returnsTrue() {
+ uniquePatientList.add(ALICE);
+ Patient editedAlice = new PatientBuilder(ALICE).withAddress(VALID_ADDRESS_BOB)
+ .build();
+ assertTrue(uniquePatientList.contains(editedAlice));
+ }
+
+ @Test
+ public void add_nullPatient_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> uniquePatientList.add(null));
+ }
+
+ @Test
+ public void add_duplicatePatient_throwsDuplicatePatientException() {
+ uniquePatientList.add(ALICE);
+ assertThrows(DuplicatePatientException.class, () -> uniquePatientList.add(ALICE));
+ }
+
+ @Test
+ public void setPatient_nullTargetPatient_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> uniquePatientList.setPatient(null, ALICE));
+ }
+
+ @Test
+ public void setPatient_nullEditedPatient_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> uniquePatientList.setPatient(ALICE, null));
+ }
+
+ @Test
+ public void setPatient_targetPatientNotInList_throwsPatientNotFoundException() {
+ assertThrows(PatientNotFoundException.class, () -> uniquePatientList.setPatient(ALICE, ALICE));
+ }
+
+ @Test
+ public void setPatient_editedPatientIsSamePatient_success() {
+ uniquePatientList.add(ALICE);
+ uniquePatientList.setPatient(ALICE, ALICE);
+ UniquePatientList expectedUniquePatientList = new UniquePatientList();
+ expectedUniquePatientList.add(ALICE);
+ assertEquals(expectedUniquePatientList, uniquePatientList);
+ }
+
+ @Test
+ public void setPatient_editedPatientHasSameIdentity_success() {
+ uniquePatientList.add(ALICE);
+ Patient editedAlice = new PatientBuilder(ALICE).withAddress(VALID_ADDRESS_BOB)
+ .build();
+ uniquePatientList.setPatient(ALICE, editedAlice);
+ UniquePatientList expectedUniquePatientList = new UniquePatientList();
+ expectedUniquePatientList.add(editedAlice);
+ assertEquals(expectedUniquePatientList, uniquePatientList);
+ }
+
+ @Test
+ public void setPatient_editedPatientHasDifferentIdentity_success() {
+ uniquePatientList.add(ALICE);
+ uniquePatientList.setPatient(ALICE, BOB);
+ UniquePatientList expectedUniquePatientList = new UniquePatientList();
+ expectedUniquePatientList.add(BOB);
+ assertEquals(expectedUniquePatientList, uniquePatientList);
+ }
+
+ @Test
+ public void setPatient_editedPatientHasNonUniqueIdentity_throwsDuplicatePatientException() {
+ uniquePatientList.add(ALICE);
+ uniquePatientList.add(BOB);
+ assertThrows(DuplicatePatientException.class, () -> uniquePatientList.setPatient(ALICE, BOB));
+ }
+
+ @Test
+ public void remove_nullPatient_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> uniquePatientList.remove(null));
+ }
+
+ @Test
+ public void remove_patientDoesNotExist_throwsPatientNotFoundException() {
+ assertThrows(PatientNotFoundException.class, () -> uniquePatientList.remove(ALICE));
+ }
+
+ @Test
+ public void remove_existingPatient_removesPatient() {
+ uniquePatientList.add(ALICE);
+ uniquePatientList.remove(ALICE);
+ UniquePatientList expectedUniquePatientList = new UniquePatientList();
+ assertEquals(expectedUniquePatientList, uniquePatientList);
+ }
+
+ @Test
+ public void setPatients_nullUniquePatientList_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> uniquePatientList.setPatients((UniquePatientList) null));
+ }
+
+ @Test
+ public void setPatient_uniquePatientList_replacesOwnListWithProvidedUniquePatientList() {
+ uniquePatientList.add(ALICE);
+ UniquePatientList expectedUniquePatientList = new UniquePatientList();
+ expectedUniquePatientList.add(BOB);
+ uniquePatientList.setPatients(expectedUniquePatientList);
+ assertEquals(expectedUniquePatientList, uniquePatientList);
+ }
+
+ @Test
+ public void setPatients_nullList_throwsNullPointerException() {
+ assertThrows(NullPointerException.class, () -> uniquePatientList.setPatients((List) null));
+ }
+
+ @Test
+ public void setPatients_list_replacesOwnListWithProvidedList() {
+ uniquePatientList.add(ALICE);
+ List patientList = Collections.singletonList(BOB);
+ uniquePatientList.setPatients(patientList);
+ UniquePatientList expectedUniquePatientList = new UniquePatientList();
+ expectedUniquePatientList.add(BOB);
+ assertEquals(expectedUniquePatientList, uniquePatientList);
+ }
+
+ @Test
+ public void setPatients_listWithDuplicatePatients_throwsDuplicatePatientException() {
+ List listWithDuplicatePatients = Arrays.asList(ALICE, ALICE);
+ assertThrows(DuplicatePatientException.class, () -> uniquePatientList.setPatients(listWithDuplicatePatients));
+ }
+
+ @Test
+ public void asUnmodifiableObservableList_modifyList_throwsUnsupportedOperationException() {
+ assertThrows(UnsupportedOperationException.class, ()
+ -> uniquePatientList.asUnmodifiableObservableList().remove(0));
+ }
+
+ @Test
+ public void toStringMethod() {
+ assertEquals(uniquePatientList.asUnmodifiableObservableList().toString(), uniquePatientList.toString());
+ }
+}
diff --git a/src/test/java/seedu/address/model/patient/VisitTest.java b/src/test/java/seedu/address/model/patient/VisitTest.java
new file mode 100644
index 00000000000..f2cf6c25644
--- /dev/null
+++ b/src/test/java/seedu/address/model/patient/VisitTest.java
@@ -0,0 +1,45 @@
+package seedu.address.model.patient;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.testutil.VisitBuilder;
+
+public class VisitTest {
+ private final Visit testVisit = new VisitBuilder().build();
+ @Test
+ public void equals() {
+ // same values -> returns true
+ Visit copyVisit = new VisitBuilder(testVisit).build();
+ assertTrue(testVisit.equals(copyVisit));
+
+ // same object -> returns true
+ assertTrue(testVisit.equals(testVisit));
+
+ // null -> returns false
+ assertFalse(testVisit.equals(null));
+
+ // different type -> returns false
+ assertFalse(testVisit.equals(5));
+
+ // different condition -> returns false
+ assertFalse(testVisit.equals(new VisitBuilder(testVisit).withCondition("other").build()));
+
+ // different severity -> returns false
+ assertFalse(testVisit.equals(new VisitBuilder(testVisit).withSeverity("High").build()));
+
+ // different date of visit -> returns false
+ assertFalse(testVisit.equals(new VisitBuilder(testVisit).withDateOfVisit("1/1/2002").build()));
+ }
+
+ @Test
+ public void toStringMethod() {
+ String expected = Visit.class.getCanonicalName() + "{condition=" + testVisit.getCondition()
+ + ", severity=" + testVisit.getSeverity()
+ + ", date of visit=" + testVisit.getDateOfVisit() + "}";
+ assertEquals(expected, testVisit.toString());
+ }
+}
diff --git a/src/test/java/seedu/address/model/person/PersonTest.java b/src/test/java/seedu/address/model/person/PersonTest.java
deleted file mode 100644
index 31a10d156c9..00000000000
--- a/src/test/java/seedu/address/model/person/PersonTest.java
+++ /dev/null
@@ -1,99 +0,0 @@
-package seedu.address.model.person;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
-import static seedu.address.testutil.Assert.assertThrows;
-import static seedu.address.testutil.TypicalPersons.ALICE;
-import static seedu.address.testutil.TypicalPersons.BOB;
-
-import org.junit.jupiter.api.Test;
-
-import seedu.address.testutil.PersonBuilder;
-
-public class PersonTest {
-
- @Test
- public void asObservableList_modifyList_throwsUnsupportedOperationException() {
- Person person = new PersonBuilder().build();
- assertThrows(UnsupportedOperationException.class, () -> person.getTags().remove(0));
- }
-
- @Test
- public void isSamePerson() {
- // same object -> returns true
- assertTrue(ALICE.isSamePerson(ALICE));
-
- // null -> returns false
- assertFalse(ALICE.isSamePerson(null));
-
- // same name, all other attributes different -> returns true
- Person editedAlice = new PersonBuilder(ALICE).withPhone(VALID_PHONE_BOB).withEmail(VALID_EMAIL_BOB)
- .withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_HUSBAND).build();
- assertTrue(ALICE.isSamePerson(editedAlice));
-
- // different name, all other attributes same -> returns false
- editedAlice = new PersonBuilder(ALICE).withName(VALID_NAME_BOB).build();
- assertFalse(ALICE.isSamePerson(editedAlice));
-
- // name differs in case, all other attributes same -> returns false
- Person editedBob = new PersonBuilder(BOB).withName(VALID_NAME_BOB.toLowerCase()).build();
- assertFalse(BOB.isSamePerson(editedBob));
-
- // name has trailing spaces, all other attributes same -> returns false
- String nameWithTrailingSpaces = VALID_NAME_BOB + " ";
- editedBob = new PersonBuilder(BOB).withName(nameWithTrailingSpaces).build();
- assertFalse(BOB.isSamePerson(editedBob));
- }
-
- @Test
- public void equals() {
- // same values -> returns true
- Person aliceCopy = new PersonBuilder(ALICE).build();
- assertTrue(ALICE.equals(aliceCopy));
-
- // same object -> returns true
- assertTrue(ALICE.equals(ALICE));
-
- // null -> returns false
- assertFalse(ALICE.equals(null));
-
- // different type -> returns false
- assertFalse(ALICE.equals(5));
-
- // different person -> returns false
- assertFalse(ALICE.equals(BOB));
-
- // different name -> returns false
- Person editedAlice = new PersonBuilder(ALICE).withName(VALID_NAME_BOB).build();
- assertFalse(ALICE.equals(editedAlice));
-
- // different phone -> returns false
- editedAlice = new PersonBuilder(ALICE).withPhone(VALID_PHONE_BOB).build();
- assertFalse(ALICE.equals(editedAlice));
-
- // different email -> returns false
- editedAlice = new PersonBuilder(ALICE).withEmail(VALID_EMAIL_BOB).build();
- assertFalse(ALICE.equals(editedAlice));
-
- // different address -> returns false
- editedAlice = new PersonBuilder(ALICE).withAddress(VALID_ADDRESS_BOB).build();
- assertFalse(ALICE.equals(editedAlice));
-
- // different tags -> returns false
- editedAlice = new PersonBuilder(ALICE).withTags(VALID_TAG_HUSBAND).build();
- assertFalse(ALICE.equals(editedAlice));
- }
-
- @Test
- public void toStringMethod() {
- String expected = Person.class.getCanonicalName() + "{name=" + ALICE.getName() + ", phone=" + ALICE.getPhone()
- + ", email=" + ALICE.getEmail() + ", address=" + ALICE.getAddress() + ", tags=" + ALICE.getTags() + "}";
- assertEquals(expected, ALICE.toString());
- }
-}
diff --git a/src/test/java/seedu/address/model/person/UniquePersonListTest.java b/src/test/java/seedu/address/model/person/UniquePersonListTest.java
deleted file mode 100644
index 17ae501df08..00000000000
--- a/src/test/java/seedu/address/model/person/UniquePersonListTest.java
+++ /dev/null
@@ -1,175 +0,0 @@
-package seedu.address.model.person;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
-import static seedu.address.testutil.Assert.assertThrows;
-import static seedu.address.testutil.TypicalPersons.ALICE;
-import static seedu.address.testutil.TypicalPersons.BOB;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-import org.junit.jupiter.api.Test;
-
-import seedu.address.model.person.exceptions.DuplicatePersonException;
-import seedu.address.model.person.exceptions.PersonNotFoundException;
-import seedu.address.testutil.PersonBuilder;
-
-public class UniquePersonListTest {
-
- private final UniquePersonList uniquePersonList = new UniquePersonList();
-
- @Test
- public void contains_nullPerson_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> uniquePersonList.contains(null));
- }
-
- @Test
- public void contains_personNotInList_returnsFalse() {
- assertFalse(uniquePersonList.contains(ALICE));
- }
-
- @Test
- public void contains_personInList_returnsTrue() {
- uniquePersonList.add(ALICE);
- assertTrue(uniquePersonList.contains(ALICE));
- }
-
- @Test
- public void contains_personWithSameIdentityFieldsInList_returnsTrue() {
- uniquePersonList.add(ALICE);
- Person editedAlice = new PersonBuilder(ALICE).withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_HUSBAND)
- .build();
- assertTrue(uniquePersonList.contains(editedAlice));
- }
-
- @Test
- public void add_nullPerson_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> uniquePersonList.add(null));
- }
-
- @Test
- public void add_duplicatePerson_throwsDuplicatePersonException() {
- uniquePersonList.add(ALICE);
- assertThrows(DuplicatePersonException.class, () -> uniquePersonList.add(ALICE));
- }
-
- @Test
- public void setPerson_nullTargetPerson_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> uniquePersonList.setPerson(null, ALICE));
- }
-
- @Test
- public void setPerson_nullEditedPerson_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> uniquePersonList.setPerson(ALICE, null));
- }
-
- @Test
- public void setPerson_targetPersonNotInList_throwsPersonNotFoundException() {
- assertThrows(PersonNotFoundException.class, () -> uniquePersonList.setPerson(ALICE, ALICE));
- }
-
- @Test
- public void setPerson_editedPersonIsSamePerson_success() {
- uniquePersonList.add(ALICE);
- uniquePersonList.setPerson(ALICE, ALICE);
- UniquePersonList expectedUniquePersonList = new UniquePersonList();
- expectedUniquePersonList.add(ALICE);
- assertEquals(expectedUniquePersonList, uniquePersonList);
- }
-
- @Test
- public void setPerson_editedPersonHasSameIdentity_success() {
- uniquePersonList.add(ALICE);
- Person editedAlice = new PersonBuilder(ALICE).withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_HUSBAND)
- .build();
- uniquePersonList.setPerson(ALICE, editedAlice);
- UniquePersonList expectedUniquePersonList = new UniquePersonList();
- expectedUniquePersonList.add(editedAlice);
- assertEquals(expectedUniquePersonList, uniquePersonList);
- }
-
- @Test
- public void setPerson_editedPersonHasDifferentIdentity_success() {
- uniquePersonList.add(ALICE);
- uniquePersonList.setPerson(ALICE, BOB);
- UniquePersonList expectedUniquePersonList = new UniquePersonList();
- expectedUniquePersonList.add(BOB);
- assertEquals(expectedUniquePersonList, uniquePersonList);
- }
-
- @Test
- public void setPerson_editedPersonHasNonUniqueIdentity_throwsDuplicatePersonException() {
- uniquePersonList.add(ALICE);
- uniquePersonList.add(BOB);
- assertThrows(DuplicatePersonException.class, () -> uniquePersonList.setPerson(ALICE, BOB));
- }
-
- @Test
- public void remove_nullPerson_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> uniquePersonList.remove(null));
- }
-
- @Test
- public void remove_personDoesNotExist_throwsPersonNotFoundException() {
- assertThrows(PersonNotFoundException.class, () -> uniquePersonList.remove(ALICE));
- }
-
- @Test
- public void remove_existingPerson_removesPerson() {
- uniquePersonList.add(ALICE);
- uniquePersonList.remove(ALICE);
- UniquePersonList expectedUniquePersonList = new UniquePersonList();
- assertEquals(expectedUniquePersonList, uniquePersonList);
- }
-
- @Test
- public void setPersons_nullUniquePersonList_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> uniquePersonList.setPersons((UniquePersonList) null));
- }
-
- @Test
- public void setPersons_uniquePersonList_replacesOwnListWithProvidedUniquePersonList() {
- uniquePersonList.add(ALICE);
- UniquePersonList expectedUniquePersonList = new UniquePersonList();
- expectedUniquePersonList.add(BOB);
- uniquePersonList.setPersons(expectedUniquePersonList);
- assertEquals(expectedUniquePersonList, uniquePersonList);
- }
-
- @Test
- public void setPersons_nullList_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> uniquePersonList.setPersons((List) null));
- }
-
- @Test
- public void setPersons_list_replacesOwnListWithProvidedList() {
- uniquePersonList.add(ALICE);
- List personList = Collections.singletonList(BOB);
- uniquePersonList.setPersons(personList);
- UniquePersonList expectedUniquePersonList = new UniquePersonList();
- expectedUniquePersonList.add(BOB);
- assertEquals(expectedUniquePersonList, uniquePersonList);
- }
-
- @Test
- public void setPersons_listWithDuplicatePersons_throwsDuplicatePersonException() {
- List listWithDuplicatePersons = Arrays.asList(ALICE, ALICE);
- assertThrows(DuplicatePersonException.class, () -> uniquePersonList.setPersons(listWithDuplicatePersons));
- }
-
- @Test
- public void asUnmodifiableObservableList_modifyList_throwsUnsupportedOperationException() {
- assertThrows(UnsupportedOperationException.class, ()
- -> uniquePersonList.asUnmodifiableObservableList().remove(0));
- }
-
- @Test
- public void toStringMethod() {
- assertEquals(uniquePersonList.asUnmodifiableObservableList().toString(), uniquePersonList.toString());
- }
-}
diff --git a/src/test/java/seedu/address/model/tag/TagTest.java b/src/test/java/seedu/address/model/tag/TagTest.java
deleted file mode 100644
index 64d07d79ee2..00000000000
--- a/src/test/java/seedu/address/model/tag/TagTest.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package seedu.address.model.tag;
-
-import static seedu.address.testutil.Assert.assertThrows;
-
-import org.junit.jupiter.api.Test;
-
-public class TagTest {
-
- @Test
- public void constructor_null_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> new Tag(null));
- }
-
- @Test
- public void constructor_invalidTagName_throwsIllegalArgumentException() {
- String invalidTagName = "";
- assertThrows(IllegalArgumentException.class, () -> new Tag(invalidTagName));
- }
-
- @Test
- public void isValidTagName() {
- // null tag name
- assertThrows(NullPointerException.class, () -> Tag.isValidTagName(null));
- }
-
-}
diff --git a/src/test/java/seedu/address/model/util/SampleDataUtilTest.java b/src/test/java/seedu/address/model/util/SampleDataUtilTest.java
new file mode 100644
index 00000000000..6053c7002c6
--- /dev/null
+++ b/src/test/java/seedu/address/model/util/SampleDataUtilTest.java
@@ -0,0 +1,16 @@
+package seedu.address.model.util;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.model.patient.Patient;
+
+public class SampleDataUtilTest {
+
+ @Test
+ public void getSamplePatients_returnsNonEmptyArray() {
+ Patient[] patients = SampleDataUtil.getSamplePatients();
+ assertTrue(patients.length != 0);
+ }
+}
diff --git a/src/test/java/seedu/address/storage/JsonAdaptedPersonTest.java b/src/test/java/seedu/address/storage/JsonAdaptedPatientTest.java
similarity index 54%
rename from src/test/java/seedu/address/storage/JsonAdaptedPersonTest.java
rename to src/test/java/seedu/address/storage/JsonAdaptedPatientTest.java
index 83b11331cdb..c491635a8b5 100644
--- a/src/test/java/seedu/address/storage/JsonAdaptedPersonTest.java
+++ b/src/test/java/seedu/address/storage/JsonAdaptedPatientTest.java
@@ -1,110 +1,108 @@
package seedu.address.storage;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static seedu.address.storage.JsonAdaptedPerson.MISSING_FIELD_MESSAGE_FORMAT;
+import static seedu.address.storage.JsonAdaptedPatient.MISSING_FIELD_MESSAGE_FORMAT;
import static seedu.address.testutil.Assert.assertThrows;
-import static seedu.address.testutil.TypicalPersons.BENSON;
+import static seedu.address.testutil.TypicalPatients.BENSON;
import java.util.ArrayList;
import java.util.List;
-import java.util.stream.Collectors;
import org.junit.jupiter.api.Test;
import seedu.address.commons.exceptions.IllegalValueException;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Phone;
+import seedu.address.model.patient.Address;
+import seedu.address.model.patient.Email;
+import seedu.address.model.patient.Name;
+import seedu.address.model.patient.Phone;
-public class JsonAdaptedPersonTest {
+public class JsonAdaptedPatientTest {
private static final String INVALID_NAME = "R@chel";
private static final String INVALID_PHONE = "+651234";
private static final String INVALID_ADDRESS = " ";
private static final String INVALID_EMAIL = "example.com";
- private static final String INVALID_TAG = "#friend";
+ private static final String INVALID_DATEOFBIRTH = "24/2022";
private static final String VALID_NAME = BENSON.getName().toString();
private static final String VALID_PHONE = BENSON.getPhone().toString();
private static final String VALID_EMAIL = BENSON.getEmail().toString();
private static final String VALID_ADDRESS = BENSON.getAddress().toString();
- private static final List VALID_TAGS = BENSON.getTags().stream()
- .map(JsonAdaptedTag::new)
- .collect(Collectors.toList());
+ private static final String VALID_DATEOFBIRTH = BENSON.getDateOfBirth().toString();
+ private static final String VALID_SEX = BENSON.getSex().toString();
+ private static final String VALID_APPOINTMENT = BENSON.getAppointment().toString();
+ private static final List VALID_VISITS = new ArrayList<>(0);
@Test
- public void toModelType_validPersonDetails_returnsPerson() throws Exception {
- JsonAdaptedPerson person = new JsonAdaptedPerson(BENSON);
+ public void toModelType_validPatientDetails_returnsPatient() throws Exception {
+ JsonAdaptedPatient person = new JsonAdaptedPatient(BENSON);
assertEquals(BENSON, person.toModelType());
}
@Test
public void toModelType_invalidName_throwsIllegalValueException() {
- JsonAdaptedPerson person =
- new JsonAdaptedPerson(INVALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS, VALID_TAGS);
+ JsonAdaptedPatient person =
+ new JsonAdaptedPatient(INVALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS, VALID_DATEOFBIRTH,
+ VALID_SEX, VALID_APPOINTMENT, VALID_VISITS);
String expectedMessage = Name.MESSAGE_CONSTRAINTS;
assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
}
@Test
public void toModelType_nullName_throwsIllegalValueException() {
- JsonAdaptedPerson person = new JsonAdaptedPerson(null, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS, VALID_TAGS);
+ JsonAdaptedPatient person = new JsonAdaptedPatient(null, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS,
+ VALID_DATEOFBIRTH, VALID_SEX, VALID_APPOINTMENT, VALID_VISITS);
String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Name.class.getSimpleName());
assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
}
@Test
public void toModelType_invalidPhone_throwsIllegalValueException() {
- JsonAdaptedPerson person =
- new JsonAdaptedPerson(VALID_NAME, INVALID_PHONE, VALID_EMAIL, VALID_ADDRESS, VALID_TAGS);
+ JsonAdaptedPatient person =
+ new JsonAdaptedPatient(VALID_NAME, INVALID_PHONE, VALID_EMAIL, VALID_ADDRESS, VALID_DATEOFBIRTH,
+ VALID_SEX, VALID_APPOINTMENT, VALID_VISITS);
String expectedMessage = Phone.MESSAGE_CONSTRAINTS;
assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
}
@Test
public void toModelType_nullPhone_throwsIllegalValueException() {
- JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_NAME, null, VALID_EMAIL, VALID_ADDRESS, VALID_TAGS);
+ JsonAdaptedPatient person = new JsonAdaptedPatient(VALID_NAME, null, VALID_EMAIL, VALID_ADDRESS,
+ VALID_DATEOFBIRTH, VALID_SEX, VALID_APPOINTMENT, VALID_VISITS);
String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Phone.class.getSimpleName());
assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
}
@Test
public void toModelType_invalidEmail_throwsIllegalValueException() {
- JsonAdaptedPerson person =
- new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, INVALID_EMAIL, VALID_ADDRESS, VALID_TAGS);
+ JsonAdaptedPatient person =
+ new JsonAdaptedPatient(VALID_NAME, VALID_PHONE, INVALID_EMAIL, VALID_ADDRESS, VALID_DATEOFBIRTH,
+ VALID_SEX, VALID_APPOINTMENT, VALID_VISITS);
String expectedMessage = Email.MESSAGE_CONSTRAINTS;
assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
}
@Test
public void toModelType_nullEmail_throwsIllegalValueException() {
- JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, null, VALID_ADDRESS, VALID_TAGS);
+ JsonAdaptedPatient person = new JsonAdaptedPatient(VALID_NAME, VALID_PHONE, null, VALID_ADDRESS,
+ VALID_DATEOFBIRTH, VALID_SEX, VALID_APPOINTMENT, VALID_VISITS);
String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Email.class.getSimpleName());
assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
}
@Test
public void toModelType_invalidAddress_throwsIllegalValueException() {
- JsonAdaptedPerson person =
- new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, INVALID_ADDRESS, VALID_TAGS);
+ JsonAdaptedPatient person =
+ new JsonAdaptedPatient(VALID_NAME, VALID_PHONE, VALID_EMAIL, INVALID_ADDRESS, VALID_DATEOFBIRTH,
+ VALID_SEX, VALID_APPOINTMENT, VALID_VISITS);
String expectedMessage = Address.MESSAGE_CONSTRAINTS;
assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
}
@Test
public void toModelType_nullAddress_throwsIllegalValueException() {
- JsonAdaptedPerson person = new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, null, VALID_TAGS);
+ JsonAdaptedPatient person = new JsonAdaptedPatient(VALID_NAME, VALID_PHONE, VALID_EMAIL, null,
+ VALID_DATEOFBIRTH, VALID_SEX, VALID_APPOINTMENT, VALID_VISITS);
String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Address.class.getSimpleName());
assertThrows(IllegalValueException.class, expectedMessage, person::toModelType);
}
-
- @Test
- public void toModelType_invalidTags_throwsIllegalValueException() {
- List invalidTags = new ArrayList<>(VALID_TAGS);
- invalidTags.add(new JsonAdaptedTag(INVALID_TAG));
- JsonAdaptedPerson person =
- new JsonAdaptedPerson(VALID_NAME, VALID_PHONE, VALID_EMAIL, VALID_ADDRESS, invalidTags);
- assertThrows(IllegalValueException.class, person::toModelType);
- }
-
}
diff --git a/src/test/java/seedu/address/storage/JsonAdaptedVisitTest.java b/src/test/java/seedu/address/storage/JsonAdaptedVisitTest.java
new file mode 100644
index 00000000000..b2022213016
--- /dev/null
+++ b/src/test/java/seedu/address/storage/JsonAdaptedVisitTest.java
@@ -0,0 +1,80 @@
+package seedu.address.storage;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static seedu.address.storage.JsonAdaptedVisit.MISSING_FIELD_MESSAGE_FORMAT;
+import static seedu.address.testutil.Assert.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.commons.exceptions.IllegalValueException;
+import seedu.address.model.patient.Condition;
+import seedu.address.model.patient.DateOfVisit;
+import seedu.address.model.patient.Severity;
+import seedu.address.model.patient.Visit;
+
+public class JsonAdaptedVisitTest {
+
+ private static final String INVALID_CONDITION = " ";
+ private static final String INVALID_SEVERITY = "low";
+ private static final String INVALID_DATEOFVISIT = "24/2022";
+
+ private static final String VALID_CONDITION = "Fever";
+ private static final String VALID_DATEOFVISIT = "25/2/2024";
+ private static final String VALID_SEVERITY = "Low";
+ private static final Visit VALID_VISIT = new Visit(new Condition(VALID_CONDITION), new Severity(VALID_SEVERITY),
+ new DateOfVisit(VALID_DATEOFVISIT));
+
+ @Test
+ public void toModelType_validVisitDetails_returnsVisit() throws Exception {
+ JsonAdaptedVisit visit = new JsonAdaptedVisit(VALID_VISIT);
+ assertEquals(VALID_VISIT, visit.toModelType());
+ }
+
+ @Test
+ public void toModelType_invalidCondition_throwsIllegalValueException() {
+ JsonAdaptedVisit visit =
+ new JsonAdaptedVisit(INVALID_CONDITION, VALID_SEVERITY, VALID_DATEOFVISIT);
+ String expectedMessage = Condition.MESSAGE_CONSTRAINTS;
+ assertThrows(IllegalValueException.class, expectedMessage, visit::toModelType);
+ }
+
+ @Test
+ public void toModelType_nullCondition_throwsIllegalValueException() {
+ JsonAdaptedVisit visit =
+ new JsonAdaptedVisit(null, VALID_SEVERITY, VALID_DATEOFVISIT);
+ String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Condition.class.getSimpleName());
+ assertThrows(IllegalValueException.class, expectedMessage, visit::toModelType);
+ }
+
+ @Test
+ public void toModelType_invalidDateOfVisit_throwsIllegalValueException() {
+ JsonAdaptedVisit visit =
+ new JsonAdaptedVisit(VALID_CONDITION, VALID_SEVERITY, INVALID_DATEOFVISIT);
+ String expectedMessage = DateOfVisit.MESSAGE_CONSTRAINTS;
+ assertThrows(IllegalValueException.class, expectedMessage, visit::toModelType);
+ }
+
+ @Test
+ public void toModelType_nullDateOfVisit_throwsIllegalValueException() {
+ JsonAdaptedVisit visit =
+ new JsonAdaptedVisit(VALID_CONDITION, VALID_SEVERITY, null);
+ String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, DateOfVisit.class.getSimpleName());
+ assertThrows(IllegalValueException.class, expectedMessage, visit::toModelType);
+ }
+
+ @Test
+ public void toModelType_invalidSeverity_throwsIllegalValueException() {
+ JsonAdaptedVisit visit =
+ new JsonAdaptedVisit(VALID_CONDITION, INVALID_SEVERITY, VALID_DATEOFVISIT);
+ String expectedMessage = Severity.MESSAGE_CONSTRAINTS;
+ assertThrows(IllegalValueException.class, expectedMessage, visit::toModelType);
+ }
+
+ @Test
+ public void toModelType_nullSeverity_throwsIllegalValueException() {
+ JsonAdaptedVisit visit =
+ new JsonAdaptedVisit(VALID_CONDITION, null, VALID_DATEOFVISIT);
+ String expectedMessage = String.format(MISSING_FIELD_MESSAGE_FORMAT, Severity.class.getSimpleName());
+ assertThrows(IllegalValueException.class, expectedMessage, visit::toModelType);
+ }
+}
diff --git a/src/test/java/seedu/address/storage/JsonAddressBookStorageTest.java b/src/test/java/seedu/address/storage/JsonPatientListStorageTest.java
similarity index 56%
rename from src/test/java/seedu/address/storage/JsonAddressBookStorageTest.java
rename to src/test/java/seedu/address/storage/JsonPatientListStorageTest.java
index 4e5ce9200c8..fa94bbc32f4 100644
--- a/src/test/java/seedu/address/storage/JsonAddressBookStorageTest.java
+++ b/src/test/java/seedu/address/storage/JsonPatientListStorageTest.java
@@ -3,10 +3,10 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static seedu.address.testutil.Assert.assertThrows;
-import static seedu.address.testutil.TypicalPersons.ALICE;
-import static seedu.address.testutil.TypicalPersons.HOON;
-import static seedu.address.testutil.TypicalPersons.IDA;
-import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
+import static seedu.address.testutil.TypicalPatients.ALICE;
+import static seedu.address.testutil.TypicalPatients.HOON;
+import static seedu.address.testutil.TypicalPatients.IDA;
+import static seedu.address.testutil.TypicalPatients.getTypicalAddressBook;
import java.io.IOException;
import java.nio.file.Path;
@@ -16,11 +16,11 @@
import org.junit.jupiter.api.io.TempDir;
import seedu.address.commons.exceptions.DataLoadingException;
-import seedu.address.model.AddressBook;
-import seedu.address.model.ReadOnlyAddressBook;
+import seedu.address.model.PatientList;
+import seedu.address.model.ReadOnlyPatientList;
-public class JsonAddressBookStorageTest {
- private static final Path TEST_DATA_FOLDER = Paths.get("src", "test", "data", "JsonAddressBookStorageTest");
+public class JsonPatientListStorageTest {
+ private static final Path TEST_DATA_FOLDER = Paths.get("src", "test", "data", "JsonPatientListStorageTest");
@TempDir
public Path testFolder;
@@ -30,8 +30,8 @@ public void readAddressBook_nullFilePath_throwsNullPointerException() {
assertThrows(NullPointerException.class, () -> readAddressBook(null));
}
- private java.util.Optional readAddressBook(String filePath) throws Exception {
- return new JsonAddressBookStorage(Paths.get(filePath)).readAddressBook(addToTestDataPathIfNotNull(filePath));
+ private java.util.Optional readAddressBook(String filePath) throws Exception {
+ return new JsonPatientListStorage(Paths.get(filePath)).readPatientList(addToTestDataPathIfNotNull(filePath));
}
private Path addToTestDataPathIfNotNull(String prefsFileInTestDataFolder) {
@@ -51,38 +51,38 @@ public void read_notJsonFormat_exceptionThrown() {
}
@Test
- public void readAddressBook_invalidPersonAddressBook_throwDataLoadingException() {
- assertThrows(DataLoadingException.class, () -> readAddressBook("invalidPersonAddressBook.json"));
+ public void readAddressBook_invalidPatientAddressBook_throwDataLoadingException() {
+ assertThrows(DataLoadingException.class, () -> readAddressBook("invalidPatientAddressBook.json"));
}
@Test
- public void readAddressBook_invalidAndValidPersonAddressBook_throwDataLoadingException() {
- assertThrows(DataLoadingException.class, () -> readAddressBook("invalidAndValidPersonAddressBook.json"));
+ public void readAddressBook_invalidAndValidPatientAddressBook_throwDataLoadingException() {
+ assertThrows(DataLoadingException.class, () -> readAddressBook("invalidAndValidPatientAddressBook.json"));
}
@Test
public void readAndSaveAddressBook_allInOrder_success() throws Exception {
Path filePath = testFolder.resolve("TempAddressBook.json");
- AddressBook original = getTypicalAddressBook();
- JsonAddressBookStorage jsonAddressBookStorage = new JsonAddressBookStorage(filePath);
+ PatientList original = getTypicalAddressBook();
+ JsonPatientListStorage jsonAddressBookStorage = new JsonPatientListStorage(filePath);
// Save in new file and read back
- jsonAddressBookStorage.saveAddressBook(original, filePath);
- ReadOnlyAddressBook readBack = jsonAddressBookStorage.readAddressBook(filePath).get();
- assertEquals(original, new AddressBook(readBack));
+ jsonAddressBookStorage.savePatientList(original, filePath);
+ ReadOnlyPatientList readBack = jsonAddressBookStorage.readPatientList(filePath).get();
+ assertEquals(original, new PatientList(readBack));
// Modify data, overwrite exiting file, and read back
- original.addPerson(HOON);
- original.removePerson(ALICE);
- jsonAddressBookStorage.saveAddressBook(original, filePath);
- readBack = jsonAddressBookStorage.readAddressBook(filePath).get();
- assertEquals(original, new AddressBook(readBack));
+ original.addPatient(HOON);
+ original.removePatient(ALICE);
+ jsonAddressBookStorage.savePatientList(original, filePath);
+ readBack = jsonAddressBookStorage.readPatientList(filePath).get();
+ assertEquals(original, new PatientList(readBack));
// Save and read without specifying file path
- original.addPerson(IDA);
- jsonAddressBookStorage.saveAddressBook(original); // file path not specified
- readBack = jsonAddressBookStorage.readAddressBook().get(); // file path not specified
- assertEquals(original, new AddressBook(readBack));
+ original.addPatient(IDA);
+ jsonAddressBookStorage.savePatientList(original); // file path not specified
+ readBack = jsonAddressBookStorage.readPatientList().get(); // file path not specified
+ assertEquals(original, new PatientList(readBack));
}
@@ -94,10 +94,10 @@ public void saveAddressBook_nullAddressBook_throwsNullPointerException() {
/**
* Saves {@code addressBook} at the specified {@code filePath}.
*/
- private void saveAddressBook(ReadOnlyAddressBook addressBook, String filePath) {
+ private void saveAddressBook(ReadOnlyPatientList addressBook, String filePath) {
try {
- new JsonAddressBookStorage(Paths.get(filePath))
- .saveAddressBook(addressBook, addToTestDataPathIfNotNull(filePath));
+ new JsonPatientListStorage(Paths.get(filePath))
+ .savePatientList(addressBook, addToTestDataPathIfNotNull(filePath));
} catch (IOException ioe) {
throw new AssertionError("There should not be an error writing to the file.", ioe);
}
@@ -105,6 +105,6 @@ private void saveAddressBook(ReadOnlyAddressBook addressBook, String filePath) {
@Test
public void saveAddressBook_nullFilePath_throwsNullPointerException() {
- assertThrows(NullPointerException.class, () -> saveAddressBook(new AddressBook(), null));
+ assertThrows(NullPointerException.class, () -> saveAddressBook(new PatientList(), null));
}
}
diff --git a/src/test/java/seedu/address/storage/JsonSerializableAddressBookTest.java b/src/test/java/seedu/address/storage/JsonSerializableAddressBookTest.java
deleted file mode 100644
index 188c9058d20..00000000000
--- a/src/test/java/seedu/address/storage/JsonSerializableAddressBookTest.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package seedu.address.storage;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static seedu.address.testutil.Assert.assertThrows;
-
-import java.nio.file.Path;
-import java.nio.file.Paths;
-
-import org.junit.jupiter.api.Test;
-
-import seedu.address.commons.exceptions.IllegalValueException;
-import seedu.address.commons.util.JsonUtil;
-import seedu.address.model.AddressBook;
-import seedu.address.testutil.TypicalPersons;
-
-public class JsonSerializableAddressBookTest {
-
- private static final Path TEST_DATA_FOLDER = Paths.get("src", "test", "data", "JsonSerializableAddressBookTest");
- private static final Path TYPICAL_PERSONS_FILE = TEST_DATA_FOLDER.resolve("typicalPersonsAddressBook.json");
- private static final Path INVALID_PERSON_FILE = TEST_DATA_FOLDER.resolve("invalidPersonAddressBook.json");
- private static final Path DUPLICATE_PERSON_FILE = TEST_DATA_FOLDER.resolve("duplicatePersonAddressBook.json");
-
- @Test
- public void toModelType_typicalPersonsFile_success() throws Exception {
- JsonSerializableAddressBook dataFromFile = JsonUtil.readJsonFile(TYPICAL_PERSONS_FILE,
- JsonSerializableAddressBook.class).get();
- AddressBook addressBookFromFile = dataFromFile.toModelType();
- AddressBook typicalPersonsAddressBook = TypicalPersons.getTypicalAddressBook();
- assertEquals(addressBookFromFile, typicalPersonsAddressBook);
- }
-
- @Test
- public void toModelType_invalidPersonFile_throwsIllegalValueException() throws Exception {
- JsonSerializableAddressBook dataFromFile = JsonUtil.readJsonFile(INVALID_PERSON_FILE,
- JsonSerializableAddressBook.class).get();
- assertThrows(IllegalValueException.class, dataFromFile::toModelType);
- }
-
- @Test
- public void toModelType_duplicatePersons_throwsIllegalValueException() throws Exception {
- JsonSerializableAddressBook dataFromFile = JsonUtil.readJsonFile(DUPLICATE_PERSON_FILE,
- JsonSerializableAddressBook.class).get();
- assertThrows(IllegalValueException.class, JsonSerializableAddressBook.MESSAGE_DUPLICATE_PERSON,
- dataFromFile::toModelType);
- }
-
-}
diff --git a/src/test/java/seedu/address/storage/JsonSerializablePatientListTest.java b/src/test/java/seedu/address/storage/JsonSerializablePatientListTest.java
new file mode 100644
index 00000000000..b02744851cc
--- /dev/null
+++ b/src/test/java/seedu/address/storage/JsonSerializablePatientListTest.java
@@ -0,0 +1,47 @@
+package seedu.address.storage;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static seedu.address.testutil.Assert.assertThrows;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import org.junit.jupiter.api.Test;
+
+import seedu.address.commons.exceptions.IllegalValueException;
+import seedu.address.commons.util.JsonUtil;
+import seedu.address.model.PatientList;
+import seedu.address.testutil.TypicalPatients;
+
+public class JsonSerializablePatientListTest {
+
+ private static final Path TEST_DATA_FOLDER = Paths.get("src", "test", "data", "JsonSerializablePatientListTest");
+ private static final Path TYPICAL_PATIENTS_FILE = TEST_DATA_FOLDER.resolve("typicalPatientAddressBook.json");
+ private static final Path INVALID_PATIENT_FILE = TEST_DATA_FOLDER.resolve("invalidPatientAddressBook.json");
+ private static final Path DUPLICATE_PATIENT_FILE = TEST_DATA_FOLDER.resolve("duplicatePatientAddressBook.json");
+
+ @Test
+ public void toModelType_typicalPatientsFile_success() throws Exception {
+ JsonSerializablePatientList dataFromFile = JsonUtil.readJsonFile(TYPICAL_PATIENTS_FILE,
+ JsonSerializablePatientList.class).get();
+ PatientList patientListFromFile = dataFromFile.toModelType();
+ PatientList typicalPatientsPatientList = TypicalPatients.getTypicalAddressBook();
+ assertEquals(patientListFromFile, typicalPatientsPatientList);
+ }
+
+ @Test
+ public void toModelType_invalidPatientFile_throwsIllegalValueException() throws Exception {
+ JsonSerializablePatientList dataFromFile = JsonUtil.readJsonFile(INVALID_PATIENT_FILE,
+ JsonSerializablePatientList.class).get();
+ assertThrows(IllegalValueException.class, dataFromFile::toModelType);
+ }
+
+ @Test
+ public void toModelType_duplicatePatients_throwsIllegalValueException() throws Exception {
+ JsonSerializablePatientList dataFromFile = JsonUtil.readJsonFile(DUPLICATE_PATIENT_FILE,
+ JsonSerializablePatientList.class).get();
+ assertThrows(IllegalValueException.class, JsonSerializablePatientList.MESSAGE_DUPLICATE_PATIENT,
+ dataFromFile::toModelType);
+ }
+
+}
diff --git a/src/test/java/seedu/address/storage/JsonUserPrefsStorageTest.java b/src/test/java/seedu/address/storage/JsonUserPrefsStorageTest.java
index ed0a413526a..63ec4b1bdcc 100644
--- a/src/test/java/seedu/address/storage/JsonUserPrefsStorageTest.java
+++ b/src/test/java/seedu/address/storage/JsonUserPrefsStorageTest.java
@@ -73,7 +73,7 @@ public void readUserPrefs_extraValuesInFile_extraValuesIgnored() throws DataLoad
private UserPrefs getTypicalUserPrefs() {
UserPrefs userPrefs = new UserPrefs();
userPrefs.setGuiSettings(new GuiSettings(1000, 500, 300, 100));
- userPrefs.setAddressBookFilePath(Paths.get("addressbook.json"));
+ userPrefs.setPatientListFilePath(Paths.get("patientlist.json"));
return userPrefs;
}
diff --git a/src/test/java/seedu/address/storage/StorageManagerTest.java b/src/test/java/seedu/address/storage/StorageManagerTest.java
index 99a16548970..1f251ac09e8 100644
--- a/src/test/java/seedu/address/storage/StorageManagerTest.java
+++ b/src/test/java/seedu/address/storage/StorageManagerTest.java
@@ -2,7 +2,7 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;
+import static seedu.address.testutil.TypicalPatients.getTypicalAddressBook;
import java.nio.file.Path;
@@ -11,8 +11,8 @@
import org.junit.jupiter.api.io.TempDir;
import seedu.address.commons.core.GuiSettings;
-import seedu.address.model.AddressBook;
-import seedu.address.model.ReadOnlyAddressBook;
+import seedu.address.model.PatientList;
+import seedu.address.model.ReadOnlyPatientList;
import seedu.address.model.UserPrefs;
public class StorageManagerTest {
@@ -24,7 +24,7 @@ public class StorageManagerTest {
@BeforeEach
public void setUp() {
- JsonAddressBookStorage addressBookStorage = new JsonAddressBookStorage(getTempFilePath("ab"));
+ JsonPatientListStorage addressBookStorage = new JsonPatientListStorage(getTempFilePath("ab"));
JsonUserPrefsStorage userPrefsStorage = new JsonUserPrefsStorage(getTempFilePath("prefs"));
storageManager = new StorageManager(addressBookStorage, userPrefsStorage);
}
@@ -51,18 +51,18 @@ public void prefsReadSave() throws Exception {
public void addressBookReadSave() throws Exception {
/*
* Note: This is an integration test that verifies the StorageManager is properly wired to the
- * {@link JsonAddressBookStorage} class.
- * More extensive testing of UserPref saving/reading is done in {@link JsonAddressBookStorageTest} class.
+ * {@link JsonPatientListStorage} class.
+ * More extensive testing of UserPref saving/reading is done in {@link JsonPatientListStorageTest} class.
*/
- AddressBook original = getTypicalAddressBook();
- storageManager.saveAddressBook(original);
- ReadOnlyAddressBook retrieved = storageManager.readAddressBook().get();
- assertEquals(original, new AddressBook(retrieved));
+ PatientList original = getTypicalAddressBook();
+ storageManager.savePatientList(original);
+ ReadOnlyPatientList retrieved = storageManager.readPatientList().get();
+ assertEquals(original, new PatientList(retrieved));
}
@Test
public void getAddressBookFilePath() {
- assertNotNull(storageManager.getAddressBookFilePath());
+ assertNotNull(storageManager.getPatientListFilePath());
}
}
diff --git a/src/test/java/seedu/address/testutil/AddressBookBuilder.java b/src/test/java/seedu/address/testutil/AddressBookBuilder.java
index d53799fd110..1b1aaae8cce 100644
--- a/src/test/java/seedu/address/testutil/AddressBookBuilder.java
+++ b/src/test/java/seedu/address/testutil/AddressBookBuilder.java
@@ -1,34 +1,34 @@
package seedu.address.testutil;
-import seedu.address.model.AddressBook;
-import seedu.address.model.person.Person;
+import seedu.address.model.PatientList;
+import seedu.address.model.patient.Patient;
/**
* A utility class to help with building Addressbook objects.
* Example usage:
- * {@code AddressBook ab = new AddressBookBuilder().withPerson("John", "Doe").build();}
+ * {@code PatientList ab = new AddressBookBuilder().withPerson("John", "Doe").build();}
*/
public class AddressBookBuilder {
- private AddressBook addressBook;
+ private PatientList patientList;
public AddressBookBuilder() {
- addressBook = new AddressBook();
+ patientList = new PatientList();
}
- public AddressBookBuilder(AddressBook addressBook) {
- this.addressBook = addressBook;
+ public AddressBookBuilder(PatientList patientList) {
+ this.patientList = patientList;
}
/**
- * Adds a new {@code Person} to the {@code AddressBook} that we are building.
+ * Adds a new {@code Patient} to the {@code PatientList} that we are building.
*/
- public AddressBookBuilder withPerson(Person person) {
- addressBook.addPerson(person);
+ public AddressBookBuilder withPatient(Patient patient) {
+ patientList.addPatient(patient);
return this;
}
- public AddressBook build() {
- return addressBook;
+ public PatientList build() {
+ return patientList;
}
}
diff --git a/src/test/java/seedu/address/testutil/EditPatientDescriptorBuilder.java b/src/test/java/seedu/address/testutil/EditPatientDescriptorBuilder.java
new file mode 100644
index 00000000000..1e41bce6541
--- /dev/null
+++ b/src/test/java/seedu/address/testutil/EditPatientDescriptorBuilder.java
@@ -0,0 +1,101 @@
+package seedu.address.testutil;
+
+import seedu.address.logic.commands.EditCommand.EditPatientDescriptor;
+import seedu.address.model.patient.Address;
+import seedu.address.model.patient.Appointment;
+import seedu.address.model.patient.DateOfBirth;
+import seedu.address.model.patient.Email;
+import seedu.address.model.patient.Name;
+import seedu.address.model.patient.Patient;
+import seedu.address.model.patient.Phone;
+import seedu.address.model.patient.Sex;
+
+/**
+ * A utility class to help with building EditPersonDescriptor objects.
+ */
+public class EditPatientDescriptorBuilder {
+
+ private EditPatientDescriptor descriptor;
+
+ public EditPatientDescriptorBuilder() {
+ descriptor = new EditPatientDescriptor();
+ }
+
+ public EditPatientDescriptorBuilder(EditPatientDescriptor descriptor) {
+ this.descriptor = new EditPatientDescriptor(descriptor);
+ }
+
+ /**
+ * Returns an {@code EditPersonDescriptor} with fields containing {@code patient}'s details
+ */
+ public EditPatientDescriptorBuilder(Patient patient) {
+ descriptor = new EditPatientDescriptor();
+ descriptor.setName(patient.getName());
+ descriptor.setPhone(patient.getPhone());
+ descriptor.setEmail(patient.getEmail());
+ descriptor.setAddress(patient.getAddress());
+ descriptor.setDateOfBirth(patient.getDateOfBirth());
+ descriptor.setSex(patient.getSex());
+ descriptor.setAppointment(patient.getAppointment());
+ }
+
+ /**
+ * Sets the {@code Name} of the {@code EditPersonDescriptor} that we are building.
+ */
+ public EditPatientDescriptorBuilder withName(String name) {
+ descriptor.setName(new Name(name));
+ return this;
+ }
+
+ /**
+ * Sets the {@code Phone} of the {@code EditPersonDescriptor} that we are building.
+ */
+ public EditPatientDescriptorBuilder withPhone(String phone) {
+ descriptor.setPhone(new Phone(phone));
+ return this;
+ }
+
+ /**
+ * Sets the {@code Email} of the {@code EditPersonDescriptor} that we are building.
+ */
+ public EditPatientDescriptorBuilder withEmail(String email) {
+ descriptor.setEmail(new Email(email));
+ return this;
+ }
+
+ /**
+ * Sets the {@code Address} of the {@code EditPersonDescriptor} that we are building.
+ */
+ public EditPatientDescriptorBuilder withAddress(String address) {
+ descriptor.setAddress(new Address(address));
+ return this;
+ }
+
+ /**
+ * Sets the {@code DateOfBirth} of the {@code EditPersonDescriptor} that we are building.
+ */
+ public EditPatientDescriptorBuilder withDateOfBirth(String dateOfBirth) {
+ descriptor.setDateOfBirth(new DateOfBirth(dateOfBirth));
+ return this;
+ }
+
+ /**
+ * Sets the {@code Sex} of the {@code EditPersonDescriptor} that we are building.
+ */
+ public EditPatientDescriptorBuilder withSex(String sex) {
+ descriptor.setSex(new Sex(sex));
+ return this;
+ }
+
+ /**
+ * Sets the {@code Appointment} of the {@code EditPersonDescriptor} that we are building.
+ */
+ public EditPatientDescriptorBuilder withAppointment(String appointment) {
+ descriptor.setAppointment(new Appointment(appointment));
+ return this;
+ }
+
+ public EditPatientDescriptor build() {
+ return descriptor;
+ }
+}
diff --git a/src/test/java/seedu/address/testutil/EditPersonDescriptorBuilder.java b/src/test/java/seedu/address/testutil/EditPersonDescriptorBuilder.java
deleted file mode 100644
index 4584bd5044e..00000000000
--- a/src/test/java/seedu/address/testutil/EditPersonDescriptorBuilder.java
+++ /dev/null
@@ -1,87 +0,0 @@
-package seedu.address.testutil;
-
-import java.util.Set;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
-
-/**
- * A utility class to help with building EditPersonDescriptor objects.
- */
-public class EditPersonDescriptorBuilder {
-
- private EditPersonDescriptor descriptor;
-
- public EditPersonDescriptorBuilder() {
- descriptor = new EditPersonDescriptor();
- }
-
- public EditPersonDescriptorBuilder(EditPersonDescriptor descriptor) {
- this.descriptor = new EditPersonDescriptor(descriptor);
- }
-
- /**
- * Returns an {@code EditPersonDescriptor} with fields containing {@code person}'s details
- */
- public EditPersonDescriptorBuilder(Person person) {
- descriptor = new EditPersonDescriptor();
- descriptor.setName(person.getName());
- descriptor.setPhone(person.getPhone());
- descriptor.setEmail(person.getEmail());
- descriptor.setAddress(person.getAddress());
- descriptor.setTags(person.getTags());
- }
-
- /**
- * Sets the {@code Name} of the {@code EditPersonDescriptor} that we are building.
- */
- public EditPersonDescriptorBuilder withName(String name) {
- descriptor.setName(new Name(name));
- return this;
- }
-
- /**
- * Sets the {@code Phone} of the {@code EditPersonDescriptor} that we are building.
- */
- public EditPersonDescriptorBuilder withPhone(String phone) {
- descriptor.setPhone(new Phone(phone));
- return this;
- }
-
- /**
- * Sets the {@code Email} of the {@code EditPersonDescriptor} that we are building.
- */
- public EditPersonDescriptorBuilder withEmail(String email) {
- descriptor.setEmail(new Email(email));
- return this;
- }
-
- /**
- * Sets the {@code Address} of the {@code EditPersonDescriptor} that we are building.
- */
- public EditPersonDescriptorBuilder withAddress(String address) {
- descriptor.setAddress(new Address(address));
- return this;
- }
-
- /**
- * Parses the {@code tags} into a {@code Set} and set it to the {@code EditPersonDescriptor}
- * that we are building.
- */
- public EditPersonDescriptorBuilder withTags(String... tags) {
- Set tagSet = Stream.of(tags).map(Tag::new).collect(Collectors.toSet());
- descriptor.setTags(tagSet);
- return this;
- }
-
- public EditPersonDescriptor build() {
- return descriptor;
- }
-}
diff --git a/src/test/java/seedu/address/testutil/EditVisitDescriptorBuilder.java b/src/test/java/seedu/address/testutil/EditVisitDescriptorBuilder.java
new file mode 100644
index 00000000000..345ceb48bb8
--- /dev/null
+++ b/src/test/java/seedu/address/testutil/EditVisitDescriptorBuilder.java
@@ -0,0 +1,60 @@
+package seedu.address.testutil;
+
+import seedu.address.logic.commands.EditVisitCommand;
+import seedu.address.model.patient.Condition;
+import seedu.address.model.patient.DateOfVisit;
+import seedu.address.model.patient.Severity;
+import seedu.address.model.patient.Visit;
+
+/**
+ * A utility class to help with building EditVisitDescriptor objects.
+ */
+public class EditVisitDescriptorBuilder {
+ private EditVisitCommand.EditVisitDescriptor descriptor;
+
+ public EditVisitDescriptorBuilder() {
+ descriptor = new EditVisitCommand.EditVisitDescriptor();
+ }
+
+ public EditVisitDescriptorBuilder(EditVisitCommand.EditVisitDescriptor descriptor) {
+ this.descriptor = new EditVisitCommand.EditVisitDescriptor(descriptor);
+ }
+
+ /**
+ * Returns an {@code EditVisitDescriptor} with fields containing {@code visit}'s details
+ */
+ public EditVisitDescriptorBuilder(Visit visit) {
+ descriptor = new EditVisitCommand.EditVisitDescriptor();
+ descriptor.setDateOfVisit(visit.getDateOfVisit());
+ descriptor.setCondition(visit.getCondition());
+ descriptor.setSeverity(visit.getSeverity());
+ }
+
+ /**
+ * Sets the {@code DateOfVisit} of the {@code EditVisitDescriptor} that we are building.
+ */
+ public EditVisitDescriptorBuilder withDateOfVisit(String dateOfVisit) {
+ descriptor.setDateOfVisit(new DateOfVisit(dateOfVisit));
+ return this;
+ }
+
+ /**
+ * Sets the {@code Severity} of the {@code EditVisitDescriptor} that we are building.
+ */
+ public EditVisitDescriptorBuilder withSeverity(String severity) {
+ descriptor.setSeverity(new Severity(severity));
+ return this;
+ }
+
+ /**
+ * Sets the {@code Condition} of the {@code EditVisitDescriptor} that we are building.
+ */
+ public EditVisitDescriptorBuilder withCondition(String condition) {
+ descriptor.setCondition(new Condition(condition));
+ return this;
+ }
+
+ public EditVisitCommand.EditVisitDescriptor build() {
+ return descriptor;
+ }
+}
diff --git a/src/test/java/seedu/address/testutil/PatientBuilder.java b/src/test/java/seedu/address/testutil/PatientBuilder.java
new file mode 100644
index 00000000000..89fba8f5b35
--- /dev/null
+++ b/src/test/java/seedu/address/testutil/PatientBuilder.java
@@ -0,0 +1,119 @@
+package seedu.address.testutil;
+
+import seedu.address.model.patient.Address;
+import seedu.address.model.patient.Appointment;
+import seedu.address.model.patient.DateOfBirth;
+import seedu.address.model.patient.Email;
+import seedu.address.model.patient.Name;
+import seedu.address.model.patient.Patient;
+import seedu.address.model.patient.Phone;
+import seedu.address.model.patient.Sex;
+
+/**
+ * A utility class to help with building Patient objects.
+ */
+public class PatientBuilder {
+
+ public static final String DEFAULT_NAME = "Amy Bee";
+ public static final String DEFAULT_PHONE = "85355255";
+ public static final String DEFAULT_EMAIL = "amy@gmail.com";
+ public static final String DEFAULT_ADDRESS = "123, Jurong West Ave 6, #08-111";
+ public static final String DEFAULT_DATEOFBIRTH = "25/2/2025";
+ public static final String DEFAULT_SEX = "Female";
+ public static final String DEFAULT_APPOINTMENT = "";
+
+ private Name name;
+ private Phone phone;
+ private Email email;
+ private Address address;
+ private DateOfBirth dateOfBirth;
+ private Sex sex;
+ private Appointment appointment;
+
+ /**
+ * Creates a {@code PatientBuilder} with the default details.
+ */
+ public PatientBuilder() {
+ name = new Name(DEFAULT_NAME);
+ phone = new Phone(DEFAULT_PHONE);
+ email = new Email(DEFAULT_EMAIL);
+ address = new Address(DEFAULT_ADDRESS);
+ dateOfBirth = new DateOfBirth(DEFAULT_DATEOFBIRTH);
+ sex = new Sex(DEFAULT_SEX);
+ appointment = new Appointment(DEFAULT_APPOINTMENT);
+ }
+
+ /**
+ * Initializes the PatientBuilder with the data of {@code patientToCopy}.
+ */
+ public PatientBuilder(Patient patientToCopy) {
+ name = patientToCopy.getName();
+ phone = patientToCopy.getPhone();
+ email = patientToCopy.getEmail();
+ address = patientToCopy.getAddress();
+ dateOfBirth = patientToCopy.getDateOfBirth();
+ sex = patientToCopy.getSex();
+ appointment = patientToCopy.getAppointment();
+ }
+
+ /**
+ * Sets the {@code Name} of the {@code Patient} that we are building.
+ */
+ public PatientBuilder withName(String name) {
+ this.name = new Name(name);
+ return this;
+ }
+
+ /**
+ * Sets the {@code Address} of the {@code Patient} that we are building.
+ */
+ public PatientBuilder withAddress(String address) {
+ this.address = new Address(address);
+ return this;
+ }
+
+ /**
+ * Sets the {@code Phone} of the {@code Patient} that we are building.
+ */
+ public PatientBuilder withPhone(String phone) {
+ this.phone = new Phone(phone);
+ return this;
+ }
+
+ /**
+ * Sets the {@code Email} of the {@code Patient} that we are building.
+ */
+ public PatientBuilder withEmail(String email) {
+ this.email = new Email(email);
+ return this;
+ }
+
+ /**
+ * Sets the {@code DateOfBirth} of the {@Code Patient} that we are buidling.
+ */
+ public PatientBuilder withDateOfBirth(String dateOfBirth) {
+ this.dateOfBirth = new DateOfBirth(dateOfBirth);
+ return this;
+ }
+
+ /**
+ * Sets the {@code Sex} of the {@Cose Patient} that we are building.
+ */
+ public PatientBuilder withSex(String sex) {
+ this.sex = new Sex(sex);
+ return this;
+ }
+
+ /**
+ * Sets the {@code Appointment} of the {@Cose Appointment} that we are building.
+ */
+ public PatientBuilder withAppointment(String appointment) {
+ this.appointment = new Appointment(appointment);
+ return this;
+ }
+
+ public Patient build() {
+ return new Patient(name, phone, email, address, dateOfBirth, sex, appointment);
+ }
+
+}
diff --git a/src/test/java/seedu/address/testutil/PatientUtil.java b/src/test/java/seedu/address/testutil/PatientUtil.java
new file mode 100644
index 00000000000..5ad53881306
--- /dev/null
+++ b/src/test/java/seedu/address/testutil/PatientUtil.java
@@ -0,0 +1,57 @@
+package seedu.address.testutil;
+
+import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_APPOINTMENT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DATEOFBIRTH;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_SEX;
+
+import seedu.address.logic.commands.AddCommand;
+import seedu.address.logic.commands.EditCommand.EditPatientDescriptor;
+import seedu.address.model.patient.Patient;
+
+/**
+ * A utility class for Patient.
+ */
+public class PatientUtil {
+
+ /**
+ * Returns an add command string for adding the {@code patient}.
+ */
+ public static String getAddCommand(Patient patient) {
+ return AddCommand.COMMAND_WORD + " " + getPatientDetails(patient);
+ }
+
+ /**
+ * Returns the part of command string for the given {@code patient}'s details.
+ */
+ public static String getPatientDetails(Patient patient) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(PREFIX_NAME + patient.getName().fullName + " ");
+ sb.append(PREFIX_PHONE + patient.getPhone().value + " ");
+ sb.append(PREFIX_EMAIL + patient.getEmail().value + " ");
+ sb.append(PREFIX_ADDRESS + patient.getAddress().value + " ");
+ sb.append(PREFIX_DATEOFBIRTH + patient.getDateOfBirth().toString() + " ");
+ sb.append(PREFIX_SEX + patient.getSex().toString() + " ");
+ return sb.toString();
+ }
+
+ /**
+ * Returns the part of command string for the given {@code EditPersonDescriptor}'s details.
+ */
+ public static String getEditPatientDescriptorDetails(EditPatientDescriptor descriptor) {
+ StringBuilder sb = new StringBuilder();
+ descriptor.getName().ifPresent(name -> sb.append(PREFIX_NAME).append(name.fullName).append(" "));
+ descriptor.getPhone().ifPresent(phone -> sb.append(PREFIX_PHONE).append(phone.value).append(" "));
+ descriptor.getEmail().ifPresent(email -> sb.append(PREFIX_EMAIL).append(email.value).append(" "));
+ descriptor.getAddress().ifPresent(address -> sb.append(PREFIX_ADDRESS).append(address.value).append(" "));
+ descriptor.getDateOfBirth().ifPresent(dateOfBirth -> sb.append(PREFIX_DATEOFBIRTH)
+ .append(dateOfBirth.dateOfBirth).append(" "));
+ descriptor.getSex().ifPresent(sex -> sb.append(PREFIX_SEX).append(sex.sex.getLabel()).append(" "));
+ descriptor.getAppointment().ifPresent(appointment -> sb.append(PREFIX_APPOINTMENT)
+ .append(appointment.appointment == null ? "" : appointment.appointment).append(" "));
+ return sb.toString();
+ }
+}
diff --git a/src/test/java/seedu/address/testutil/PersonBuilder.java b/src/test/java/seedu/address/testutil/PersonBuilder.java
deleted file mode 100644
index 6be381d39ba..00000000000
--- a/src/test/java/seedu/address/testutil/PersonBuilder.java
+++ /dev/null
@@ -1,96 +0,0 @@
-package seedu.address.testutil;
-
-import java.util.HashSet;
-import java.util.Set;
-
-import seedu.address.model.person.Address;
-import seedu.address.model.person.Email;
-import seedu.address.model.person.Name;
-import seedu.address.model.person.Person;
-import seedu.address.model.person.Phone;
-import seedu.address.model.tag.Tag;
-import seedu.address.model.util.SampleDataUtil;
-
-/**
- * A utility class to help with building Person objects.
- */
-public class PersonBuilder {
-
- public static final String DEFAULT_NAME = "Amy Bee";
- public static final String DEFAULT_PHONE = "85355255";
- public static final String DEFAULT_EMAIL = "amy@gmail.com";
- public static final String DEFAULT_ADDRESS = "123, Jurong West Ave 6, #08-111";
-
- private Name name;
- private Phone phone;
- private Email email;
- private Address address;
- private Set tags;
-
- /**
- * Creates a {@code PersonBuilder} with the default details.
- */
- public PersonBuilder() {
- name = new Name(DEFAULT_NAME);
- phone = new Phone(DEFAULT_PHONE);
- email = new Email(DEFAULT_EMAIL);
- address = new Address(DEFAULT_ADDRESS);
- tags = new HashSet<>();
- }
-
- /**
- * Initializes the PersonBuilder with the data of {@code personToCopy}.
- */
- public PersonBuilder(Person personToCopy) {
- name = personToCopy.getName();
- phone = personToCopy.getPhone();
- email = personToCopy.getEmail();
- address = personToCopy.getAddress();
- tags = new HashSet<>(personToCopy.getTags());
- }
-
- /**
- * Sets the {@code Name} of the {@code Person} that we are building.
- */
- public PersonBuilder withName(String name) {
- this.name = new Name(name);
- return this;
- }
-
- /**
- * Parses the {@code tags} into a {@code Set} and set it to the {@code Person} that we are building.
- */
- public PersonBuilder withTags(String ... tags) {
- this.tags = SampleDataUtil.getTagSet(tags);
- return this;
- }
-
- /**
- * Sets the {@code Address} of the {@code Person} that we are building.
- */
- public PersonBuilder withAddress(String address) {
- this.address = new Address(address);
- return this;
- }
-
- /**
- * Sets the {@code Phone} of the {@code Person} that we are building.
- */
- public PersonBuilder withPhone(String phone) {
- this.phone = new Phone(phone);
- return this;
- }
-
- /**
- * Sets the {@code Email} of the {@code Person} that we are building.
- */
- public PersonBuilder withEmail(String email) {
- this.email = new Email(email);
- return this;
- }
-
- public Person build() {
- return new Person(name, phone, email, address, tags);
- }
-
-}
diff --git a/src/test/java/seedu/address/testutil/PersonUtil.java b/src/test/java/seedu/address/testutil/PersonUtil.java
deleted file mode 100644
index 90849945183..00000000000
--- a/src/test/java/seedu/address/testutil/PersonUtil.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package seedu.address.testutil;
-
-import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
-import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
-
-import java.util.Set;
-
-import seedu.address.logic.commands.AddCommand;
-import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
-import seedu.address.model.person.Person;
-import seedu.address.model.tag.Tag;
-
-/**
- * A utility class for Person.
- */
-public class PersonUtil {
-
- /**
- * Returns an add command string for adding the {@code person}.
- */
- public static String getAddCommand(Person person) {
- return AddCommand.COMMAND_WORD + " " + getPersonDetails(person);
- }
-
- /**
- * Returns the part of command string for the given {@code person}'s details.
- */
- public static String getPersonDetails(Person person) {
- StringBuilder sb = new StringBuilder();
- sb.append(PREFIX_NAME + person.getName().fullName + " ");
- sb.append(PREFIX_PHONE + person.getPhone().value + " ");
- sb.append(PREFIX_EMAIL + person.getEmail().value + " ");
- sb.append(PREFIX_ADDRESS + person.getAddress().value + " ");
- person.getTags().stream().forEach(
- s -> sb.append(PREFIX_TAG + s.tagName + " ")
- );
- return sb.toString();
- }
-
- /**
- * Returns the part of command string for the given {@code EditPersonDescriptor}'s details.
- */
- public static String getEditPersonDescriptorDetails(EditPersonDescriptor descriptor) {
- StringBuilder sb = new StringBuilder();
- descriptor.getName().ifPresent(name -> sb.append(PREFIX_NAME).append(name.fullName).append(" "));
- descriptor.getPhone().ifPresent(phone -> sb.append(PREFIX_PHONE).append(phone.value).append(" "));
- descriptor.getEmail().ifPresent(email -> sb.append(PREFIX_EMAIL).append(email.value).append(" "));
- descriptor.getAddress().ifPresent(address -> sb.append(PREFIX_ADDRESS).append(address.value).append(" "));
- if (descriptor.getTags().isPresent()) {
- Set tags = descriptor.getTags().get();
- if (tags.isEmpty()) {
- sb.append(PREFIX_TAG);
- } else {
- tags.forEach(s -> sb.append(PREFIX_TAG).append(s.tagName).append(" "));
- }
- }
- return sb.toString();
- }
-}
diff --git a/src/test/java/seedu/address/testutil/TestUtil.java b/src/test/java/seedu/address/testutil/TestUtil.java
index 896d103eb0b..c9e95f4b4a8 100644
--- a/src/test/java/seedu/address/testutil/TestUtil.java
+++ b/src/test/java/seedu/address/testutil/TestUtil.java
@@ -7,7 +7,7 @@
import seedu.address.commons.core.index.Index;
import seedu.address.model.Model;
-import seedu.address.model.person.Person;
+import seedu.address.model.patient.Patient;
/**
* A utility class for test cases.
@@ -33,23 +33,23 @@ public static Path getFilePathInSandboxFolder(String fileName) {
}
/**
- * Returns the middle index of the person in the {@code model}'s person list.
+ * Returns the middle index of the patient in the {@code model}'s patient list.
*/
public static Index getMidIndex(Model model) {
- return Index.fromOneBased(model.getFilteredPersonList().size() / 2);
+ return Index.fromOneBased(model.getFilteredPatientList().size() / 2);
}
/**
- * Returns the last index of the person in the {@code model}'s person list.
+ * Returns the last index of the patient in the {@code model}'s patient list.
*/
public static Index getLastIndex(Model model) {
- return Index.fromOneBased(model.getFilteredPersonList().size());
+ return Index.fromOneBased(model.getFilteredPatientList().size());
}
/**
- * Returns the person in the {@code model}'s person list at {@code index}.
+ * Returns the patient in the {@code model}'s patient list at {@code index}.
*/
- public static Person getPerson(Model model, Index index) {
- return model.getFilteredPersonList().get(index.getZeroBased());
+ public static Patient getPatient(Model model, Index index) {
+ return model.getFilteredPatientList().get(index.getZeroBased());
}
}
diff --git a/src/test/java/seedu/address/testutil/TypicalIndexes.java b/src/test/java/seedu/address/testutil/TypicalIndexes.java
index 1e613937657..fe923e4dbb5 100644
--- a/src/test/java/seedu/address/testutil/TypicalIndexes.java
+++ b/src/test/java/seedu/address/testutil/TypicalIndexes.java
@@ -6,7 +6,7 @@
* A utility class containing a list of {@code Index} objects to be used in tests.
*/
public class TypicalIndexes {
- public static final Index INDEX_FIRST_PERSON = Index.fromOneBased(1);
- public static final Index INDEX_SECOND_PERSON = Index.fromOneBased(2);
- public static final Index INDEX_THIRD_PERSON = Index.fromOneBased(3);
+ public static final Index INDEX_FIRST_PATIENT = Index.fromOneBased(1);
+ public static final Index INDEX_SECOND_PATIENT = Index.fromOneBased(2);
+ public static final Index INDEX_THIRD_PATIENT = Index.fromOneBased(3);
}
diff --git a/src/test/java/seedu/address/testutil/TypicalPatients.java b/src/test/java/seedu/address/testutil/TypicalPatients.java
new file mode 100644
index 00000000000..07f5add640f
--- /dev/null
+++ b/src/test/java/seedu/address/testutil/TypicalPatients.java
@@ -0,0 +1,96 @@
+package seedu.address.testutil;
+
+import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_APPOINTMENT_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_APPOINTMENT_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_DATEOFBIRTH_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_DATEOFBIRTH_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_BOB;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_SEX_AMY;
+import static seedu.address.logic.commands.CommandTestUtil.VALID_SEX_BOB;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import seedu.address.model.PatientList;
+import seedu.address.model.patient.Patient;
+
+/**
+ * A utility class containing a list of {@code Patient} objects to be used in tests.
+ */
+public class TypicalPatients {
+
+ public static final Patient ALICE = new PatientBuilder().withName("Alice Pauline")
+ .withAddress("123, Jurong West Ave 6, #08-111").withEmail("alice@example.com")
+ .withPhone("94351253").withDateOfBirth("25/2/2024").withSex("Female").withAppointment("2025-2-25")
+ .build();
+ public static final Patient BENSON = new PatientBuilder().withName("Benson Meier")
+ .withAddress("311, Clementi Ave 2, #02-25")
+ .withEmail("johnd@example.com").withPhone("98765432").withDateOfBirth("25/2/2024").withSex("Male")
+ .withAppointment("")
+ .build();
+ public static final Patient CARL = new PatientBuilder().withName("Carl Kurz").withPhone("95352563")
+ .withEmail("heinz@example.com").withAddress("wall street").withDateOfBirth("2032-06-23")
+ .withAppointment("2026-12-2")
+ .withSex("Male").build();
+ public static final Patient DANIEL = new PatientBuilder().withName("Daniel Meier").withPhone("87652533")
+ .withEmail("cornelia@example.com").withAddress("10th street").withDateOfBirth("2028-11-28")
+ .withAppointment("")
+ .withSex("Male").build();
+ public static final Patient ELLE = new PatientBuilder().withName("Elle Meyer").withPhone("9482224")
+ .withEmail("werner@example.com").withAddress("michegan ave").withDateOfBirth("2024-01-01")
+ .withAppointment("")
+ .withSex("Male").build();
+ public static final Patient FIONA = new PatientBuilder().withName("Fiona Kunz").withPhone("9482427")
+ .withEmail("lydia@example.com").withAddress("little tokyo").withDateOfBirth("2024-06-25")
+ .withAppointment("2192-5-12")
+ .withSex("Female").build();
+ public static final Patient GEORGE = new PatientBuilder().withName("George Best").withPhone("9482442")
+ .withEmail("anna@example.com").withAddress("4th street").withDateOfBirth("25/2/2024")
+ .withAppointment("")
+ .withSex("Male").build();
+
+ // Manually added
+ public static final Patient HOON = new PatientBuilder().withName("Hoon Meier").withPhone("8482424")
+ .withEmail("stefan@example.com").withAddress("little india").withDateOfBirth("25/2/2024")
+ .withAppointment("")
+ .withSex("Male").build();
+ public static final Patient IDA = new PatientBuilder().withName("Ida Mueller").withPhone("8482131")
+ .withEmail("hans@example.com").withAddress("chicago ave").withDateOfBirth("25/2/2024")
+ .withAppointment("")
+ .withSex("Female").build();
+
+ // Manually added - Person's details found in {@code CommandTestUtil}
+ public static final Patient AMY = new PatientBuilder().withName(VALID_NAME_AMY).withPhone(VALID_PHONE_AMY)
+ .withEmail(VALID_EMAIL_AMY).withAddress(VALID_ADDRESS_AMY).withDateOfBirth(VALID_DATEOFBIRTH_AMY)
+ .withSex(VALID_SEX_AMY).withAppointment(VALID_APPOINTMENT_AMY).build();
+ public static final Patient BOB = new PatientBuilder().withName(VALID_NAME_BOB).withPhone(VALID_PHONE_BOB)
+ .withEmail(VALID_EMAIL_BOB).withAddress(VALID_ADDRESS_BOB).withDateOfBirth(VALID_DATEOFBIRTH_BOB)
+ .withSex(VALID_SEX_BOB).withAppointment(VALID_APPOINTMENT_BOB).build();
+
+ public static final String KEYWORD_MATCHING_MEIER = "Meier"; // A keyword that matches MEIER
+
+ private TypicalPatients() {} // prevents instantiation
+
+ /**
+ * Returns an {@code PatientList} with all the typical persons.
+ */
+ public static PatientList getTypicalAddressBook() {
+ PatientList ab = new PatientList();
+ for (Patient patient : getTypicalPatients()) {
+ ab.addPatient(patient);
+ }
+ return ab;
+ }
+
+ public static List getTypicalPatients() {
+ return new ArrayList<>(Arrays.asList(ALICE, BENSON, CARL, DANIEL, ELLE, FIONA, GEORGE));
+ }
+}
diff --git a/src/test/java/seedu/address/testutil/TypicalPersons.java b/src/test/java/seedu/address/testutil/TypicalPersons.java
deleted file mode 100644
index fec76fb7129..00000000000
--- a/src/test/java/seedu/address/testutil/TypicalPersons.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package seedu.address.testutil;
-
-import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_ADDRESS_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_EMAIL_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_NAME_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_AMY;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_PHONE_BOB;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_FRIEND;
-import static seedu.address.logic.commands.CommandTestUtil.VALID_TAG_HUSBAND;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import seedu.address.model.AddressBook;
-import seedu.address.model.person.Person;
-
-/**
- * A utility class containing a list of {@code Person} objects to be used in tests.
- */
-public class TypicalPersons {
-
- public static final Person ALICE = new PersonBuilder().withName("Alice Pauline")
- .withAddress("123, Jurong West Ave 6, #08-111").withEmail("alice@example.com")
- .withPhone("94351253")
- .withTags("friends").build();
- public static final Person BENSON = new PersonBuilder().withName("Benson Meier")
- .withAddress("311, Clementi Ave 2, #02-25")
- .withEmail("johnd@example.com").withPhone("98765432")
- .withTags("owesMoney", "friends").build();
- public static final Person CARL = new PersonBuilder().withName("Carl Kurz").withPhone("95352563")
- .withEmail("heinz@example.com").withAddress("wall street").build();
- public static final Person DANIEL = new PersonBuilder().withName("Daniel Meier").withPhone("87652533")
- .withEmail("cornelia@example.com").withAddress("10th street").withTags("friends").build();
- public static final Person ELLE = new PersonBuilder().withName("Elle Meyer").withPhone("9482224")
- .withEmail("werner@example.com").withAddress("michegan ave").build();
- public static final Person FIONA = new PersonBuilder().withName("Fiona Kunz").withPhone("9482427")
- .withEmail("lydia@example.com").withAddress("little tokyo").build();
- public static final Person GEORGE = new PersonBuilder().withName("George Best").withPhone("9482442")
- .withEmail("anna@example.com").withAddress("4th street").build();
-
- // Manually added
- public static final Person HOON = new PersonBuilder().withName("Hoon Meier").withPhone("8482424")
- .withEmail("stefan@example.com").withAddress("little india").build();
- public static final Person IDA = new PersonBuilder().withName("Ida Mueller").withPhone("8482131")
- .withEmail("hans@example.com").withAddress("chicago ave").build();
-
- // Manually added - Person's details found in {@code CommandTestUtil}
- public static final Person AMY = new PersonBuilder().withName(VALID_NAME_AMY).withPhone(VALID_PHONE_AMY)
- .withEmail(VALID_EMAIL_AMY).withAddress(VALID_ADDRESS_AMY).withTags(VALID_TAG_FRIEND).build();
- public static final Person BOB = new PersonBuilder().withName(VALID_NAME_BOB).withPhone(VALID_PHONE_BOB)
- .withEmail(VALID_EMAIL_BOB).withAddress(VALID_ADDRESS_BOB).withTags(VALID_TAG_HUSBAND, VALID_TAG_FRIEND)
- .build();
-
- public static final String KEYWORD_MATCHING_MEIER = "Meier"; // A keyword that matches MEIER
-
- private TypicalPersons() {} // prevents instantiation
-
- /**
- * Returns an {@code AddressBook} with all the typical persons.
- */
- public static AddressBook getTypicalAddressBook() {
- AddressBook ab = new AddressBook();
- for (Person person : getTypicalPersons()) {
- ab.addPerson(person);
- }
- return ab;
- }
-
- public static List getTypicalPersons() {
- return new ArrayList<>(Arrays.asList(ALICE, BENSON, CARL, DANIEL, ELLE, FIONA, GEORGE));
- }
-}
diff --git a/src/test/java/seedu/address/testutil/VisitBuilder.java b/src/test/java/seedu/address/testutil/VisitBuilder.java
new file mode 100644
index 00000000000..4e309668bf6
--- /dev/null
+++ b/src/test/java/seedu/address/testutil/VisitBuilder.java
@@ -0,0 +1,65 @@
+package seedu.address.testutil;
+
+import seedu.address.model.patient.Condition;
+import seedu.address.model.patient.DateOfVisit;
+import seedu.address.model.patient.Severity;
+import seedu.address.model.patient.Visit;
+
+/**
+ * A utility class to help with building Visit objects.
+ */
+public class VisitBuilder {
+ public static final String DEFAULT_DATEOFVISIT = "25/2/2025";
+ public static final String DEFAULT_SEVERITY = "Low";
+ public static final String DEFAULT_CONDITION = "Fever";
+
+ private DateOfVisit dateOfVisit;
+ private Severity severity;
+ private Condition condition;
+
+ /**
+ * Creates a {@code VisitBuilder} with the default details.
+ */
+ public VisitBuilder() {
+ condition = new Condition(DEFAULT_CONDITION);
+ dateOfVisit = new DateOfVisit(DEFAULT_DATEOFVISIT);
+ severity = new Severity(DEFAULT_SEVERITY);
+ }
+
+ /**
+ * Initializes the VisitBuilder with the data of {@code visitToCopy}.
+ */
+ public VisitBuilder(Visit visitToCopy) {
+ condition = visitToCopy.getCondition();
+ dateOfVisit = visitToCopy.getDateOfVisit();
+ severity = visitToCopy.getSeverity();
+ }
+
+ /**
+ * Sets the {@code Condition} of the {@code Visit} that we are building.
+ */
+ public VisitBuilder withCondition(String condition) {
+ this.condition = new Condition(condition);
+ return this;
+ }
+
+ /**
+ * Sets the {@code DateOfVisit} of the {@Code Visit} that we are building.
+ */
+ public VisitBuilder withDateOfVisit(String dateOfVisit) {
+ this.dateOfVisit = new DateOfVisit(dateOfVisit);
+ return this;
+ }
+
+ /**
+ * Sets the {@code Severity} of the {@Cose Visit} that we are building.
+ */
+ public VisitBuilder withSeverity(String severity) {
+ this.severity = new Severity(severity);
+ return this;
+ }
+
+ public Visit build() {
+ return new Visit(condition, severity, dateOfVisit);
+ }
+}