diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
new file mode 100644
index 00000000000..1e1862b0e82
--- /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' # replace with your repo name
+ version: '^5.1.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..b837f053c2b 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,20 @@
-[![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/se-edu/addressbook-level3/workflows/Java%20CI/badge.svg)](https://github.com/AY2324S1-CS2103T-W16-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.
+## EzContact
+This is a contact book that is designed for salespersons to keep track of their past, current and potential customer.
+This is a CLI application and is supposed to be beneficial for users that are able to type **FAST**.
+
+### Features
+* Add customer to contact book, where name, phone number and email address are required details
+* Edit an existing entry of contact book, i.e. updating a new phone number of a customer
+* Remove entries from the contact book
+* Searching of customers using whole or partial information
+* Adding priorities to customers in contact book, i.e. customers with ongoing sales deal can be given higher priority
+* Tagging appearances to customers to help visualise the appearance of the customers
+
+Click [here](https://ay2324s1-cs2103t-w16-2.github.io/tp) to learn more!
+
+
+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..f958e206257 100644
--- a/build.gradle
+++ b/build.gradle
@@ -66,7 +66,11 @@ dependencies {
}
shadowJar {
- archiveFileName = 'addressbook.jar'
+ archiveFileName = 'EzContact.jar'
}
defaultTasks 'clean', 'test'
+
+run {
+ enableAssertions = true
+}
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..0972ff7a4ef 100644
--- a/docs/AboutUs.md
+++ b/docs/AboutUs.md
@@ -1,59 +1,62 @@
---
-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`
+You can reach us at the email `ezcontact@gmail.com`
## Project team
-### John Doe
+### Koo Yu Cong
-
+
-[[homepage](http://www.comp.nus.edu.sg/~damithch)]
-[[github](https://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](https://github.com/yucongkoo)]
+[[portfolio](team/yucongkoo.md)]
-* Role: Project Advisor
+* Role: Developer
+* Responsibilities: Ensuring deliverables and deadlines are met
-### Jane Doe
+### Joshua Wee
-
+
-[[github](http://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](http://github.com/jweewee)]
+[[portfolio](team/jweewee.md)]
-* Role: Team Lead
-* Responsibilities: UI
+* Role: Integration
+* Responsibilities: In charge of versioning of the code, maintaining the code repository, integrating various parts of the software to create a whole.
-### Johnny Doe
+### Song Fang Yi
-
+
-[[github](http://github.com/johndoe)] [[portfolio](team/johndoe.md)]
+[[github](http://github.com/songfangyl)]
+[[portfolio](team/songfangyl.md)]
-* Role: Developer
-* Responsibilities: Data
+* Role: Code quality
+* Responsibilities: Looks after code quality, ensures adherence to coding standards.
-### Jean Doe
+### Lian Zhi Xuan
-
+
-[[github](http://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](https://github.com/TehOPanas)] [[portfolio](team/tehopanas.md)]
-* Role: Developer
-* Responsibilities: Dev Ops + Threading
+* Role: Developer, Documentation
+* Responsibilities: Responsible for the quality of various project documents
-### James Doe
+### Lam Jiu Fong
-
+
-[[github](http://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](http://github.com/LamJiuFong)]
+[[portfolio](team/lamjiufong.md)]
+
+* Role: Developer, Code Testing
+* Responsibilities: Ensures the testing of the project is done properly and on time
-* Role: Developer
-* Responsibilities: UI
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 8a861859bfd..124d7a1e951 100644
--- a/docs/DeveloperGuide.md
+++ b/docs/DeveloperGuide.md
@@ -1,34 +1,36 @@
---
-layout: page
-title: Developer Guide
+layout: default.md
+title: "Developer Guide"
+pageNav: 3
---
-* Table of Contents
-{:toc}
+
+# EzContact Developer Guide
+
+
+
--------------------------------------------------------------------------------------------------------------------
-## **Acknowledgements**
+# **Acknowledgements**
-* {list here sources of all reused/adapted ideas, code, documentation, and third-party libraries -- include links to the original source as well}
+* Libraries used: [JavaFX](https://openjfx.io/), [Jackson](https://github.com/FasterXML/jackson), [JUnit5](https://github.com/junit-team/junit5)
--------------------------------------------------------------------------------------------------------------------
-## **Setting up, getting started**
+# **Setting up, getting started**
Refer to the guide [_Setting up and getting started_](SettingUp.md).
--------------------------------------------------------------------------------------------------------------------
+
-## **Design**
+# **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.
@@ -49,11 +51,15 @@ The bulk of the app's work is done by the following four components:
[**`Commons`**](#common-classes) represents a collection of classes used by multiple other components.
+
+
**How the architecture components interact with each other**
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,15 +68,17 @@ 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
+## 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)
-![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.
@@ -83,20 +91,26 @@ The `UI` component,
* 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`.
-### Logic component
+
+
+## Logic component
**API** : [`Logic.java`](https://github.com/se-edu/addressbook-level3/tree/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.
-![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 reaches the end of diagram.
-
+
+
+**Note:** The lifeline for `DeleteCommandParser` and `DeleteCommand` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
+
How the `Logic` component works:
@@ -105,18 +119,23 @@ How the `Logic` component works:
1. The command can communicate with the `Model` when it is executed (e.g. to delete a person).
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.
-### Model component
+
+
+## Model component
**API** : [`Model.java`](https://github.com/se-edu/addressbook-level3/tree/master/src/main/java/seedu/address/model/Model.java)
-
+
+
The `Model` component,
@@ -126,122 +145,669 @@ The `Model` component,
* 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)
-: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.
-
-
+
-
-
-
-### Storage component
+## Storage component
**API** : [`Storage.java`](https://github.com/se-edu/addressbook-level3/tree/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`)
-### Common classes
+## Common classes
Classes used by multiple components are in the `seedu.addressbook.commons` package.
--------------------------------------------------------------------------------------------------------------------
+
-## **Implementation**
+# **Implementation**
This section describes some noteworthy details on how certain features are implemented.
-### \[Proposed\] Undo/redo feature
+## Tag feature
+
+This feature allows users to assign tags to / remove tags from customers in EzContact, making customers more recognizable to the users.
+
+
+###### **Overview**
+
+The activity diagram below shows the action sequence of updating the tags of a customer. Note that definition of not
+valid indexes/tags/tag set will be defined later in following sections.
+
+
+
+
+
+### Implementation
+
+###### **Implementing `Tag`**
+
+Before implementing the actual command execution of tag,
+tags first needs to be stored in a `Person` object accordingly.
+Hence, a `Person` will now also be associated to any number of `Tag`s.
+
+
+
+###### **Integrating a command for handling tag features into the overall execution logic**
+
+In order to integrate the command for handling tag features into the execution logic as described in [LogicComponent](#logic-component),
+there are 3 main steps we need to implement:
+1. Modify `AddressBookParser` to recognise the **tag** _command word_ and will create a `TagCommandParser` subsequently.
+(Modification required is trivial and hence not described in detail)
+2. Implement a `TagCommandParser` class that will parse the _command arguments_ and construct a `TagCommand` accordingly.
+3. Implement a `TagCommand` class that will handle the main execution logic of the tag features and return a `CommandResult` accordingly.
+
+
+
+The sequence diagram below illustrates the interactions within the `Logic` component when executing a tag command,
+taking `execute("tag 1 at/tall dt/short at/handsome")` API call to `LogicManager` as an example.
+
+
+
+
+**Note:** The lifeline for `TagCommandParser` and `TagCommand` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
+
+
+###### **Implementing `TagCommandParser`**
+
+`TagCommandParser` plays the role of parsing _command arguments_ into two information:
+* **index** indicating the index of the targeted customer in the displayed customer list, and
+* **descriptor** encapsulating tags to add to and/or delete from the targeted customer.
+
+Both **index** and **descriptor** will then be used to construct a `TagCommand`.
+
+Note that **duplicate tags will be ignored** (see [Design Considerations](#design-considerations) for more information).
+
+The sequence diagram below illustrates the interactions of `TagCommandParser#parse(String arguments)`,
+taking `parse(1 at/tall dt/short at/handsome)` call to the `TagCommandParser` as an example.
+
+
+
+
+###### **Implementing `TagCommand`**
+
+The following class diagram illustrates how a `TagCommand` holds information required for its execution.
+
+
+
+`TagCommand` plays the role of executing the main logic of the tag feature, it will:
+* Use information encapsulated in it to create the updated `Person` object accordingly.
+* Update the `Model` accordingly to reflect the changes.
+
+Note that a `TagCommand` is **non-executable** if there are **conflicting tags** (i.e. there are common tags to add and delete).
+
+The sequence diagram below illustrates the interations of `TagCommand#execute(Model model)`,
+taking `execute(m)` call to the `TagCommand` as an example. Note that the **reference frames have been omitted**
+as the operations performed are trivial and low-level details.
+
+
+
+###### **Wrapping up the tag feature**
+
+As reaching this point, we have completed the implementation of the tag feature.
+The following section will discuss certain design considerations when implementing this feature.
+
+
+
+
+### Design considerations:
+
+###### **Aspect: Data structure to store tags in a Person object:**
+
+* **Alternative 1 (Current choice)** : Using `Set`.
+ * Pros: Easy to implement, enforces implicit uniqueness of each `Tag` in the `Set`.
+ * Cons: Tags are not ordered according to the time it is added.
+* **Alternative 2** : Using `List`.
+ * Pros: Tags are ordered according to the time it is added.
+ * Cons: Hard to implement, handling of duplicate `Tag` is more complicated.
+
+**Reasoning :**
+Alternative 1 was chosen over alternative 2 as the ordering of tags is considered not that important in the case of
+storing tags.
+
+###### **Aspect: Duplicate tags handling:**
+
+* **Alternative 1 (Current choice)** : Allow users to add/delete duplicate tags as long as not conflicting(i.e. not adding and deleting the same tag).
+ * Pros: Users will not be blocked from their action if they accidentally entered a duplicate tag.
+ * Cons: Users might not be warned that they have entered a duplicate tag.
+* **Alternative 2** : Block users from adding/deleting duplicate tags
+ * Pros: Easy to implement
+ * Cons: Users might be blocked from their action because they forgot that they already entered such a tag.
+
+**Reasoning :**
+Alternative 1 was chosen over alternative 2 based on the following reasons:
+* Repeated action signals the users' strong intention of performing that action(e.g. wanting to add the same tag twice shows the importance of that tag).
+* The target audience is forgetful and careless, it is common for the users to enter duplicate tags without realising it, blocking such actions brings no value to the product.
+
+###### **Aspect: Deletion of non-existing tags:**
+* **Alternative 1(current choice):** Simply ignore such deletions.
+ * Pros: Users will not be blocked from their action(other tags will still be added/deleted) even though the command consists of such deletions.
+ * Cons: Users will not be aware that the tag they are deleting from the customer does not exist, this may lead to certain misconceptions.
+* **Alternative 2** : Block users from such deletions.
+ * Pros: Easy to implement, users will be aware that the customer does not have the tag they are trying to delete.
+ * Cons: User might be blocked from their action because they thought that the targeted customer does have the tag.
+
+**Reasoning:**
+Alternative 1 was selected over alternative 2 because the primary reason for users deleting a specific tag is that
+they wish to prevent the tagged customer from having that tag. Therefore, whether the targeted customer
+initially possesses the tag is of lesser importance in this context.
+
+###### **Aspect: Addition of existing tags:**
+This aspect is similar to the above aspect regarding **Deletion of non-existing tags**, the current choice is to simply
+ignore such additions due to the same reason stated above.
+
+
+
+
+
+
+## Find feature
+This find feature is designed to do partial search or prefix search on the customer list.
+
+### Implementation
+
+Sequence diagram below shows the interactions between `Logic` components when executing `execute("find n/Song r/vegetarian")`
+
+
+
+
+
+###### **Implementing `XYZContainsKeywordsPredicate`**
+`XYZContainsKeywordsPredicate` = `AddressContainsKeywordsPredicate`, `NameContainsKeywordsPredicate` etc
+
+
+
+This class inherits from Predicate interface and determine how the `find` feature searches for the right customers.
+It tests each customer in the list with given `keywords`(search prompt given by users) in the following way:
+
+1. The `attribute(name/address/...)` will be tested over each `keyword` in the search prompt (e.g. "james bond" is broken down into "james" & "bond")
+1. The `attribute(name/address/...)` will also be tested **word by word** for every `keyword` in the prompt on these criteria:
+
+ - If `attribute` **fully matches** all the `keywords` _(e.g. "james bond" = "james bond")_, it returns true
+ - If `attribute` **contains all** the `keywords` _(e.g. searches "james" in "james bond")_, it returns true
+ - If the `keyword` is **prefix** of the `attribute` _(e.g. searches "ja" in "james bond)_, it returns true
+ - else returns false
+
+###### **Implementing `PersonContainsKeywordsPredicate`**
+
+This class serves as the primary predicate for testing multiple conditions. It houses various predicates such as
+`NameContainsKeywordsPredicate` to check if specific criteria are met.
+
+
+
+###### **Implementing `FindCommandParser`**
+`FindCommandParser` processes the input following the 'find' command, parsing it into distinct predicates based on the provided prefixes.
+These predicates are then combined to create a `PersonContainsKeywordsPredicate` which is used by `FincCommand`
+
+
+
+
+
+###### **Implementing `FindCommand`**
+`FindCommand` is executed on the `Model`, it will update the `Model` accordingly to
+reflect the changes after the `FindCommand` completes its execution.
+
+
+
+
+
+### Design considerations:
+
+###### **Aspect: Overall design of predicate:**
+
+* **Alternative 1 (Current choice)** : Each attribute has their corresponding `Predicate`, `PersonContainsKeywordsPredicate` is responsible for testing them."
+ * Pros: Code base be more modular.
+ * Cons: Need to create quite amount of class.
+* **Alternative 2** : Create a single predicate `PersonContainsKeywordsPredicate` which contains different methods to test different attributes against keywords.
+ * Pros: Easier to implement, and the code is more straightforward to understand.
+ * Cons: Harder to maintain the code when extending the search to include new attributes, as modifications to this class are required.
+
+**Reasoning :**
+
+Due to the Open-Closed Principle, we have opted for Alternative 1 to maintain modularity in our codebase.
+
+###### **Aspect: Implementation of `XYZContainsKeywordsPredicate` regarding prefix:**
+
+* **Alternative 1** (Current choice): Return customer when all keywords can be found as prefix in customer's name in **arbitrary order**.
+ * Pros: Easy to implement, provides more flexibility to users for finding their customers.
+ * Cons: Cannot differentiate `Lam Jiu` from `Jiu Lam`, a name can also match with multiple keywords (i.e. name `song` match with keywords `song song`).
+* **Alternative 2** : Return customer when all keywords can be found as prefix in customer's name **in order**.
+ * Pros: Can easily and accurately find a specified customer.
+ * Cons: Harder to implement, less flexibility for the users to find the customer.
+* **Alternative 3** : Returns customer when all keywords can be found as prefix in customer's name, where each prefix corresponds to a different word in name, i.e. name `song` cannot match with keywords `song song`.
+ * Pros: More intuitive design.
+ * Cons: Harder to implement, required a long algorithm to do so.
+
+
+
+**Reasoning :**
+
+In this case, we chose Alternative 1 over Alternative 2 because the find feature becomes less versatile when we enforce the rule that
+the name must match keywords in order. The consideration about our target users being forgetful affects our decision,
+where users might forget and input the name in the wrong order.
+
+We also chose Alternative 1 over Alternative 3, although Alternative 3 provides a more accurate result, after doing some
+research on many contact book-like applications, we found that most applications do not enforce that each word of the name can only match with one keyword.
+In addition, Alternative 3 requires a more complicated algorithm.
+
+###### **Aspect: Implementation of test method:**
+
+* **Alternative 1 (Current choice)** : Convert keywords to `Stream` and use `allMatch`.
+ * Pros: Easy to implement, code is clean.
+ * Cons: Less flexible, e.g. cannot check the name matches the keywords in order.
+* **Alternative 2** : Directly using the keywords as `List` and using a for loop.
+ * Pros: More flexible, can add more constraint on the test method.
+ * Cons: Harder to implement, given many constraint, code becomes untidy.
+
+**Reasoning :**
+
+Alternative 1 is chosen over Alternative 2, because we want a slightly simpler design that does not need as much flexibility.
+
+
+
+
+## Insurance Feature
+This feature allows users to assign / remove insurance package(s) to / from customers in EzContact to help users keep track of customers' insurances.
+
+The activity diagram below shows the action sequence of updating insurances of a customer.
+
+
+
+### Implementation
+The implementation of the Insurance feature consists of few parts, distributed across different components :
+
+1. `Insurance` : stores the information about the insurance
+1. `InsuranceCommand` : executes the action to assign/remove insurance
+1. `InsuranceCommandParser` : parses the command to obtain required information
+
+
+
+**Implementing `Insurance`**
+
+`Insurance` plays the role of storing information about an insurance and to be displayed on the product, as a single unit. It holds only one information, `insuranceName`.
+
+
+
+**Implementing `InsuranceCommand`**
+
+`InsuranceCommand` executes its command on the `Model`, it will update the `Model` accordingly to reflect the changes made by the command on the `Model`.
+
+Sequence diagram below shows the execution of `InsuranceCommand`.
+
+
+
+
-#### Proposed Implementation
+**Implementing `InsuranceCommandParser`**
-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:
+`InsuranceCommandParser` interprets the remaining input after the `insurance` command, and parses it into relevant information needed by `InsuranceCommand`, which are
+`Index` and `UpdatedPersonInsuranceDescriptor`.
-* `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.
+* `Index` indicates the customer on the list to perform action on.
+* `UpdatedPersonInsruanceDescriptor` holds the sets of insurances to add(`insurancesToAdd`) and delete(`insurancesToDelete`).
-These operations are exposed in the `Model` interface as `Model#commitAddressBook()`, `Model#undoAddressBook()` and `Model#redoAddressBook()` respectively.
+Sequence diagram below shows the execution of `InsuranceCommandParser#parse(String arguments)` with input `(1 ai/car insurance\n di/health insurance)`
-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)
+**Integrating `InsuranceCommand` and `InsuranceCommandParser`**
-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.
+In order to integrate them into current logic component, `AddressBookParser` has to be updated to recognise the command
+`insurance` and call `parse(arguments)` from `InsuranceCommandParser`.
-![UndoRedoState1](images/UndoRedoState1.png)
+From here, `InsuranceCommandParser` will extract out the relevant information and create the corresponding `InsuranceCommand` and the command will be executed by other `Logic` components.
-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`.
+Sequence diagram below shows the interactions between `Logic` components when executing `execute("insurance 1 \nai/AIA di/Great Eastern)`
-![UndoRedoState2](images/UndoRedoState2.png)
+
-: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`.
+
-
+### Design Considerations:
-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.
+###### **Aspect: Storing of `Insurance` in `Person`**
-![UndoRedoState3](images/UndoRedoState3.png)
-: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.
+* **Alternative 1 (Current choice)** : use `Set` to hold all `Insurance` instances in `Person` object
+ * Pros: Able to handle duplicates gracefully and maintain the uniqueness of each insurance with `Set`
+ * Cons: Chronological order of `Insurance` inserted is not maintained
+* **Alternative 2**: use `List` to hold all `Insurance` instances in `Person` object
+ * Pros: Maintain the chronological order of `Insurance` inserted and sorting can be easily done on `Insurance` instances
+ * Cons: Cannot ensure the uniqueness of each insurance and unable to handle duplicates in an efficient manner
-
+**Reasoning:**
-The following sequence diagram shows how the undo operation works:
+Alternative 1 is chosen over Alternative 2 for its ability to handle the duplicates more efficiently. We believe that this ability is more important
+than the ability to sort the list in a more effective manner, as there are other workarounds that can be almost as efficient using `Set`.
-![UndoSequenceDiagram](images/UndoSequenceDiagram.png)
-: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.
+###### **Aspect: Handling duplicate `Insurnace` entries**
-
+* **Alternative 1 (Current choice)** : Allows the users to add / delete duplicate `Insurance` as long as no conflict exists (i.e. adding and deleting the same `Insurance`)
+ * Pros: Ease of use for the users, as the users are not blocked for entering a duplicate
+ * Cons: Users might not be aware of themselves entering duplicate `Insurance`
+* **Alternative 2** : Blocks the users from performing the action and warn them about the duplicate `Insurance`
+ * Pros: Easy to implement
+ * Cons: Users will be clearly aware of their mistakes in entering duplicate `Insurance`
-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.
+**Reasoning:**
-: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.
+Alternative 1 is chosen over Alternative 2 because we believe doing so will provide users a smoother experience with our product.
+The reasoning comes from the users' intention of inserting the `InsuranceCommand`, that is wanting to assign an `Insurance` to a customer, so with
+entering duplicate `Insurance`, the users' goal is still achieved, thus we think that there is no need to purposely block the users
+for such action. With our handling of duplicate `Insurance`, no duplicate values will be added into the model with duplicate `Insurance` entries, and thus
+it will not cause any error.
-
+
-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.
+###### **Aspect: Deleting non-existing `Insurance`**
-![UndoRedoState4](images/UndoRedoState4.png)
+* **Alternative 1 (Current choice)** : Allows the users to delete non-existing `Insurance` as long as no conflict exists (i.e. adding and deleting the same `Insurance`)
+ * Pros: Ease of use for the users, as the users are not blocked for deleting non-existing `Insurance`
+ * Cons: Users might not be aware of their mistakes
+* **Alternative 2** : Blocks the users from performing the action and warn them about the mistake
+ * Pros: Easy to implement
+ * Cons: Users will be clearly aware of their mistakes
-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.
+**Reasoning:**
-![UndoRedoState5](images/UndoRedoState5.png)
+Alternative 1 is chosen over Alternative 2 because we believe doing so will provide users a smoother experience with our product.
+The reasoning comes from the users' intention of deleting an `Insurance`, that is wanting to remove that `Insurance` from the customer, so removing
+a non-existing `Insurance` does not defeat the purpose, thus we think that there is no need to purposely block the users
+for such action.
-The following activity diagram summarizes what happens when a user executes a new command:
+
-
+## Appointment feature
-#### Design considerations:
+### Implementation
-**Aspect: How undo & redo executes:**
+The appointment feature supports 4 different types of commands:
+1. `addappt`
+2. `deleteappt`
+3. `markappt`
+4. `unmarkappt`
-* **Alternative 1 (current choice):** Saves the entire address book.
- * Pros: Easy to implement.
- * Cons: May have performance issues in terms of memory usage.
+All 4 features extends from the `abstract` `Command` class, managing the details of an apppointment
+with a customer by editing the details of the `Appointment` and `AppointmentCount` class.
-* **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.
+**Implementing `Appointment`**
-_{more aspects and alternatives to be added}_
+This class is used to represent the appointment that each `Person` has, containing data:
+* `date` of the appointment in `dd-MMM-yyyy` format as a `String`
+* `time` of the appointment in `HHmm` format as a `String`
+* `venue` of the appointment as a `String` lesser than or equals to 30 characters.
-### \[Proposed\] Data archiving
+By default, each `Person` has an empty default appointment.
-_{Explain here how the data archiving feature will be implemented}_
+
+
+
+**Implementing `AppointmentCommand`**
+
+`AppointmentCommand` executes its command on the Model, updating the Model accordingly to reflect the changes made by the command on the Model. Note that an `AppointmentCommand` is **non-executable** if the index is not in range or the person has an existing appointment.
+
+
+The sequence diagram below illustrates the interactions of `AppointmentCommand#execute(Model model)`, taking `execute(m)` call to the `AppointmentCommand` as an example. Note that the **reference frames have been omitted** as the operations performed are trivial.
+
+
+
+
+
+**Implementing `AppointmentCommandParser`**
+
+`AppointmentCommandParser` plays the role of parsing *command arguments* into two or more fields:
+
+* **index** indicating the index of the targeted customer in the displayed customer list
+* **date** the date of the appointment
+* **time** the time of the appointment(optional)
+* **venue** the venue of the appointment(optional)
+
+Both **index** and **date** minimally, will then be used to construct an AppointmentCommand.
+
+The sequence diagram below illustrates the interactions of `AppointmentCommandParser#parse(String arguments)`, taking `parse(1 d/2025-12-12 t/12:55 v/Clementi Mall)` call to the `AppointmentCommandParser` as an example.
+
+
+
+
+
+**Integrating `AppointmentCommand` and `AppointmentCommandParser`**
+
+`AddressBookParser` recognises the command `addappt` and calls `parse(arguements)` from `AppointmentCommandParser`.
+
+`AppointmentCommandParser` will extract out the relevant information and create the corresponding `AppointmentCommand`
+which will be executed by other `Logic` components.
+
+
+The sequence diagram below shows the interactions between `Logic` components when the user inputs the command
+`addappt 1 d/2025-12-12 t/12:55 v/Clementi Mall`.
+
+
+
+**Implementing `Addappt`**
+
+`AppointmentCommandParser::parse()` uses `ParserUtil::parseDateString()`, `ParserUtil::parseTimeString()`
+to check if `date`, `time`, `venue` follows the required formatting and the new `Appointment` object created by `AppointmentCommandParser:parse()`.
+
+`AppointmentCommand::execute()` checks if the current `Appointment` is an `empty` appointment and if `true`, executes the `AppointmentCommand`.
+
+
+
+**Implementing `Deleteappt`**
+
+Using a similar logic flow as `addappt`, it creates a new `Appointment` object with empty `date`, `time` and `venue` to replace the existing `Appointment` object. The new `Appointment` object is created in `DeleteAppointmentCommandParser::parse()`.
+
+`Deleteappt` prevents the deletion of an appointment if there is no existing appointment by checking if the current `Appointment` is different from the `empty` appointment and if `true`, executes the `DeleteAppointmentCommand`.
+
+
+
+**Implementing `AppointmentCount`**
+
+This class contains the number of marked appointments with a customer, stored as `count`, the
+number of completed appointments as an `int`.
+
+
+
+**Implementing `Mark Appointment`**
+
+Using a similar logic flow as `addappt`, it checks if the current `Appointment` is different from the `empty` appointment and if `true`, `MarkAppointmentCommand::execute()` will use `AppointmentCount::incrementAppointmentCount()` to increase the count by 1.
+The existing `Appointment` object will be replaced by a new empty `Appointment` object, created in `MarkAppointmentCommandParser::parse()`.
+
+
+
+**Implementing `Unmarkappt`**
+
+Using a similar logic flow as `addappt`, it prevents the user from unmarking an appointment if there is an existing
+appointment by checking if the current `Appointment` is the same as the `empty` appointment and if `true`,
+`UnmarkAppointmentCommand::execute()` will use `AppointmentCount::DecrementAppointmentCount()` to decrease the count by 1.
+
+
+
+### Design Considerations:
+
+###### **Aspect: Implementation of Appointment feature**
+
+* **Alternative 1 (Current choice)** : Have the appointment features split into 4 sub-features.
+ * Pros: Isolation of a single sub-feature to a specific command is more intuitive
+ * Pros: Reduces coupling
+ * Cons: More checks and testcases are needed
+ * Cons: More classes added, resulting in a larger codebase
+* **Alternative 2**: Combine all sub-features into one appointment command.
+ * Pros: Reduce the number of commands in the application making lesser to manage
+ * Cons: There will be less abstraction, more coupling and more bug-prone: The same command
+ class and parser class will handle all the four different features
+
+
+
+## Priority feature
+
+This feature allows users to assign priority to a `Person`.
+The default priority of each `Person` is `NONE`, unless a priority is explicitly assigned to the `Person`.
+
+The activity diagram below shows the sequence of actions when users assign a priority to a `Person`.
+
+
+
+### Implementation
+
+**The `Priority` class**
+
+The class is used to store the priority level of a `Person`.
+The priority level can only be one of the values in the `Level` enumeration.
+
+Each `Person` now has an additional attribute called priority.
+The `Person` class now has a reference to the `Priority` class.
+
+
+
+
+
+
+
+**Adding a new command word `priority`**
+
+To allow users to assign priorities, we added a new command word `priority`.
+The sequence diagram shows a series of actions in EzContact when a user inputs the command `priority 1 high`.
+
+
+
+
+
+
+
+**Note:** The lifeline for `PriorityCommandParser` and `PriorityCommand` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
+
+
+
+
+**The `PriorityCommandParser` class**
+
+The class is used to parse the string provided.
+It will return a `PriorityCommand` if the index and priority are valid.
+
+The sequence diagram below illustrates the interaction between `PriorityCommandParser` and `PriorityCommand` when `PriorityCommandParser#parse(String)` is invoked.
+
+Taking `parse("1 high")`as an example.
+
+
+
+
+
+The sequence diagram below illustrates how the index and priority are parsed.
+
+
+
+
+
+**The `PriorityCommand` class**
+
+The class diagram below shows the main attributes and methods involved when assigning a priority to a `Person`.
+
+
+
+
+
+
+
+The sequence diagram illustrates the execution of the `PriorityCommand` and how the `Person` is updated.
+
+
+
+
+
+### Design Consideration:
+
+###### **Aspect: `Person` without an explicitly assigned `Priority`.**
+* **Alternative 1 (Current Choice):** Give each `Person` a default priority `NONE`.
+ * Pros:
+ * Enhances code readability.
+ * Do not need to handle null cases which happens when `Person` has `null` priority.
+ * Cons:
+ * More complexity during testing, have to make sure that the default value does not affect the outcome of test cases.
+* **Alternative 2:** Keep the priority as `null`.
+ * Pros:
+ * Do not need to worry about the effect of default values on test cases.
+ * Cons:
+ * More `null` cases to handle.
+
+
+
+###### **Aspect: Choices of priority levels.**
+* **Alternative 1 (Current Choice):** Fix the choices of priority level, namely `HIGH`, `MEDIUM`, `LOW` and `NONE`. (`NONE` is chosen when user removes or does not assign a priority).
+ * Pros:
+ * Simplicity, users do not have to create an extensive list of options for priority levels.
+ * Ease of implementation.
+ * Cons:
+ * Reduced flexibility, users are now confined to limited choices of priority levels.
+* **Alternative 2:** Allow users to define their own priority levels.
+ * Pros:
+ * Flexibility, users can customise the product according to their needs.
+ * Cons:
+ * Hard to implement, need to handle dynamic or custom priority levels.
+
+
+
+## Remark feature
+
+### Implementation
+
+The action of assigning a remark is mainly facilitated by three classes: `Remark`, `RemarkCommandParser` and `RemarkCommand`.
+
+**The `Remark` class**
+
+
+This class represents a person's attribute, including a remark string with a maximum length of 150 characters.
+Every person created has this attribute, with the default value being an empty string, signifying no remark.
+
+
+**The `RemarkCommandParser` class**
+
+The class is used to parse the arguments into two information: `index` and `remark` and
+returns a `RemarkCommand` if the arguments are valid.
+
+The sequence diagram below illustrates the interaction between `RemarkCommandParser`, `RemarkCommand` and `Remark`.
+
+Taking `parse("2 he likes pizza")`as an example.
+
+
+
+**The `RemarkCommand` class**
+
+The class is responsible in executing the task parsed by the `RemarkCommandParser`.
+It will update the `Remark` of a `Person` and generate a `CommandResult` for the output.
+Below is the class diagram of the `RemarkCommand` class.
+
+
+
+### Design Consideration:
+
+###### **Aspect: Delete `Remark`**
+
+* **Alternative 1 (Current choice)** : Using `remark ` without argument.
+ * Pros: User-friendly, no need to remember an extra command.
+ * Cons: User cannot store empty string as a remark
+* **Alternative 2** : Implement a separate delete remark command.
+ * Pros: Distinguishes between adding and deleting remarks.
+ * Cons: Requires users to remember an additional command.
+
+**Reasoning:**
+
+In real-life scenarios, storing empty strings as remark is unlikely, hence
+alternative 1 is preferred due to its user-friendliness.
+
+
--------------------------------------------------------------------------------------------------------------------
-## **Documentation, logging, testing, configuration, dev-ops**
+# **Documentation, logging, testing, configuration, dev-ops**
* [Documentation guide](Documentation.md)
* [Testing guide](Testing.md)
@@ -251,127 +817,885 @@ _{Explain here how the data archiving feature will be implemented}_
--------------------------------------------------------------------------------------------------------------------
-## **Appendix: Requirements**
+# **Appendix: Requirements**
-### Product scope
+## Product scope
**Target user profile**:
-* has a need to manage a significant number of contacts
+Target user : Insurance agent
+
+* needs to provide services / insurance plans to customer
+* has a need to manage a significant number of customers
+* needs to remember customer's information
+* busy
+* needs to maintain interactions with his/her customers over a long time span
+* often forgets details about his/her customers
* 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**:
+
+Manage customers' contact for existing/potential insurance contracts faster than GUI driven apps,
+alongside helping users increase the chance of sealing deals with customers.
+
+
+
+## User stories
+
+Priorities: High - `* * *`, Medium - `* *`, Low - `*`
+
+| Priority | As a … | I want to … | So that I can… |
+|----------|------------------|----------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------|
+| `* * *` | user | be able to add new contacts to EzContact | keep track of my contacts using EzContact |
+| `* * *` | user | be able to update my contacts' information easily | easily maintain up-to-date information of my contacts |
+| `* * *` | user | be able to search for specific contacts using their names | quickly lookup a contact and get their information |
+| `* * *` | user | be able to delete contacts | |
+| `* * *` | user | be able to list out my contacts in EzContact | see all my saved contacts in one view |
+| `* * *` | insurance agent | be able to add customers' contacts to EzContact | reach out to existing and potential customers easily |
+| `* * *` | insurance agent | be able to assign priorities to each customer | prioritise customers that have a higher chance on sealing a deal |
+| `* * *` | insurance agent | be able to view the type of insurance my customer currently holds | check customers' insurance profile easily |
+| `* * *` | insurance agent | be able to easily know customers subscribed under a specific insurance plan | quickly know who to find when there are changes to a specific insurance plan |
+| `* * *` | insurance agent | be able to apply descriptive tags to my customers | easily identify and remember my customers using these tag |
+| `* * *` | insurance agent | be able to add details of appointments with customers | keep track of appointments with customers |
+| `* * *` | insurance agent | be able to delete cancelled appointments with customers | prevent confusion when arranging my schedule |
+| `* * *` | insurance agent | be able to mark completed appointments with customers | keep track of appointments completed with the customer to guage their potential interest |
+| `* *` | user | be able to search for a contact using its other particulars(not necessarily names) | be more flexible when searching for contacts |
+| `* *` | user | be able to see my total numbers of contact entries in EzContact | know how many contacts I have in EzContact |
+| `* *` | forgetful person | be able to search for contacts using partial names | find a contact without having to remember their full name |
+| `* *` | forgetful person | have EzContact remind me of important task associated with certain contacts | prevent myself from forgetting important tasks |
+| `* *` | forgetful person | be able to add remarks to a certain contact | be reminded of things to take note of when contacting a person |
+| `* *` | careless person | be able to undo previous command | recover from unintentional commands |
+| `* *` | careless person | be stopped from adding duplicate entries | avoid myself from adding redundant data |
+| `* *` | careless person | be suggested by EzContact for similar names when I'm searching for a person | avoid myself from typographical errors |
+| `* *` | first time user | be able to know commands in EzContact | play around with the features and get used to the application |
+| `* *` | fast typist | have short commands | execute commands faster |
+| `*` | user | be able to import my data from external sources into EzContact | avoid myself from having to copy my data manually |
+| `*` | user | be able to export my data | have a backup of data in case of data loss |
+| `*` | advanced user | have multiple contact books | neatly organize my contacts based on contexts |
+
+
+
+## Use cases
+
+(For all use cases below, the **System** is the `EzContact` and the **Actor** is the `User`, unless specified otherwise)
+#### Adding a customer
-### User stories
+**Use Case: UC01 - add a customer**
-Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unlikely to have) - `*`
+**MSS:**
+ 1. User provides the details of a customer to be added.
+ 2. EzContact displays the details of the customer added by User.
+ Use case ends.
-| 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 |
+**Extensions:**
+ 1a. Details provided by User is incomplete or invalid.
+ 1a1. EzContact displays an error message to alert User.
+ Use case ends.
-*{More to be added}*
+ 1b. Customer to be added is already in the EzContact.
+ 1b1. EzContact displays an error message to alert User.
+ Use case ends.
-### Use cases
-(For all use cases below, the **System** is the `AddressBook` and the **Actor** is the `user`, unless specified otherwise)
+#### Filtering customers
-**Use case: Delete a person**
+**Use case: UC02 - filter customers**
-**MSS**
+**MSS:**
+ 1. User chooses to filter customers.
+ 2. User selectively adds one/multiple category parameters to filter the customers for.
+ 3. EzContact displays the list of customers that meet the criteria.
+ Use case ends.
-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
+**Extensions:**
+ 2a. User doesn't select any categories to filter for.
+ 2a1. EzContact displays the entire list of customers.
+ Use case ends.
- Use case ends.
+ 3a. None of the contacts meet the filter criteria.
+ 3a1. EzContact shows an empty list with a warning message.
+ Use case ends.
-**Extensions**
+
-* 2a. The list is empty.
+#### Deleting a customer
- Use case ends.
+**Use Case: UC03 - delete a customer**
-* 3a. The given index is invalid.
+**MSS:**
+ 1. User requests a list of customers by filtering customers(UC02) .
+ 2. User provides the index of customer to be deleted.
+ 3. EzContact displays the details of the removed customer.
+ Use case ends.
- * 3a1. AddressBook shows an error message.
+**Extensions:**
+ 2a. User provides invalid index.
+ 2a1. EzContact shows an error message to alert User.
+ Use case ends.
- Use case resumes at step 2.
+#### Editing a customer
-*{More to be added}*
+**Use Case: UC04 - edit a customer's details**
-### Non-Functional Requirements
+**MSS:**
+ 1. User requests a list of customers by filtering customers(UC02) .
+ 2. User provides information to the customer with its respective index.
+ 3. EzContact displays the details of the edited customer.
+ Use case ends.
+
+**Extensions:**
+ 2a. User provides invalid index or information.
+ 2a1. EzContact shows an error message to alert User.
+ Use case ends.
+
+
+
+#### Searching for a customer
+
+**Use Case: UC05 - search for a customer**
+
+**MSS:**
+
+ 1. User searches with a prompt.
+ 2. EzContact shows a list of customers matching the prompt.
+ 3. User views the customers' information.
+ Use case ends.
+
+**Extensions:**
+ 1a. User searches with an invalid prompt format
+ 1a1. EzContact shows an error message to User.
+ Use case ends.
+
+ 2a. There is no customer that match the prompt.
+ 2a1. EzContact shows an empty list.
+ Use case ends.
+
+#### Assigning priority to customer
+
+**Use Case: UC06 - assign priority to a customer**
+
+**MSS:**
+
+ 1. User requests a list of customers by filtering customers(UC02) .
+ 2. User provides priority to the customer with its respective index.
+ 3. EzContact displays the new priority of customer.
+ Use case ends.
+
+**Extensions:**
+ 2a. User provides invalid index or priority.
+ 2a1. EzContact shows an error message to alert User about the invalid command.
+ Use case ends.
+
+
+
+#### Assigning insurance to customer
+
+**Use Case: UC07 - assign insurance to a customer**
+
+**MSS:**
+
+ 1. User requests the list of customers by filtering customers(UCO2) .
+ 2. User assigns insurance to the customer with its respective index.
+ 3. EzContact displays the new insurance of customer.
+ Use case ends.
+
+**Extensions:**
+ 2a. User provides invalid index or information.
+ 2a1. EzContact shows an error message to alert User about the invalid command.
+ Use case ends.
+
+#### Removing insurance from customer
+
+**Use Case: UC08 - remove insurance from a customer**
+
+**MSS:**
+
+ 1. User requests the list of customers by filtering customers(UCO2) .
+ 2. User removes insurance from the customer with its respective index.
+ 3. EzContact displays the new insurance of customer.
+ Use case ends.
+
+**Extensions:**
+ 2a. User provides invalid index or information.
+ 2a1. EzContact shows an error message to alert User about the invalid command.
+ Use case ends.
+
+
+
+#### Updating tags of a customer
+
+**Use Case: UC09 - update tags of a customer**
+
+**Mss:**
+ 1. User requests a list of customers by filtering customers(UC02) .
+ 2. User provides index of the targeted customer in the displayed list.
+ 3. User provides information of tags to add to and/or delete from the targeted customer.
+ 4. EzContact displays the details of the updated customer to the User.
+ Use case ends.
+
+**Extensions:**
+ 1a. Requested list is empty.
+ Use case ends.
+
+ 2a. User provided invalid index.
+ 2a1. EzContact displays an error message to alert the User.
+ Use case ends.
+
+ 3a. User provided invalid information of tags.
+ 3a1. EzContact displays an error message to alert the User.
+ Use case ends.
+
+ 3b. User provided information of tags that will not update the targeted customer.
+ 3b1. EzContact displays an error message to alert the User.
+ Use case ends.
+
+
+#### Updating remark of a customer
+
+**Use Case: UC10 - update remark of a customer**
+
+**Mss:**
+ 1. User requests a list of customers by filtering customers(UC02) .
+ 2. User enters index and remark of the target customer.
+ 3. EzContact updates the remark of specified customer accordingly.
+ 4. EzContact displays the details of the updated customer.
+ Use case ends.
+
+**Extensions:**
+ 2a. User provided invalid index or information.
+ 2a1. EzContact displays an error message to alert the User.
+ Use case ends.
+
+ 2b. User provided remark that will not update the specified customer.
+ 2b1. EzContact displays an error message to alert the User.
+ Use case ends.
+
+
+
+#### Updating appointment of a customer
+
+**Use Case: UC11 - add an appointment to a customer**
+
+**Mss:**
+ 1. User requests a list of customers by filtering customers(UC02) .
+ 2. User enters index and appointment details(date, time, venue) of the target customer.
+ 3. EzContact adds the appointment to the specified customer accordingly.
+ 4. EzContact displays the updated appointment details of the customer.
+ Use case ends.
+
+**Extensions:**
+ 2a. User provided invalid index.
+ 2a1. EzContact displays an error message to alert the User.
+ Use case ends.
+
+ 2b. User provided invalid appointment input parameters.
+ 2b1. EzContact shows an error message of the input constraints.
+ Use case ends.
+
+ 2c. An appointment has already been scheduled.
+ 2c1. EzContact shows an error message to alert the User.
+ Use case ends.
+
+#### Updating appointment of a customer
+
+**Use Case: UC12 - delete a customer's appointment**
+
+**Mss:**
+ 1. User requests a list of customers by filtering customers(UC02) .
+ 2. User enters index of the target customer.
+ 3. EzContact deletes the appointment of the specified customer accordingly.
+ 4. EzContact displays the updated empty appointment details of the customer.
+ Use case ends.
+
+**Extensions:**
+ 2a. User provided invalid index.
+ 2a1. EzContact displays an error message to alert the User.
+ Use case ends.
+
+ 2b. There is no existing appointment to delete.
+ 2b1. EzContact shows an error message to alert the User.
+ Use case ends.
+
+
+
+**Use Case: UC13 - mark a customer's appointment**
+
+**Mss:**
+ 1. User requests a list of customers by filtering customers(UC02) .
+ 2. User enters index of the target customer.
+ 3. EzContact marks the appointment of the specified customer accordingly.
+ 4. EzContact displays the updated appointment details of the customer.
+ Use case ends.
+
+**Extensions:**
+ 2a. User provided invalid index.
+ 2a1. EzContact displays an error message to alert the User.
+ Use case ends.
+
+ 2b. There is no existing appointment to mark.
+ 2c1. EzContact shows an error message to alert the User.
+ Use case ends.
+
+**Use Case: UC14 - unmark a customer's appointment**
+
+**Mss:**
+ 1. User requests a list of customers by filtering customers(UC02) .
+ 2. User enters index of the target customer.
+ 3. EzContact unmarks the appointment of the specified customer accordingly.
+ 4. EzContact displays the updated appointment details of the customer.
+ Use case ends.
+
+**Extensions:**
+ 2a. User provided invalid index.
+ 2a1. EzContact displays an error message to alert the User.
+ Use case ends.
+
+ 2b. There is an existing appointment.
+ 2b1. EzContact shows an error message to alert the User.
+ Use case ends.
+
+
+
+
+## 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 1000 customer without a noticeable sluggishness 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.
+4. The user interface should be intuitive, easy to navigate and understand (i.e. concise and simple)
+5. The application should gracefully handle errors to prevent system crashes and data corruption.
+6. The application should be offered as a free service to the public.
+7. The application should be able to respond within one second.
+8. The application should be able to handle and support manual edits to the data file, erroneous data files should not crash the application.
-*{More to be added}*
-
-### Glossary
+## Glossary
* **Mainstream OS**: Windows, Linux, Unix, OS-X
* **Private contact detail**: A contact detail that is not meant to be shared with others
+* **Command word:** The first word of a user command(e.g. `tag` is the command word of the command `tag 1 at/tall dt/short`)
+* **Command arguments:** The remaining input of a user command(e.g. `1 at/tall dt/short` is the command arguments of the command `tag 1 at/tall dt/short`)
+
+
+
+--------------------------------------------------------------------------------------------------------------------
+# **Appendix: Planned Enhancements**
+
+This section covers the enhancements we plan to implement in the future.
+
+#### Enhancement 1 : Deletion of all tags in a single command
+
+**Feature flaw:**
+As a customer might have many tags, and they could potentially want to remove all the
+tags in one command, they would have to type out all the tags separately in order to achieve that.
+
+**Proposed enhancement:**
+We provide a convenient way for users to delete all the tags in one command by adding an optional parameter
+to the command. The updated command format would be as follows:
+`tag [at/]... [dt/]... [dat/deleteall]`.
+
+Justifications:
+* As deleting all the tags is a destructive action, we require users to specify the `dat/` prefix to indicate
+their interest in deleting all tags, and `deleteall` value to the prefix to serve as a confirmation of this
+destructive command.
+
+Updated behaviours (original behaviours of tag still hold):
+* When a `dat/` prefix is supplied, there should not be any `at/` or `dt/` prefix supplied in the same command, if there
+is, a format error message will be shown to the user.
+* If the value provided to parameter `dat/` is not `deleteall`, show an error message to users, indicating that
+they should supply the `deleteall` value to `dat/` in order to confirm the deletion.
+
+**Examples:**
+* `tag 1 dat/deleteall`
+Expected: All the tags of customer at index 1 is deleted, a `successfully deleted all tags` message is shown to user.
+
+* `tag 1 at/tall dat/deleteall`
+Expected: Error, an error message showing the usage of tag command is shown to the user.
+
+* `tag 1 dat/delete`
+Expected: Error, an error message informing the user that they should input `deleteall` to confirm the deletion of all tags
+is shown to the user.
+
+
+
+#### Enhancement 2: Edit appointment details
+
+**Feature flaw:**
+Users will not be able to easily update or modify appointment details if there are any changes or mistakes. If the appointment meeting location changes, or the scheduled time needs adjustment—without the ability to edit, users would have to delete and create a new appointment, potentially leading to confusion and decreased efficiency.
+
+**Proposed enhancement:**
+We provide a convenient way for users to edit the appointment details, date, time and venue, in a edit appointment command.The updated command format would be as follows:
+`editappt [d/] [t/time] [v/venue]`
+
+Justifications:
+* As we need the details of the new appointment to be changed, at least one of the optional fields must be present.
+
+Updated behaviours (original behaviours of appointment still hold):
+* If the proposed appointment details entered in `editappt` are the same as the current appointment, there will be a error message to the user that there is no change.
+
+**Examples:**
+* `editappt 1 d/2026-12-16`
+Expected: Edits the date of the first customer's appointment in the displayed list to be 16 Dec 2026, if it is different at first.
+
+* `editappt 1`
+Expected: Error, an error message informing the user to provide at least 1 appointment detail field to be changed.
+
+
+
+#### Enhancement 3: Unmark appointment recovers appointment details
+
+**Feature flaw:**
+After marking an appointment, the appointment details gets removed. However, after unmarking the appointment, the appointment details do not come back. This might cause the user to need to manually create the appointment meeting again, which can be a hassle, decreasing efficiency.
+
+
+**Proposed enhancement:**
+The unmark appointment `unmarkappt` will not only decrement the appointments completed counter by 1, but also restore the "marked" appointment details.
+
+Updated behaviours (original behaviours of appointment still hold):
+* Can be undone by marking the appointment again.
+
+**Examples:**
+* `unmarkappt 1`
+Expected: Decrements the customer's appointment completed counter by 1, and restores the customer's appointment details to the previous marked appointment details.
+
+#### Enhancement 4: Inserting `clear` pops out a confirmation window
+
+**Feature flaw:**
+After the user inputs the `clear` command, the customer list is cleared immediately. In some situations where the user just type `clear` in accident, the consequence is undesirable.
+
+**Proposed enhancement:**
+Pop a confirmation window for users to confirm once again if the user indeed wants to clear the customer list.
+
+
+
+#### Enhancement 5: find multiple tags and insurances
+**Feature flaw:**
+The current implementation employs a single prefix for multiple keywords in the find feature, such as `find i/Health Auto.`
+This approach, however, lacks the ability to distinguish between distinct sets of keywords, leading to potential ambiguity.
+For instance, it becomes challenging to differentiate whether the keywords correspond to a combination like `Health Auto` or separate entities like `Health Insurance` and `Auto Coverage`.
+
+**Proposed enhancement:**
+To address this limitation, it is recommended to enable the use of multiple identical prefixes for individual keywords. For instance, the enhanced syntax could be `find i/Health i/Auto`.
+This modification allows the find feature to accommodate duplicate prefixes for both find and tag operations, thereby providing a more precise and unambiguous search capability.
+
+**Justifications:**
+* The problem we've spotted isn't just about insurance searches; it also affects tag searches.
+* This problem only arises with tags and insurances since these are only two attribute allowed multiple instances.
+
+**Examples:**
+* `find i/abc i/apple`
+ Expected: Identifies customers with two insurance entities whose names match the keywords `abc` and `apple` respectively.
+ For instance, if there are customer with insurances named `abc insurance` and `apple insurance`, they would be included in the results.
+* `find i/abc apple`
+ Expected: Locates customers with an insurance entity whose name corresponds to the combined keyword `abc apple`, such as `abc apple insurance`.
+
+The enhanced feature ensures accurate and targeted search results.
+
+
+
+#### Enhancement 6: Increase flexibility of value input for phone number
+
+**Feature flaw:**
+In `add` and `edit` command, when entering `` under `p/`, it takes in the 8 digits (Singaporean number) with no spaces or `-` (e.g. `12345678`).
+However, it does not allow other common formats for Singaporean number that includes space and `-` (e.g. `1234-5678`, `1234 5678`), which can be a hassle to
+users for not being allowed to so.
+
+**Proposed enhancement:**
+Allow `` with format of `1234 5678` and `1234-5678`
+
+**Updated behaviours** (original behaviour of `/p` still holds):
+* `` can now take the format of `1234-5678` and `1234 5678` and display the information in EzContact
+
+**Examples:**
+* `edit 1 p/1234-5678`
+ Expected: Update the `` of customer at index 1 to `1234-5678`
+* `edit 1 p/1234 5678`
+ Expected: Update the `` of customer at index 1 to `1234 5678`
+
+
+
+#### Enhancement 7: Improve criteria for duplicate customer
+
+**Feature flaw:**
+Currently, duplicated customer is defined as customers that have either identical `` or ``, given that each customer
+should have their respective contact details. However, this does not take into consideration that some customers might not have email (e.g. elderly)
+and would have others to handle their incoming emails.
+
+**Proposed enhancement:**
+Modify the implementation on checking for duplicate customer such that it accepts identical `` exist in EzContact, and update the
+error message to `This phone number already exists in the contact book` instead of the original duplicate customer message to give users
+more accurate feedback on what went wrong.
+
+**Justification:**
+The purpose of EzContact is to help our users (i.e. insurance agent) to manage contacts of customers that he needs to approach / interact with
+thus the most important value our product has to offer, is to keep track of and contact customers effectively. Thus, we need to make sure that
+each customer is contactable, leading to us enforcing the uniqueness of ``. `` is allowed to have duplicates because it is
+possible and common for people to share ``(especially elderly who have no email). `` is also allowed because it is common to have
+identical name. These restrictions give the users maximum flexibility and functionality while still ensuring that each customer is contactable.
+
+**Updated behaviours**:
+* Adding customers with existing `` are not allowed, error will be thrown indicating that the `` already exists
+* Adding customers where values of their fields (except `p/`) already exist in the contact book are allowed.
+
+**Examples:**
+* `add n/joshua p/12345678 e/abc@gmail.com`, `add n/james p/78945612 /abc@gmail.com`
+ Expected : Add `james` successfully into the contact book with no error
+* `add n/joshua p/12345678 e/abc@gmail.com`, `add n/james p/12345678 /defg@gmail.com`
+ Expected : Error message is thrown indicating that the `12345678` already exist in the contact book
+
+
+
+#### Enhancement 8: Delete all insurances with one command
+
+**Feature flaw:**
+With current implementation, when a customer has multiple insurances assigned to he/she, deleting all insurances requires the user to list out
+all the insurances with `di/` prefix in our `insurance` command, which is inconvenient
+
+**Proposed enhancement:**
+Add a new optional prefix `dai/` and parameter `deleteall` for `insurance` command to indicate deleting all insurances,
+the new command takes the format of
+`insurance [ai/]... [di/]... [dai/deleteall]`
+
+**Justification:**
+Given that `dai/` will remove all the insurances of the customer at once, we require users to do a confirmation by specifying `deleteall`
+for `dai/` to ensure that the user execute this command intentionally.
+
+**Updated behaviours** (Original behaviour of `insurance` still holds) :
+* When `dai/` is supplied, `ai/` and `di/` are not allowed. Format error will appear if either prefixes are used
+* When `dai/` is supplied, if the value supplied to it is not `deleteall`, an error message will be thrown, indicating that `deleteall`
+has to be supplied to confirm the deletion
+
+**Examples:**
+* `insurance 2 dai/deleteall`
+ Expected : All insurances of customer at index 2 are removed
+* `insurance 2 dai/deleteall ai/AIA di/cars`
+ Expected : Error message is thrown, showing the usage of insurance
+* `insurance 2 dai/dvsdv`
+ Expected : Error message is thrown, telling users that `deleteall` has to be supplied to confirm deletion.
+
--------------------------------------------------------------------------------------------------------------------
+
+
+# **Appendix: Effort**
+
+This section gives an overview of the challenges, we as a team faced and the effort we have put in to make this project work.
+
+#### Enhanced Logic Component `* * *`
+
+With the implementation of various new features in EzContact, the `logic` component who’s responsible for the parsing and
+handling of our `commands` have to go through various modifications and enhancements to fulfill the needs of these features.
+The new `logic` component needs to be more flexible regarding its constraint on the user input and also need to accommodate
+the newly defined `commands` by us for the new features
+
+**Effort:**
+
+The enhancement can be broken down into a few parts:
+
+* `ArgumentTokenizer`
+* `CommandParser` & `AddressBookParser`
+* `Command`
+
+
+1. Implementation and logics of `ArgumentTokenizer` has to be understood thoroughly before putting our hands on the codebase.
+Along the way, we have had multiple discussions on the choice of prefixes and restriction to put on the prefix input. Upon finalizing
+the prefixes and constraints, work is split among members and each take up some part to work on.
+2. For `CommandParser` and `AddressBookParser`, we each implement the parser associated with the features we are implementing. We also
+integrate our parsers with `AddressBookParser` as it parses the command word and determines the `CommandParser` to use for remaining of
+the command.
+3. `Commands` are also implemented separately according to the features we are assigned to implement. We ensure that our implementation
+does not break the Liskov Substitution Principle since all `commands` we implemented inherited the `Commmand` class. We also ensure that
+our implementation integrates well with each other and does not break others' functionality.
+
+All changes were done in small increments, in addition with testing using the newly written test cases. After finishing respective parts,
+we also perform cross-checking on each other's implementation to ensure no bugs or flaws exist in our product. Some changes were made after
+the rigorous testing as we found some feature flaws that can be further improved.
+
+**Result :**
+
+Our new `logic` component now accommodates multiple new features that drastically improve users experience and previous features are also
+refined to provide users more flexibility and functionality.
+
+
+
+#### Enhanced UI `* *`
+
+The `UI` first has to be redesigned from the perspective of the purpose it serves. We have to ensure that all usages have to be accounted
+in the new `UI` to ensure that users will always have a clear view of what's going on.
+
+**Effort:**
+
+We first redesign the structure of our `UI` to fit the new features in a sensible and user-friendly way. We tried out different layouts
+and ways to present our data, and finalize on the current design, where the customer's information are displayed as `Customer Card`. After ensuring
+the functionality is covered by `UI`, we move on to changing the colour scheme of our product. After many trial and error, and requesting feedbacks
+from our friends, we have decided to use the current pastel green colour scheme.
+
+**Result :**
+
+A newly designed `UI` for EzContact and improved UI component with increased usability.
+
-## **Appendix: Instructions for manual testing**
+#### Enhanced Storage `* * *`
+
+Given the newly introduced `attributes` in EzContact, the `storage` component is required to accommodate these new data when creating
+the save file.
+
+**Effort:**
+
+Given that our saving system is implemented using `Jackson (JSON package)`, we first have to understand how the package works and how
+it is integrated into our system. For each new `attribute`, we have created the corresponding `JSON-friendly data class` to handle these
+data during saving. These classes handle the conversion between application-used and JSON-compatible data during loading and saving.
+These classes are integrated to the existing `storage` component carefully to ensure that we do not break the existing system. The original
+`storage` component is also refined and fixed of all discovered bugs.
+
+**Result :**
+
+A refined `storage` component that is able to handle all new `attributes` safely and correctly.
+
+
+
+#### Enhanced Model `* *`
+
+To accommodate the new features and `attributes`, the `model` component now has to handle these new `commands` and process these new `attributes`.
+
+**Effort:**
+
+New classes are created to represent and abstract these data to a higher level for easy manipulation. These classes are then integrated into
+the `Person` class as it is the over-arching class represents the customer. New methods are also added to `model` component to perform the execution
+specified by the different `commands`. We are implementing the respective classes corresponding to the features we are responsible for. The implementations
+are done in small increment and are tested along the way.
+
+**Result :**
+
+A comprehensive model that holds and operates on our customer data according to the command given by logic component.
+
+--------------------------------------------------------------------------------------------------------------------
+
+
+# **Appendix: Instructions for manual testing**
Given below are instructions to test the app manually.
-:information_source: **Note:** These instructions only provide a starting point for testers to work on;
+
+
+## Feature to show
+
+**Scenario**
+
+Prerequisite : [condition needed to be fulfilled to perform the action if applicable]
+
+1. Test case : `value`
+ Expected : `result`
+1. ...
+
+_{ more test cases … }_
+
+**Note:** These instructions only provide a starting point for testers to work on;
testers are expected to do more *exploratory* testing.
-
+
-### Launch and shutdown
+## Adding a customer
-1. Initial launch
+**Adding a customer to the contact book**
- 1. Download the jar file and copy into an empty folder
+Prerequisites: -
- 1. Double-click the jar file Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum.
+1. Test case: `add n/Joshua p/1234-5678 e/opqr@gmail.com`
+ Expected: Customer of name `Joshua` with the above details is added
-1. Saving window preferences
+1. Test case: `add n/Joshua p/1234-5678 e/opqr@gmail.com a/1A Kent Ridge Rd t/morning person`
+ Expected: Customer of name `Joshua` with the above details is added
- 1. Resize the window to an optimum size. Move the window to a different location. Close the window.
+1. Test case: `add n/Joshua`
+ Expected: No customer is added. Error message is thrown indicating that compulsory field `p/` and `e/` are missing
- 1. Re-launch the app by double-clicking the jar file.
- Expected: The most recent window size and location is retained.
+1. Test case: `add n/Joshua p/acaf e/abcdeg@gmail.com`
+ Expected: No customer is added. Error message is thrown indicating that `` format is incorrect
-1. _{ more test cases … }_
+1. Test case: `add `
+ Expected: No customer is added. Error message is thrown indicating format for `add` command is wrong
-### Deleting a person
+
-1. Deleting a person while all persons are being shown
+## Deleting a customer
- 1. Prerequisites: List all persons using the `list` command. Multiple persons in the list.
+**Deleting a customer while all customers are being shown**
+
+Prerequisites: List all customers using the `list` command. Multiple customers 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 customer is deleted from the list. Details of the deleted customer 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 customer is deleted. Error details shown in the status message. Customer list remains the same.
1. Other incorrect delete commands to try: `delete`, `delete x`, `...` (where x is larger than the list size)
- Expected: Similar to previous.
+ Expected: No customer is deleted. Error details shown in the status message. Customer list remains the same.
+
+
+## Updating tags of a customer
+
+**Updating the tags of a specific customer**
+
+Prerequisite : -
+
+1. Test case : `tag 1 at/tall at/fat dt/short dt/skinny`
+ Expected : The tags assigned to the customer at index 1 will be updated accordingly(adds `tall` and `fat` tag, deletes `short` and `skinny` tag).
+
+1. Test case : `tag 0 at/tall`
+ Expected : Error, details shown in the status message(format error since the index is not a positive integer).
+
+1. Test case : `tag 1`
+ Expected : Error, details shown in the status message(format error since no tag to update is provided).
+
+1. Test case: `tag 1 at/tall dt/tall`
+ Expected : Error, details shown in the status message(conflicting tags).
+
+1. Test case: `tag 1 dt/dsajdkl`, the tag to delete does not exist in cutomer 1
+ Expected: Error, details shown in the status message(customer not updated).
+
+
+
+
+
+## Update insurance of a customer
+
+**Updating the insurances of a customer**
+
+Prerequisite : -
+
+1. Test case : `insurance 2 ai/AIA ai/cars di/health di/ABC`
+ Expected : Customer is updated, `health` and `ABC` insurance are removed and `AIA` and `cars` insurance are added
+
+1. Test case : `insurance 0 ai/AIA ai/cars di/health di/ABC` ``
+ Expected : Customer is not updated. Error details shown in the status message (format error since the index is not a positive integer).
+
+1. Test case : `insur 3 ai/EFG ai/JFK`
+ Expected : Customer is not updated. Error details shown in the status message (Incorrect command word).
+
+1. Test case : `insurance 4 ai/ABC di/ABC`
+ Expected : Customer is not updated. Error details shown in the status message (conflicting changes).
+
+1. Test case : `insurance 1 `
+ Expected : No customer is updated. Error details shown in the status message(format error since no insurances to update is provided).
+
+
+
+## Find customers
+
+**Find customers**
+
+Prerequisite : -
+
+1. Test case : `find n/`
+ Expected : Show all customers in the list, because every customer must has a name.
+
+1. Test case : `find n/a`
+ Expected : Show all customers has a as a prefix in their name.
+
+1. Test case : `find i/ABC t/male`
+ Expected : Show all customers has ABC matches with their insurances and has male matches with their tags.
+
+1. Test case : `find 123`
+ Expected : Customer list not updated. Error details shown in the status message (format error, one prefix must be provided).
+
+
+
+
+## Update remark of a customer
+
+**Updating the remark of a customer**
+
+Prerequisite : -
+
+1. Test case : `remark 2 he don't like pizza`
+ Expected : Customer is updated. Customer's remark update to `he don't like pizza`.
+
+1. Test case : `remark 2` ``
+ Expected : Customer is updated. Customer's remark is deleted.
+
+1. Test case : `remark`
+ Expected : Customer is not updated. Error details shown in the status message (No index provided).
+
+
+## Updating priority of a customer
+
+**Updating the priority of a specific customer**
+
+Prerequisite : -
+
+1. Test case : `priority 1 low`
+ Expected : Priority of customer at index 1 is updated to `low`.
+
+1. Test case : `priority 1 low`, old priority of customer at index 1 is also `low`
+ Expected : Error, details shown in the status message (person is not changed).
+
+1. Test case : `priority 0`
+ Expected : Error, details shown in the status message (format error since the index is not a positive integer).
+
+1. Test case : `priority 1`
+ Expected : Error, details shown in the status message (format error since no priority is provided).
+
+1. Test case: `priority 1 -`
+ Expected : Priority of customer at index 1 is removed (and set to `NONE`), no priority label is shown in the Ui.
+
+
+
+
+
+## Updating appointment of a customer
+
+**Updating the appointment of a specific customer**
+
+Prerequisite : -
+
+1. Test case : `addappt 1 d/2025-12-12`
+ Expected : Appointment of customer at index 1 is updated to 12 Dec 2025 with empty time and venue.
+
+1. Test case : `addappt 1 d/2025-12-12`, customer at index 1 has existing appointment
+ Expected : Error, details shown in the status message(appointment is not added).
+
+1. Test case : `deleteappt 1`, customer at index 1 has existing appointment
+ Expected : Appointment of customer at index 1 is deleted, updated to become an empty appointment.
+
+1. Test case : `deleteappt 1`, customer at index 1 does not have an existing appointment
+ Expected : Error, details shown in the status message(no appointment).
+
+1. Test case : `markappt 1`, customer at index 1 has an existing appointment
+ Expected : Appointment of customer at index 1 is deleted, updated to become an empty appointment, and the appointments
+completed counter is incremented by 1.
+
+1. Test case : `markappt 1`, customer at index 1 does not have an existing appointment
+ Expected : Error, details shown in the status message(No appointment exists to be marked).
+
+1. Test case : `markappt 1`, customer at index 1 does not have existing appointment
+ Expected : Appointments completed counter of customer at index 1 is deceremented by 1.
+
+1. Test case : `umarkappt 1`, customer at index 1 has an existing appointment
+ Expected : Error, details shown in the status message(cannot be undone if no completed appointment).
+
+
+
+## Editing a customer
+
+**Editing the information of a specific customer**
+
+Prerequisite : -
-1. _{ more test cases … }_
+1. Test case : `edit 1 n/John`
+ Expected : Name of customer at index 1 is updated to `John`.
-### Saving data
+1. Test case : `edit 0`
+ Expected : Error, details shown in the status message (format error since the index is not a positive integer).
-1. Dealing with missing/corrupted data files
+1. Test case : `edit 1`
+ Expected : Error, details shown in the status message (format error since no information is provided).
- 1. _{explain how to simulate a missing/corrupted file, and the expected behavior}_
+1. Test case: `edit 1 pr/high`
+ Expected : Error, details shown in status message (priority is not allowed to be edited using the edit command).
-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 57437026c7b..91f58a9f8e9 100644
--- a/docs/UserGuide.md
+++ b/docs/UserGuide.md
@@ -1,197 +1,748 @@
---
-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.
+# EzContact User Guide
-* Table of Contents
-{:toc}
+
+
---------------------------------------------------------------------------------------------------------------------
+
-## Quick start
+## Introduction
-1. Ensure you have Java `11` or above installed in your Computer.
+Welcome to the User Guide (UG) of **EZContact**
+
+ In the dynamic and ever-evolving world of insurance, staying connected and organized is paramount.
+Meet EzContact, your go-to solution designed exclusively for insurance agents. Navigating the complex network of clients,
+policies, and leads has never been easier. EzContact empowers you to manage your contacts, streamline communication,
+and boost your productivity, all from the tips of your fingers.
+
+ EzContact is a desktop application that can help you organize your customers' information and reduce the
+hassle of having to remember everything. It is optimized for use via Command Line Interface (CLI), meaning that users would
+have to enter text command to execute them, while still having the benefits of Graphical User Interface (GUI) where users
+can view the information easily through the application.
-1. Download the latest `addressbook.jar` from [here](https://github.com/se-edu/addressbook-level3/releases).
+With EZContact, our users are able to :
-1. Copy the file to the folder you want to use as the _home folder_ for your AddressBook.
+* Seamlessly organize their clients' details, policy information, and communication history.
+* Stay on top of their leads, and convert potential clients into loyal customers.
+* Schedule appointments and follow-ups without missing a beat.
-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.
- A GUI similar to the below should appear in a few seconds. Note how the app contains some sample data.
- ![Ui](images/Ui.png)
+ If you are a fast typist, EzContact is the perfect tool for you to keep track of all your customer
+, it is faster than any other traditional GUI-based application available in the market! Remember, Time is Money ! The
+faster you approach your customer, the more deals you seal.
-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:
+ If you are interested in EzContact, hop on over to our [Quick Start](#quick-start) to get started and
+embark on your journey of using EzContact.
- * `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.
+## Quick start
+
+1. Ensure you have Java `11` or above installed in your Computer.
- * `delete 3` : Deletes the 3rd contact shown in the current list.
+2. Download the latest `EzContact.jar` from [here](https://github.com/AY2324S1-CS2103T-W16-2/tp/releases).
- * `clear` : Deletes all contacts.
+3. Copy the file to the folder you want to use as the _home folder_ for your EzContact.
+4. Open a command terminal, `cd` into the folder you put the jar file in
+5. After reaching the folder, execute the command `java -jar EzContact.jar`. The GUI similar to the below should appear in a few seconds.
+Note how the app contains some sample data. ![Ui](images/Ui.png)
+5. Type the command in the [Command Box](#ui-layout-description) and press Enter to execute it.
+6. Refer to the [Features](#features) below for details of each command.
- * `exit` : Exits the app.
+
-1. Refer to the [Features](#features) below for details of each command.
+## UI Layout Description
---------------------------------------------------------------------------------------------------------------------
+Consider the following UI split into three parts:
+
+![UiWithDescription](images/UiWithDescription.png)
+
+As illustrated above, the UI will be split into three sections, we will be providing a name for each section and
+will be using these names to refer to the section specified in the following User Guide.
+
+1. **Command Box:** Box for users to input the command to be executed by EzContact.
+1. **Result Display Box:** Box that displays the result of executing the entered command.
+1. **Customer List Panel:** Panel that displays the list of Customer Cards.
+ - **Customer Card:** Card that displays information about each customer.
+
+
## 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`.
+* Words in `<>` are the parameters to be supplied by the user.
+ e.g. in `add n/
`, `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 in `[]` are optional.
+ e.g `n/ [a/]` can be used as `n/John Doe a/Kent Ridge` 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.
+ e.g. `[t/]…` can be used as ` ` (i.e. 0 times), `t/friend`, `t/friend t/family` etc.
* 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.
+ e.g. if the command specifies `n/ p/`, `p/12341234 n/John` is also acceptable.
+
+* Prefixes (e.g. `n/`, `p/`, `e/`) are designed to be short, however, we do still provide the functionality to detect
+full-name prefixes ,and they can be used interchangeably(e.g. `n/` and `name/` are interchangeable),
+click [here](#prefix-to-full-name-prefix-translation-table) to see a full table of prefix to full-name prefix relation.
* Extraneous parameters for commands that do not take in parameters (such as `help`, `list`, `exit` and `clear`) will be ignored.
- e.g. if the command specifies `help 123`, it will be interpreted as `help`.
+ e.g. if the command is `help 123`, it will be interpreted as `help`.
+
+* Duplicate customer is defined as 2 person who have identical `` or ``.
+
+* `` must be value of between (1 -> 2147483647), any value out of this range will be considered as incorrect format;
+whereas value in range but not in customer list is considered out of bound.
+
+* Unless otherwise stated, when specifying restrictions on number of characters, spaces in between words
+are included in the count, while leading and trailing spaces are excluded.
* 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.
-### Viewing help : `help`
+
-Shows a message explaning how to access the help page.
+### Adding a customer: `add`
-![help message](images/helpMessage.png)
+**Format:**
-Format: `help`
+`add n/ p/ e/ [a/] [pr/] [t/]... [i/]... [r/]`
+**Description:**
-### Adding a person: `add`
+Adds a new customer with the respective details to EzContact.
-Adds a person to the address book.
+
-Format: `add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]…`
+**Caution:**
+* `` should be **alphanumeric**, **non-empty** and **not longer than 64 characters**.
+* `` should be an **8-digit number**(i.e. a Singapore number).
+* `` should be a **valid email address**(i.e. `local-part@domain`).
+* `` should **not be longer than 100 characters**.
+* `` should **only be one of**: `high`, `medium`, `low`, `-` (all case-insensitive).
+* `` should be **alphanumeric**, **non-empty** and **not longer than 20 characters(excluding spaces)**.
+* `` should be **alphanumeric**, **non-empty** and **not longer than 32 characters**.
+* `` should **not be longer than 150 characters**.
+* A customer **must not have more than 10 tags** assigned to it.
+* A customer **must not have more than 5 insurances** assigned to it.
+* Adding a [**duplicate customer**](#features) in EzContact is **not allowed**.
+
-:bulb: **Tip:**
-A person can have any number of tags (including 0)
-
+**Examples:**
-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`
+* `add n/Ryan Ong p/64238876 e/ryanong@gmail.com t/tall t/skinny t/wears spectacles pr/medium i/car insurance`
+Adds the following [Customer Card](#ui-layout-description) to the [Customer List Panel](#ui-layout-description). Note how omission of optional parameters
+are allowed.
-### Listing all persons : `list`
+![AddEg2](images/add-command-examples/example2.png)
-Shows a list of all persons in the address book.
+
-Format: `list`
+### Deleting a customer : `delete`
-### Editing a person : `edit`
+**Format:**
+`delete `
-Edits an existing person in the address book.
+**Description:**
+* Deletes the customer at the specified ``.
+* `` refers to the index number shown in the displayed customer list.
-Format: `edit INDEX [n/NAME] [p/PHONE] [e/EMAIL] [a/ADDRESS] [t/TAG]…`
+
-* 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, …
-* 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.
+**Caution:**
+* `` should **only be one of** the indices shown in the displayed list.
+
-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.
+**Examples:**
+* `delete 2` deletes the 2nd customer in the displayed list.
-### Locating persons by name: `find`
-Finds persons whose names contain any of the given keywords.
+Before:
-Format: `find KEYWORD [MORE_KEYWORDS]`
+![deleteBefore](images/delete-command-example/delete-before.png)
-* 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`
+After:
-Examples:
-* `find John` returns `john` and `John Doe`
-* `find alex david` returns `Alex Yeoh`, `David Li`
- ![result for 'find alex david'](images/findAlexDavidResult.png)
+![deleteAfter](images/delete-command-example/delete-after.png)
+
+
+
+### Editing a customer : `edit`
+
+**Format:** `edit [n/] [p/] [e/] [a/]`
+
+**Description:**
+* Edits the customer at the specified ``.
+* `` refers to the index number shown in the displayed customer list.
+* If values are provided for certain fields, existing values of their respective fields will be edited to the provided values.
+* If no value is provided, the values of the fields remain unchanged.
+
+
+
+**Caution:**
+* **At least one** of the optional fields must be provided.
+* `` should **only be one of** the indices shown in the displayed list.
+* `` should be **alphanumeric**, **non-empty** and **not longer than 64 characters**.
+* `` should be an **8-digit number**(i.e. a Singapore number).
+* `` should be a **valid email address**(i.e. `local-part@domain`).
+* `` should **not be longer than 100 characters**.
+* Tags, Priorities, and Remarks are not editable.
+* Editing a customer to have the same `` or `` to other existing customers will cause [**duplicate customer**](#features) error.
+
+
+
+**Examples:**
+* `edit 3 n/Betsy Crower p/91234567 e/fong@example.com` edits the name, phone number and email address of the 3rd customer to be `Betsy Crower`, `91234567` and `fong@example.com` respectively.
+
+Before:
+
+![editBefore](images/edit-command-example/edit-before.png)
+
+After:
+
+![editAfter](images/edit-command-example/edit-after.png)
+
+
+
+### Finding customers : `find`
+
+**Format:**
+
+`find [n/] [p/] [e/] [a/] [t/] [i/] [pr/] [r/]`
+
+**Description:**
+
+Search for customers with specified keywords of different attributes (except `appointment`).
+
+* Attribute matches with the keywords when:
+ - Any word in the attribute contains the single keyword as a prefix.
+ - If there are multiple keywords, all keywords must be present in the attribute as prefix.
+* Keywords are not case-sensitive and can be in any order.
+* For `tag` and `insurance`, only one of the customer's `tags` / `insurances` has to contain the keywords as a prefix.
+These keywords can be spread across different `tag` / `insurance` entries.
+* When searching with multiple attributes, the customer's attributes must match all the corresponding ones in `find`.
+
+
+
+**Caution:**
+* **At least one** of the optional fields must be provided.
+* Keyword is **NOT** mandatory.
+
+
+
+**Examples:**
+
+* `find t/tall pr/h` finds all the customers whose tag matches keyword `tall` and whose priority matches keyword `h` from the [Customer List](#ui-layout-description).
+
+![findExample](images/find-command-examples/find%20example.png)
+
+* `find i/car insurance pr/` finds all the customers whose insurance matches keyword `car insurance` and have priority from the [Customer List](#ui-layout-description).
+
+![findExamplew](images/find-command-examples/find%20example%202.png)
+
+
+
+**Note**:
+
+Note that if you search using `find n/Song Song`,
+it will match a customer named `Song Guo Xuan` because all the specified keywords are present in the customer's name.
+
+
+
+
+
+### Tagging a customer: `tag`
+
+**Format:** `tag [at/]... [dt/]...`
+
+**Description:**
+
+* Updates the tags assigned to the customer at `` in the displayed customer list.
+* Tags are not case-sensitive (i.e. `friends` is equivalent to `FriEnds`), the GUI will display tags in lower case.
+* Contiguous spaces in between words will be treated as 1 single space.
+* **Duplicate tags** to add/delete will be **ignored** by EzContact.
+* **Adding an existing tag** or **deleting a non-existing tag** will be **ignored** by EzContact.
+
+
+
+**Caution:**
+* **At least one** `` or `` should be provided.
+* Adding and deleting the same tag is **not allowed**.
+* `` should **only be one of** the indices shown in the displayed list.
+* `` and `` should be **alphanumeric**, **non-empty** and **not longer than 20 characters(excluding spaces)**.
+* The number of tags assigned to the customer after the update should **not exceed 10 tags**.
+* The targeted customer's tags should **not remain unchanged** after the update command.
+
+
+
+**Examples:**
+
+* `tag 3 at/tall at/male dt/short dt/skinny`
+Adds `tall`(existing tag) and `male` tags, delete `short`(non-existing tag) and `skinny` tags from the third customer in the displayed customer list.
+
+Before:
+
+![TagEgBefore](images/tag-command-examples/before.png)
+
+After:
+
+![TagEgAfter](images/tag-command-examples/after.png)
+
+
+### Updating insurance of a customer: `insurance`
+
+**Format:**
+
+`insurance [ai/]... [di/]...`
+
+**Description:**
+
+* Updated the insurance of the customer at `` in the customer list
+* **Duplicate insurances** to add/delete is ignored
+* Adding **existing insurance** and **deleting non-existing** insurance from customer has no effect
+
+
+
+**Caution:**
+* **At least one** `` or `` should be present in the command
+* Adding and deleting the same tag in a single command is **not allowed**.
+* `` should **only be one of** the indices shown in the displayed list.
+* `` and `` should be **alphanumeric**, **non-empty** and **not longer than 32 characters**.
+* The number of insurance of the customer after the update should **not exceed 8 insurances**.
+* The targeted customer's insurance should **not remain unchanged** after the update command.
+
+
+
+
+
+**Example:**
+
+* `insurance 2 ai/AIA Insurance di/Great Eastern Insurance`
+Assign `AIA Insurance` to and remove `Great Eastern Insurance` from the second customer in the displayed customer list
+
+Before:
+
+![insuranceBefore](images/InsuranceCommandExample/InsuranceBefore.png)
+
+After:
+
+![insuranceAfter](images/InsuranceCommandExample/InsuranceAfter.png)
+
+
+
+### Updating priority of a customer: `priority`
+
+**Format:**
+
+`priority `
+
+**Description:**
+
+* Updates the priority of the customer at the specified `` in the displayed customer list to ``.
+* If the customer has not been assigned any priority previously, `` is assigned directly to the customer.
+* If `` is `-` , the priority previously assigned the customer will be **removed**.
+
+
+**Caution:**
+* `` should **only be one of** the indices shown in the displayed list.
+* `` should **only be one of:** `high`, `medium`, `low`, `-` (all case-insensitive).
+
+
+
+
+
+**Note:**
+* The customer list is sorted by priority according to this order: `high` -> `medium` -> `low`
+* Customers with no priority assigned to them will be displayed at the bottom of the list.
+* Changing a customer's priority **may** change its position in the list because of the sorted property.
+
+
+**Examples:**
+
+* `priority 3 high` updates the priority of the third customer to be `high`. Note that the position of the customer is changed.
+
+Before:
+
+![priorityBefore](images/priority-command-example/priority-before.png)
+
+
+
+After:
+
+![priorityAfter](images/priority-command-example/priority-after.png)
+
+
+
+* `priority 3 -` removes the priority assigned to the third customer. Note that the customer remains at the bottom of the list.
+
+Before:
-### Deleting a person : `delete`
+![removePriorityBefore](images/priority-command-example/remove-priority-before.png)
-Deletes the specified person from the address book.
+After:
-Format: `delete INDEX`
+![removePriorityAfter](images/priority-command-example/remove-priority-after.png)
-* 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, …
+
+
+### Adding a remark to a customer: `remark`
+
+Format: `remark `
+
+**Description:**
+
+* Add/updates the remark of the customer at `` in the displayed customer list.
+* If you wish to delete the remark, update the remark without text after the command, i.e. `remark `.
+
+
+
+**Caution:**
+* ``should **only be one of** the indices shown in the displayed list.
+* `` cannot be longer than 150 characters.
+
+
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`
+* `remark 4 he likes pizza` Updates the remark of the first customer in the displayed list to `he likes pizza`.
+
+Before :
+
+![remarkBefore](images/remark-command-example/remarkBefore.png)
+
+After:
+
+![remarkAfter](images/remark-command-example/remarkAfter.png)
+
+
+
+* `remark 4` Removes the remark from the second customer in the displayed list.
+
+Before :
+
+![remarkAfter](images/remark-command-example/remarkAfter.png)
+
+After:
+
+![remarkBefore](images/remark-command-example/remarkBefore.png)
+
+
+
+### Adding an appointment to a customer: `addappt`
+
+**Format:**
+`addappt d/ [t/] [v/]`
+
+**Description:**
+
+* Adds an appointment to the customer at `` in the displayed customer list.
+* An appointment can includes a date, time and venue.
+* This allows you to keep track of all your customers' appointment dates all within the same app
+* If you wish to delete the customer's appointment, use the command `deleteappt`
+
+
+
+**Caution:**
+
+* The customer must not have a current appointment
+* `` should **only be one of** the indices shown in the displayed list
+* `` must be specified
+* `` must be in YYYY-MM-DD format, not a past date and a valid date
+(eg. 30 Feb 2025 is invalid).
+* `` format must be in 24h HH:MM format
+* `` cannot be longer than 30 characters
+
+
+
+
+**Examples:**
+
+* `addappt 1 d/2025-12-12` adds an appointment on 12 Dec 2025 for the first customer in the displayed list
+
+* `addappt 1 d/2025-12-12 t/12:55` adds an appointment on 12 Dec 2025, 1255hrs for the first customer in the displayed list
+
+* `addappt 1 d/2025-12-12 t/12:55 v/Clementi Mall` adds an appointment on 12 Dec 2025, 1255hrs, Clementi Mall for the first customer in the displayed list
+
+Before:
+
+![addApptBefore](images/appointment-command-examples/DeleteApptAfter.png)
+
+After:
+
+![addApptAfter](images/appointment-command-examples/AddApptAfter.png)
+
+
+
+### Deleting a customer's appointment: `deleteappt`
+
+**Format:**
+`deleteappt `
+
+**Description:**
+
+* Deletes a customer's appointment at `` in the displayed customer list.
+* Used when the appointment has been cancelled.
+
+
+
+**Caution:**
+
+* The customer must have a current appointment
+* `` should **only be one of** the indices shown in the displayed list
+* Cannot be undone
+
+
+
+**Examples:**
+* `deleteappt 1` deletes the appointment of the first customer in the displayed list, if applicable
+
+Before:
+
+![deleteApptBefore](images/appointment-command-examples/DeleteApptBefore.png)
+
+After:
+
+![deleteApptAfter](images/appointment-command-examples/DeleteApptAfter.png)
+
+
-Clears all entries from the address book.
+### Marking an appointment: `markappt`
-Format: `clear`
+**Format:**
+`markappt `
+
+**Description:**
+* Marks the appointment of the customer at `` in the displayed customer list.
+* Increments the customer's completed appointments count by 1.
+* Deletes the current appointment.
+* Use to keep track of the number of completed appointments with the customer
+
+
+
+**Caution:**
+* `` should **only be one of** the indices shown in the displayed list
+* The customer at `` must have a current appointment.
+* This cannot be undone.
+
+
+
+**Example:**
+* `markappt 1` increments the appointment counter of the first customer in the displayed list.
+
+Before:
+
+![markApptBefore](images/appointment-command-examples/AddApptAfter.png)
+
+After:
+
+![markApptAfter](images/appointment-command-examples/MarkApptAfter.png)
+
+
+
+### Unmarking an appointment: `unmarkappt`
+
+**Format:**
+
+`unmarkappt `
+
+**Description:**
+
+* Decrements the customer's completed appointments count at `` by 1.
+* Use to reduce the appointment count of customers as needed.
+* Does not recover the marked appointment details.
+
+
+
+**Caution:**
+* `` should **only be one of** the indices shown in the displayed list
+* This cannot be undone.
+* The current appointment count must be greater than 0.
+
+
+
+**Examples:**
+* `unmarkappt 1` decrements the appointment counter of the first customer in the displayed list by 1.
+
+
+
+### Listing all customers : `list`
+
+**Format:**
+`list`
+
+**Description**
+* Shows a list of all customers in EZContact and the size of the list.
+* You can return to viewing your full client list after executing a `find` command.
+* No parameter is needed for this command, all parameter provided will be ignored.
+
+**Example**:
+* `list` shows a list of all existing customers and the size of the list.
+* `list 123` will be interpreted as `list`.
+
+
+
+----------------------------------------------------------------------------------------------------------------
+
+
+### Clearing the customer list : `clear`
+
+**Format:**
+`clear`
+
+**Description:**
+* Clears the customer list.
+* No parameter is needed for this command, all parameter provided will be ignored.
+
+**Examples:**
+
+* `clear` clears the customer list in EzContact.
+* `clear 123` will be interpreted as `clear`.
+
+
+
+### Requesting for help : `help`
+
+**Format:**
+`help`
+
+**Description:**
+* Opens the help window.
+* No parameter is needed for this command, all parameter provided will be ignored.
+
+**Examples:**
+
+* `help` opens the help window.
+* `help 123` will be interpreted as `help`.
+
+
+
+----------------------------------------------------------------------------------------------------------------
+
### Exiting the program : `exit`
-Exits the program.
+**Format:**
-Format: `exit`
+`exit`
-### Saving the data
+**Description:**
+* Exits the program.
+* No parameter is needed for this command, all parameter provided will be ignored.
-AddressBook data are saved in the hard disk automatically after any command that changes the data. There is no need to save manually.
+**Examples:**
-### Editing the data file
+* `exit` exits EzContact.
+* `exit 123` will be interpreted as `exit`.
-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.
+
-: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.
-
+## Advanced Features
-### Archiving data files `[coming in v2.0]`
+### Managing data
-_Details coming soon ..._
+EzContact's data is stored as a json file at : `/data/addressbook.json`, where ``
+is the directory you placed our `EzContact.jar` file.
---------------------------------------------------------------------------------------------------------------------
+**Saving data:**
-## FAQ
+EzContact's data is saved automaticaly whenever a command that changes the data is executed.
+
+**Editing the data file:**
+
+Advanced users are welcomed to update the data stored in EzContact directly by editing the `addressbook.json` file.
+
+
-**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.
+**Caution:**
+If the format of the file becomes invalid after an edit, EzContact will launch with an empty data file, and will
+overwrite the whole data file after a command that changes the data file is executed. Hence, users are **strongly
+recommended to store a backup** of the data file before editing it.
---------------------------------------------------------------------------------------------------------------------
+
-## Known issues
+**Storing/Restoring backup data files:**
-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.
+Users can store a backup of the current data file by simply creating a copy of the `addressbook.json` file.
+To restore a previously backed-up file, simply place the json file in the `/data` directory
+and rename the file to `addressbook.json`.
---------------------------------------------------------------------------------------------------------------------
+
+
+----------------------------------------------------------------------------------------------------------------
+
+
+## FAQ
+
+**Q:** Can I transfer my data to another computer?
+**A:** Yes, you can. Install EzContact in the computer and replace the `addressbook.json` file in the `/data` directory
+with the `addressbook.json` file from your previous computer.
+**Q:** Why are there sample customers when I first launch EzContact and how do I get rid of them?
+**A:** The sample customers are for new users to try out various commands in EzContact. To get rid of them, simply type `clear` in the
+command box.
+
+
## Command summary
-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`
+| Action | Format and Examples |
+|----------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| **Add** | `add n/ p/ e/ [a/] [pr/] [t/]... [i/]... [r/]` `add n/James Ho p/22224444 e/jamesho@example.com a/123, Clementi Rd, 1234665 t/tall r/some remarks` |
+| **Delete** | `delete ` `delete 3` |
+| **Edit** | `edit [n/] [p/] [e/] [a/] ` `edit 2 n/James Lee e/jameslee@example.com` |
+| **Find** | `find [n/] [p/] [e/] [a/] [t/] [i/] [pr/] [r/]` `find n/song i/abc` |
+| **Tag** | `tag [at/]... [dt/]...` `tag 1 at/tall dt/short at/male` |
+| **Insurance** | `insurance [ai/]... [di/]...` `insurance 2 ai/AIA insurance di/Great Eastern Insurance` |
+| **Remark** | `remark ` `remark 2 some remarks` |
+| **Priority** | `priority ` `priority 1 medium`
|
+| **Addappt** | `addappt d/ [t/] [v/]` `addappt 3 d/2025-12-12 t/23:59 v/Starbucks` |
+| **Deleteappt** | `deleteappt ` `deleteappt 1` |
+| **Markappt** | `markappt ` `markappt 1` |
+| **Unmarkappt** | `unmarkappt ` `unmarkappt 1` |
+| **List** | `list` |
+| **Clear** | `clear` |
+| **Help** | `help` |
+| **Exit** | `exit` |
+
+
+
+
+#### Prefix to full-name prefix translation table
+
+****Note that prefixes are not case-sensitive**
+
+| Prefix | Full-name prefix | Remarks |
+|--------|------------------|------------------------------------------|
+| n/ | name/ | |
+| p/ | phone/ | |
+| e/ | email/ | |
+| a/ | address/ | |
+| pr/ | priority/ | |
+| t/ | tag/ | used in `add` command |
+| i/ | insurance/ | |
+| r/ | remark/ | |
+| at/ | addtag/ | |
+| dt/ | deletetag/ | |
+| ai/ | addinsurance/ | |
+| di/ | deleteinsurance/ | |
+| d/ | date/ | |
+| t/ | time/ | used in **appointment** related commands |
+| v/ | venue/ | |
+
+
+
+## Glossary
+
+| Term | Meaning |
+|--------------------------------|------------------------------------------------------------------------------------------------------------------------------------|
+| Alphanumeric | Alphanumeric characters include uppercase letters from ‘A’ to ‘Z’, lowercase letters from ‘a’ to ‘z’, and numbers from ‘0` to ‘9’. |
+| json file | Acronym for JavaScript Object Notation file, a file format that stores data in a human-readable form. |
+| Command-line Interface (CLI) | Text-based user interface that receives text commands to run the program |
+| Graphical User Interface (GUI) | Interface where user interact with graphical component, such as icons, buttons and menus to run the program |
+
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..ef991cdd3ed
--- /dev/null
+++ b/docs/_markbind/layouts/default.md
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+
+
+
+
+* [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#command-summary)
+ * [Glossary]({{ baseUrl }}/UserGuide.html#glossary)
+* [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: Planned Enhancements]({{ baseUrl }}/DeveloperGuide.html#appendix-planned-enhancements)
+ * [Appendix: Effort]({{ baseUrl }}/DeveloperGuide.html#appendix-effort)
+ * [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/DeleteSequenceDiagram.puml b/docs/diagrams/DeleteSequenceDiagram.puml
index 40ea6c9dc4c..c47475ca77b 100644
--- a/docs/diagrams/DeleteSequenceDiagram.puml
+++ b/docs/diagrams/DeleteSequenceDiagram.puml
@@ -7,7 +7,7 @@ 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 ":CommandResult" as CommandResult LOGIC_COLOR
+participant "r:CommandResult" as CommandResult LOGIC_COLOR
end box
box Model MODEL_COLOR_T1
@@ -62,9 +62,13 @@ activate CommandResult
CommandResult --> DeleteCommand
deactivate CommandResult
-DeleteCommand --> LogicManager : result
+DeleteCommand --> LogicManager : r
deactivate DeleteCommand
-[<--LogicManager
+'Hidden arrow to position the destroy marker below the end of the activation bar.
+DeleteCommand -[hidden]-> LogicManager
+destroy DeleteCommand
+
+[<--LogicManager : r
deactivate LogicManager
@enduml
diff --git a/docs/diagrams/ModelClassDiagram.puml b/docs/diagrams/ModelClassDiagram.puml
index 0de5673070d..ae826f4aeec 100644
--- a/docs/diagrams/ModelClassDiagram.puml
+++ b/docs/diagrams/ModelClassDiagram.puml
@@ -19,9 +19,10 @@ Class Email
Class Name
Class Phone
Class Tag
-
-Class I #FFFFFF
-}
+Class Insurance
+Class Priority
+Class Insurance
+Class Remark
Class HiddenOutside #FFFFFF
HiddenOutside ..> Model
@@ -36,19 +37,21 @@ ModelManager -right-> "1" UserPrefs
UserPrefs .up.|> ReadOnlyUserPrefs
AddressBook *--> "1" UniquePersonList
-UniquePersonList --> "~* all" Person
-Person *--> Name
-Person *--> Phone
-Person *--> Email
-Person *--> Address
-Person *--> "*" Tag
-
-Person -[hidden]up--> I
-UniquePersonList -[hidden]right-> I
+UniquePersonList -right-> "~* all" Person
+Person --> "1" Name
+Person --> "1" Phone
+Person --> "1" Email
+Person --> "1" Address
+Person --> "1" Priority
+Person --> "1" Remark
+Person --> "*" Tag
+Person --> "*" Insurance
Name -[hidden]right-> Phone
Phone -[hidden]right-> Address
Address -[hidden]right-> Email
+Email -[hidden]right-> Priority
+Priority -[hidden]right-> Remark
-ModelManager --> "~* filtered" Person
+ModelManager ----> "~* filtered" Person
@enduml
diff --git a/docs/diagrams/StorageClassDiagram.puml b/docs/diagrams/StorageClassDiagram.puml
index a821e06458c..f35ae40005c 100644
--- a/docs/diagrams/StorageClassDiagram.puml
+++ b/docs/diagrams/StorageClassDiagram.puml
@@ -19,7 +19,7 @@ Class "<>\nAddressBookStorage" as AddressBookStorage
Class JsonAddressBookStorage
Class JsonSerializableAddressBook
Class JsonAdaptedPerson
-Class JsonAdaptedTag
+
}
}
@@ -38,6 +38,7 @@ JsonUserPrefsStorage .up.|> UserPrefsStorage
JsonAddressBookStorage .up.|> AddressBookStorage
JsonAddressBookStorage ..> JsonSerializableAddressBook
JsonSerializableAddressBook --> "*" JsonAdaptedPerson
-JsonAdaptedPerson --> "*" JsonAdaptedTag
+
+
@enduml
diff --git a/docs/diagrams/appointment-feature/AddedAppointmentClassDiagram.puml b/docs/diagrams/appointment-feature/AddedAppointmentClassDiagram.puml
new file mode 100644
index 00000000000..240bc1c3aae
--- /dev/null
+++ b/docs/diagrams/appointment-feature/AddedAppointmentClassDiagram.puml
@@ -0,0 +1,34 @@
+@startuml
+skinparam arrowThickness 1.1
+skinparam arrowColor #000000
+skinparam classBackgroundColor MODEL_COLOR
+skinparam classAttributeIconSize 0
+show fields
+
+title Adding an Appointment
+
+object "__:Person__" as normalHuman {
+}
+
+object "__:Appointment__" as emptyAppointment {
+ - date = "12 Dec 2025"
+ - time = "1255"
+ - venue = "Clementi Mall"
+}
+
+
+
+object "__:AppointmentCount__" as emptyAppointmentCount {
+ - count = 0
+}
+
+normalHuman --> emptyAppointment
+normalHuman --> emptyAppointmentCount
+
+note right of normalHuman
+ Other attribute classes such as
+ Name , Phone , Email ...
+ are ommited here as they are irrelevant
+ in the current context.
+end note
+@enduml
diff --git a/docs/diagrams/appointment-feature/AddedAppointmentSequenceDiagram.puml b/docs/diagrams/appointment-feature/AddedAppointmentSequenceDiagram.puml
new file mode 100644
index 00000000000..9d341eb157c
--- /dev/null
+++ b/docs/diagrams/appointment-feature/AddedAppointmentSequenceDiagram.puml
@@ -0,0 +1,78 @@
+@startuml
+!include ../style.puml
+
+box Logic Logic LOGIC_COLOR_T1
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR
+participant ":AppointmentCommandParser" as AppointmentCommandParser LOGIC_COLOR
+participant "ac:AppointmentCommand" as AppointmentCommand LOGIC_COLOR
+participant ":CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant ":Model" as Model MODEL_COLOR
+participant "a:Appointment" as Appointment MODEL_COLOR
+end box
+
+[-> LogicManager : execute("addappt 1 d/2025-12-12 t/12:55 v/Clementi Mall")
+activate LogicManager
+
+LogicManager -> AddressBookParser : parseCommand("addappt 1 d/2025-12-12 t/12:55 v/Clementi Mall")
+activate AddressBookParser
+
+create AppointmentCommandParser
+AddressBookParser -> AppointmentCommandParser
+activate AppointmentCommandParser
+
+AppointmentCommandParser --> AddressBookParser
+deactivate AppointmentCommandParser
+
+AddressBookParser -> AppointmentCommandParser : parse("addappt 1 d/2025-12-12 t/12:55 v/Clementi Mall")
+activate AppointmentCommandParser
+
+create Appointment
+AppointmentCommandParser -> Appointment : Appointment("12 Dec 2025", "1255", "Clementi Mall")
+activate Appointment
+
+Appointment --> AppointmentCommandParser : a
+deactivate Appointment
+
+create AppointmentCommand
+AppointmentCommandParser -> AppointmentCommand : AppointmentCommand(1, a)
+activate AppointmentCommand
+
+AppointmentCommand --> AppointmentCommandParser : ac
+deactivate AppointmentCommand
+
+AppointmentCommandParser --> AddressBookParser : ac
+deactivate AppointmentCommandParser
+'Hidden arrow to position the destroy marker below the end of the activation bar.
+AppointmentCommandParser -[hidden]-> AddressBookParser
+destroy AppointmentCommandParser
+
+AddressBookParser --> LogicManager : ac
+deactivate AddressBookParser
+
+LogicManager -> AppointmentCommand : execute()
+activate AppointmentCommand
+
+AppointmentCommand -> Model : setPerson(PersonToEdit, editedPerson)
+activate Model
+
+Model --> AppointmentCommand
+deactivate Model
+
+create CommandResult
+AppointmentCommand -> CommandResult : CommandResult(successMsg)
+activate CommandResult
+
+CommandResult --> AppointmentCommand
+deactivate CommandResult
+
+AppointmentCommand --> LogicManager
+deactivate AppointmentCommand
+
+[<--LogicManager
+destroy AppointmentCommand
+deactivate LogicManager
+@enduml
diff --git a/docs/diagrams/appointment-feature/AppointmentClassDiagram.puml b/docs/diagrams/appointment-feature/AppointmentClassDiagram.puml
new file mode 100644
index 00000000000..b17b59a0219
--- /dev/null
+++ b/docs/diagrams/appointment-feature/AppointmentClassDiagram.puml
@@ -0,0 +1,33 @@
+@startuml
+skinparam arrowThickness 1.1
+skinparam arrowColor #000000
+skinparam classBackgroundColor MODEL_COLOR
+skinparam classAttributeIconSize 0
+show fields
+
+title Default Appointment
+
+object "__:Person__" as normalHuman {
+}
+
+object "__:Appointment__" as emptyAppointment {
+ - date = "-"
+ - time = ""
+ - venue = ""
+}
+
+object "__:AppointmentCount__" as emptyAppointmentCount {
+ - count = 0
+}
+
+normalHuman --> emptyAppointment
+normalHuman --> emptyAppointmentCount
+
+note right of normalHuman
+ Other attribute classes such as
+ Name , Phone , Email ...
+ are ommited here as they are irrelevant
+ in the current context.
+end note
+
+@enduml
diff --git a/docs/diagrams/appointment-feature/AppointmentParserSequenceDiagram.puml b/docs/diagrams/appointment-feature/AppointmentParserSequenceDiagram.puml
new file mode 100644
index 00000000000..ab53de594e3
--- /dev/null
+++ b/docs/diagrams/appointment-feature/AppointmentParserSequenceDiagram.puml
@@ -0,0 +1,27 @@
+@startuml
+!include ../style.puml
+
+
+participant ":AppointmentCommandParser" as AppointmentCommandParser LOGIC_COLOR
+participant ":AppointmentCommand" as AppointmentCommand LOGIC_COLOR
+participant ":Appointment" as Appointment LOGIC_COLOR
+
+[-> AppointmentCommandParser : parse("1 d/2025-12-12 t/12:55 v/Clementi Mall")
+
+|||
+
+ref over AppointmentCommandParser : parse arguments
+note right : Parsing of index, date, time and venue \nis done here and omitted
+|||
+
+create Appointment
+ AppointmentCommandParser -> Appointment: Appointment("12 Dec 2025", "1255", "Clementi Mall")
+ activate Appointment
+ return appointment
+create AppointmentCommand
+ AppointmentCommandParser -> AppointmentCommand: AppointmentCommand(index, appointment)
+ activate AppointmentCommand
+ return command
+ [<--AppointmentCommandParser : command
+
+@enduml
diff --git a/docs/diagrams/appointment-feature/ExecutedAppointmentSequenceDiagram.puml b/docs/diagrams/appointment-feature/ExecutedAppointmentSequenceDiagram.puml
new file mode 100644
index 00000000000..e336ed9c9f6
--- /dev/null
+++ b/docs/diagrams/appointment-feature/ExecutedAppointmentSequenceDiagram.puml
@@ -0,0 +1,43 @@
+@startuml
+!include ../style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":AppointmentCommand" as AppointmentCommand LOGIC_COLOR
+participant ":CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant "m:Model" as Model MODEL_COLOR
+participant "Person" as PersonClass <> MODEL_COLOR
+participant ":Person" as Person MODEL_COLOR
+end box
+
+[-> AppointmentCommand: execute(m)
+
+AppointmentCommand -> AppointmentCommand: verifyCommandExecutable(m)
+|||
+ref over AppointmentCommand, Model: retrieve information required\n(i.e. personToEdit, appointment)
+|||
+
+AppointmentCommand -> PersonClass: createPersonWithEditedAppointment(personToEdit, appointment)
+activate PersonClass
+
+create Person
+PersonClass -> Person
+activate Person
+return editedPerson
+
+return editedPerson
+|||
+ref over AppointmentCommand: verify editedPerson is valid
+|||
+AppointmentCommand -> Model: setPerson(personToEdit, editedPerson)
+|||
+|||
+create CommandResult
+AppointmentCommand -> CommandResult
+activate CommandResult
+return result
+
+[<-- AppointmentCommand: result
+@enduml
diff --git a/docs/diagrams/find-feature/ExecuteFindCommandSequenceDiagram.puml b/docs/diagrams/find-feature/ExecuteFindCommandSequenceDiagram.puml
new file mode 100644
index 00000000000..7fe1e5fbbfb
--- /dev/null
+++ b/docs/diagrams/find-feature/ExecuteFindCommandSequenceDiagram.puml
@@ -0,0 +1,36 @@
+@startuml
+!include ../style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ": FindCommand" as command LOGIC_COLOR
+participant ": CommandResult" as result LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant "m: Model" as model MODEL_COLOR
+end box
+
+[-> command : execute(m)
+|||
+command -> model : updateFilterPersonList(personPredicate)
+|||
+command -> model : getFilteredPersonList()
+|||
+return
+|||
+create result
+command -> result
+activate result
+return result
+
+
+
+
+
+
+
+
+
+
+[<-- command : result
+@enduml
diff --git a/docs/diagrams/find-feature/FindSequence.puml b/docs/diagrams/find-feature/FindSequence.puml
new file mode 100644
index 00000000000..3700757fc7b
--- /dev/null
+++ b/docs/diagrams/find-feature/FindSequence.puml
@@ -0,0 +1,58 @@
+@startuml
+!include ../style.puml
+skinparam ArrowFontStyle plain
+
+box Logic LOGIC_COLOR_T1
+participant ": LogicManager" as manager LOGIC_COLOR
+participant ": AddressBookParser" as parser LOGIC_COLOR
+participant ": FindCommandParser" as findParser LOGIC_COLOR
+participant ": FindCommand" as command LOGIC_COLOR
+participant ": CommandResult" as result LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant "m: Model" as model MODEL_COLOR
+end box
+
+[-> manager : execute("find n/Song \nr/vegetarian")
+activate manager
+
+manager -> parser : parseCommand("find n/Song \nr/vegetarian")
+activate parser
+
+create findParser
+parser -> findParser
+activate findParser
+return
+|||
+parser -> findParser : parse("n/Song \nr/vegetarian")
+activate findParser
+
+create command
+findParser -> command
+activate command
+return
+
+return
+findParser -[hidden]-> parser
+destroy findParser
+
+return
+
+manager -> command : execute(m)
+activate command
+command -> model : updateFilteredPersonList(Predicate)
+activate model
+return
+|||
+
+create result
+command -> result
+activate result
+return result
+
+return result
+return result
+
+
+@enduml
diff --git a/docs/diagrams/find-feature/ParseFindCommandSequenceDiagram.puml b/docs/diagrams/find-feature/ParseFindCommandSequenceDiagram.puml
new file mode 100644
index 00000000000..dadf44471ec
--- /dev/null
+++ b/docs/diagrams/find-feature/ParseFindCommandSequenceDiagram.puml
@@ -0,0 +1,51 @@
+@startuml
+!include ../style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ": FindCommandParser" as parser LOGIC_COLOR
+participant ": ParserUtil" as keywordParser LOGIC_COLOR
+participant ": FindCommand" as command LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant "n: NameContains\nKeywordsPredicate" as namePredicate MODEL_COLOR
+participant "r: RemarkContains\nKeywordsPredicate" as remarkPredicate MODEL_COLOR
+participant "p: PersonContains\nKeywordsPredicate" as personPredicate MODEL_COLOR
+end box
+
+
+[-> parser : parse("n/Song \nr/vegetarian")
+|||
+
+parser -> keywordParser : parseNameKeyword("Song")
+activate keywordParser
+create namePredicate
+keywordParser -> namePredicate
+activate namePredicate
+return n
+return n
+|||
+
+parser -> keywordParser : parseRemarkKeyword("vegetarian")
+activate keywordParser
+create remarkPredicate
+|||
+keywordParser -> remarkPredicate
+activate remarkPredicate
+return r
+return r
+|||
+create personPredicate
+parser -> personPredicate : PersonContainsKeywordsPredicate(n, r)
+|||
+activate personPredicate
+return p
+
+create command
+parser -> command : FindCommand(p)
+activate command
+|||
+return command
+
+[<--parser : command
+@enduml
diff --git a/docs/diagrams/find-feature/PredicateClassDiagram.puml b/docs/diagrams/find-feature/PredicateClassDiagram.puml
new file mode 100644
index 00000000000..44ed5952e25
--- /dev/null
+++ b/docs/diagrams/find-feature/PredicateClassDiagram.puml
@@ -0,0 +1,21 @@
+@startuml
+!include ../style.puml
+skinparam arrowThickness 1.1
+skinparam arrowColor MODEL_COLOR
+skinparam classBackgroundColor MODEL_COLOR
+
+class "<>\nPredicate" as Predicate
+class XYZContainsKeywordsPredicate
+class PersonContainsKeywordsPredicate
+class FindComand
+note left of XYZContainsKeywordsPredicate
+ XYZContainsKeywordsPredicate =
+ AddressContainsKeywordsPredicate,
+ NameContainsKeywordsPredicate, etc.
+end note
+
+XYZContainsKeywordsPredicate ..|> Predicate
+PersonContainsKeywordsPredicate --> "*" Predicate : test >
+FindComand --> "1" PersonContainsKeywordsPredicate : contains >
+
+@enduml
diff --git a/docs/diagrams/insurance-feature/ExecuteInsuranceActivityDiagram.puml b/docs/diagrams/insurance-feature/ExecuteInsuranceActivityDiagram.puml
new file mode 100644
index 00000000000..9c98cdabde2
--- /dev/null
+++ b/docs/diagrams/insurance-feature/ExecuteInsuranceActivityDiagram.puml
@@ -0,0 +1,25 @@
+@startuml
+skin rose
+skinparam ActivityFontSize 15
+skinparam ArrowFontSize 12
+start
+:User provides index of the targeted
+customer in the displayed list;
+
+if () then
+ :User provides insurances to add to and/or \ndelete from the targeted customer;
+ if () then
+ :System update insurances of targeted customer;
+ if () then
+ :System saves updated customer to Model;
+ else ([updated customer's insurance set is invalid])
+ stop
+ endif
+ stop
+ else ([insurances provided are invalid])
+ stop
+ endif
+else ([index provided is invalid])
+ stop
+endif
+@enduml
diff --git a/docs/diagrams/insurance-feature/ExecuteInsuranceSequenceDiagram.puml b/docs/diagrams/insurance-feature/ExecuteInsuranceSequenceDiagram.puml
new file mode 100644
index 00000000000..a5b95dc8f30
--- /dev/null
+++ b/docs/diagrams/insurance-feature/ExecuteInsuranceSequenceDiagram.puml
@@ -0,0 +1,62 @@
+@startuml
+!include ../style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ": InsuranceCommand" as command LOGIC_COLOR
+participant "r: CommandResult" as result LOGIC_COLOR
+participant ": UpdatePersonInsuranceDescriptor" as descriptor LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant "m: Model" as model MODEL_COLOR
+participant "Person" as personClass <> MODEL_COLOR
+participant ": Person" as person MODEL_COLOR
+end box
+
+[-> command : execute(m)
+|||
+command -> model : m.getFilteredPersonList()
+return personList
+
+opt not in range of personList
+[<--command : throw CommandException
+end
+|||
+command -> descriptor : hasCommonInsurance()
+return hasCommonInsurance
+
+opt hasCommonInsurance
+[<--command : throws CommandException
+end
+|||
+command -> personClass : createPersonWithUpdatedInsurances(personToUpdate, insurancesToAdd, insurancesToDelete)
+activate personClass
+create person
+personClass -> person :
+activate person
+return updatedPerson
+
+return updatedPerson
+|||
+opt updatedPerson's number of insurance \nexceeds maximum insurances allowed
+[<--command : throws CommandException
+end
+|||
+command -> model : setPerson(personToUpdate, updatedPerson)
+|||
+create result
+command -> result
+activate result
+return r
+
+
+
+
+
+
+
+
+
+
+[<-- command : r
+@enduml
diff --git a/docs/diagrams/insurance-feature/InsuranceSequence.puml b/docs/diagrams/insurance-feature/InsuranceSequence.puml
new file mode 100644
index 00000000000..64926b3f165
--- /dev/null
+++ b/docs/diagrams/insurance-feature/InsuranceSequence.puml
@@ -0,0 +1,58 @@
+@startuml
+!include ../style.puml
+skinparam ArrowFontStyle plain
+
+box Logic LOGIC_COLOR_T1
+participant ": LogicManager" as manager LOGIC_COLOR
+participant ": AddressBookParser" as parser LOGIC_COLOR
+participant ": InsuranceCommandParser" as insuranceParser LOGIC_COLOR
+participant "i: InsuranceCommand" as command LOGIC_COLOR
+participant "r: CommandResult" as result LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant "m: Model" as model MODEL_COLOR
+end box
+
+[-> manager : execute("insurance 1 \nai/AIA di/Great Eastern)
+activate manager
+
+manager -> parser : parseCommand("insurance 1 \nai/AIA di/Great Eastern)
+activate parser
+
+create insuranceParser
+parser -> insuranceParser
+activate insuranceParser
+return
+|||
+parser -> insuranceParser : parse(1 ai/AIA di/Great Eastern)
+activate insuranceParser
+
+create command
+insuranceParser -> command
+activate command
+return i
+
+return i
+insuranceParser -[hidden]-> parser
+destroy insuranceParser
+
+return i
+
+manager -> command : execute(m)
+activate command
+command -> model : setPerson(toUpdatePerson, UpdatedPerson)
+activate model
+return
+|||
+
+create result
+command -> result
+activate result
+return r
+
+return r
+return r
+
+
+@enduml
diff --git a/docs/diagrams/insurance-feature/ParseInsuranceSequenceDiagram.puml b/docs/diagrams/insurance-feature/ParseInsuranceSequenceDiagram.puml
new file mode 100644
index 00000000000..0d5c8ed7f97
--- /dev/null
+++ b/docs/diagrams/insurance-feature/ParseInsuranceSequenceDiagram.puml
@@ -0,0 +1,35 @@
+@startuml
+!include ../style.puml
+
+
+participant ": InsuranceCommandParser" as parser LOGIC_COLOR
+participant "d: UpdatePersonInsuranceDescriptor" as descriptor LOGIC_COLOR
+participant "c: InsuranceCommand" as command LOGIC_COLOR
+
+[-> parser : parse("1 ai/car insurance\n di/health insurance")
+|||
+ref over parser : parse arguments
+note right : Parsing of index, insurances to update and delete \nis done here and is omitted
+|||
+create descriptor
+parser -> descriptor
+note right : contains the insurances \nto add and delete from customer
+activate descriptor
+|||
+return d
+|||
+parser -> descriptor : hasInsuranceToUpdate()
+return
+|||
+opt over parser : no insurance to update
+[<-- parser : throwParserException
+end
+|||
+create command
+parser -> command : new InsuranceCommand(1, descriptor)
+activate command
+|||
+return c
+
+[<--parser : c
+@enduml
diff --git a/docs/diagrams/insurance-feature/PersonInsuranceClassDiagram.puml b/docs/diagrams/insurance-feature/PersonInsuranceClassDiagram.puml
new file mode 100644
index 00000000000..2a0a7b2bb32
--- /dev/null
+++ b/docs/diagrams/insurance-feature/PersonInsuranceClassDiagram.puml
@@ -0,0 +1,18 @@
+@startuml
+!include ../style.puml
+skinparam arrowThickness 1.1
+skinparam arrowColor MODEL_COLOR
+skinparam classBackgroundColor MODEL_COLOR
+
+class Insurance
+class Person
+note right of Person
+ Other attribute classes such as
+ Name , Phone , Email ...
+ are ommited here as they are irrelevant
+ in the current context.
+end note
+
+Person -->"*" Insurance
+
+@enduml
diff --git a/docs/diagrams/priority-feature/ParseIndexAndArgumentsSequenceDiagram.puml b/docs/diagrams/priority-feature/ParseIndexAndArgumentsSequenceDiagram.puml
new file mode 100644
index 00000000000..f38b40e7f08
--- /dev/null
+++ b/docs/diagrams/priority-feature/ParseIndexAndArgumentsSequenceDiagram.puml
@@ -0,0 +1,27 @@
+@startuml
+!include ../style.puml
+
+mainframe sd parse index and level
+
+participant ":PriorityCommandParser" as PriorityCommandParser LOGIC_COLOR
+participant "ParserUtil" as ParserUtilClass <> LOGIC_COLOR
+participant "p:Priority" as Priority LOGIC_COLOR
+
+PriorityCommandParser -> ParserUtilClass: parseIndex("1")
+opt invalid index
+ ParserUtilClass --> PriorityCommandParser: throws ParseException
+ PriorityCommandParser -->[: throws ParseException
+end
+ ParserUtilClass --> PriorityCommandParser: index
+ PriorityCommandParser -> ParserUtilClass: parsePriority("high")
+opt invalid priority
+ ParserUtilClass --> PriorityCommandParser: throws ParseException
+ PriorityCommandParser -->[: throws ParseException
+end
+ create Priority
+ ParserUtilClass -> Priority : Priority("high")
+ activate Priority
+ return p
+ ParserUtilClass --> PriorityCommandParser : p
+
+@enduml
diff --git a/docs/diagrams/priority-feature/PriorityClassDiagram.puml b/docs/diagrams/priority-feature/PriorityClassDiagram.puml
new file mode 100644
index 00000000000..ea238f041d5
--- /dev/null
+++ b/docs/diagrams/priority-feature/PriorityClassDiagram.puml
@@ -0,0 +1,34 @@
+@startuml
+!include ../style.puml
+skinparam arrowThickness 1.1
+skinparam arrowColor MODEL_COLOR
+skinparam classBackgroundColor MODEL_COLOR
+
+Class Person
+note left of Person
+ A person is associated to other attribute classes such as
+ Name , Phone , Email ...
+ which are ommited here as they are irrelevant
+ when discussing about priority.
+end note
+
+Class Level <> {
+HIGH
+MEDIUM
+LOW
+NONE
+}
+
+Class Priority {
+level: Level
+}
+
+Person --> "1" Priority
+
+show Priority members
+hide Priority methods
+
+show Level members
+hide Level methods
+
+@enduml
diff --git a/docs/diagrams/priority-feature/PriorityCommandClassDiagram.puml b/docs/diagrams/priority-feature/PriorityCommandClassDiagram.puml
new file mode 100644
index 00000000000..3649c9ab208
--- /dev/null
+++ b/docs/diagrams/priority-feature/PriorityCommandClassDiagram.puml
@@ -0,0 +1,17 @@
+@startuml
+!include ../style.puml
+skinparam arrowThickness 1.1
+skinparam arrowColor MODEL_COLOR
+skinparam classBackgroundColor MODEL_COLOR
+
+Class PriorityCommand {
+index: Index
+priority: Priority
+execute(m: Model): CommandResult
+checkIsOldPriority(personToUpdate: Person)
+}
+
+show PriorityCommand members
+show PriorityCommand methods
+
+@enduml
diff --git a/docs/diagrams/priority-feature/PriorityCommandParserSequenceDiagram.puml b/docs/diagrams/priority-feature/PriorityCommandParserSequenceDiagram.puml
new file mode 100644
index 00000000000..ff69c09bc1a
--- /dev/null
+++ b/docs/diagrams/priority-feature/PriorityCommandParserSequenceDiagram.puml
@@ -0,0 +1,28 @@
+'@startuml
+!include ../style.puml
+
+participant ":PriorityCommandParser" as PriorityCommandParser LOGIC_COLOR
+participant ":PriorityCommand" as PriorityCommand LOGIC_COLOR
+
+[-> PriorityCommandParser : parse("1 high")
+
+ref over PriorityCommandParser
+parse index and priority
+end
+
+opt valid index and priority
+ create PriorityCommand
+ PriorityCommandParser -> PriorityCommand : PriorityCommand(1, p)
+ activate PriorityCommand
+ note left
+ A Priority object, p, is created
+ from the parsing action above
+ if the provided index and priority are valid
+ end note
+ return command
+ PriorityCommandParser -->[ : command
+end
+
+@enduml
+
+
diff --git a/docs/diagrams/priority-feature/PriorityCommandSequenceDiagram.puml b/docs/diagrams/priority-feature/PriorityCommandSequenceDiagram.puml
new file mode 100644
index 00000000000..95fb3378cef
--- /dev/null
+++ b/docs/diagrams/priority-feature/PriorityCommandSequenceDiagram.puml
@@ -0,0 +1,44 @@
+@startuml
+!include ../style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":PriorityCommand" as PriorityCommand LOGIC_COLOR
+participant ":CommandResult" as CommandResult LOGIC_COLOR
+participant "CommandUtil" as CommandUtilClass <> LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant "m:Model" as Model MODEL_COLOR
+participant "Person" as PersonClass <> MODEL_COLOR
+participant ":Person" as Person MODEL_COLOR
+end box
+
+[-> PriorityCommand : execute(m)
+PriorityCommand -> CommandUtilClass : getPersonAtIndex(m, index)
+CommandUtilClass --> PriorityCommand : personToUpdate
+|||
+PriorityCommand -> PersonClass :createPersonWithUpdatedPriority(personToUpdate, priority)
+create Person
+PersonClass -> Person
+activate Person
+return updatedPerson
+PersonClass --> PriorityCommand : updatedPerson
+
+|||
+PriorityCommand -> PriorityCommand : checkIsOldPriority(personToUpdate)
+
+|||
+opt priority provided is same as the old priority
+PriorityCommand -->[ : throws CommandException
+end
+
+PriorityCommand -> Model : setPerson(personToUpdate, updatedPerson)
+|||
+
+create CommandResult
+PriorityCommand -> CommandResult : CommandResult(feedback)
+activate CommandResult
+return command result
+PriorityCommand -->[ : command result
+
+@enduml
diff --git a/docs/diagrams/priority-feature/PriorityFeatureSequenceDiagram.puml b/docs/diagrams/priority-feature/PriorityFeatureSequenceDiagram.puml
new file mode 100644
index 00000000000..70821a0a33d
--- /dev/null
+++ b/docs/diagrams/priority-feature/PriorityFeatureSequenceDiagram.puml
@@ -0,0 +1,62 @@
+@startuml
+!include ../style.puml
+skinparam ArrowFontStyle plain
+
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR
+participant ":PriorityCommandParser" as PriorityCommandParser LOGIC_COLOR
+participant "p:PriorityCommand" as PriorityCommand LOGIC_COLOR
+participant "result:CommandResult" as CommandResult LOGIC_COLOR
+
+[-> LogicManager : execute("priority 1 high")
+activate LogicManager
+
+LogicManager -> AddressBookParser : parseCommand("priority 1 high")
+activate AddressBookParser
+
+create PriorityCommandParser
+AddressBookParser -> PriorityCommandParser
+activate PriorityCommandParser
+
+PriorityCommandParser --> AddressBookParser
+deactivate PriorityCommandParser
+
+AddressBookParser -> PriorityCommandParser : parse("1 high")
+activate PriorityCommandParser
+
+create PriorityCommand
+PriorityCommandParser -> PriorityCommand
+activate PriorityCommand
+
+PriorityCommand --> PriorityCommandParser : p
+deactivate PriorityCommand
+
+PriorityCommandParser --> AddressBookParser : p
+deactivate PriorityCommandParser
+'Hidden arrow to position the destroy marker below the end of the activation bar.
+PriorityCommandParser -[hidden]-> AddressBookParser
+destroy PriorityCommandParser
+
+AddressBookParser --> LogicManager : p
+deactivate AddressBookParser
+
+LogicManager -> PriorityCommand : execute()
+activate PriorityCommand
+
+
+create CommandResult
+PriorityCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> PriorityCommand : result
+deactivate CommandResult
+
+PriorityCommand --> LogicManager : result
+deactivate PriorityCommand
+'Hidden arrow to position the destroy marker below the end of the activation bar.
+PriorityCommand -[hidden]-> LogicManager
+destroy PriorityCommand
+
+[<--LogicManager : result
+deactivate LogicManager
+@enduml
diff --git a/docs/diagrams/priority-feature/UpdatePriorityActivityDiagram.puml b/docs/diagrams/priority-feature/UpdatePriorityActivityDiagram.puml
new file mode 100644
index 00000000000..839ce0c5955
--- /dev/null
+++ b/docs/diagrams/priority-feature/UpdatePriorityActivityDiagram.puml
@@ -0,0 +1,20 @@
+@startuml
+skin rose
+skinparam ActivityFontSize 13
+skinparam ArrowFontSize 12
+
+start
+:User provides the priority to assign to a person;
+
+if () then
+ :Update priority of the target person ;
+ if () then
+ :Save updated person to model;
+ else ([updated person's priority is unchanged])
+ stop
+ endif
+ stop
+else ([provided priority is invalid])
+ stop
+endif
+@enduml
diff --git a/docs/diagrams/add-remark/ParserClass.puml b/docs/diagrams/remark-feature/ParserClass.puml
similarity index 100%
rename from docs/diagrams/add-remark/ParserClass.puml
rename to docs/diagrams/remark-feature/ParserClass.puml
diff --git a/docs/diagrams/add-remark/RemarkClass.puml b/docs/diagrams/remark-feature/RemarkClass.puml
similarity index 81%
rename from docs/diagrams/add-remark/RemarkClass.puml
rename to docs/diagrams/remark-feature/RemarkClass.puml
index 019c1ecbbf1..661ce15ea44 100644
--- a/docs/diagrams/add-remark/RemarkClass.puml
+++ b/docs/diagrams/remark-feature/RemarkClass.puml
@@ -8,8 +8,8 @@ Class "{abstract}\nCommand" as Command {
Class RemarkCommand {
+COMMAND_WORD: String
+MESSAGE_USAGE: String
- +MESSAGE_NOT_IMPLEMENTED_YET: String
- +execute(Model): CommandResult
+ +MESSAGE_ADD_REMARK_SUCCESS: String
+ +MESSAGE_DELETE_REMARK_SUCCESS: String
}
Class CommandException
diff --git a/docs/diagrams/remark-feature/RemarkCommandParserSequenceDiagram.puml b/docs/diagrams/remark-feature/RemarkCommandParserSequenceDiagram.puml
new file mode 100644
index 00000000000..3d03b7f36be
--- /dev/null
+++ b/docs/diagrams/remark-feature/RemarkCommandParserSequenceDiagram.puml
@@ -0,0 +1,36 @@
+@startuml
+!include ../style.puml
+
+participant ":RemarkCommandParser" as RemarkCommandParser LOGIC_COLOR
+participant "e:Remark" as emptyRemark MODEL_COLOR
+participant "r:Remark" as remark MODEL_COLOR
+participant ":RemarkCommand" as RemarkCommand LOGIC_COLOR
+
+[-> RemarkCommandParser : parse("2 he likes pizza")
+opt Invalid index
+[<-- RemarkCommandParser : throwParserException
+end
+|||
+alt empty argument
+ create emptyRemark
+ RemarkCommandParser --> emptyRemark : Remark("")
+ activate emptyRemark
+ return e
+|||
+else
+ create remark
+ RemarkCommandParser --> remark : Remark(argument)
+ activate remark
+ return r
+end
+|||
+create RemarkCommand
+RemarkCommandParser --> RemarkCommand
+activate RemarkCommand
+|||
+return command
+
+[<--RemarkCommandParser : command
+
+
+@enduml
diff --git a/docs/diagrams/style.puml b/docs/diagrams/style.puml
index f7d7347ae84..6b82d6fc6a3 100644
--- a/docs/diagrams/style.puml
+++ b/docs/diagrams/style.puml
@@ -19,7 +19,7 @@
!define LOGIC_COLOR_T3 #1616B0
!define LOGIC_COLOR_T4 #101086
-!define MODEL_COLOR #9D0012
+!define MODEL_COLOR #E36B78
!define MODEL_COLOR_T1 #F97181
!define MODEL_COLOR_T2 #E41F36
!define MODEL_COLOR_T3 #7B000E
diff --git a/docs/diagrams/tag-feature/ExecuteActivityDiagram.puml b/docs/diagrams/tag-feature/ExecuteActivityDiagram.puml
new file mode 100644
index 00000000000..85e7f3ad008
--- /dev/null
+++ b/docs/diagrams/tag-feature/ExecuteActivityDiagram.puml
@@ -0,0 +1,29 @@
+@startuml
+skin rose
+skinparam ActivityFontSize 15
+skinparam ArrowFontSize 12
+start
+:User provides index of the targeted
+customer in the displayed list;
+
+if () then
+ :User provides tags to add to and/or \ndelete from the targeted customer;
+
+ 'Since the beta syntax does not support placing the condition outside the
+ 'diamond we place it as the true branch instead.
+ if () then
+ :System update tags of targeted customer;
+ if () then
+ :System saves updated customer to Model;
+ else ([updated customer's tag set is not valid])
+ stop
+ endif
+ stop
+ else ([tags provided is not valid])
+ stop
+ endif
+else ([index provided is not valid])
+ stop
+endif
+
+@enduml
diff --git a/docs/diagrams/tag-feature/ExecuteSequenceDiagram.puml b/docs/diagrams/tag-feature/ExecuteSequenceDiagram.puml
new file mode 100644
index 00000000000..5d7287d84a8
--- /dev/null
+++ b/docs/diagrams/tag-feature/ExecuteSequenceDiagram.puml
@@ -0,0 +1,36 @@
+@startuml
+!include ../style.puml
+
+box Logic LOGIC_COLOR_T1
+participant ":TagCommand" as TagCommand LOGIC_COLOR
+participant "r:CommandResult" as CommandResult LOGIC_COLOR
+end box
+
+box Model MODEL_COLOR_T1
+participant "m:Model" as Model MODEL_COLOR
+participant "Person" as PersonClass <> MODEL_COLOR
+end box
+
+[-> TagCommand: execute(m)
+
+TagCommand -> TagCommand: verifyCommandExecutable(m)
+|||
+ref over TagCommand, Model: retrieve information required\n(i.e. personToUpdate, tagsToAdd, and tagsToDelete)
+|||
+
+TagCommand -> PersonClass: createPersonWithUpdatedTags(personToUpdate, tagsToAdd, tagsToDelete)
+activate PersonClass
+return updatedPerson
+|||
+ref over TagCommand: verify updatedPerson is valid
+|||
+TagCommand -> Model: setPerson(personToUpdate, updatedPerson)
+|||
+|||
+create CommandResult
+TagCommand -> CommandResult
+activate CommandResult
+return
+
+[<-- TagCommand: r
+@enduml
diff --git a/docs/diagrams/tag-feature/ParseDetailsSequenceDiagram.puml b/docs/diagrams/tag-feature/ParseDetailsSequenceDiagram.puml
new file mode 100644
index 00000000000..91313300510
--- /dev/null
+++ b/docs/diagrams/tag-feature/ParseDetailsSequenceDiagram.puml
@@ -0,0 +1,32 @@
+@startuml
+!include ../style.puml
+
+mainframe sd parse arguments
+
+participant ":TagCommandParser" as TagCommandParser LOGIC_COLOR
+participant ":ParserUtil" as ParserUtil LOGIC_COLOR
+
+TagCommandParser -> ParserUtil: <> \nparseIndex("1")
+alt valid index
+ ParserUtil --> TagCommandParser: index
+else
+ ParserUtil --> TagCommandParser: throws ParseException
+ deactivate ParserUtil
+end
+
+|||
+TagCommandParser -> TagCommandParser: parseTags("tall", "handsome")
+alt all tags valid
+ TagCommandParser --> TagCommandParser: tagsToAdd
+else
+ TagCommandParser --> TagCommandParser: throws ParseException
+end
+
+|||
+TagCommandParser -> TagCommandParser: parseTags("short")
+alt all tags valid
+ TagCommandParser --> TagCommandParser: tagsToDelete
+else
+ TagCommandParser --> TagCommandParser: throws ParseException
+end
+@enduml
diff --git a/docs/diagrams/tag-feature/ParseSequenceDiagram.puml b/docs/diagrams/tag-feature/ParseSequenceDiagram.puml
new file mode 100644
index 00000000000..ceb74e7caae
--- /dev/null
+++ b/docs/diagrams/tag-feature/ParseSequenceDiagram.puml
@@ -0,0 +1,35 @@
+@startuml
+!include ../style.puml
+
+
+participant ":TagCommandParser" as TagCommandParser LOGIC_COLOR
+participant "descriptor:UpdatePersonTagsDescriptor" as UpdatePersonTagsDescriptor LOGIC_COLOR
+participant "t:TagCommand" as TagCommand LOGIC_COLOR
+
+[-> TagCommandParser : parse("1 at/tall \ndt/short at/handsome")
+
+|||
+
+TagCommandParser -> TagCommandParser: parseArguments("1 at/tall dt/short at/handsome")
+note right : Parses the arguments into **index**,\n**tagsToAdd** and **tagsToDelete**.
+|||
+
+create UpdatePersonTagsDescriptor
+TagCommandParser -> UpdatePersonTagsDescriptor
+note right : **descriptor** is constructed\n using **tagsToAdd**\n and **tagsToDelete**.
+activate UpdatePersonTagsDescriptor
+return
+
+|||
+
+TagCommandParser -> TagCommandParser: verifyHasTagToUpdate(descriptor)
+
+|||
+create TagCommand
+TagCommandParser -> TagCommand : TagCommand(index, descriptor)
+
+activate TagCommand
+return
+[<--TagCommandParser : t
+
+@enduml
diff --git a/docs/diagrams/tag-feature/PersonClassDiagram.puml b/docs/diagrams/tag-feature/PersonClassDiagram.puml
new file mode 100644
index 00000000000..903e7b26f83
--- /dev/null
+++ b/docs/diagrams/tag-feature/PersonClassDiagram.puml
@@ -0,0 +1,18 @@
+@startuml
+!include ../style.puml
+skinparam arrowThickness 1.1
+skinparam arrowColor MODEL_COLOR
+skinparam classBackgroundColor MODEL_COLOR
+
+Class Person
+note right of Person
+ A person is associated to other attribute classes such as
+ Name , Phone , Email ...
+ which are ommited here as they are irrelevant
+ when discussing the tag feature.
+end note
+
+Class Tag
+
+Person --> "*" Tag
+@enduml
diff --git a/docs/diagrams/tag-feature/TagCommandClassDiagram.puml b/docs/diagrams/tag-feature/TagCommandClassDiagram.puml
new file mode 100644
index 00000000000..62c4c253185
--- /dev/null
+++ b/docs/diagrams/tag-feature/TagCommandClassDiagram.puml
@@ -0,0 +1,17 @@
+@startuml
+!include ../style.puml
+skinparam arrowThickness 1.1
+skinparam arrowColor LOGIC_COLOR
+skinparam classBackgroundColor LOGIC_COLOR
+
+Class TagCommand
+Class Index
+Class UpdatePersonTagsDescriptor
+Class Tag
+
+TagCommand --> "1" Index
+TagCommand --> "1" UpdatePersonTagsDescriptor
+UpdatePersonTagsDescriptor --> "~* tagsToAdd" Tag
+UpdatePersonTagsDescriptor --> "~* tagsToDelete" Tag
+
+@enduml
diff --git a/docs/diagrams/tag-feature/TagSequenceDiagram.puml b/docs/diagrams/tag-feature/TagSequenceDiagram.puml
new file mode 100644
index 00000000000..f8bd921a57b
--- /dev/null
+++ b/docs/diagrams/tag-feature/TagSequenceDiagram.puml
@@ -0,0 +1,62 @@
+@startuml
+!include ../style.puml
+skinparam ArrowFontStyle plain
+
+participant ":LogicManager" as LogicManager LOGIC_COLOR
+participant ":AddressBookParser" as AddressBookParser LOGIC_COLOR
+participant ":TagCommandParser" as TagCommandParser LOGIC_COLOR
+participant "t:TagCommand" as TagCommand LOGIC_COLOR
+participant "r:CommandResult" as CommandResult LOGIC_COLOR
+
+[-> LogicManager : execute("tag 1 at/tall \ndt/short at/handsome")
+activate LogicManager
+
+LogicManager -> AddressBookParser : parseCommand("tag 1 at/tall \ndt/short at/handsome")
+activate AddressBookParser
+
+create TagCommandParser
+AddressBookParser -> TagCommandParser
+activate TagCommandParser
+
+TagCommandParser --> AddressBookParser
+deactivate TagCommandParser
+
+AddressBookParser -> TagCommandParser : parse("1 at/tall \ndt/short at/handsome")
+activate TagCommandParser
+
+create TagCommand
+TagCommandParser -> TagCommand
+activate TagCommand
+
+TagCommand --> TagCommandParser
+deactivate TagCommand
+
+TagCommandParser --> AddressBookParser : t
+deactivate TagCommandParser
+'Hidden arrow to position the destroy marker below the end of the activation bar.
+TagCommandParser -[hidden]-> AddressBookParser
+destroy TagCommandParser
+
+AddressBookParser --> LogicManager : t
+deactivate AddressBookParser
+
+LogicManager -> TagCommand : execute()
+activate TagCommand
+
+
+create CommandResult
+TagCommand -> CommandResult
+activate CommandResult
+
+CommandResult --> TagCommand
+deactivate CommandResult
+
+TagCommand --> LogicManager : r
+deactivate TagCommand
+'Hidden arrow to position the destroy marker below the end of the activation bar.
+TagCommand -[hidden]-> LogicManager
+destroy TagCommand
+
+[<--LogicManager : r
+deactivate LogicManager
+@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 e186f7ba096..00000000000
Binary files a/docs/images/DeleteSequenceDiagram.png and /dev/null differ
diff --git a/docs/images/InsuranceCommandExample/InsuranceAfter.png b/docs/images/InsuranceCommandExample/InsuranceAfter.png
new file mode 100644
index 00000000000..ad9f76b692b
Binary files /dev/null and b/docs/images/InsuranceCommandExample/InsuranceAfter.png differ
diff --git a/docs/images/InsuranceCommandExample/InsuranceBefore.png b/docs/images/InsuranceCommandExample/InsuranceBefore.png
new file mode 100644
index 00000000000..0a9b1479074
Binary files /dev/null and b/docs/images/InsuranceCommandExample/InsuranceBefore.png differ
diff --git a/docs/images/LogicClassDiagram.png b/docs/images/LogicClassDiagram.png
deleted file mode 100644
index e3b784310fe..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 edfd1ff7897..00000000000
Binary files a/docs/images/ParserClasses.png and /dev/null differ
diff --git a/docs/images/SeEduLogo.png b/docs/images/SeEduLogo.png
deleted file mode 100644
index 31ad50b6f88..00000000000
Binary files a/docs/images/SeEduLogo.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..a51cc95e196 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/UiWithDescription.png b/docs/images/UiWithDescription.png
new file mode 100644
index 00000000000..52ca3813ec5
Binary files /dev/null and b/docs/images/UiWithDescription.png 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/UndoSequenceDiagram.png b/docs/images/UndoSequenceDiagram.png
deleted file mode 100644
index c7a7e637266..00000000000
Binary files a/docs/images/UndoSequenceDiagram.png and /dev/null differ
diff --git a/docs/images/add-command-examples/example1.png b/docs/images/add-command-examples/example1.png
new file mode 100644
index 00000000000..efcdcd59ad1
Binary files /dev/null and b/docs/images/add-command-examples/example1.png differ
diff --git a/docs/images/add-command-examples/example2.png b/docs/images/add-command-examples/example2.png
new file mode 100644
index 00000000000..079a93e5e14
Binary files /dev/null and b/docs/images/add-command-examples/example2.png differ
diff --git a/docs/images/address_book.png b/docs/images/address_book.png
new file mode 100644
index 00000000000..0d75692eeed
Binary files /dev/null and b/docs/images/address_book.png differ
diff --git a/docs/images/appointment-command-examples/AddApptAfter.png b/docs/images/appointment-command-examples/AddApptAfter.png
new file mode 100644
index 00000000000..dbcb191ec06
Binary files /dev/null and b/docs/images/appointment-command-examples/AddApptAfter.png differ
diff --git a/docs/images/appointment-command-examples/DeleteApptAfter.png b/docs/images/appointment-command-examples/DeleteApptAfter.png
new file mode 100644
index 00000000000..decdbf23d69
Binary files /dev/null and b/docs/images/appointment-command-examples/DeleteApptAfter.png differ
diff --git a/docs/images/appointment-command-examples/DeleteApptBefore.png b/docs/images/appointment-command-examples/DeleteApptBefore.png
new file mode 100644
index 00000000000..63f6ea7b5d4
Binary files /dev/null and b/docs/images/appointment-command-examples/DeleteApptBefore.png differ
diff --git a/docs/images/appointment-command-examples/MarkApptAfter.png b/docs/images/appointment-command-examples/MarkApptAfter.png
new file mode 100644
index 00000000000..1f28cf908e3
Binary files /dev/null and b/docs/images/appointment-command-examples/MarkApptAfter.png differ
diff --git a/docs/images/delete-command-example/delete-after.png b/docs/images/delete-command-example/delete-after.png
new file mode 100644
index 00000000000..e43aeaa7f65
Binary files /dev/null and b/docs/images/delete-command-example/delete-after.png differ
diff --git a/docs/images/delete-command-example/delete-before.png b/docs/images/delete-command-example/delete-before.png
new file mode 100644
index 00000000000..a4883bd70f1
Binary files /dev/null and b/docs/images/delete-command-example/delete-before.png differ
diff --git a/docs/images/edit-command-example/edit-after.png b/docs/images/edit-command-example/edit-after.png
new file mode 100644
index 00000000000..424bee0693d
Binary files /dev/null and b/docs/images/edit-command-example/edit-after.png differ
diff --git a/docs/images/edit-command-example/edit-before.png b/docs/images/edit-command-example/edit-before.png
new file mode 100644
index 00000000000..54cea132c64
Binary files /dev/null and b/docs/images/edit-command-example/edit-before.png differ
diff --git a/docs/images/find-command-examples/find example 2.png b/docs/images/find-command-examples/find example 2.png
new file mode 100644
index 00000000000..d0b6539aa3d
Binary files /dev/null and b/docs/images/find-command-examples/find example 2.png differ
diff --git a/docs/images/find-command-examples/find example.png b/docs/images/find-command-examples/find example.png
new file mode 100644
index 00000000000..23a10544105
Binary files /dev/null and b/docs/images/find-command-examples/find example.png 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/github-icon.png b/docs/images/github-icon.png
deleted file mode 100755
index 8b25551a979..00000000000
Binary files a/docs/images/github-icon.png and /dev/null differ
diff --git a/docs/images/helpMessage.png b/docs/images/helpMessage.png
deleted file mode 100644
index b1f70470137..00000000000
Binary files a/docs/images/helpMessage.png and /dev/null differ
diff --git a/docs/images/johndoe.png b/docs/images/johndoe.png
deleted file mode 100644
index 1ce7ce16dc8..00000000000
Binary files a/docs/images/johndoe.png and /dev/null differ
diff --git a/docs/images/jweewee.png b/docs/images/jweewee.png
new file mode 100644
index 00000000000..bf485d1e946
Binary files /dev/null and b/docs/images/jweewee.png differ
diff --git a/docs/images/lamjiufong.png b/docs/images/lamjiufong.png
new file mode 100644
index 00000000000..aff368dc407
Binary files /dev/null and b/docs/images/lamjiufong.png differ
diff --git a/docs/images/priority-command-example/priority-after.png b/docs/images/priority-command-example/priority-after.png
new file mode 100644
index 00000000000..4401baa00b4
Binary files /dev/null and b/docs/images/priority-command-example/priority-after.png differ
diff --git a/docs/images/priority-command-example/priority-before.png b/docs/images/priority-command-example/priority-before.png
new file mode 100644
index 00000000000..010ce8ea708
Binary files /dev/null and b/docs/images/priority-command-example/priority-before.png differ
diff --git a/docs/images/priority-command-example/remove-priority-after.png b/docs/images/priority-command-example/remove-priority-after.png
new file mode 100644
index 00000000000..f6e16779cf3
Binary files /dev/null and b/docs/images/priority-command-example/remove-priority-after.png differ
diff --git a/docs/images/priority-command-example/remove-priority-before.png b/docs/images/priority-command-example/remove-priority-before.png
new file mode 100644
index 00000000000..b9e433e4414
Binary files /dev/null and b/docs/images/priority-command-example/remove-priority-before.png differ
diff --git a/docs/images/remark-command-example/remarkAfter.png b/docs/images/remark-command-example/remarkAfter.png
new file mode 100644
index 00000000000..c65dfc8bae6
Binary files /dev/null and b/docs/images/remark-command-example/remarkAfter.png differ
diff --git a/docs/images/remark-command-example/remarkBefore.png b/docs/images/remark-command-example/remarkBefore.png
new file mode 100644
index 00000000000..475795566e5
Binary files /dev/null and b/docs/images/remark-command-example/remarkBefore.png differ
diff --git a/docs/images/request_access.png b/docs/images/request_access.png
deleted file mode 100644
index 12e8a81bd28..00000000000
Binary files a/docs/images/request_access.png and /dev/null differ
diff --git a/docs/images/songfangyl.png b/docs/images/songfangyl.png
new file mode 100644
index 00000000000..3d61692fb52
Binary files /dev/null and b/docs/images/songfangyl.png differ
diff --git a/docs/images/tag-command-examples/after.png b/docs/images/tag-command-examples/after.png
new file mode 100644
index 00000000000..800918917dd
Binary files /dev/null and b/docs/images/tag-command-examples/after.png differ
diff --git a/docs/images/tag-command-examples/before.png b/docs/images/tag-command-examples/before.png
new file mode 100644
index 00000000000..c04c556516e
Binary files /dev/null and b/docs/images/tag-command-examples/before.png differ
diff --git a/docs/images/tehopanas.png b/docs/images/tehopanas.png
new file mode 100644
index 00000000000..1b6766f43f7
Binary files /dev/null and b/docs/images/tehopanas.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/yucongkoo.png b/docs/images/yucongkoo.png
new file mode 100644
index 00000000000..972fe84ee96
Binary files /dev/null and b/docs/images/yucongkoo.png differ
diff --git a/docs/img.png b/docs/img.png
new file mode 100644
index 00000000000..cc82c691238
Binary files /dev/null and b/docs/img.png differ
diff --git a/docs/index.md b/docs/index.md
index 7601dbaad0d..cc21ff60e42 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -1,17 +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)
+# EzContact
+
+[![CI Status](https://github.com/se-edu/addressbook-level3/workflows/Java%20CI/badge.svg)](https://github.com/AY2324S1-CS2103T-W16-2/tp/actions)
+[![codecov](https://codecov.io/gh/AY2324S1-CS2103T-W16-2/tp/branch/master/graph/badge.svg)](https://app.codecov.io/gh/AY2324S1-CS2103T-W16-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).
+**EzContact is a desktop app made for insurance agents to manage customer details, optimized for usage via Command Line Interface (CLI)
+while still having the benefits of a Graphical User Interface (GUI).
+If you can type fast, EzContact can get your contact management tasks done faster than traditional GUI apps.**
-* 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 EzContact, head over to the [_Quick Start_ section of the **User Guide**](UserGuide.html#quick-start).
+* If you are interested about developing EzContact, the [**Developer Guide**](DeveloperGuide.html) is a good place to start.
**Acknowledgements**
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..0c2cf66d1e0
--- /dev/null
+++ b/docs/site.json
@@ -0,0 +1,29 @@
+{
+ "baseUrl": "",
+ "titlePrefix": "EzContact",
+ "titleSuffix": "AddressBook Level-3",
+ "faviconPath": "images/address_book.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..1074ade42dd
--- /dev/null
+++ b/docs/stylesheets/main.css
@@ -0,0 +1,144 @@
+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;
+ }
+}
+
+h2,
+h3,
+h4,
+h5,
+h6 {
+ color: #e46c0a;
+}
diff --git a/docs/team/johndoe.md b/docs/team/johndoe.md
deleted file mode 100644
index 773a07794e2..00000000000
--- a/docs/team/johndoe.md
+++ /dev/null
@@ -1,46 +0,0 @@
----
-layout: page
-title: John Doe's Project Portfolio Page
----
-
-### Project: AddressBook Level 3
-
-AddressBook - Level 3 is a desktop address book application used for teaching Software Engineering principles. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java, and has about 10 kLoC.
-
-Given below are my contributions to the project.
-
-* **New Feature**: Added the ability to undo/redo previous commands.
- * What it does: allows the user to undo all previous commands one at a time. Preceding undo commands can be reversed by using the redo command.
- * Justification: This feature improves the product significantly because a user can make mistakes in commands and the app should provide a convenient way to rectify them.
- * Highlights: This enhancement affects existing commands and commands to be added in future. It required an in-depth analysis of design alternatives. The implementation too was challenging as it required changes to existing commands.
- * Credits: *{mention here if you reused any code/ideas from elsewhere or if a third-party library is heavily used in the feature so that a reader can make a more accurate judgement of how much effort went into the feature}*
-
-* **New Feature**: Added a history command that allows the user to navigate to previous commands using up/down keys.
-
-* **Code contributed**: [RepoSense link]()
-
-* **Project management**:
- * Managed releases `v1.3` - `v1.5rc` (3 releases) on GitHub
-
-* **Enhancements to existing features**:
- * Updated the GUI color scheme (Pull requests [\#33](), [\#34]())
- * Wrote additional tests for existing features to increase coverage from 88% to 92% (Pull requests [\#36](), [\#38]())
-
-* **Documentation**:
- * User Guide:
- * Added documentation for the features `delete` and `find` [\#72]()
- * Did cosmetic tweaks to existing documentation of features `clear`, `exit`: [\#74]()
- * Developer Guide:
- * Added implementation details of the `delete` feature.
-
-* **Community**:
- * PRs reviewed (with non-trivial review comments): [\#12](), [\#32](), [\#19](), [\#42]()
- * Contributed to forum discussions (examples: [1](), [2](), [3](), [4]())
- * Reported bugs and suggestions for other teams in the class (examples: [1](), [2](), [3]())
- * Some parts of the history feature I added was adopted by several other class mates ([1](), [2]())
-
-* **Tools**:
- * Integrated a third party library (Natty) to the project ([\#42]())
- * Integrated a new Github plugin (CircleCI) to the team repo
-
-* _{you can add/remove categories in the list above}_
diff --git a/docs/team/jweewee.md b/docs/team/jweewee.md
new file mode 100644
index 00000000000..b3a7efc43e3
--- /dev/null
+++ b/docs/team/jweewee.md
@@ -0,0 +1,61 @@
+---
+layout: default.md
+title: "Jweewee's Project Portfolio Page"
+---
+
+### Project EzContact
+
+EzContact is a desktop app made for insurance agents to manage customer details,
+optimized for usage via Command Line Interface (CLI) while still having the benefits of a Graphical User Interface (GUI).
+If you can type fast, EzContact can get your contact management tasks done faster than traditional GUI apps.
+AddressBook Level 3
+
+
+Given below are my contributions to the project.
+
+###### **New Feature**: Appointment, Add Appointment, Delete Appointment, Mark Appointment, Unmark Appointment
+
+* What it does: Allows the user to assign appointment details: Date, Time, Venue, to a customer, and keep track of the number of
+appointments completed with a customers.
+* Justification: This feature significantly enhances the product's suitability for the target user.
+Users can keep track of appointments with customers to gauge the stage in the selling process that a customer is in to maximise
+efficiency and increase their conversion rate of closing customer deals.
+* Highlights:
+ * Analysed design alternatives, from the implementation of `Appointment` and `AppointmentCount`
+ classes, to handling addition/deletion of `Appointment`, marking/unmarking of `AppointmentCount`
+ * Designed the details of what an appointment should contain and its restrictions(Date, Time, Venue) using the
+ `LocalDateTime` class vs `String` representations
+ * Also detailed the UI appearance output of `Appointment`.
+ * The decisions made were mainly driven by ensuring the best user experience
+ of an insurance salesman needing the essential tools to keep track of appointments.
+
+###### **Code contributed**: [RepoSense link](https://nus-cs2103-ay2324s1.github.io/tp-dashboard/?search=jweewee&breakdown=false&sort=groupTitle%20dsc&sortWithin=title&since=2023-09-22&timeframe=commit&mergegroup=&groupSelect=groupByRepos)
+
+###### **Project management**:
+* Have weekly meetings and brainstorm sessions to decide direction of the project.
+* Have some commits and merged some pull requests in every milestone.
+* Have some reviews and comments on teammates' pull requests. [#171](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/171) [#154](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/154)
+* Responses to teammates' comments. [#77](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/77)
+* Discussed project ideation, use cases, target audience revamp
+
+
+
+###### **Documentation**:
+* User Guide:
+ * Added a comprehensive user guide section for the appointment feature which includes:
+ * Appointment details
+ * Addappt feature
+ * Deleteappt feature
+ * Markappt feature
+ * Unmarkappt feature
+ * List feature
+* Developer Guide:
+ * Offers in-depth insights into the implementation details of the Appointment feature,
+ providing developers with a clear understanding of its structure and functionality
+ * Includes a section on design considerations, highlighting the principles and best practices that guided the development of these features.
+ This section promotes code extensibility, maintainability, and adherence to SOLID principles, enhancing the overall quality of the codebase.
+ * Adds use cases for Appointment feature and list feature.
+ * Added user stories for Appointment feature and list feature.
+ * Added the manual testing instructions for the Appointment-related features.
+
+
diff --git a/docs/team/lamjiufong.md b/docs/team/lamjiufong.md
new file mode 100644
index 00000000000..2d98bf2a014
--- /dev/null
+++ b/docs/team/lamjiufong.md
@@ -0,0 +1,59 @@
+---
+layout: default.md
+title: "LamJiuFong's Project Portfolio Page"
+---
+
+### Project: EzContact
+
+EzContact is a desktop app made for insurance agents to manage customer details,
+optimized for usage via Command Line Interface (CLI) while still having the benefits of a Graphical User Interface (GUI).
+If you can type fast, EzContact can get your contact management tasks done faster than traditional GUI apps.
+
+Given below are my contributions to the project.
+
+* **New Feature**: Priority feature.
+ * What it does: Allows users to assign, update or remove priorities from customers in EzContact.
+ * Justification: This feature is well-suited for our target users as now they can classify customers into different
+ priorities levels, allowing them to know who should they find first for a higher chance of sealing the deal.
+ * Highlights:
+ * Users can assign three different priority levels: high, medium and low. They can also choose to update or remove the
+ priorities assigned to users.
+ * The customer list is now sorted according to priority levels, allowing users to have a clear view on who has higher priorities.
+
+
+* **Code contributed**: [RepoSense link](https://nus-cs2103-ay2324s1.github.io/tp-dashboard/?search=LamJiuFong&breakdown=false&sort=groupTitle%20dsc&sortWithin=title&since=2023-09-22&timeframe=commit&mergegroup=&groupSelect=groupByRepos)
+
+
+* **Project management**:
+ * Attend weekly meetings and brainstorm sessions to decide direction of the project.
+ * Have some commits and merged some pull requests in every milestone.
+ * Have some reviews and comments on teammates' pull requests. [#110](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/110), [#114](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/114), [#120](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/120)
+ * Responses to teammates' comments. [#148](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/148)
+ * Set up codecov and project website. [1](https://github.com/nus-cs2103-AY2324S1/tp/commit/705ebf91061fa5b9d4a1449c228687621a3ea1c1), [2](https://github.com/nus-cs2103-AY2324S1/tp/commit/4f3eeea37ef77acc9f89cded9f1d90859e712320), [3](https://github.com/nus-cs2103-AY2324S1/tp/commit/5cc1c387611804cd0d7a591eb14b3b29a95b80e3), [#56](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/56)
+ * Maintain and update project websites. [#198](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/198), [#211](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/211)
+
+
+
+* **Enhancements to existing features**:
+ * Edit feature is not allowed to edit tags, this is to make way for the `tag` feature where users can now add or delete tags without clearing all existing tags.
+ * Users can now add priorities through the `add` feature.
+ * Displayed list is now in sorted form, ordered by priority levels. [#185](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/185)
+ * Improve the overall Ui by adding vectors, product logo and layouts. [#116](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/116), [#193](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/193), [#219](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/219)
+
+
+
+* **Documentation**:
+ * User Guide:
+ * Updated the `Features` section.
+ * Added documentation for the features `delete`, `edit`, `priority`, `clear`, `help`, `exit`.
+ * Added the `FAQ` section.
+ * Developer Guide:
+ * Added the implementation details of the `priority` feature (including all the UML diagrams used in the explanation).
+ * Added use case for deleting a customer(UC03), editing a customer(UC04) and updating priority of a customer(UC06).
+ * Added the manual testing instructions for the `priority` and `edit` features.
+ * Added the Planned Enhancement 4.
+
+
+* **Community**:
+ * Reported 10 bugs in other team during PE-D
+
diff --git a/docs/team/songfangyl.md b/docs/team/songfangyl.md
new file mode 100644
index 00000000000..909342328c0
--- /dev/null
+++ b/docs/team/songfangyl.md
@@ -0,0 +1,56 @@
+---
+ layout: default.md
+ title: "songfangyl's Project Portfolio Page"
+---
+
+### Project EzContact
+
+EzContact is a desktop app made for insurance agents to manage customer details,
+optimized for usage via Command Line Interface (CLI) while still having the benefits of a Graphical User Interface (GUI).
+If you can type fast, EzContact can get your contact management tasks done faster than traditional GUI apps.
+
+
+Given below are my contributions to the project.
+
+###### **New Feature**: Advanced Search Functionality
+
+* What it does: Enhances the search feature, allowing users to perform detailed searches by specifying individual attributes,
+ while also providing the convenience of partial search functionality
+* Justification: This feature significantly enhances the product's suitability for the target user.
+ Users can effortlessly locate specific customers,
+* Highlights: This feature represents a substantial extension of the original functionality,
+ require a considerable amount of code. As such, the code design places a strong emphasis on extensibility and adherence to SOLID principles
+
+###### **New Feature**: Customer Remark Functionality
+
+* What it does: Enable users to record brief notes about specific customers.
+* Justification: This feature enhances the overall product by providing users with a more comprehensive tool. With the remark feature,
+ users gain increased flexibility and utility in their interaction with the application.
+
+###### **Code contributed**: [RepoSense link](https://nus-cs2103-ay2324s1.github.io/tp-dashboard/?search=songfangyl&breakdown=false&sort=groupTitle%20dsc&sortWithin=title&since=2023-09-22&timeframe=commit&mergegroup=&groupSelect=groupByRepos)
+
+###### **Enhancements to existing features**:
+* Standardize output format for delete feature [#73](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/73)
+
+###### **Project management**:
+* Set up weekly meeting.
+* Have some commits and merged some pull requests in every milestone.
+* Have some reviews and comments on teammates' pull requests. [#110](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/110) [#169](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/169)
+* Responses to teammates' comments. [#120](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/120)
+
+###### **Documentation**:
+* User Guide:
+ * Added a comprehensive user guide for the Remark feature.
+ * Included a user guide for the Find feature.
+ * Provide delete feature user guide.
+* Developer Guide:
+ * Offers in-depth insights into the implementation details of the Remark feature,
+ providing developers with a clear understanding of its structure and functionality
+ * Presents comprehensive information on the implementation of the Find feature,
+ including code and architecture details, ensuring developers can effectively utilize this feature.
+ * Includes a section on design considerations, highlighting the principles and best practices that guided the development of these features.
+ This section promotes code extensibility, maintainability, and adherence to SOLID principles, enhancing the overall quality of the codebase.
+ * Adds use cases for remark feature and delete feature.
+ * Added the manual testing instructions for the `find` and `remark` feature.
+
+
diff --git a/docs/team/tehopanas.md b/docs/team/tehopanas.md
new file mode 100644
index 00000000000..30438d86db5
--- /dev/null
+++ b/docs/team/tehopanas.md
@@ -0,0 +1,60 @@
+---
+layout: default.md
+title: "TehOPanas's Project Portfolio Page"
+---
+
+## Project EzContact
+
+EzContact is a desktop app made for insurance agents to manage customer details,
+optimized for usage via Command Line Interface (CLI) while still having the benefits of a Graphical User Interface (GUI).
+If you can type fast, EzContact can get your contact management tasks done faster than traditional GUI apps.
+
+Given below are my contributions to the project.
+
+
+###### **New Feature**:
+* Implemented `Insurance` feature that includes a new `insurance` command and a new attribute to the customers in our EzContact.
+ * What it does: User can assign or remove insurances associated with a customer on EzContact, by providing the name of the insurance.
+ * Justification: Given that our users are insurance agents, our users have to constantly keep track of what insurances each customer
+currently holds, has interest in or plans to cancel. With this feature, our users can efficiently keep track of these information and make the
+correct decisions and moves when interacting with their customers, subsequently increasing their efficiency and chances of securing deals.
+ * Highlights: Implementation of this feature requires in-depth analysis of the model component, different data structures to handle the information
+and handling of user behaviours (e.g. duplicate, conflicting insurances). These analysis determine our design choices from all the possible alternatives.
+
+
+###### **Code contributed**: [RepoSense link](https://nus-cs2103-ay2324s1.github.io/tp-dashboard/?search=tehopanas&breakdown=false&sort=groupTitle%20dsc&sortWithin=title&since=2023-09-22&timeframe=commit&mergegroup=&groupSelect=groupByRepos)
+
+###### **Enhancements to existing features**:
+ * Improve validation of input value for customer's information (e.g. name, phone, email...) [#85](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/85)
+ * Change the definition of duplicate entries, allowing same name, but phone and email must be unique [#191](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/191)
+ * Make command words and prefixes case-insensitive, giving users more flexibility in using the product [#227](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/227)
+
+###### **Documentation**:
+* User Guide:
+ * Added documentation for `insurance` feature [#222](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/222) [#285](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/285)
+ * Standardise formatting and layout of the entire User Guide [#316](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/316)
+ * Added introduction to the User Guide [#222](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/222)
+ * Added examples for `find` and `remark` feature [#245](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/245)
+ * Improve description for `find` feature's documentation [#245](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/245)
+ * Update the glossary [#110](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/110)
+ * Ensure that all parts of the documentation are consistent and correct [#316](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/316)
+* Developer Guide:
+ * Added documentation for `Insurance` feature (i.e. Implementation, design choices, UML diagrams...) [#175](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/175) [#214](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/214)
+ * Standardise the formatting and layout for Developer Guide [#294](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/294/files) [#316](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/316)
+ * Standardise the format for Appendix: Effort, Appendix: Planned Enhancement,Appendix: Instruction for Manual Testing and Acknowledgement [#316](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/316)
+ * Added uses cases for `Insurance` feature
+ * Updated product scope to be focused on insurance agents [#110](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/110)
+ * Update and improve user stories to become more targeted towards insurance agents [#110](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/110) [#69](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/69)
+ * Wrote Appendix: Effort [#316](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/316)
+ * Wrote Appendix: Planned Enhancement,Appendix: Instruction for Manual Testing and Acknowledgement for Insurance feature [#294](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/294/files)
+
+###### **Project management**:
+ * Attend weekly meetings and brainstorm sessions to decide direction of the project.
+ * Have some commits and merged some pull requests in every milestone.
+ * Have some reviews and comments on teammates' pull requests. [#68](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/68) [#33](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/33)
+ * Responses to teammates' comments. [#110](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/110) [#85](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/85)
+
+###### **Community**:
+ * Reported 14 bugs in other team during PE-D [repo](https://github.com/TehOPanas/ped/issues)
+
+
diff --git a/docs/team/yucongkoo.md b/docs/team/yucongkoo.md
new file mode 100644
index 00000000000..27ff9690186
--- /dev/null
+++ b/docs/team/yucongkoo.md
@@ -0,0 +1,73 @@
+---
+ layout: default.md
+ title: "Yucongkoo's Project Portfolio Page"
+---
+
+## Project: EzContact
+
+EzContact is a desktop app made for insurance agents to manage customer details,
+optimized for usage via Command Line Interface (CLI) while still having the benefits of a Graphical User Interface (GUI).
+If you can type fast, EzContact can get your contact management tasks done faster than traditional GUI apps.
+
+Given below are my contributions to the project.
+
+
+* **New Feature**: Added a `tag` command that allows users to update tags of a specific customer in EzContact.
+ * **What it does:** Users can update tags associated to a specific customer, by providing tags to add and tags to delete
+ through the tag command.
+ * **Justification:** This feature significantly improved the product to make it a better fit to our target audience.
+ Through associating descriptive tags to a customer, our users will be more likely to remember their customers and will also be
+ helpful in identifying their customers.
+ * **Highlights:** This enhancement required an in-depth analysis of design alternatives, from choice of data structure to hold the
+ tags, to handling of certain user behaviours such as handling of duplicate tags provided, conflicting tags provided and
+ addition(deletion) of existing(non-existing). The decisions made were mainly driven by ensuring the best user experience.
+ * **Credits:** The association between the `Tag` class and `Person` class was originally implemented in AB-3,
+ there was not much modification done to this association
+
+
+* **Code contributed**: [RepoSense link](https://nus-cs2103-ay2324s1.github.io/tp-dashboard/?search=yucongkoo&breakdown=false&sort=groupTitle%20dsc&sortWithin=title&since=2023-09-22&timeframe=commit&mergegroup=&groupSelect=groupByRepos)
+
+
+
+* **Project management**:
+ * Managed releases `v1.2` - `v1.4` (5 releases) on GitHub
+ * Managed the issue tracker and milestones, ensured team members' timely delivery of deliverables and team tasks
+ * Distributed team tasks on a weekly basis. Hosted the features brainstorming session (Issues [#101](https://github.com/AY2324S1-CS2103T-W16-2/tp/issues/101), [141](https://github.com/AY2324S1-CS2103T-W16-2/tp/issues/141))
+ * Managed bugs reported in PE-D, identified and filtered out duplicate bugs, while assigning each bug to the responsible developer and provided a summary (Issue [#289](https://github.com/AY2324S1-CS2103T-W16-2/tp/issues/289)).
+
+
+
+* **Enhancements to existing features**:
+ * Made the address field of a customer optional (PRs [#68](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/68), [#83](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/83),[#102](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/102), [#197](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/197))
+ * Refactored the `JsonAdaptedPerson` structure, introduced JsonAdaptedAttributes(`JsonAdaptedName`, `JsonAdaptedPhone` etc.) to facilitate
+ conversion between json format and model type(PR [#103](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/103)). Throughout the process of refactoring,discovered and solved a bug in original AB-3 conversion[PR [#204](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/204)].
+ * Created UI componenet `FlowPaneLabel` used to display priority, tags and insurances associated to a customer (PRs [#162](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/162), [#208](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/208)).
+ * Updated the GUI color scheme and overall design (PR [#189](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/189))
+ * Added the functionality of secondary prefix, that is every prefix now has a shorthand representation and a full name representation,
+ while also making the prefixes not case-sensitive (PR [#238](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/238))
+
+
+* **Documentation**:
+ * User Guide:
+ * Updated the `Quick Start` section and created the `UI Layout Description` section.
+ * Drafted the overall structure and formatting for features section to be used across team members.
+ * Added documentation for the features `add`, `tag` and also the `Advanced Features` section.
+ * Added the `Prefix to full-name prefix translation table` section.
+ * Checked the degree of standardization between different sections of the UG.
+ * Tweaked the UG to make it pdf-version friendly.
+ * Developer Guide:
+ * Added the implementation details of the `tag` feature (including all the UML diagrams used in the explanation).
+ * Added use case for adding a customer(UC01) and updating tags of a customer(UC09).
+ * Added the manual testing instructions for the `tag` feature.
+ * Added the Planned Enhancement 1: Deletion of all tags(and insurances) in one command.
+ * Identified and fixed a bug of UML diagram in the `Design - Model Component` section.
+
+
+* **Community**:
+ * PRs reviewed(with non-trivial review comments): [#77](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/77/files/c7bff1718ed1ad97f10a426a26ddbd38c7f9d88f),
+ [#110](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/110/files/21f6f6890e91e85acba38fe4b4c6924dc4dda5e8),
+ [#120-1](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/120/files/14f6a08e3141168016ea041cf8a1c440f69b3d2d), [#120-2](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/120/files/14f6a08e3141168016ea041cf8a1c440f69b3d2d),
+ [#119](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/119/files/737161d463230bae517c56e3e339fc9594c1565e),
+ [#148](https://github.com/AY2324S1-CS2103T-W16-2/tp/pull/148/files/140747789d7932a9f5f9382bd39d56577f6c1bd7)
+ * Contributed to forum discussions (examples: [1](https://github.com/nus-cs2103-AY2324S1/forum/issues/368#issuecomment-1801798119), [2](https://github.com/nus-cs2103-AY2324S1/forum/issues/317), [3](https://github.com/nus-cs2103-AY2324S1/forum/issues/393))
+ * Reported bugs and suggestions for other teams in the class (examples can be found [here](https://github.com/yucongkoo/ped/issues))
diff --git a/docs/tutorials/AddRemark.md b/docs/tutorials/AddRemark.md
index d98f38982e7..8b18f27946b 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,7 +25,7 @@ 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;
@@ -57,13 +60,13 @@ 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. "
@@ -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 {
@@ -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,11 +215,11 @@ 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).
@@ -244,7 +247,7 @@ Simply add the following to [`seedu.address.ui.PersonCard`](https://github.com/s
**`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,7 +311,7 @@ Just add [this one line of code!](https://github.com/se-edu/addressbook-level3/c
**`PersonCard.java`:**
-``` java
+```java
public PersonCard(Person person, int displayedIndex) {
//...
remark.setText(person.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";
diff --git a/docs/tutorials/RemovingFields.md b/docs/tutorials/RemovingFields.md
index f29169bc924..c73bd379e5e 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`
@@ -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;
diff --git a/docs/tutorials/TracingCode.md b/docs/tutorials/TracingCode.md
index 4fb62a83ef6..2b1b0f2d6b7 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,17 +181,17 @@ 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 {
...
@@ -205,25 +211,28 @@ Recall from the User Guide that the `edit` command has the format: `edit INDEX [
* 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.
-
+
* :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.
*
@@ -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/Main.java b/src/main/java/seedu/address/Main.java
index ec1b7958746..eb6216546c8 100644
--- a/src/main/java/seedu/address/Main.java
+++ b/src/main/java/seedu/address/Main.java
@@ -34,7 +34,6 @@ public static void main(String[] args) {
// The warning however, can be safely ignored. Thus, the following log informs
// the user (if looking at the log output) that the said warning appearing in the log
// can be ignored.
-
logger.warning("The warning about Unsupported JavaFX configuration below can be ignored.");
Application.launch(MainApp.class, args);
}
diff --git a/src/main/java/seedu/address/MainApp.java b/src/main/java/seedu/address/MainApp.java
index 3d6bd06d5af..e5273ca3617 100644
--- a/src/main/java/seedu/address/MainApp.java
+++ b/src/main/java/seedu/address/MainApp.java
@@ -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, 4, 1, true);
private static final Logger logger = LogsCenter.getLogger(MainApp.class);
@@ -50,7 +50,6 @@ public class MainApp extends Application {
public void init() throws Exception {
logger.info("=============================[ Initializing AddressBook ]===========================");
super.init();
-
AppParameters appParameters = AppParameters.parse(getParameters());
config = initConfig(appParameters.getConfigPath());
initLogging(config);
diff --git a/src/main/java/seedu/address/commons/util/AppUtil.java b/src/main/java/seedu/address/commons/util/AppUtil.java
index 87aa89c0326..01cc391e31e 100644
--- a/src/main/java/seedu/address/commons/util/AppUtil.java
+++ b/src/main/java/seedu/address/commons/util/AppUtil.java
@@ -15,7 +15,7 @@ public class AppUtil {
*/
public static Image getImage(String imagePath) {
requireNonNull(imagePath);
- return new Image(MainApp.class.getResourceAsStream(imagePath));
+ return new Image(requireNonNull(MainApp.class.getResourceAsStream(imagePath)));
}
/**
diff --git a/src/main/java/seedu/address/commons/util/StringUtil.java b/src/main/java/seedu/address/commons/util/StringUtil.java
index 61cc8c9a1cb..e01302f5f82 100644
--- a/src/main/java/seedu/address/commons/util/StringUtil.java
+++ b/src/main/java/seedu/address/commons/util/StringUtil.java
@@ -65,4 +65,33 @@ public static boolean isNonZeroUnsignedInteger(String s) {
return false;
}
}
+
+ /**
+ * Trims the {@code input} and removes contiguous space between words.
+ */
+ public static String trimContiguousSpaces(String input) {
+ requireNonNull(input);
+ String trimmedInput = input.trim();
+
+ // Split the input string by spaces into an array of words
+ String[] words = trimmedInput.split("\\s+");
+
+ // Join the words back together with single spaces
+ String trimmed = String.join(" ", words);
+
+ return trimmed;
+ }
+
+ /**
+ * Counts the number of characters in {@code input} ignoring spaces.
+ */
+ public static int countCharactersWithoutSpaces(String input) {
+ // Remove spaces from the input string using regular expression
+ String stringWithoutSpaces = input.replaceAll("\\s", "");
+
+ // Count the number of characters in the modified string
+ int charCount = stringWithoutSpaces.length();
+
+ return charCount;
+ }
}
diff --git a/src/main/java/seedu/address/logic/Messages.java b/src/main/java/seedu/address/logic/Messages.java
index ecd32c31b53..b737b14d770 100644
--- a/src/main/java/seedu/address/logic/Messages.java
+++ b/src/main/java/seedu/address/logic/Messages.java
@@ -1,5 +1,8 @@
package seedu.address.logic;
+import static seedu.address.model.person.Insurance.MAX_INSURANCE_COUNT;
+import static seedu.address.model.person.Tag.MAXIMUM_TAGS_PER_PERSON;
+
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -14,10 +17,22 @@ 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_PERSON_DISPLAYED_INDEX = "The customer index provided is invalid";
+ public static final String MESSAGE_PERSONS_LISTED_OVERVIEW = "%1$d customers listed!";
public static final String MESSAGE_DUPLICATE_FIELDS =
"Multiple values specified for the following single-valued field(s): ";
+ public static final String MESSAGE_NO_PERSON_FOUND = "No customer found!";
+
+ public static final String MESSAGE_TAG_COUNT_EXCEED =
+ String.format("Command will cause number of tags to exceed the limit of %d.", MAXIMUM_TAGS_PER_PERSON);
+
+ public static final String MESSAGE_INSURANCE_COUNT_EXCEED =
+ String.format("Command will cause number of insurance to exceed the limit of %d.", MAX_INSURANCE_COUNT);
+
+ public static final String MESSAGE_PERSON_NOT_CHANGED =
+ "Information provided in the command does not change the targeted customer.";
+
+ public static final String MESSAGE_DUPLICATE_PERSON = "This customer already exists in the address book";
/**
* Returns an error message indicating the duplicate prefixes.
@@ -26,7 +41,7 @@ public static String getErrorMessageForDuplicatePrefixes(Prefix... duplicatePref
assert duplicatePrefixes.length > 0;
Set duplicateFields =
- Stream.of(duplicatePrefixes).map(Prefix::toString).collect(Collectors.toSet());
+ Stream.of(duplicatePrefixes).map(Prefix::getDisplayMessage).collect(Collectors.toSet());
return MESSAGE_DUPLICATE_FIELDS + String.join(" ", duplicateFields);
}
@@ -36,16 +51,50 @@ public static String getErrorMessageForDuplicatePrefixes(Prefix... duplicatePref
*/
public static String format(Person person) {
final StringBuilder builder = new StringBuilder();
- builder.append(person.getName())
- .append("; Phone: ")
+ builder.append("\nName: ")
+ .append(person.getName())
+ .append(" | Phone: ")
.append(person.getPhone())
- .append("; Email: ")
+ .append(" | Email: ")
.append(person.getEmail())
- .append("; Address: ")
+ .append("\nAddress: ")
.append(person.getAddress())
- .append("; Tags: ");
- person.getTags().forEach(builder::append);
+ .append("\nPriority: ")
+ .append(person.getPriority());
+
+ addTagString(builder, person);
+ addInsuranceString(builder, person);
+ addRemarkString(builder, person);
+ builder.append("\nAppointment: ")
+ .append(person.getAppointment());
+
return builder.toString();
}
+ private static void addTagString(StringBuilder builder, Person person) {
+ builder.append("\nTags: ");
+ if (person.getTagsCount() == 0) {
+ builder.append("-");
+ } else {
+ person.getTags().forEach(builder::append);
+ }
+ }
+
+ private static void addInsuranceString(StringBuilder builder, Person person) {
+ builder.append("\nInsurances: ");
+ if (person.getInsurancesCount() == 0) {
+ builder.append("-");
+ } else {
+ person.getInsurances().forEach(builder::append);
+ }
+ }
+
+ private static void addRemarkString(StringBuilder builder, Person person) {
+ builder.append("\nRemarks: ");
+ if (person.hasRemark()) {
+ builder.append(person.getRemark());
+ } else {
+ builder.append("-");
+ }
+ }
}
diff --git a/src/main/java/seedu/address/logic/commands/AddCommand.java b/src/main/java/seedu/address/logic/commands/AddCommand.java
index 5d7185a9680..91e33211eac 100644
--- a/src/main/java/seedu/address/logic/commands/AddCommand.java
+++ b/src/main/java/seedu/address/logic/commands/AddCommand.java
@@ -1,10 +1,16 @@
package seedu.address.logic.commands;
import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.commands.CommandUtil.verifyPersonInsuranceCountIsValid;
+import static seedu.address.logic.commands.CommandUtil.verifyPersonNotInModel;
+import static seedu.address.logic.commands.CommandUtil.verifyPersonTagCountIsValid;
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_INSURANCE;
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_PRIORITY;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_REMARK;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
import seedu.address.commons.util.ToStringBuilder;
@@ -20,28 +26,22 @@ 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. "
- + "Parameters: "
- + PREFIX_NAME + "NAME "
- + PREFIX_PHONE + "PHONE "
- + PREFIX_EMAIL + "EMAIL "
- + PREFIX_ADDRESS + "ADDRESS "
- + "[" + PREFIX_TAG + "TAG]...\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";
-
- 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_USAGE = "Usage: \n" + COMMAND_WORD + " "
+ + PREFIX_NAME + " "
+ + PREFIX_PHONE + " "
+ + PREFIX_EMAIL + " "
+ + "[" + PREFIX_ADDRESS + "] "
+ + "[" + PREFIX_PRIORITY + "] "
+ + "[" + PREFIX_TAG + "]... "
+ + "[" + PREFIX_INSURANCE + "]... "
+ + "[" + PREFIX_REMARK + "]\n";
+
+ public static final String MESSAGE_SUCCESS = "New customer added: %1$s";
private final Person toAdd;
/**
- * Creates an AddCommand to add the specified {@code Person}
+ * Creates an AddCommand to add the specified {@code Person}.
*/
public AddCommand(Person person) {
requireNonNull(person);
@@ -52,14 +52,25 @@ public AddCommand(Person person) {
public CommandResult execute(Model model) throws CommandException {
requireNonNull(model);
- if (model.hasPerson(toAdd)) {
- throw new CommandException(MESSAGE_DUPLICATE_PERSON);
- }
-
+ verifyCommandIsExecutable(model);
model.addPerson(toAdd);
+
return new CommandResult(String.format(MESSAGE_SUCCESS, Messages.format(toAdd)));
}
+ /**
+ * Throws a {@code CommandException} if {@code toAdd} is not a valid person to add to {@code model}.
+ */
+ private void verifyCommandIsExecutable(Model model) throws CommandException {
+ requireNonNull(model);
+
+ verifyPersonTagCountIsValid(toAdd);
+ verifyPersonInsuranceCountIsValid(toAdd);
+ verifyPersonNotInModel(model, toAdd);
+ }
+
+
+
@Override
public boolean equals(Object other) {
if (other == this) {
diff --git a/src/main/java/seedu/address/logic/commands/AppointmentCommand.java b/src/main/java/seedu/address/logic/commands/AppointmentCommand.java
new file mode 100644
index 00000000000..5bcd480a03d
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/AppointmentCommand.java
@@ -0,0 +1,103 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
+import static seedu.address.logic.commands.CommandUtil.getPersonAtIndex;
+import static seedu.address.logic.commands.CommandUtil.verifyPersonChanged;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_APPOINTMENT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_APPOINTMENT_TIME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_APPOINTMENT_VENUE;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
+
+import java.util.logging.Logger;
+
+import seedu.address.commons.core.LogsCenter;
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.person.Appointment;
+import seedu.address.model.person.Person;
+
+//@@author AY2122S1-CS2103T-T09-4/tp--reused
+//Reused from https://github.com/AY2122S1-CS2103T-T09-4/tp/blob/
+//master/src/main/java/seedu/fast/logic/commands/AppointmentCommand.java
+//with minor modifications
+/**
+ * Adds/Edits the appointment with an existing person in the address book.
+ */
+public class AppointmentCommand extends Command {
+
+ public static final String COMMAND_WORD = "addappt";
+ public static final String MESSAGE_USAGE = "Usage: \n" + COMMAND_WORD
+ + " "
+ + PREFIX_APPOINTMENT + ""
+ + "[" + PREFIX_APPOINTMENT_TIME + "]"
+ + "[" + PREFIX_APPOINTMENT_VENUE + "]\n";
+
+ public static final String MESSAGE_ADD_APPOINTMENT_SUCCESS = "Added appointment with customer: %1$s %2$s %3$s %4$s";
+ public static final String MESSAGE_ADD_APPOINTMENT_FAILURE_APPT_EXIST = "Appointment already exists!";
+ private static final Logger logger = LogsCenter.getLogger(AppointmentCommand.class);
+ private final Index index;
+ private final Appointment appointment;
+
+
+ /**
+ * Constructor for an {@code AppointmentCommand}
+ *
+ * @param index index of the customer list to add appointment for
+ * @param appointment appointment scheduled with the target
+ */
+ public AppointmentCommand(Index index, Appointment appointment) {
+ requireAllNonNull(index, appointment);
+
+ this.index = index;
+ this.appointment = appointment;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+
+ Person personToEdit = getPersonAtIndex(model, index);
+ logger.fine("AppointmentCommand executing...");
+
+ if (!Appointment.isAppointmentEmpty(personToEdit.getAppointment())) {
+ logger.warning("-----Invalid Add Appointment Command: Appointment Already Exist-----");
+ throw new CommandException(MESSAGE_ADD_APPOINTMENT_FAILURE_APPT_EXIST);
+ }
+ Person editedPerson = Person.createPersonWithEditedAppointment(personToEdit, appointment);
+ verifyPersonChanged(personToEdit, editedPerson);
+ model.setPerson(personToEdit, editedPerson);
+ model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
+ logger.info("-----Add Appointment Command: Appointment added successfully-----");
+
+ return new CommandResult(generateSuccessMessage(editedPerson));
+ }
+
+ /**
+ * Generates a command execution success message when appointment has been added successfully.
+ * {@code editedPerson}.
+ */
+ private String generateSuccessMessage(Person editedPerson) {
+ return String.format(MESSAGE_ADD_APPOINTMENT_SUCCESS, editedPerson.getName().fullName,
+ editedPerson.getAppointment().getDate(),
+ editedPerson.getAppointment().getTimeFormatted(),
+ editedPerson.getAppointment().getVenue());
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof AppointmentCommand)) {
+ return false;
+ }
+
+ AppointmentCommand a = (AppointmentCommand) other;
+ return index.equals(a.index)
+ && appointment.equals(a.appointment);
+ }
+}
+//@@author
diff --git a/src/main/java/seedu/address/logic/commands/ClearCommand.java b/src/main/java/seedu/address/logic/commands/ClearCommand.java
index 9c86b1fa6e4..f8c326aa824 100644
--- a/src/main/java/seedu/address/logic/commands/ClearCommand.java
+++ b/src/main/java/seedu/address/logic/commands/ClearCommand.java
@@ -11,8 +11,7 @@
public class ClearCommand extends Command {
public static final String COMMAND_WORD = "clear";
- public static final String MESSAGE_SUCCESS = "Address book has been cleared!";
-
+ public static final String MESSAGE_SUCCESS = "List has been cleared!";
@Override
public CommandResult execute(Model model) {
diff --git a/src/main/java/seedu/address/logic/commands/Command.java b/src/main/java/seedu/address/logic/commands/Command.java
index 64f18992160..a7bfb81bb93 100644
--- a/src/main/java/seedu/address/logic/commands/Command.java
+++ b/src/main/java/seedu/address/logic/commands/Command.java
@@ -12,9 +12,8 @@ public abstract class Command {
* 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
+ * @return feedback message of the operation result for display.
* @throws CommandException If an error occurs during command execution.
*/
public abstract CommandResult execute(Model model) throws CommandException;
-
}
diff --git a/src/main/java/seedu/address/logic/commands/CommandUtil.java b/src/main/java/seedu/address/logic/commands/CommandUtil.java
new file mode 100644
index 00000000000..285b31fda41
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/CommandUtil.java
@@ -0,0 +1,103 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
+import static seedu.address.logic.Messages.MESSAGE_DUPLICATE_PERSON;
+import static seedu.address.logic.Messages.MESSAGE_INSURANCE_COUNT_EXCEED;
+import static seedu.address.logic.Messages.MESSAGE_PERSON_NOT_CHANGED;
+import static seedu.address.logic.Messages.MESSAGE_TAG_COUNT_EXCEED;
+import static seedu.address.model.person.Insurance.MAX_INSURANCE_COUNT;
+import static seedu.address.model.person.Tag.MAXIMUM_TAGS_PER_PERSON;
+
+import java.util.List;
+import java.util.logging.Logger;
+
+import seedu.address.commons.core.LogsCenter;
+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.person.Person;
+
+/** Contains utility methods for commands. **/
+public class CommandUtil {
+ private static final Logger logger = LogsCenter.getLogger(CommandUtil.class);
+
+ /**
+ * Returns the person from the model at a specific index.
+ */
+ public static Person getPersonAtIndex(Model model, Index index) throws CommandException {
+ requireAllNonNull(model, index);
+ List lastShownList = model.getFilteredPersonList();
+
+ assert lastShownList.size() >= 0 : "Size of list should not be a negative number";
+ assert index.getZeroBased() >= 0 : "index.getZeroBased() should not be a negative number";
+
+ if (index.getZeroBased() >= lastShownList.size()) {
+ logger.finer(String.format("Execution failed due to index %d out of bound", index.getOneBased()));
+ throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ }
+
+ Person personToUpdate = lastShownList.get(index.getZeroBased());
+ assert personToUpdate != null : "null instance in filtered person list";
+
+ return personToUpdate;
+ }
+
+ /**
+ * Throws a {@code CommandException} if {@code updatedPerson} is equal to {@code personToUpdate}.
+ */
+ public static void verifyPersonChanged(Person personToUpdate, Person updatedPerson,
+ String reasons) throws CommandException {
+ requireAllNonNull(personToUpdate, updatedPerson, reasons);
+ if (personToUpdate.equals(updatedPerson)) {
+ logger.finer("Command execution failed due to no changes in person." + reasons);
+ throw new CommandException(MESSAGE_PERSON_NOT_CHANGED + "\n" + reasons);
+ }
+ }
+
+ /**
+ * Throws a {@code CommandException} if {@code updatedPerson} is equal to {@code personToUpdate}.
+ */
+ public static void verifyPersonChanged(Person personToUpdate, Person updatedPerson) throws CommandException {
+ requireAllNonNull(personToUpdate, updatedPerson);
+
+ if (personToUpdate.equals(updatedPerson)) {
+ logger.finer("Command execution failed due to no changes in person.");
+ throw new CommandException(MESSAGE_PERSON_NOT_CHANGED);
+ }
+ }
+
+ /**
+ * Throws a {@code CommandException} if the {@code person}'s tag count exceeds the allowed count.
+ */
+ public static void verifyPersonTagCountIsValid(Person person) throws CommandException {
+ requireNonNull(person);
+ if (person.getTagsCount() > MAXIMUM_TAGS_PER_PERSON) {
+ logger.finer("Command execution failed due to exceeding maximum tag counts allowed.");
+ throw new CommandException(MESSAGE_TAG_COUNT_EXCEED);
+ }
+ }
+
+ /**
+ * Throws a {@code CommandException} if the {@code person}'s insurance count exceeds the allowed count.
+ */
+ public static void verifyPersonInsuranceCountIsValid(Person person) throws CommandException {
+ requireNonNull(person);
+ if (person.getInsurancesCount() > MAX_INSURANCE_COUNT) {
+ logger.finer("Command execution failed due to exceeding maximum insurance counts allowed.");
+ throw new CommandException(MESSAGE_INSURANCE_COUNT_EXCEED);
+ }
+ }
+
+ /**
+ * Throws a {@code CommandException} if the {@code model} has the {@code person}.
+ */
+ public static void verifyPersonNotInModel(Model model, Person person) throws CommandException {
+ requireAllNonNull(model, person);
+ if (model.hasPerson(person)) {
+ logger.finer("Command execution failed due to person already exist in model.");
+ throw new CommandException(MESSAGE_DUPLICATE_PERSON);
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/DeleteAppointmentCommand.java b/src/main/java/seedu/address/logic/commands/DeleteAppointmentCommand.java
new file mode 100644
index 00000000000..e8cae298b2a
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/DeleteAppointmentCommand.java
@@ -0,0 +1,93 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
+
+import java.util.List;
+import java.util.logging.Logger;
+
+import seedu.address.commons.core.LogsCenter;
+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.person.Appointment;
+import seedu.address.model.person.Person;
+
+//@@author AY2122S1-CS2103T-T09-4/tp--reused
+//Reused from https://github.com/AY2122S1-CS2103T-T09-4/tp/blob/
+//master/src/main/java/seedu/fast/logic/commands/DeleteAppointmentCommand.java
+//with minor modifications
+/**
+ * Deletes the appointment with an existing person in the address book.
+ */
+public class DeleteAppointmentCommand extends Command {
+
+ public static final String COMMAND_WORD = "deleteappt";
+
+ public static final String MESSAGE_USAGE = "Usage: \n" + COMMAND_WORD
+ + " ";
+
+ public static final String MESSAGE_DELETE_APPOINTMENT_SUCCESS = "Deleted appointment with %1$s";
+ public static final String MESSAGE_DELETE_APPOINTMENT_FAILED_EMPTY_APPT = "No appointment with %1$s yet!";
+
+ private final Logger logger = LogsCenter.getLogger(getClass());
+ private final Index index;
+ private final Appointment appointment;
+
+ /**
+ * Construct for an {@code DeleteAppointmentCommand}
+ *
+ * @param index index of the person in the filtered person list to delete the appointment
+ * @param appointment appointment scheduled with the person
+ */
+ public DeleteAppointmentCommand(Index index, Appointment appointment) {
+ this.index = index;
+ this.appointment = appointment;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+ List lastShownList = model.getFilteredPersonList();
+
+ if (index.getZeroBased() >= lastShownList.size()) {
+ throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
+ }
+
+ Person personToDelete = lastShownList.get(index.getZeroBased());
+ Person updatedPerson = Person.createPersonWithEditedAppointment(personToDelete, appointment);
+
+ String name = personToDelete.getName().fullName;
+
+ if (Appointment.isAppointmentEmpty(personToDelete.getAppointment())) {
+ logger.warning("-----Invalid Delete Appointment Command: Appointment does not exist-----");
+ throw new CommandException(String.format(MESSAGE_DELETE_APPOINTMENT_FAILED_EMPTY_APPT, name));
+ }
+
+ model.setPerson(personToDelete, updatedPerson);
+ model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
+ logger.info("-----Delete Appointment Command: Appointment deleted successfully-----");
+
+ return new CommandResult(String.format(MESSAGE_DELETE_APPOINTMENT_SUCCESS, name));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // short circuit if same object
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof DeleteAppointmentCommand)) {
+ return false;
+ }
+
+ // state check
+ DeleteAppointmentCommand e = (DeleteAppointmentCommand) other;
+ return index.equals(e.index)
+ && appointment.equals(e.appointment);
+ }
+}
+//@@author
diff --git a/src/main/java/seedu/address/logic/commands/DeleteCommand.java b/src/main/java/seedu/address/logic/commands/DeleteCommand.java
index 1135ac19b74..ae737353413 100644
--- a/src/main/java/seedu/address/logic/commands/DeleteCommand.java
+++ b/src/main/java/seedu/address/logic/commands/DeleteCommand.java
@@ -18,12 +18,9 @@ public class DeleteCommand 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"
- + "Parameters: INDEX (must be a positive integer)\n"
- + "Example: " + COMMAND_WORD + " 1";
+ public static final String MESSAGE_USAGE = "Usage: \n" + COMMAND_WORD + " \n";
- public static final String MESSAGE_DELETE_PERSON_SUCCESS = "Deleted Person: %1$s";
+ public static final String MESSAGE_DELETE_PERSON_SUCCESS = "Deleted customer: %1$s";
private final Index targetIndex;
diff --git a/src/main/java/seedu/address/logic/commands/EditCommand.java b/src/main/java/seedu/address/logic/commands/EditCommand.java
index 4b581c7331e..4f38d10ebd3 100644
--- a/src/main/java/seedu/address/logic/commands/EditCommand.java
+++ b/src/main/java/seedu/address/logic/commands/EditCommand.java
@@ -1,32 +1,36 @@
package seedu.address.logic.commands;
import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.commands.CommandUtil.getPersonAtIndex;
+import static seedu.address.logic.commands.CommandUtil.verifyPersonChanged;
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_INSURANCE;
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_PRIORITY;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_REMARK;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
-import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
+import static seedu.address.model.person.Person.createPersonWithEditedInformation;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
+import java.util.HashMap;
import java.util.Objects;
import java.util.Optional;
-import java.util.Set;
+import java.util.logging.Logger;
+import seedu.address.commons.core.LogsCenter;
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.logic.parser.Prefix;
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;
/**
* Edits the details of an existing person in the address book.
@@ -35,29 +39,44 @@ 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. "
- + "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"
- + "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_USAGE = "Usage: \n" + COMMAND_WORD
+ + " "
+ + "[" + PREFIX_NAME + "] "
+ + "[" + PREFIX_PHONE + "] "
+ + "[" + PREFIX_EMAIL + "] "
+ + "[" + PREFIX_ADDRESS + "]\n";
+
+ public static final String MESSAGE_EDIT_PERSON_SUCCESS = "Edited customer: %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_EDIT_TAG_ERROR = "Cannot edit tags. "
+ + "Please use \"tag\" command to add/delete tags.";
+ public static final String MESSAGE_EDIT_PRIORITY_ERROR = "Cannot edit priority. "
+ + "Please use \"pr\" command to assign new priority.";
+ public static final String MESSAGE_EDIT_REMARK_ERROR = "Cannot edit remark. "
+ + "Please use \"remark\" command to modify remark.";
+ public static final String MESSAGE_EDIT_INSURANCE_ERROR = "Cannot edit insurance. "
+ + "Please use \"insurance\" command to add/delete insurances.";
+
+ /** Stores a prefix and its corresponding edit error message as a key-value pair. **/
+ public static final HashMap PREFIX_EDIT_ERROR_MESSAGE_MAP = new HashMap<>() {
+ {
+ put(PREFIX_TAG, MESSAGE_EDIT_TAG_ERROR);
+ put(PREFIX_PRIORITY, MESSAGE_EDIT_PRIORITY_ERROR);
+ put(PREFIX_REMARK, MESSAGE_EDIT_REMARK_ERROR);
+ put(PREFIX_INSURANCE, MESSAGE_EDIT_INSURANCE_ERROR);
+ }
+ };
+
+ private static final Logger logger = LogsCenter.getLogger(EditCommand.class);
private final Index index;
private final EditPersonDescriptor editPersonDescriptor;
/**
- * @param index of the person in the filtered person list to edit
- * @param editPersonDescriptor details to edit the person with
+ * Constructs a new EditCommand.
+ *
+ * @param index of the person in the filtered person list to edit.
+ * @param editPersonDescriptor details to edit the person with.
*/
public EditCommand(Index index, EditPersonDescriptor editPersonDescriptor) {
requireNonNull(index);
@@ -70,38 +89,35 @@ public EditCommand(Index index, EditPersonDescriptor editPersonDescriptor) {
@Override
public CommandResult execute(Model model) throws CommandException {
requireNonNull(model);
- List lastShownList = model.getFilteredPersonList();
- if (index.getZeroBased() >= lastShownList.size()) {
- throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX);
- }
+ logger.fine("EditCommand executing...");
- Person personToEdit = lastShownList.get(index.getZeroBased());
- Person editedPerson = createEditedPerson(personToEdit, editPersonDescriptor);
+ Person personToEdit = getPersonAtIndex(model, index);
+ Person editedPerson = createPersonWithEditedInformation(personToEdit, editPersonDescriptor);
- if (!personToEdit.isSamePerson(editedPerson) && model.hasPerson(editedPerson)) {
- throw new CommandException(MESSAGE_DUPLICATE_PERSON);
- }
+ verifyPersonChanged(personToEdit, editedPerson);
+ checkIsDuplicatePerson(model, personToEdit, editedPerson);
model.setPerson(personToEdit, editedPerson);
- model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
+
return new CommandResult(String.format(MESSAGE_EDIT_PERSON_SUCCESS, Messages.format(editedPerson)));
}
- /**
- * Creates and returns a {@code Person} with the details of {@code personToEdit}
- * edited with {@code editPersonDescriptor}.
- */
- private static Person createEditedPerson(Person personToEdit, EditPersonDescriptor editPersonDescriptor) {
- assert personToEdit != null;
+ private void checkIsDuplicatePerson(Model model, Person personToEdit, Person editedPerson) throws CommandException {
+ boolean hasDuplicateInModel = !personToEdit.isSamePerson(editedPerson) && model.hasPerson(editedPerson);
+ boolean isDuplicateOfOthersInModel = false;
- 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());
+ for (int i = 0; i < model.getFilteredPersonListSize(); i++) {
+ Person personAtIndex = getPersonAtIndex(model, Index.fromZeroBased(i));
+ if (i != index.getZeroBased() && editedPerson.isSamePerson(personAtIndex)) {
+ isDuplicateOfOthersInModel = true;
+ }
+ }
- return new Person(updatedName, updatedPhone, updatedEmail, updatedAddress, updatedTags);
+ if (hasDuplicateInModel || isDuplicateOfOthersInModel) {
+ logger.finer("EditCommand execution failed due to duplicated persons in list");
+ throw new CommandException(Messages.MESSAGE_DUPLICATE_PERSON);
+ }
}
@Override
@@ -137,27 +153,28 @@ public static class EditPersonDescriptor {
private Phone phone;
private Email email;
private Address address;
- private Set tags;
+ /**
+ * Constructs an empty EditPersonDescriptor instance.
+ */
public EditPersonDescriptor() {}
/**
- * Copy constructor.
- * A defensive copy of {@code tags} is used internally.
+ * Constructs an EditPersonDescriptor instance with the given {@code descriptionToCopy}.
*/
- public EditPersonDescriptor(EditPersonDescriptor toCopy) {
- setName(toCopy.name);
- setPhone(toCopy.phone);
- setEmail(toCopy.email);
- setAddress(toCopy.address);
- setTags(toCopy.tags);
+ public EditPersonDescriptor(EditPersonDescriptor descriptionToCopy) {
+ requireNonNull(descriptionToCopy);
+ setName(descriptionToCopy.name);
+ setPhone(descriptionToCopy.phone);
+ setEmail(descriptionToCopy.email);
+ setAddress(descriptionToCopy.address);
}
/**
* 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);
}
public void setName(Name name) {
@@ -192,23 +209,6 @@ 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;
- }
-
- /**
- * 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();
- }
-
@Override
public boolean equals(Object other) {
if (other == this) {
@@ -224,8 +224,7 @@ public boolean equals(Object 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);
+ && Objects.equals(address, otherEditPersonDescriptor.address);
}
@Override
@@ -235,7 +234,6 @@ public String toString() {
.add("phone", phone)
.add("email", email)
.add("address", address)
- .add("tags", tags)
.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..e95a2a6790d 100644
--- a/src/main/java/seedu/address/logic/commands/ExitCommand.java
+++ b/src/main/java/seedu/address/logic/commands/ExitCommand.java
@@ -9,7 +9,7 @@ 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 MESSAGE_EXIT_ACKNOWLEDGEMENT = "Exiting EzContact as requested ...";
@Override
public CommandResult execute(Model model) {
diff --git a/src/main/java/seedu/address/logic/commands/FindCommand.java b/src/main/java/seedu/address/logic/commands/FindCommand.java
index 72b9eddd3a7..c1c921bbefc 100644
--- a/src/main/java/seedu/address/logic/commands/FindCommand.java
+++ b/src/main/java/seedu/address/logic/commands/FindCommand.java
@@ -2,34 +2,43 @@
import static java.util.Objects.requireNonNull;
+import java.util.logging.Logger;
+
+import seedu.address.commons.core.LogsCenter;
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.person.predicate.PersonContainsKeywordsPredicate;
/**
* Finds and lists all persons in address book whose name contains any of the argument keywords.
- * Keyword matching is case insensitive.
+ * Keyword 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 =
+ "Usage: \n"
+ + COMMAND_WORD + " [n/[keywords]] [p/[keywords]] [e/[keywords]] "
+ + "[a/[keywords]] [t/[keywords]] [i/[keywords]] [pr/[keywords]] [r/[keywords]]\n";
+ private static final Logger logger = LogsCenter.getLogger(FindCommand.class);
+ private final PersonContainsKeywordsPredicate predicate;
- public FindCommand(NameContainsKeywordsPredicate predicate) {
+ public FindCommand(PersonContainsKeywordsPredicate predicate) {
this.predicate = predicate;
}
@Override
public CommandResult execute(Model model) {
+
+ logger.fine("FindCommand executing...");
+
requireNonNull(model);
model.updateFilteredPersonList(predicate);
+ if (model.getFilteredPersonList().size() == 0) {
+ return new CommandResult(Messages.MESSAGE_NO_PERSON_FOUND);
+ }
return new CommandResult(
String.format(Messages.MESSAGE_PERSONS_LISTED_OVERVIEW, model.getFilteredPersonList().size()));
}
diff --git a/src/main/java/seedu/address/logic/commands/HelpCommand.java b/src/main/java/seedu/address/logic/commands/HelpCommand.java
index bf824f91bd0..cc8b4f98c7e 100644
--- a/src/main/java/seedu/address/logic/commands/HelpCommand.java
+++ b/src/main/java/seedu/address/logic/commands/HelpCommand.java
@@ -3,14 +3,13 @@
import seedu.address.model.Model;
/**
- * Format full help instructions for every command for display.
+ * Formats full help instructions for every command for display.
*/
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"
- + "Example: " + COMMAND_WORD;
+ public static final String MESSAGE_USAGE = "Usage:\n" + COMMAND_WORD + " (no parameters)\n";
public static final String SHOWING_HELP_MESSAGE = "Opened help window.";
diff --git a/src/main/java/seedu/address/logic/commands/InsuranceCommand.java b/src/main/java/seedu/address/logic/commands/InsuranceCommand.java
new file mode 100644
index 00000000000..b51cfa5fc6a
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/InsuranceCommand.java
@@ -0,0 +1,192 @@
+package seedu.address.logic.commands;
+
+import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
+import static seedu.address.logic.commands.CommandUtil.getPersonAtIndex;
+import static seedu.address.logic.commands.CommandUtil.verifyPersonChanged;
+import static seedu.address.logic.commands.CommandUtil.verifyPersonInsuranceCountIsValid;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_ADD_INSURANCE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DELETE_INSURANCE;
+import static seedu.address.model.person.Person.createPersonWithUpdatedInsurances;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.logging.Logger;
+
+import seedu.address.commons.core.LogsCenter;
+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.person.Insurance;
+import seedu.address.model.person.Person;
+
+/**
+ * Parse input argument and create InsuranceCommand Object
+ *
+ */
+public class InsuranceCommand extends Command {
+
+ public static final String COMMAND_WORD = "insurance";
+
+ public static final String MESSAGE_USAGE = "Usage: \n" + COMMAND_WORD
+ + " "
+ + "[" + PREFIX_ADD_INSURANCE + "]... "
+ + "[" + PREFIX_DELETE_INSURANCE + "]...\n";
+
+ public static final String MESSAGE_INSURANCE_PERSON_SUCCESS = "Update insurance of customer: %s";
+
+ public static final String MESSAGE_INSURANCE_NO_UPDATE = "There has to be at least one insurance updated/deleted.";
+
+ public static final String MESSAGE_INSURANCE_CONFLICT = "Should not assign and remove the same insurance.";
+
+ public static final String MESSAGE_INSURANCE_UNCHANGED_REASONS =
+ "(Possible reason: only adding insurances that already exist and/or deleting insurances that do not exist)";
+
+ private static final Logger logger = LogsCenter.getLogger(InsuranceCommand.class);
+
+ private final Index index;
+
+ private final UpdatePersonInsuranceDescriptor updatePersonInsuranceDescriptor;
+
+ /**
+ * Instantiate {@code InsuranceCommand}
+ */
+ public InsuranceCommand(Index i, UpdatePersonInsuranceDescriptor u) {
+ requireAllNonNull(i, u);
+ assert u.hasInsuranceToUpdate() : "It should have insurance to update";
+
+ this.index = i;
+ this.updatePersonInsuranceDescriptor = u;
+ }
+
+ /**
+ * Assigns an insurance to a customer identified by index
+ *
+ * @param m {@code Model} which the command should operate on.
+ * @return {@code CommandResult} for Ui component to display
+ * @throws CommandException when index is out of bound or maximum amount of insurance is exceeded
+ */
+ @Override
+ public CommandResult execute(Model m) throws CommandException {
+ requireAllNonNull(m);
+ verifyNoConflictingInsurance();
+
+ return updatePerson(m);
+ }
+
+ /**
+ * Check for conflicting {@code Insurance} for the given command
+ *
+ * @throws CommandException when command add and delete the same {@code Insurance} at the same time
+ */
+ private void verifyNoConflictingInsurance() throws CommandException {
+ if (updatePersonInsuranceDescriptor.hasCommonInsurance()) {
+ throw new CommandException(MESSAGE_INSURANCE_CONFLICT);
+ }
+ }
+
+ /**
+ * Update the customer details in the contact book
+ *
+ * @param m {@code Model}
+ * @return {@code CommandResult} result message of the command execution
+ * @throws CommandException when the execution of command is not allowed
+ */
+ private CommandResult updatePerson(Model m) throws CommandException {
+ Person personToUpdate = getPersonAtIndex(m, index);
+ Person updatedPerson = createPersonWithUpdatedInsurances(personToUpdate,
+ updatePersonInsuranceDescriptor.insurancesToAdd,
+ updatePersonInsuranceDescriptor.insurancesToDelete);
+
+ verifyPersonInsuranceCountIsValid(updatedPerson);
+ verifyPersonChanged(personToUpdate, updatedPerson, MESSAGE_INSURANCE_UNCHANGED_REASONS);
+
+ m.setPerson(personToUpdate, updatedPerson);
+
+ return new CommandResult(String.format(MESSAGE_INSURANCE_PERSON_SUCCESS, Messages.format(updatedPerson)));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof InsuranceCommand)) {
+ return false;
+ }
+
+ if (other == this) {
+ return true;
+ }
+
+ InsuranceCommand temp = (InsuranceCommand) other;
+
+ return this.index.equals(temp.index)
+ && this.updatePersonInsuranceDescriptor.equals(temp.updatePersonInsuranceDescriptor);
+ }
+
+ /**
+ * Wrapper class to hold the changes to insurance of a customer
+ */
+ public static class UpdatePersonInsuranceDescriptor {
+
+ private Set insurancesToAdd;
+ private Set insurancesToDelete;
+
+ /**
+ * Instantiate {@code UpdatePersonInsuranceDescriptor}
+ */
+ public UpdatePersonInsuranceDescriptor(Set toAdd, Set toDelete) {
+ this.insurancesToAdd = toAdd;
+ this.insurancesToDelete = toDelete;
+ }
+
+ public Set getInsurancesToAdd() {
+ return insurancesToAdd;
+ }
+
+ public Set getInsurancesToDelete() {
+ return insurancesToDelete;
+ }
+
+ public void setInsurancesToAdd(Insurance i) {
+ this.insurancesToAdd.add(i);
+ }
+ public void setInsurancesToDelete(Insurance i) {
+ this.insurancesToDelete.add(i);
+ }
+
+ /**
+ * Checks for common insurance between add and delete sets
+ *
+ * @return false if there is no common insurance
+ */
+ public boolean hasCommonInsurance() {
+ Set intersection = new HashSet<>(insurancesToAdd);
+ intersection.retainAll(insurancesToDelete);
+
+ return !intersection.isEmpty();
+ }
+
+ /**
+ * Checks for available insurance to modify
+ *
+ * @return true if there exist insurance to add or delete
+ */
+ public boolean hasInsuranceToUpdate() {
+ return !(insurancesToAdd.isEmpty() && insurancesToDelete.isEmpty());
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof UpdatePersonInsuranceDescriptor)) {
+ return false;
+ }
+
+ UpdatePersonInsuranceDescriptor temp = (UpdatePersonInsuranceDescriptor) other;
+ return this.insurancesToAdd.equals(temp.insurancesToAdd)
+ && this.insurancesToDelete.equals(temp.insurancesToDelete);
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/ListCommand.java b/src/main/java/seedu/address/logic/commands/ListCommand.java
index 84be6ad2596..2bbeea3abb9 100644
--- a/src/main/java/seedu/address/logic/commands/ListCommand.java
+++ b/src/main/java/seedu/address/logic/commands/ListCommand.java
@@ -12,13 +12,15 @@ 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 %1$d customer(s)";
+ public static final String MESSAGE_USAGE = "Usage: "
+ + COMMAND_WORD + " (no parameters)\n";
@Override
public CommandResult execute(Model model) {
requireNonNull(model);
model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
- return new CommandResult(MESSAGE_SUCCESS);
+ return new CommandResult(String.format(MESSAGE_SUCCESS, model.getFilteredPersonListSize()));
}
}
diff --git a/src/main/java/seedu/address/logic/commands/MarkAppointmentCommand.java b/src/main/java/seedu/address/logic/commands/MarkAppointmentCommand.java
new file mode 100644
index 00000000000..1b7dcc78946
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/MarkAppointmentCommand.java
@@ -0,0 +1,101 @@
+package seedu.address.logic.commands;
+
+import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
+import static seedu.address.logic.commands.CommandUtil.getPersonAtIndex;
+import static seedu.address.logic.commands.CommandUtil.verifyPersonChanged;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
+
+import java.util.logging.Logger;
+
+import seedu.address.commons.core.LogsCenter;
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.person.Appointment;
+import seedu.address.model.person.Person;
+
+//@@author AY2122S1-CS2103T-T09-4/tp--reused
+//Reused from https://github.com/AY2122S1-CS2103T-T09-4/tp/blob/master/
+//src/main/java/seedu/fast/logic/commands/MarkAppointmentCommand.java
+//with minor modifications
+/**
+ * Marks the appointment with an existing person in the address book.
+ */
+public class MarkAppointmentCommand extends Command {
+ public static final String COMMAND_WORD = "markappt";
+
+ public static final String MESSAGE_USAGE = "Usage: \n" + COMMAND_WORD
+ + " ";
+
+ public static final String MESSAGE_MARK_APPOINTMENT_SUCCESS = "Marked an appointment with "
+ + "%1$s %2$s %3$s %4$s";
+ public static final String MESSAGE_MARK_APPOINTMENT_FAILURE_EMPTY_APPT = "No appointment exists!";
+
+ private static final Logger logger = LogsCenter.getLogger(MarkAppointmentCommand.class);
+
+ private final Index index;
+ private final Appointment appointment;
+
+ /**
+ * Construct for an {@code MarkAppointmentCommand}
+ *
+ * @param index index of the person in the filtered person list to mark the appointment as completed
+ * @param appointment the existing appointment that has been completed
+ */
+ public MarkAppointmentCommand(Index index, Appointment appointment) {
+ requireAllNonNull(index, appointment);
+
+ this.index = index;
+ this.appointment = appointment;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ Person personToEdit = getPersonAtIndex(model, index);
+
+ if (Appointment.isAppointmentEmpty(personToEdit.getAppointment())) {
+ logger.warning("-----Invalid Mark Appointment Command: Appointment does not exist-----");
+ throw new CommandException(MESSAGE_MARK_APPOINTMENT_FAILURE_EMPTY_APPT);
+ }
+
+ Person editedPerson = Person.createPersonWithIncreasedCount(personToEdit,
+ appointment, personToEdit.getAppointmentCount());
+ verifyPersonChanged(personToEdit, editedPerson);
+ model.setPerson(personToEdit, editedPerson);
+ model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
+ logger.info("-----Mark Appointment Command: Appointment marked successfully-----");
+
+ return new CommandResult(generateSuccessMessage(personToEdit));
+ }
+
+ /**
+ * Generates a command execution success message when the appointment is marked as completed successfully.
+ * {@code personToEdit}.
+ */
+ private String generateSuccessMessage(Person personToEdit) {
+
+ return String.format(MESSAGE_MARK_APPOINTMENT_SUCCESS, personToEdit.getName().fullName,
+ personToEdit.getAppointment().getDate(),
+ personToEdit.getAppointment().getTimeFormatted(),
+ personToEdit.getAppointment().getVenue());
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // short circuit if same object
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof MarkAppointmentCommand)) {
+ return false;
+ }
+
+ // state check
+ MarkAppointmentCommand e = (MarkAppointmentCommand) other;
+ return index.equals(e.index)
+ && appointment.equals(e.appointment);
+ }
+}
+//@@author
diff --git a/src/main/java/seedu/address/logic/commands/PriorityCommand.java b/src/main/java/seedu/address/logic/commands/PriorityCommand.java
new file mode 100644
index 00000000000..b7023244af7
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/PriorityCommand.java
@@ -0,0 +1,92 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.Messages.MESSAGE_PERSON_NOT_CHANGED;
+import static seedu.address.logic.commands.CommandUtil.getPersonAtIndex;
+import static seedu.address.model.person.Person.createPersonWithUpdatedPriority;
+
+import java.util.logging.Logger;
+
+import seedu.address.commons.core.LogsCenter;
+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.person.Person;
+import seedu.address.model.priority.Priority;
+
+/** Assigns priority to a person. **/
+public class PriorityCommand extends Command {
+ public static final String COMMAND_WORD = "priority";
+
+ public static final String MESSAGE_USAGE = "Usage: \n" + COMMAND_WORD
+ + " "
+ + "\n";
+
+ public static final String MESSAGE_ASSIGN_PRIORITY_SUCCESS = "Updated priority of customer: %1$s";
+
+ private static final Logger logger = LogsCenter.getLogger(PriorityCommand.class);
+
+ private final Index index;
+ private final Priority priority;
+
+ /**
+ * Constructs a PriorityCommand.
+ *
+ * @param index of the person in the filtered list to assign priority to.
+ * @param priority assigned to the person.
+ */
+ public PriorityCommand(Index index, Priority priority) {
+ requireNonNull(index);
+ requireNonNull(priority);
+
+ this.index = index;
+ this.priority = priority;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+
+ logger.fine("PriorityCommand executing...");
+
+ Person personToUpdate = getPersonAtIndex(model, index);
+ Person updatedPerson = createPersonWithUpdatedPriority(personToUpdate, priority);
+
+ checkIsOldPriority(personToUpdate);
+
+ model.setPerson(personToUpdate, updatedPerson);
+
+ return new CommandResult(String.format(MESSAGE_ASSIGN_PRIORITY_SUCCESS, Messages.format(updatedPerson)));
+ }
+
+ private void checkIsOldPriority(Person personToUpdate) throws CommandException {
+ if (personToUpdate.hasSamePriority(priority)) {
+ logger.finer("Executing failed due to provided priority is the same as previously assigned priority");
+ throw new CommandException(MESSAGE_PERSON_NOT_CHANGED);
+ }
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof PriorityCommand)) {
+ return false;
+ }
+
+ PriorityCommand otherPriorityCommand = (PriorityCommand) other;
+ return priority.equals(otherPriorityCommand.priority) && index.equals(otherPriorityCommand.index);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .add("priority", priority)
+ .toString();
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/RemarkCommand.java b/src/main/java/seedu/address/logic/commands/RemarkCommand.java
new file mode 100644
index 00000000000..5e765581e31
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/RemarkCommand.java
@@ -0,0 +1,95 @@
+package seedu.address.logic.commands;
+
+import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
+
+import java.util.List;
+import java.util.logging.Logger;
+
+import seedu.address.commons.core.LogsCenter;
+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.person.Person;
+import seedu.address.model.person.Remark;
+
+
+/**
+ * Remark a person.
+ */
+public class RemarkCommand extends Command {
+
+
+ public static final String COMMAND_WORD = "remark";
+ public static final String MESSAGE_ADD_REMARK_SUCCESS = "Added remark to customer: %1$s";
+ public static final String MESSAGE_DELETE_REMARK_SUCCESS = "Removed remark from customer: %1$s";
+ public static final String MESSAGE_USAGE = "Usage: \n" + COMMAND_WORD
+ + " "
+ + "[remarks]\n";
+
+ private static final Logger logger = LogsCenter.getLogger(RemarkCommand.class);
+ private final Index index;
+ private final Remark remark;
+
+
+
+ /**
+ * @param index of the person in the filtered person list to edit the remark
+ * @param remark of the person to be updated to
+ */
+ public RemarkCommand(Index index, Remark remark) {
+ requireAllNonNull(index, remark);
+
+ this.index = index;
+ this.remark = remark;
+ }
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+
+ logger.fine("RemarkCommand executing...");
+
+ List lastShownList = model.getFilteredPersonList();
+
+ if (index.getZeroBased() >= lastShownList.size()) {
+ 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(), personToEdit.getInsurances(),
+ personToEdit.getAppointment(), personToEdit.getAppointmentCount(), personToEdit.getPriority());
+
+ CommandUtil.verifyPersonChanged(personToEdit, editedPerson);
+
+ model.setPerson(personToEdit, editedPerson);
+
+ return new CommandResult(generateSuccessMessage(editedPerson));
+ }
+
+ /**
+ * Generates a command execution success message based on whether
+ * the remark is added to or removed from
+ * {@code personToEdit}.
+ */
+ private String generateSuccessMessage(Person personToEdit) {
+ String message = !remark.toString().isEmpty() ? MESSAGE_ADD_REMARK_SUCCESS : MESSAGE_DELETE_REMARK_SUCCESS;
+ return String.format(message, Messages.format(personToEdit));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof RemarkCommand)) {
+ return false;
+ }
+
+ RemarkCommand e = (RemarkCommand) other;
+ return index.equals(e.index)
+ && remark.equals(e.remark);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/TagCommand.java b/src/main/java/seedu/address/logic/commands/TagCommand.java
new file mode 100644
index 00000000000..3b05e5b6021
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/TagCommand.java
@@ -0,0 +1,189 @@
+package seedu.address.logic.commands;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
+import static seedu.address.logic.commands.CommandUtil.getPersonAtIndex;
+import static seedu.address.logic.commands.CommandUtil.verifyPersonChanged;
+import static seedu.address.logic.commands.CommandUtil.verifyPersonTagCountIsValid;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_ADD_TAG;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DELETE_TAG;
+import static seedu.address.model.person.Person.createPersonWithUpdatedTags;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.logging.Logger;
+
+import seedu.address.commons.core.LogsCenter;
+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.person.Person;
+import seedu.address.model.person.Tag;
+
+/**
+ * Adds or deletes tags of a person identified using it's displayed index from the address book.
+ */
+public class TagCommand extends Command {
+ public static final String COMMAND_WORD = "tag";
+
+ public static final String MESSAGE_USAGE = "Usage: \n" + COMMAND_WORD
+ + " "
+ + "[" + PREFIX_ADD_TAG + "]... "
+ + "[" + PREFIX_DELETE_TAG + "]...\n";
+
+ public static final String MESSAGE_TAG_PERSON_SUCCESS = "Updated tag of customer: %s";
+ public static final String MESSAGE_NOT_UPDATED = "At least one tag to add or delete must be provided.";
+ public static final String MESSAGE_COMMON_TAG_FAILURE = "Should not add and delete the same tag.";
+ public static final String MESSAGE_TAG_UNCHANGED_REASONS =
+ "(Possible reason: only adding tags that already exist and/or deleting tags that do not exist)";
+
+ private static final Logger logger = LogsCenter.getLogger(TagCommand.class);
+
+ private final Index index;
+ private final UpdatePersonTagsDescriptor updatePersonTagsDescriptor;
+
+ /**
+ * Constructs a Tag Command.
+ *
+ * @param index of the person in the filtered person list to tag.
+ * @param updatePersonTagsDescriptor containing details of tags to update.
+ */
+ public TagCommand(Index index, UpdatePersonTagsDescriptor updatePersonTagsDescriptor) {
+ requireAllNonNull(index, updatePersonTagsDescriptor);
+ assert updatePersonTagsDescriptor.hasTagToUpdate()
+ : "TagCommand expects an updatePersonTagsDescriptor that has tags to be updated";
+
+ this.index = index;
+ this.updatePersonTagsDescriptor = new UpdatePersonTagsDescriptor(updatePersonTagsDescriptor);
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ requireNonNull(model);
+
+ logger.fine("TagCommand executing...");
+
+ verifyCommandIsExecutable(model);
+
+ Person personToUpdate = getPersonAtIndex(model, index);
+ Person updatedPerson = createPersonWithUpdatedTags(personToUpdate,
+ updatePersonTagsDescriptor.getTagsToAdd(),
+ updatePersonTagsDescriptor.getTagsToDelete());
+ requireAllNonNull(personToUpdate, updatedPerson);
+
+ verifyPersonChanged(personToUpdate, updatedPerson, MESSAGE_TAG_UNCHANGED_REASONS);
+ verifyPersonTagCountIsValid(updatedPerson);
+
+ model.setPerson(personToUpdate, updatedPerson);
+
+ return new CommandResult(String.format(MESSAGE_TAG_PERSON_SUCCESS, Messages.format(updatedPerson)));
+ }
+
+ /**
+ * Throws a {@code CommandException} if the command is not executable.
+ */
+ private void verifyCommandIsExecutable(Model model) throws CommandException {
+ requireNonNull(model);
+
+ if (updatePersonTagsDescriptor.containsCommonTagToAddAndDelete()) {
+ logger.finer("TagCommand execution failed due to common tag in add and delete");
+ throw new CommandException(MESSAGE_COMMON_TAG_FAILURE);
+ }
+ }
+
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof TagCommand)) {
+ return false;
+ }
+
+ TagCommand otherTagCommand = (TagCommand) other;
+ return index.equals(otherTagCommand.index)
+ && updatePersonTagsDescriptor.equals(otherTagCommand.updatePersonTagsDescriptor);
+ }
+
+ /**
+ * Stores the information of tags to add to and tags to delete from a person.
+ */
+ public static class UpdatePersonTagsDescriptor {
+ private Set tagsToAdd;
+ private Set tagsToDelete;
+
+ /**
+ * Constructs a {@code UpdatePersonTagsDescriptor} with {@code tagsToAdd} and {@code tagsToDelete}.
+ * A defensive copy of {@code tagsToAdd} and {@code tagsToDelete} is used internally.
+ */
+ public UpdatePersonTagsDescriptor(Set tagsToAdd, Set tagsToDelete) {
+ requireAllNonNull(tagsToAdd, tagsToDelete);
+
+ this.tagsToAdd = new HashSet<>(tagsToAdd);
+ this.tagsToDelete = new HashSet<>(tagsToDelete);
+ }
+
+ /**
+ * Constructs a defensive copy of {@code toCopy}.
+ */
+ public UpdatePersonTagsDescriptor(UpdatePersonTagsDescriptor toCopy) {
+ requireNonNull(toCopy);
+
+ this.tagsToAdd = new HashSet<>(toCopy.tagsToAdd);
+ this.tagsToDelete = new HashSet<>(toCopy.tagsToDelete);
+ }
+
+
+ public void setTagsToAdd(Set tagsToAdd) {
+ requireNonNull(tagsToAdd);
+
+ this.tagsToAdd = new HashSet<>(tagsToAdd);
+ }
+
+ public void setTagsToDelete(Set tagsToDelete) {
+ requireNonNull(tagsToDelete);
+
+ this.tagsToDelete = new HashSet<>(tagsToDelete);
+ }
+
+ public Set getTagsToAdd() {
+ return new HashSet<>(tagsToAdd);
+ }
+
+ public Set getTagsToDelete() {
+ return new HashSet<>(tagsToDelete);
+ }
+
+ /**
+ * Returns true if there is at least one tag to update.
+ */
+ public boolean hasTagToUpdate() {
+ return !(tagsToAdd.isEmpty() && tagsToDelete.isEmpty());
+ }
+
+ private boolean containsCommonTagToAddAndDelete() {
+ Set intersectionSet = new HashSet<>(tagsToAdd);
+ intersectionSet.retainAll(tagsToDelete);
+ return !intersectionSet.isEmpty();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof UpdatePersonTagsDescriptor)) {
+ return false;
+ }
+
+ UpdatePersonTagsDescriptor otherUpdatePersonTagsDescriptor = (UpdatePersonTagsDescriptor) other;
+ return tagsToAdd.equals(otherUpdatePersonTagsDescriptor.tagsToAdd)
+ && tagsToDelete.equals(otherUpdatePersonTagsDescriptor.tagsToDelete);
+ }
+ }
+}
diff --git a/src/main/java/seedu/address/logic/commands/UnmarkAppointmentCommand.java b/src/main/java/seedu/address/logic/commands/UnmarkAppointmentCommand.java
new file mode 100644
index 00000000000..78bf252a16a
--- /dev/null
+++ b/src/main/java/seedu/address/logic/commands/UnmarkAppointmentCommand.java
@@ -0,0 +1,109 @@
+package seedu.address.logic.commands;
+
+import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
+import static seedu.address.logic.commands.CommandUtil.getPersonAtIndex;
+import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS;
+
+import java.util.logging.Logger;
+
+import seedu.address.commons.core.LogsCenter;
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.exceptions.CommandException;
+import seedu.address.model.Model;
+import seedu.address.model.person.Appointment;
+import seedu.address.model.person.AppointmentCount;
+import seedu.address.model.person.Person;
+
+//@@author AY2122S1-CS2103T-T09-4/tp--reused
+//Reused from https://github.com/AY2122S1-CS2103T-T09-4/tp/blob/master/
+//src/main/java/seedu/fast/logic/commands/UnmarkAppointmentCommand.java
+//with minor modifications
+/**
+ * Unmarks the appointment with an existing person in the address book.
+ */
+public class UnmarkAppointmentCommand extends Command {
+ public static final String COMMAND_WORD = "unmarkappt";
+
+ public static final String MESSAGE_USAGE = "Usage: \n" + COMMAND_WORD
+ + " ";
+
+ public static final String MESSAGE_UNMARK_APPOINTMENT_SUCCESS = "Successfully undo marking of appointment with "
+ + "%1$s.";
+ public static final String MESSAGE_UNMARK_APPOINTMENT_FAILURE_ZERO_COUNT = "You cannot undo marking of appointment "
+ + "if you have not finished any appointment!";
+
+ public static final String MESSAGE_UNMARK_APPOINTMENT_FAILURE_APPT_EXIST = "You cannot undo marking of appointment "
+ + "if you have a scheduled appointment with %1$s currently!";
+
+ private final Logger logger = LogsCenter.getLogger(getClass());
+
+ private final Index index;
+ private final Appointment appointment;
+
+ /**
+ * Construct for an {@code UnmarkAppointmentCommand}
+ *
+ * @param index index of the person in the filtered person list to mark the appointment as completed
+ * @param appointment the existing appointment that has been marked completed
+ */
+ public UnmarkAppointmentCommand(Index index, Appointment appointment) {
+ requireAllNonNull(index, appointment);
+
+ this.index = index;
+ this.appointment = appointment;
+ }
+
+ @Override
+ public CommandResult execute(Model model) throws CommandException {
+ Person personToEdit = getPersonAtIndex(model, index);
+
+ // AppointmentCount cannot go below 0.
+ if (!AppointmentCount.isValidDecrementCount(personToEdit.getAppointmentCount())) {
+ logger.warning("-----Invalid Unmark Appointment Command: Appointment Count cannot go below 0-----");
+ throw new CommandException(MESSAGE_UNMARK_APPOINTMENT_FAILURE_ZERO_COUNT);
+ }
+
+ // Has an appointment -> means did not accidentally mark an appointment as completed.
+ if (!(Appointment.isAppointmentEmpty(personToEdit.getAppointment()))) {
+ logger.warning("-----Invalid Unmark Appointment Command: Appointment Exist-----");
+ throw new CommandException(String.format(MESSAGE_UNMARK_APPOINTMENT_FAILURE_APPT_EXIST,
+ personToEdit.getName()));
+ }
+
+ Person editedPerson = Person.createPersonWithDecreasedCount(personToEdit,
+ appointment, personToEdit.getAppointmentCount());
+ model.setPerson(personToEdit, editedPerson);
+ model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS);
+ logger.info("-----Unmark Appointment Command: Appointment unmarked successfully-----");
+
+ return new CommandResult(generateSuccessMessage(personToEdit));
+ }
+
+ /**
+ * Generates a command execution success message when the appointment is marked as completed successfully.
+ * {@code personToEdit}.
+ */
+ private String generateSuccessMessage(Person personToEdit) {
+
+ return String.format(MESSAGE_UNMARK_APPOINTMENT_SUCCESS, personToEdit.getName().fullName);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // short circuit if same object
+ if (other == this) {
+ return true;
+ }
+
+ // instanceof handles nulls
+ if (!(other instanceof UnmarkAppointmentCommand)) {
+ return false;
+ }
+
+ // state check
+ UnmarkAppointmentCommand e = (UnmarkAppointmentCommand) other;
+ return index.equals(e.index)
+ && appointment.equals(e.appointment);
+ }
+}
+//@@author
diff --git a/src/main/java/seedu/address/logic/parser/AddCommandParser.java b/src/main/java/seedu/address/logic/parser/AddCommandParser.java
index 4ff1a97ed77..53112cbd8ff 100644
--- a/src/main/java/seedu/address/logic/parser/AddCommandParser.java
+++ b/src/main/java/seedu/address/logic/parser/AddCommandParser.java
@@ -1,61 +1,100 @@
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_ADDRESS;
import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_INSURANCE;
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_PRIORITY;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_REMARK;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
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.Appointment;
+import seedu.address.model.person.AppointmentCount;
import seedu.address.model.person.Email;
+import seedu.address.model.person.Insurance;
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.person.Remark;
+import seedu.address.model.person.Tag;
+import seedu.address.model.priority.Priority;
/**
* Parses input arguments and creates a new AddCommand object
*/
public class AddCommandParser implements Parser {
+ private static final Prefix[] validPrefixes = new Prefix[] { PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL,
+ PREFIX_ADDRESS, PREFIX_TAG, PREFIX_INSURANCE, PREFIX_REMARK, PREFIX_PRIORITY};
+ private static final Prefix[] compulsoryPrefixes =
+ new Prefix[] { PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL };
+ private static final Prefix[] nonRepeatingPrefixes =
+ new Prefix[] { PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_REMARK, PREFIX_PRIORITY };
+
/**
* Parses the given {@code String} of arguments in the context of the AddCommand
* and returns an AddCommand object for execution.
* @throws ParseException if the user input does not conform the expected format
*/
public AddCommand parse(String args) throws ParseException {
- ArgumentMultimap argMultimap =
- ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_TAG);
+ requireNonNull(args);
+
+ ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args, validPrefixes);
+ verifyIsValidArgumentMultimap(argMultimap);
+
+ Person personToAdd = createPersonToAdd(argMultimap);
+
+ return new AddCommand(personToAdd);
+ }
+
+ /**
+ * Throws a {@code ParseException} if the {@code map} is not a valid {@code ArgumentMultimap}
+ * for {@code AddCommand}.
+ */
+ private static void verifyIsValidArgumentMultimap(ArgumentMultimap argMultimap) throws ParseException {
+ requireNonNull(argMultimap);
+
+ if (!argMultimap.areAllPrefixesPresent(compulsoryPrefixes)) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE));
+ }
- if (!arePrefixesPresent(argMultimap, PREFIX_NAME, PREFIX_ADDRESS, PREFIX_PHONE, PREFIX_EMAIL)
- || !argMultimap.getPreamble().isEmpty()) {
+ if (!argMultimap.isPreambleEmpty()) {
throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, AddCommand.MESSAGE_USAGE));
}
- argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS);
+ argMultimap.verifyNoDuplicatePrefixesFor(nonRepeatingPrefixes);
+ }
+
+ /**
+ * Creates a {@code Person} using the information in {@code argMultimap}.
+ * @param argMultimap contains the information of the attributes of the person.
+ * @throws ParseException if there are certain attributes that could not be parsed.
+ */
+ private static Person createPersonToAdd(ArgumentMultimap argMultimap) throws ParseException {
+ requireNonNull(argMultimap);
+
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());
+ Remark remark = ParserUtil.parseRemark(argMultimap.getValue(PREFIX_REMARK).orElse(""));
+ Address address = ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).orElse(""));
Set tagList = ParserUtil.parseTags(argMultimap.getAllValues(PREFIX_TAG));
+ Set insurances = ParserUtil.parseInsurances(argMultimap.getAllValues(PREFIX_INSURANCE));
+ Appointment appointment = Appointment.getDefaultEmptyAppointment();
+ AppointmentCount count = AppointmentCount.getDefaultAppointmentCount();
- Person person = new Person(name, phone, email, address, tagList);
+ Priority priority = ParserUtil.parsePriority(argMultimap.getValue(PREFIX_PRIORITY)
+ .orElse(Priority.NONE_PRIORITY_KEYWORD));
- return new AddCommand(person);
+ return new Person(name, phone, email, address, remark, tagList, insurances,
+ appointment, count, priority);
}
-
- /**
- * 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());
- }
-
}
diff --git a/src/main/java/seedu/address/logic/parser/AddressBookParser.java b/src/main/java/seedu/address/logic/parser/AddressBookParser.java
index 3149ee07e0b..0c216bdc2a0 100644
--- a/src/main/java/seedu/address/logic/parser/AddressBookParser.java
+++ b/src/main/java/seedu/address/logic/parser/AddressBookParser.java
@@ -9,14 +9,22 @@
import seedu.address.commons.core.LogsCenter;
import seedu.address.logic.commands.AddCommand;
+import seedu.address.logic.commands.AppointmentCommand;
import seedu.address.logic.commands.ClearCommand;
import seedu.address.logic.commands.Command;
+import seedu.address.logic.commands.DeleteAppointmentCommand;
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.InsuranceCommand;
import seedu.address.logic.commands.ListCommand;
+import seedu.address.logic.commands.MarkAppointmentCommand;
+import seedu.address.logic.commands.PriorityCommand;
+import seedu.address.logic.commands.RemarkCommand;
+import seedu.address.logic.commands.TagCommand;
+import seedu.address.logic.commands.UnmarkAppointmentCommand;
import seedu.address.logic.parser.exceptions.ParseException;
/**
@@ -46,12 +54,15 @@ public Command parseCommand(String userInput) throws ParseException {
final String commandWord = matcher.group("commandWord");
final String arguments = matcher.group("arguments");
+ // Convert all Uppercase to lowercase
+ final String processedCommandWord = commandWord.toLowerCase();
+
// 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) {
+ switch (processedCommandWord) {
case AddCommand.COMMAND_WORD:
return new AddCommandParser().parse(arguments);
@@ -77,6 +88,30 @@ public Command parseCommand(String userInput) throws ParseException {
case HelpCommand.COMMAND_WORD:
return new HelpCommand();
+ case RemarkCommand.COMMAND_WORD:
+ return new RemarkCommandParser().parse(arguments);
+
+ case TagCommand.COMMAND_WORD:
+ return new TagCommandParser().parse(arguments);
+
+ case PriorityCommand.COMMAND_WORD:
+ return new PriorityCommandParser().parse(arguments);
+
+ case InsuranceCommand.COMMAND_WORD:
+ return new InsuranceCommandParser().parse(arguments);
+
+ case AppointmentCommand.COMMAND_WORD:
+ return new AppointmentCommandParser().parse(arguments);
+
+ case DeleteAppointmentCommand.COMMAND_WORD:
+ return new DeleteAppointmentCommandParser().parse(arguments);
+
+ case MarkAppointmentCommand.COMMAND_WORD:
+ return new MarkAppointmentCommandParser().parse(arguments);
+
+ case UnmarkAppointmentCommand.COMMAND_WORD:
+ return new UnmarkAppointmentCommandParser().parse(arguments);
+
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/AppointmentCommandParser.java b/src/main/java/seedu/address/logic/parser/AppointmentCommandParser.java
new file mode 100644
index 00000000000..cf6d7bf3369
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/AppointmentCommandParser.java
@@ -0,0 +1,92 @@
+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_APPOINTMENT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_APPOINTMENT_TIME;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_APPOINTMENT_VENUE;
+import static seedu.address.logic.parser.ParserUtil.parseDateString;
+import static seedu.address.logic.parser.ParserUtil.parseTimeString;
+
+import java.util.logging.Logger;
+
+import seedu.address.commons.core.LogsCenter;
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.AppointmentCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.person.Appointment;
+
+/**
+ * Parses input arguments and creates a new AppointmentCommand object
+ */
+public class AppointmentCommandParser implements Parser {
+ private static final Logger logger = LogsCenter.getLogger(AppointmentCommandParser.class);
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the AppointmentCommand
+ * and returns an AppointmentCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public AppointmentCommand parse(String args) throws ParseException {
+ requireNonNull(args);
+ logger.fine("AppointmentCommandParser parsing: " + args);
+
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(args,
+ PREFIX_APPOINTMENT, PREFIX_APPOINTMENT_TIME, PREFIX_APPOINTMENT_VENUE);
+
+ Index index;
+ try {
+ index = ParserUtil.parseIndex(argMultimap.getPreamble());
+ } catch (ParseException pe) {
+ logger.finer("AppointmentCommandParser parse failed due to invalid index: " + argMultimap.getPreamble());
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ AppointmentCommand.MESSAGE_USAGE), pe);
+ }
+ String parsedDate = getParsedDate(argMultimap);
+ String parsedTime = getParsedTime(argMultimap);
+ String parsedVenue = getParsedVenue(argMultimap);
+ return new AppointmentCommand(index, new Appointment(parsedDate, parsedTime, parsedVenue));
+ }
+
+ //@@author AY2122S1-CS2103T-T09-4/tp--reused
+ //Reused from https://github.com/AY2122S1-CS2103T-T09-4/tp/blob/master/
+ //src/main/java/seedu/fast/logic/parser/AppointmentCommandParser.java
+ //with minor modifications
+ private String checkInputDate(String retrievedDate) throws ParseException {
+ if (retrievedDate.equalsIgnoreCase(Appointment.NO_APPOINTMENT)) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ AppointmentCommand.MESSAGE_USAGE));
+ }
+
+ return retrievedDate;
+ }
+ private String getParsedDate(ArgumentMultimap argMultimap) throws ParseException {
+ String retrievedDate = checkInputDate(argMultimap.getValue(PREFIX_APPOINTMENT)
+ .orElse(Appointment.NO_APPOINTMENT));
+ String parsedDate = parseDateString(retrievedDate);
+ return parsedDate;
+ }
+
+ private String getParsedTime(ArgumentMultimap argMultimap) throws ParseException {
+ String retrievedTime = argMultimap.getValue(PREFIX_APPOINTMENT_TIME).orElse(Appointment.NO_TIME);
+ String parsedTime = parseTimeString(retrievedTime);
+ logger.info(parsedTime + "get to apptcmd parser");
+ return parsedTime;
+ }
+
+ private String checkVenueLength(String venue) throws ParseException {
+ if (!Appointment.isValidVenueFormat(venue)) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ Appointment.INVALID_VENUE_INPUT));
+ }
+ return venue;
+ }
+
+ private String getParsedVenue(ArgumentMultimap argMultimap) throws ParseException {
+ String retrievedVenue = argMultimap.getValue(PREFIX_APPOINTMENT_VENUE).orElse(Appointment.NO_VENUE);
+ String parsedVenue = checkVenueLength(retrievedVenue);
+ return parsedVenue;
+ }
+}
+ //@@author
diff --git a/src/main/java/seedu/address/logic/parser/ArgumentMultimap.java b/src/main/java/seedu/address/logic/parser/ArgumentMultimap.java
index 21e26887a83..5aa2567ae7c 100644
--- a/src/main/java/seedu/address/logic/parser/ArgumentMultimap.java
+++ b/src/main/java/seedu/address/logic/parser/ArgumentMultimap.java
@@ -1,5 +1,8 @@
package seedu.address.logic.parser;
+import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_EMPTY;
+
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -59,7 +62,7 @@ public List getAllValues(Prefix prefix) {
* Returns the preamble (text before the first valid prefix). Trims any leading/trailing spaces.
*/
public String getPreamble() {
- return getValue(new Prefix("")).orElse("");
+ return getValue(PREFIX_EMPTY).orElse("");
}
/**
@@ -75,4 +78,19 @@ public void verifyNoDuplicatePrefixesFor(Prefix... prefixes) throws ParseExcepti
throw new ParseException(Messages.getErrorMessageForDuplicatePrefixes(duplicatedPrefixes));
}
}
+
+ /**
+ * Returns true if all the prefixes given in {@code prefixes} appeared among the arguments.
+ */
+ public boolean areAllPrefixesPresent(Prefix... prefixes) {
+ requireAllNonNull((Object) prefixes);
+ return Stream.of(prefixes).distinct().allMatch(prefix -> getValue(prefix).isPresent());
+ }
+
+ /**
+ * Returns true if the preamble is empty.
+ */
+ public boolean isPreambleEmpty() {
+ return getPreamble().isEmpty();
+ }
}
diff --git a/src/main/java/seedu/address/logic/parser/ArgumentTokenizer.java b/src/main/java/seedu/address/logic/parser/ArgumentTokenizer.java
index 5c9aebfa488..35889271158 100644
--- a/src/main/java/seedu/address/logic/parser/ArgumentTokenizer.java
+++ b/src/main/java/seedu/address/logic/parser/ArgumentTokenizer.java
@@ -1,5 +1,7 @@
package seedu.address.logic.parser;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_EMPTY;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -47,32 +49,55 @@ private static List findAllPrefixPositions(String argsString, Pr
private static List findPrefixPositions(String argsString, Prefix prefix) {
List positions = new ArrayList<>();
- int prefixPosition = findPrefixPosition(argsString, prefix.getPrefix(), 0);
- while (prefixPosition != -1) {
- PrefixPosition extendedPrefix = new PrefixPosition(prefix, prefixPosition);
- positions.add(extendedPrefix);
- prefixPosition = findPrefixPosition(argsString, prefix.getPrefix(), prefixPosition);
+ PrefixPosition prefixPosition = findPrefixPosition(argsString, prefix, 0);
+ while (prefixPosition != null) {
+ positions.add(prefixPosition);
+ prefixPosition = findPrefixPosition(argsString, prefix, prefixPosition.getEndPosition());
}
return positions;
}
/**
- * Returns the index of the first occurrence of {@code prefix} in
+ * Returns the {@code PrefixPosition} of the first occurrence of {@code prefix} in
* {@code argsString} starting from index {@code fromIndex}. An occurrence
- * is valid if there is a whitespace before {@code prefix}. Returns -1 if no
+ * is valid if there is a whitespace before {@code prefix}. Returns null if no
* such occurrence can be found.
*
* E.g if {@code argsString} = "e/hip/900", {@code prefix} = "p/" and
- * {@code fromIndex} = 0, this method returns -1 as there are no valid
+ * {@code fromIndex} = 0, this method returns null as there are no valid
* occurrences of "p/" with whitespace before it. However, if
* {@code argsString} = "e/hi p/900", {@code prefix} = "p/" and
* {@code fromIndex} = 0, this method returns 5.
*/
- private static int findPrefixPosition(String argsString, String prefix, int fromIndex) {
- int prefixIndex = argsString.indexOf(" " + prefix, fromIndex);
- return prefixIndex == -1 ? -1
- : prefixIndex + 1; // +1 as offset for whitespace
+ private static PrefixPosition findPrefixPosition(String argsString, Prefix prefix, int fromIndex) {
+ String convertedArgsString = argsString.toLowerCase();
+
+ int prefixIndex = convertedArgsString.indexOf(" " + prefix.getPrefix(), fromIndex);
+ int secondaryPrefixIndex = convertedArgsString.indexOf(" " + prefix.getSecondaryPrefix(), fromIndex);
+
+ if (prefixIndex == -1 && secondaryPrefixIndex == -1) {
+ return null;
+ }
+
+ if (prefixIndex == -1) {
+ return new PrefixPosition(prefix, secondaryPrefixIndex + 1,
+ secondaryPrefixIndex + 1 + prefix.getSecondaryPrefixLength());
+ }
+
+ if (secondaryPrefixIndex == -1) {
+ return new PrefixPosition(prefix, prefixIndex + 1,
+ prefixIndex + 1 + prefix.getPrefixLength());
+ }
+
+ // both indexes are present
+ if (prefixIndex < secondaryPrefixIndex) {
+ return new PrefixPosition(prefix, prefixIndex + 1,
+ prefixIndex + 1 + prefix.getPrefixLength());
+ } else {
+ return new PrefixPosition(prefix, secondaryPrefixIndex + 1,
+ secondaryPrefixIndex + 1 + prefix.getSecondaryPrefixLength());
+ }
}
/**
@@ -90,11 +115,11 @@ private static ArgumentMultimap extractArguments(String argsString, List prefix1.getStartPosition() - prefix2.getStartPosition());
// Insert a PrefixPosition to represent the preamble
- PrefixPosition preambleMarker = new PrefixPosition(new Prefix(""), 0);
+ PrefixPosition preambleMarker = new PrefixPosition(PREFIX_EMPTY, 0, 0);
prefixPositions.add(0, preambleMarker);
// Add a dummy PrefixPosition to represent the end of the string
- PrefixPosition endPositionMarker = new PrefixPosition(new Prefix(""), argsString.length());
+ PrefixPosition endPositionMarker = new PrefixPosition(PREFIX_EMPTY, argsString.length(), argsString.length());
prefixPositions.add(endPositionMarker);
// Map prefixes to their argument values (if any)
@@ -116,10 +141,9 @@ private static ArgumentMultimap extractArguments(String argsString, List {
+ @Override
+ public DeleteAppointmentCommand parse(String args) throws ParseException {
+ requireNonNull(args);
+ ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args);
+
+ Index index;
+ try {
+ index = ParserUtil.parseIndex(argMultimap.getPreamble());
+ } catch (IllegalValueException ive) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ DeleteAppointmentCommand.MESSAGE_USAGE), ive);
+ }
+
+ return new DeleteAppointmentCommand(index, Appointment.getDefaultEmptyAppointment());
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/EditCommandParser.java b/src/main/java/seedu/address/logic/parser/EditCommandParser.java
index 46b3309a78b..b288406d744 100644
--- a/src/main/java/seedu/address/logic/parser/EditCommandParser.java
+++ b/src/main/java/seedu/address/logic/parser/EditCommandParser.java
@@ -2,84 +2,108 @@
import static java.util.Objects.requireNonNull;
import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.commands.EditCommand.PREFIX_EDIT_ERROR_MESSAGE_MAP;
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_INSURANCE;
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_PRIORITY;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_REMARK;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Optional;
-import java.util.Set;
+import java.util.logging.Logger;
+import seedu.address.commons.core.LogsCenter;
import seedu.address.commons.core.index.Index;
import seedu.address.logic.commands.EditCommand;
import seedu.address.logic.commands.EditCommand.EditPersonDescriptor;
import seedu.address.logic.parser.exceptions.ParseException;
-import seedu.address.model.tag.Tag;
+import seedu.address.model.person.Address;
+import seedu.address.model.person.Email;
+import seedu.address.model.person.Name;
+import seedu.address.model.person.Phone;
/**
- * Parses input arguments and creates a new EditCommand object
+ * Parses input arguments and creates a new EditCommand object.
*/
public class EditCommandParser implements Parser {
+ private static final Logger logger = LogsCenter.getLogger(EditCommandParser.class);
/**
* Parses the given {@code String} of arguments in the context of the EditCommand
* and returns an EditCommand object for execution.
- * @throws ParseException if the user input does not conform the expected format
+ *
+ * @throws ParseException if the user input does not conform the expected format.
*/
public EditCommand parse(String args) throws ParseException {
requireNonNull(args);
+
+ logger.fine("EditCommandParser parsing...");
+
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_TAG,
+ PREFIX_PRIORITY, PREFIX_INSURANCE, PREFIX_REMARK);
+ assert argMultimap != null : "ArgumentTokenizer.tokenize returns null";
Index index;
-
try {
index = ParserUtil.parseIndex(argMultimap.getPreamble());
} catch (ParseException pe) {
+ logger.finer("Parsing failed due to invalid command format");
throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE), pe);
}
+ checkPrefixPresent(argMultimap, PREFIX_TAG, PREFIX_PRIORITY, PREFIX_INSURANCE, PREFIX_REMARK);
+
argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS);
+ EditPersonDescriptor editPersonDescriptor = getEditPersonDescriptor(argMultimap);
+
+ if (!editPersonDescriptor.isAnyFieldEdited()) {
+ logger.finer("Parsing failed due to person's information not edited");
+ throw new ParseException(EditCommand.MESSAGE_NOT_EDITED);
+ }
+
+ return new EditCommand(index, editPersonDescriptor);
+ }
+
+ private EditPersonDescriptor getEditPersonDescriptor(ArgumentMultimap argMultimap) throws ParseException {
EditPersonDescriptor editPersonDescriptor = new EditPersonDescriptor();
if (argMultimap.getValue(PREFIX_NAME).isPresent()) {
- editPersonDescriptor.setName(ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get()));
+ Name name = ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get());
+ editPersonDescriptor.setName(name);
}
if (argMultimap.getValue(PREFIX_PHONE).isPresent()) {
- editPersonDescriptor.setPhone(ParserUtil.parsePhone(argMultimap.getValue(PREFIX_PHONE).get()));
+ Phone phone = ParserUtil.parsePhone(argMultimap.getValue(PREFIX_PHONE).get());
+ editPersonDescriptor.setPhone(phone);
}
if (argMultimap.getValue(PREFIX_EMAIL).isPresent()) {
- editPersonDescriptor.setEmail(ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get()));
+ Email email = ParserUtil.parseEmail(argMultimap.getValue(PREFIX_EMAIL).get());
+ editPersonDescriptor.setEmail(email);
}
if (argMultimap.getValue(PREFIX_ADDRESS).isPresent()) {
- editPersonDescriptor.setAddress(ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get()));
+ Address address = ParserUtil.parseAddress(argMultimap.getValue(PREFIX_ADDRESS).get());
+ editPersonDescriptor.setAddress(address);
}
- parseTagsForEdit(argMultimap.getAllValues(PREFIX_TAG)).ifPresent(editPersonDescriptor::setTags);
- if (!editPersonDescriptor.isAnyFieldEdited()) {
- throw new ParseException(EditCommand.MESSAGE_NOT_EDITED);
- }
-
- return new EditCommand(index, editPersonDescriptor);
+ return 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.
+ * Checks if {@code prefixes} are present in the {@code argMultimap}.
+ *
+ * @param argMultimap that we are performing search on.
+ * @param prefixes to search for.
+ * @throws ParseException when prefixes are found.
*/
- private Optional> parseTagsForEdit(Collection tags) throws ParseException {
- assert tags != null;
-
- if (tags.isEmpty()) {
- return Optional.empty();
+ private void checkPrefixPresent(ArgumentMultimap argMultimap, Prefix... prefixes) throws ParseException {
+ for (Prefix targetPrefix : prefixes) {
+ if (argMultimap.getValue(targetPrefix).isPresent()) {
+ logger.finer("Parsing failed due to invalid prefixes provided.");
+ throw new ParseException(PREFIX_EDIT_ERROR_MESSAGE_MAP.get(targetPrefix));
+ }
}
- Collection tagSet = tags.size() == 1 && tags.contains("") ? Collections.emptySet() : tags;
- return Optional.of(ParserUtil.parseTags(tagSet));
}
-
}
diff --git a/src/main/java/seedu/address/logic/parser/FindCommandParser.java b/src/main/java/seedu/address/logic/parser/FindCommandParser.java
index 2867bde857b..272ccaa1a73 100644
--- a/src/main/java/seedu/address/logic/parser/FindCommandParser.java
+++ b/src/main/java/seedu/address/logic/parser/FindCommandParser.java
@@ -1,33 +1,92 @@
package seedu.address.logic.parser;
+import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
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_EMAIL;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_INSURANCE;
+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_PRIORITY;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_REMARK;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;
-import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Predicate;
+import java.util.logging.Logger;
+import java.util.stream.Stream;
+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.person.Person;
+import seedu.address.model.person.predicate.PersonContainsKeywordsPredicate;
/**
* Parses input arguments and creates a new FindCommand object
*/
public class FindCommandParser implements Parser {
+ private static final Logger logger = LogsCenter.getLogger(FindCommandParser.class);
+ private static final Prefix[] validPrefixes = new Prefix[] {
+ PREFIX_INSURANCE, PREFIX_NAME, PREFIX_TAG, PREFIX_PRIORITY,
+ PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_REMARK
+ };
+
+
/**
* 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));
+ requireAllNonNull(args);
+
+ logger.fine("FindCommandParser parsing...");
+
+ ArgumentMultimap argMultimap =
+ ArgumentTokenizer.tokenize(" " + args, validPrefixes);
+
+ if (!isPrefixPresent(argMultimap, validPrefixes) || !argMultimap.getPreamble().isEmpty()) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE));
}
- String[] nameKeywords = trimmedArgs.split("\\s+");
+ argMultimap.verifyNoDuplicatePrefixesFor(validPrefixes);
- return new FindCommand(new NameContainsKeywordsPredicate(Arrays.asList(nameKeywords)));
+ List> predicateList = new ArrayList<>();
+
+ if (argMultimap.getValue(PREFIX_NAME).isPresent()) {
+ predicateList.add(ParserUtil.parseNameKeywords(argMultimap.getValue(PREFIX_NAME).get()));
+ }
+ if (argMultimap.getValue(PREFIX_INSURANCE).isPresent()) {
+ predicateList.add(ParserUtil.parseInsuranceKeywords(argMultimap.getValue(PREFIX_INSURANCE).get()));
+ }
+ if (argMultimap.getValue(PREFIX_ADDRESS).isPresent()) {
+ predicateList.add(ParserUtil.parseAddressKeywords(argMultimap.getValue(PREFIX_ADDRESS).get()));
+ }
+ if (argMultimap.getValue(PREFIX_EMAIL).isPresent()) {
+ predicateList.add(ParserUtil.parseEmailKeywords(argMultimap.getValue(PREFIX_EMAIL).get()));
+ }
+ if (argMultimap.getValue(PREFIX_PHONE).isPresent()) {
+ predicateList.add(ParserUtil.parsePhoneKeywords(argMultimap.getValue(PREFIX_PHONE).get()));
+ }
+ if (argMultimap.getValue(PREFIX_TAG).isPresent()) {
+ predicateList.add(ParserUtil.parseTagKeywords(argMultimap.getValue(PREFIX_TAG).get()));
+ }
+ if (argMultimap.getValue(PREFIX_REMARK).isPresent()) {
+ predicateList.add(ParserUtil.parseRemarkKeywords(argMultimap.getValue(PREFIX_REMARK).get()));
+ }
+ if (argMultimap.getValue(PREFIX_PRIORITY).isPresent()) {
+ predicateList.add(ParserUtil.parsePriorityKeywords(argMultimap.getValue(PREFIX_PRIORITY).get()));
+ }
+
+
+ return new FindCommand(new PersonContainsKeywordsPredicate(predicateList));
}
+ private static boolean isPrefixPresent(ArgumentMultimap argumentMultimap, Prefix... prefixes) {
+ requireAllNonNull(argumentMultimap, prefixes);
+ return Stream.of(prefixes).anyMatch(prefix -> argumentMultimap.getValue(prefix).isPresent());
+ }
}
diff --git a/src/main/java/seedu/address/logic/parser/InsuranceCommandParser.java b/src/main/java/seedu/address/logic/parser/InsuranceCommandParser.java
new file mode 100644
index 00000000000..bb72049455a
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/InsuranceCommandParser.java
@@ -0,0 +1,102 @@
+package seedu.address.logic.parser;
+
+import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_ADD_INSURANCE;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DELETE_INSURANCE;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Optional;
+import java.util.Set;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.InsuranceCommand;
+import seedu.address.logic.commands.InsuranceCommand.UpdatePersonInsuranceDescriptor;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.person.Insurance;
+
+
+/**
+ * Parse the required details and creates InsuranceCommand
+ *
+ */
+public class InsuranceCommandParser implements Parser {
+
+ private ArgumentMultimap argMultimap;
+
+ /**
+ * Parse the given arguments and extract out the useful information for InsuranceCommand
+ *
+ * @param args input arguments
+ * @return InsuranceCommand object to be executed
+ * @throws ParseException when there is error in the input
+ */
+ @Override
+ public InsuranceCommand parse(String args) throws ParseException {
+ requireAllNonNull(args);
+
+ argMultimap = ArgumentTokenizer.tokenize(args, PREFIX_ADD_INSURANCE, PREFIX_DELETE_INSURANCE);
+
+ Index index = obtainIndex();
+ UpdatePersonInsuranceDescriptor changes = obtainChanges();
+
+ return new InsuranceCommand(index, changes);
+ }
+
+ /**
+ * Check the parsed arguments for the {@code Index}
+ *
+ * @return {@code Index} indicated by the command if valid
+ * @throws ParseException when {@code Index} is out of bound or invalid values is passed in
+ */
+ private Index obtainIndex() throws ParseException {
+ try {
+ return ParserUtil.parseIndex(argMultimap.getPreamble());
+ } catch (ParseException e) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, InsuranceCommand.MESSAGE_USAGE), e);
+ }
+ }
+
+ /**
+ * Check the parsed arguments for {@code Insurance} to update
+ *
+ * @return {@code UpdatePersonInsuranceDescriptor} that holds the {@code Insurance} to update on {@code Person}
+ * @throws ParseException when there is invalid or conflicting {@code Insurance}
+ */
+ private UpdatePersonInsuranceDescriptor obtainChanges() throws ParseException {
+ Set insurancesToAdd =
+ parseInsurances(argMultimap.getAllValues(PREFIX_ADD_INSURANCE)).orElse(new HashSet<>());
+
+ Set insurancesToDelete =
+ parseInsurances(argMultimap.getAllValues(PREFIX_DELETE_INSURANCE)).orElse(new HashSet<>());
+
+ requireAllNonNull(insurancesToAdd, insurancesToDelete);
+
+ UpdatePersonInsuranceDescriptor changes =
+ new UpdatePersonInsuranceDescriptor(insurancesToAdd, insurancesToDelete);
+
+ if (!changes.hasInsuranceToUpdate()) {
+ throw new ParseException(InsuranceCommand.MESSAGE_INSURANCE_NO_UPDATE);
+ }
+
+ return changes;
+ }
+
+ /**
+ * Parse the all insurance name values
+ *
+ * @param insurances all insurance names
+ * @return {@code Optional>}
+ * @throws ParseException if
+ */
+ private Optional> parseInsurances(Collection insurances) throws ParseException {
+ requireAllNonNull(insurances);
+
+ if (insurances.isEmpty()) {
+ return Optional.empty();
+ }
+
+ return Optional.of(ParserUtil.parseInsurances(insurances));
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/ListCommandParser.java b/src/main/java/seedu/address/logic/parser/ListCommandParser.java
new file mode 100644
index 00000000000..80398354f85
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/ListCommandParser.java
@@ -0,0 +1,25 @@
+package seedu.address.logic.parser;
+
+import seedu.address.logic.commands.ListCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+
+/**
+ * Parses input arguments and creates a new ListCommand object
+ */
+public class ListCommandParser implements Parser {
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the ListCommand
+ * and returns a ListCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public ListCommand parse(String args) throws ParseException {
+ if (!args.isEmpty()) {
+ throw new ParseException(ListCommand.MESSAGE_USAGE);
+ }
+ return new ListCommand();
+ }
+}
+
+
+
diff --git a/src/main/java/seedu/address/logic/parser/MarkAppointmentCommandParser.java b/src/main/java/seedu/address/logic/parser/MarkAppointmentCommandParser.java
new file mode 100644
index 00000000000..d1f114a4e43
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/MarkAppointmentCommandParser.java
@@ -0,0 +1,31 @@
+package seedu.address.logic.parser;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import seedu.address.commons.core.index.Index;
+import seedu.address.commons.exceptions.IllegalValueException;
+import seedu.address.logic.commands.MarkAppointmentCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.person.Appointment;
+
+/**
+ * Parses input arguments and creates a new MarkAppointmentCommand object
+ */
+public class MarkAppointmentCommandParser implements Parser {
+ @Override
+ public MarkAppointmentCommand parse(String args) throws ParseException {
+ requireNonNull(args);
+ ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args);
+
+ Index index;
+ try {
+ index = ParserUtil.parseIndex(argMultimap.getPreamble());
+ } catch (IllegalValueException ive) {
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ MarkAppointmentCommand.MESSAGE_USAGE), ive);
+ }
+
+ return new MarkAppointmentCommand(index, Appointment.getDefaultEmptyAppointment());
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/ParserUtil.java b/src/main/java/seedu/address/logic/parser/ParserUtil.java
index b117acb9c55..4024f21a7ce 100644
--- a/src/main/java/seedu/address/logic/parser/ParserUtil.java
+++ b/src/main/java/seedu/address/logic/parser/ParserUtil.java
@@ -1,19 +1,39 @@
package seedu.address.logic.parser;
import static java.util.Objects.requireNonNull;
+import static seedu.address.model.priority.Priority.isValidPriority;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
+import java.util.function.Predicate;
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.Appointment;
import seedu.address.model.person.Email;
+import seedu.address.model.person.Insurance;
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.person.Remark;
+import seedu.address.model.person.Tag;
+import seedu.address.model.person.predicate.AddressContainsKeywordsPredicate;
+import seedu.address.model.person.predicate.EmailContainsKeywordsPredicate;
+import seedu.address.model.person.predicate.InsuranceContainsKeywordsPredicate;
+import seedu.address.model.person.predicate.NameContainsKeywordsPredicate;
+import seedu.address.model.person.predicate.PhoneContainsKeywordsPredicate;
+import seedu.address.model.person.predicate.PriorityContainsKeywordsPredicate;
+import seedu.address.model.person.predicate.RemarkContainsKeywordsPredicate;
+import seedu.address.model.person.predicate.TagContainsKeywordsPredicate;
+import seedu.address.model.priority.Priority;
/**
* Contains utility methods used for parsing strings in the various *Parser classes.
@@ -68,8 +88,6 @@ public static Phone parsePhone(String phone) throws ParseException {
/**
* Parses a {@code String address} into an {@code Address}.
* Leading and trailing whitespaces will be trimmed.
- *
- * @throws ParseException if the given {@code address} is invalid.
*/
public static Address parseAddress(String address) throws ParseException {
requireNonNull(address);
@@ -77,7 +95,7 @@ public static Address parseAddress(String address) throws ParseException {
if (!Address.isValidAddress(trimmedAddress)) {
throw new ParseException(Address.MESSAGE_CONSTRAINTS);
}
- return new Address(trimmedAddress);
+ return Address.createAddress(address.trim());
}
/**
@@ -121,4 +139,227 @@ public static Set parseTags(Collection tags) throws ParseException
}
return tagSet;
}
+
+ /**
+ * Parse a {@code String insurance} into a {@code Insurance}
+ * Leading, trailing and contiguous whitespaces between words will be trimmed.
+ *
+ */
+ private static Insurance parseInsurance(String insurance) throws ParseException {
+ requireNonNull(insurance);
+
+ String trimmed = insurance.trim();
+ trimmed = trimmed.replaceAll("\\s+", " ");
+
+ if (!Insurance.isValidInsuranceName(trimmed)) {
+ throw new ParseException(Insurance.MESSAGE_CONSTRAINTS);
+ }
+
+ return new Insurance(trimmed);
+ }
+
+ /**
+ * Parses {@code Collection insurances} into a {@code Set}.
+ */
+ public static Set parseInsurances(Collection insurances) throws ParseException {
+ requireNonNull(insurances);
+ Set insuranceSet = new HashSet<>();
+ for (String i : insurances) {
+ insuranceSet.add(parseInsurance(i));
+ }
+
+ return insuranceSet;
+ }
+
+ /**
+ * Parses a {@code String priority} into a {@code Priority}.
+ * Leading and trailing whitespaces will be trimmed.
+ * Input will be formatted to lower case to disable case-sensitivity.
+ *
+ * @throws ParseException if the given {@code priority} is invalid.
+ */
+ public static Priority parsePriority(String priority) throws ParseException {
+ requireNonNull(priority);
+ String trimmedPriority = priority.trim();
+ String formattedPriority = trimmedPriority.toLowerCase(); // disable case-sensitivity
+ if (!isValidPriority(formattedPriority)) {
+ throw new ParseException((Priority.MESSAGE_CONSTRAINTS));
+ }
+ return new Priority(formattedPriority);
+ }
+
+ /**
+ * Parses a {@code String remark} into a {@code remark}.
+ * Leading and trailing whitespaces will be trimmed.
+ *
+ * @throws ParseException if the given {@code remark} is invalid.
+ */
+ public static Remark parseRemark(String remark) throws ParseException {
+ requireNonNull(remark);
+ String trimmedRemark = remark.trim();
+ if (!Remark.isValidRemark(trimmedRemark)) {
+ throw new ParseException((Remark.MESSAGE_CONSTRAINTS));
+ }
+ return new Remark(trimmedRemark);
+ }
+
+ /**
+ * Parses a {@code String keyword} into corresponding {@code Predicate}.
+ * Leading and trailing whitespaces will be trimmed.
+ */
+ public static Predicate parseNameKeywords(String keyword) {
+ requireNonNull(keyword);
+ String trimmedKeywords = keyword.trim();
+ String[] keywords = trimmedKeywords.split("\\s+");
+ return new NameContainsKeywordsPredicate(Arrays.asList(keywords));
+ }
+
+ /**
+ * Parses a {@code String keyword} into corresponding {@code Predicate}.
+ * Leading and trailing whitespaces will be trimmed.
+ */
+ public static Predicate parseAddressKeywords(String keyword) {
+ requireNonNull(keyword);
+ String trimmedKeywords = keyword.trim();
+ String[] keywords = trimmedKeywords.split("\\s+");
+ return new AddressContainsKeywordsPredicate(Arrays.asList(keywords));
+ }
+
+ /**
+ * Parses a {@code String keyword} into corresponding {@code Predicate}.
+ * Leading and trailing whitespaces will be trimmed.
+ */
+ public static Predicate parseEmailKeywords(String keyword) {
+ requireNonNull(keyword);
+ String trimmedKeywords = keyword.trim();
+ String[] keywords = trimmedKeywords.split("\\s+");
+ return new EmailContainsKeywordsPredicate(Arrays.asList(keywords));
+ }
+
+ /**
+ * Parses a {@code String keyword} into corresponding {@code Predicate}.
+ * Leading and trailing whitespaces will be trimmed.
+ */
+ public static Predicate parseInsuranceKeywords(String keyword) {
+ requireNonNull(keyword);
+ String trimmedKeywords = keyword.trim();
+ String[] keywords = trimmedKeywords.split("\\s+");
+ return new InsuranceContainsKeywordsPredicate(Arrays.asList(keywords));
+ }
+
+ /**
+ * Parses a {@code String keyword} into corresponding {@code Predicate}.
+ * Leading and trailing whitespaces will be trimmed.
+ */
+ public static Predicate parsePhoneKeywords(String keyword) {
+ requireNonNull(keyword);
+ String trimmedKeywords = keyword.trim();
+ String[] keywords = trimmedKeywords.split("\\s+");
+ return new PhoneContainsKeywordsPredicate(Arrays.asList(keywords));
+ }
+
+ /**
+ * Parses a {@code String keyword} into corresponding {@code Predicate}.
+ * Leading and trailing whitespaces will be trimmed.
+ */
+ public static Predicate parseTagKeywords(String keyword) {
+ requireNonNull(keyword);
+ String trimmedKeywords = keyword.trim();
+ String[] keywords = trimmedKeywords.split("\\s+");
+ return new TagContainsKeywordsPredicate(Arrays.asList(keywords));
+ }
+
+ /**
+ * Parses a {@code String keyword} into corresponding {@code Predicate}.
+ * Leading and trailing whitespaces will be trimmed.
+ */
+ public static Predicate parseRemarkKeywords(String keyword) {
+ requireNonNull(keyword);
+ String trimmedKeywords = keyword.trim();
+ String[] keywords = trimmedKeywords.split("\\s+");
+ return new RemarkContainsKeywordsPredicate(Arrays.asList(keywords));
+ }
+
+ /**
+ * Parses a {@code String keyword} into corresponding {@code Predicate}.
+ * Leading and trailing whitespaces will be trimmed.
+ */
+ public static Predicate parsePriorityKeywords(String keyword) {
+ requireNonNull(keyword);
+ String trimmedKeywords = keyword.trim();
+ String[] keywords = trimmedKeywords.split("\\s+");
+ return new PriorityContainsKeywordsPredicate(Arrays.asList(keywords));
+ }
+
+ /**
+ * Checks if the retrieved date from user input is valid.
+ *
+ * A valid date input is of the format yyyy-mm-dd.
+ * `mm` is a 2-digit number in the range 01-12, which represents a calendar month.
+ * `dd` is a 2-digit number in the range of 01-31, depending on the number of days in the calendar month.
+ *
+ * If the retrieved date is valid, returns the date in `dd MMM yyyy` format.
+ * Otherwise, it means that the user did not enter the correct input. A ParseException will be thrown.
+ *
+ * @param date Date String retrieved from user input
+ * @return A String representing the date in the specified format if it is valid (for add/update)
+ * @throws ParseException Thrown when the date retrieved is invalid
+ */
+ public static String parseDateString(String date) throws ParseException {
+ try {
+ checkDate(date);
+ // converts the date to the specified format
+ date = LocalDate.parse(date).format(DateTimeFormatter.ofPattern("dd MMM yyyy"));
+ } catch (DateTimeParseException dtpe) {
+ throw new ParseException(Appointment.MESSAGE_CONSTRAINTS);
+ }
+
+ return date.trim();
+ }
+
+ /**
+ * Checks if the date input has already passed.
+ * If date input is in the past, date is invalid, throws an error.
+ *
+ * @param date Input date string.
+ * @throws ParseException Date input has passed.
+ */
+ private static void checkDate(String date) throws ParseException {
+ LocalDate localDate = LocalDate.parse(date);
+ LocalDate now = LocalDate.now();
+
+ if (localDate.isBefore(now)) {
+ throw new ParseException(Appointment.PREVIOUS_DATE_INPUT);
+ }
+ }
+
+ /**
+ * Checks if the retrieved time from user input is valid.
+ *
+ * A valid time input is of the format hh:mm (in 24-hour format).
+ * `hh` is a 2-digit number in the range 00-23, which represents the hour in the 24-hour format.
+ * `mm` is a 2-digit number in the range of 00-59, which represents the minute in the 24-hour format.
+ *
+ * If the retrieved time is valid, returns the time in `HHmm` format.
+ * Otherwise, it means that the user did not enter the correct input. A ParseException will be thrown.
+ *
+ * @param time Time String retrieved from user input
+ * @return A String representing the time in the specified format if it is valid.
+ * @throws ParseException Thrown when the date retrieved is invalid
+ */
+ public static String parseTimeString(String time) throws ParseException {
+ String validationPattern = "^([0-1]?[0-9]|2[0-3]):[0-5][0-9]$";
+
+ if (!time.equals(Appointment.NO_TIME)) {
+ // checks that time only contains HH:mm and nothing else
+ if (!time.matches(validationPattern)) {
+ throw new ParseException(Appointment.MESSAGE_CONSTRAINTS);
+ }
+
+ // converts the time to the specified format
+ time = LocalTime.parse(time).format(DateTimeFormatter.ofPattern("HHmm"));
+ }
+
+ return time.trim();
+ }
}
diff --git a/src/main/java/seedu/address/logic/parser/Prefix.java b/src/main/java/seedu/address/logic/parser/Prefix.java
index 348b7686c8a..bfeae5c49bc 100644
--- a/src/main/java/seedu/address/logic/parser/Prefix.java
+++ b/src/main/java/seedu/address/logic/parser/Prefix.java
@@ -1,20 +1,55 @@
package seedu.address.logic.parser;
+import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
+
/**
* A prefix that marks the beginning of an argument in an arguments string.
* E.g. 't/' in 'add James t/ friend'.
*/
public class Prefix {
private final String prefix;
+ private final String secondaryPrefix;
+
+ /**
+ * Constructs a {@code Prefix} with {@code prefix} and {@code secondaryPrefix}.
+ */
+ public Prefix(String prefix, String secondaryPrefix) {
+ requireAllNonNull(prefix, secondaryPrefix);
- public Prefix(String prefix) {
- this.prefix = prefix;
+ this.prefix = prefix.toLowerCase();
+ this.secondaryPrefix = secondaryPrefix.toLowerCase();
}
public String getPrefix() {
return prefix;
}
+ public String getSecondaryPrefix() {
+ return secondaryPrefix;
+ }
+
+ /**
+ * Returns the length of the prefix.
+ */
+ public int getPrefixLength() {
+ return prefix.length();
+ }
+
+ /**
+ * Returns the length of the secondaryPrefix.
+ */
+ public int getSecondaryPrefixLength() {
+ return secondaryPrefix.length();
+ }
+
+ /**
+ * Returns a formatter display message for this {@code Prefix}.
+ * @return
+ */
+ public String getDisplayMessage() {
+ return String.format("%s (%s)", prefix, secondaryPrefix);
+ }
+
@Override
public String toString() {
return getPrefix();
diff --git a/src/main/java/seedu/address/logic/parser/PriorityCommandParser.java b/src/main/java/seedu/address/logic/parser/PriorityCommandParser.java
new file mode 100644
index 00000000000..7dd6b01737f
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/PriorityCommandParser.java
@@ -0,0 +1,56 @@
+package seedu.address.logic.parser;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import java.util.logging.Logger;
+
+import seedu.address.commons.core.LogsCenter;
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.PriorityCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.priority.Priority;
+
+/**
+ * Parses input arguments and creates a new PriorityCommand object.
+ */
+public class PriorityCommandParser implements Parser {
+ private static final Logger logger = LogsCenter.getLogger(PriorityCommandParser.class);
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the ParserCommand
+ * and returns a ParserCommand object for execution.
+ *
+ * @throws ParseException if the user input does not conform the expected format.
+ */
+ @Override
+ public PriorityCommand parse(String args) throws ParseException {
+ requireNonNull(args);
+
+ logger.fine("PriorityCommandParser parsing...");
+
+ String trimmedArgs = args.trim();
+ String[] separatedArgs = trimmedArgs.split("\\s+", 2);
+
+ assert separatedArgs.length >= 1 : "separatedArgs length is smaller than 1";
+ Index index;
+
+ try {
+ index = ParserUtil.parseIndex(separatedArgs[0]);
+ } catch (ParseException pe) {
+ logger.finer("Parsing failed due to invalid command format");
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, PriorityCommand.MESSAGE_USAGE), pe);
+ }
+
+ if (separatedArgs.length != 2) {
+ logger.finer("Parsing failed due to invalid command format");
+ throw new ParseException(
+ String.format(MESSAGE_INVALID_COMMAND_FORMAT, PriorityCommand.MESSAGE_USAGE));
+ }
+
+ Priority priority = ParserUtil.parsePriority(separatedArgs[1]);
+
+ return new PriorityCommand(index, priority);
+ }
+}
diff --git a/src/main/java/seedu/address/logic/parser/RemarkCommandParser.java b/src/main/java/seedu/address/logic/parser/RemarkCommandParser.java
new file mode 100644
index 00000000000..9fbfd99f8e6
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/RemarkCommandParser.java
@@ -0,0 +1,61 @@
+package seedu.address.logic.parser;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+
+import java.util.logging.Logger;
+
+import seedu.address.commons.core.LogsCenter;
+import seedu.address.commons.core.index.Index;
+import seedu.address.commons.exceptions.IllegalValueException;
+import seedu.address.logic.commands.RemarkCommand;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.person.Remark;
+
+
+
+/**
+ * Parses input arguments and creates a new RemarkCommand object
+ */
+public class RemarkCommandParser implements Parser {
+
+ private static final Logger logger = LogsCenter.getLogger(RemarkCommandParser.class);
+
+ /**
+ * Parses input and return the RemarkCommand object.
+ *
+ * @param args Input string.
+ * @return Corresponding RemarkCommand Object.
+ * @throws ParseException When there is an exception.
+ */
+ public RemarkCommand parse(String args) throws ParseException {
+ requireNonNull(args);
+
+ logger.fine("RemarkCommandParser parsing...");
+
+ String trimmedArgs = args.trim();
+ String[] separatedArgs = trimmedArgs.split("\\s+", 2);
+
+ assert separatedArgs.length >= 1 : "separatedArgs length is smaller than 1";
+ Index index;
+
+ try {
+ index = ParserUtil.parseIndex(separatedArgs[0]);
+ } catch (IllegalValueException ive) {
+ logger.finer("Parsing failed due to invalid command format");
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT,
+ RemarkCommand.MESSAGE_USAGE), ive);
+ }
+
+ Remark remark;
+
+ if (separatedArgs.length == 1) {
+ remark = ParserUtil.parseRemark("");
+ } else {
+ remark = ParserUtil.parseRemark(separatedArgs[1]);
+ }
+
+ return new RemarkCommand(index, remark);
+ }
+
+}
diff --git a/src/main/java/seedu/address/logic/parser/TagCommandParser.java b/src/main/java/seedu/address/logic/parser/TagCommandParser.java
new file mode 100644
index 00000000000..5b7c6d6bf02
--- /dev/null
+++ b/src/main/java/seedu/address/logic/parser/TagCommandParser.java
@@ -0,0 +1,102 @@
+package seedu.address.logic.parser;
+
+import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
+import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_ADD_TAG;
+import static seedu.address.logic.parser.CliSyntax.PREFIX_DELETE_TAG;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Optional;
+import java.util.Set;
+import java.util.logging.Logger;
+
+import seedu.address.commons.core.LogsCenter;
+import seedu.address.commons.core.index.Index;
+import seedu.address.logic.commands.TagCommand;
+import seedu.address.logic.commands.TagCommand.UpdatePersonTagsDescriptor;
+import seedu.address.logic.parser.exceptions.ParseException;
+import seedu.address.model.person.Tag;
+
+/**
+ * Parses input arguments and creates a new TagCommand object
+ */
+public class TagCommandParser implements Parser {
+
+ private static final Logger logger = LogsCenter.getLogger(TagCommandParser.class);
+
+ private static final Prefix[] validPrefixes = new Prefix[] { PREFIX_ADD_TAG, PREFIX_DELETE_TAG };
+
+ private Index index;
+ private Set tagsToAdd;
+ private Set tagsToDelete;
+
+ /**
+ * Parses the given {@code String} of arguments in the context of the TagCommand
+ * and returns a TagCommand object for execution.
+ * @throws ParseException if the user input does not conform the expected format
+ */
+ public TagCommand parse(String args) throws ParseException {
+ requireNonNull(args);
+ logger.fine("TagCommandParser parsing: " + args);
+
+ parseArguments(args);
+ requireAllNonNull(index, tagsToAdd, tagsToDelete); // defensive, to ensure that parsing succeeded
+
+ UpdatePersonTagsDescriptor descriptor = new UpdatePersonTagsDescriptor(tagsToAdd, tagsToDelete);
+ verifyHasTagsToUpdate(descriptor); // defensive, verifies that at least one tag is provided
+
+ return new TagCommand(index, descriptor);
+ }
+
+ /**
+ * Parses a {@code String index} into a {@code Index}.
+ * @throws ParseException if {@code index} could not be successfully parsed.
+ */
+ private Index parseIndex(String index) throws ParseException {
+ requireNonNull(index);
+
+ try {
+ return ParserUtil.parseIndex(index);
+ } catch (ParseException pe) {
+ logger.finer("TagCommandParser parse failed due to invalid index: " + index);
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, TagCommand.MESSAGE_USAGE), pe);
+ }
+ }
+
+ /**
+ * 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