diff --git a/.gitignore b/.gitignore
index 71c9194e8bd..321a1f38d5b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,6 +8,12 @@ src/main/resources/docs/
/out/
/*.iml
+# VSCode/Eclipse files
+/.vscode/
+/.classpath
+/.settings/
+bin/
+
# Storage/log files
/data/
/config.json
diff --git a/.project b/.project
new file mode 100644
index 00000000000..83158496212
--- /dev/null
+++ b/.project
@@ -0,0 +1,34 @@
+
+
+ tp
+ Project tp created by Buildship.
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.buildship.core.gradleprojectbuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+ org.eclipse.buildship.core.gradleprojectnature
+
+
+
+ 1631532383419
+
+ 30
+
+ org.eclipse.core.resources.regexFilterMatcher
+ node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__
+
+
+
+
diff --git a/README.md b/README.md
index 13f5c77403f..2473762bda5 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,19 @@
-[](https://github.com/se-edu/addressbook-level3/actions)
+[](https://github.com/AY2122S1-CS2103T-W13-2/tp/actions)
+[](https://codecov.io/gh/AY2122S1-CS2103T-W13-2/tp)

-* 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.
+**NUSpam is a desktop app for managing contacts** targeted at marketers who require fast manipulation and precise handling of contact data. It enables marketers to more easily manage and make use of email and phone leads, and minimise tedious and repetitive tasks such as data entry, email blasts, and mail merge.
+
+- If you are interested in using NUSpam, head over to the [_Quick Start_ section of the **User Guide**](https://ay2122s1-cs2103t-w13-2.github.io/tp/UserGuide.html#quick-start).
+- If you are interested about developing NUSpam, the [**Developer Guide**](https://ay2122s1-cs2103t-w13-2.github.io/tp/DeveloperGuide.html) is a good place to start.
+
+## Acknowledgements
+
+This project is based on the AddressBook-Level3 project created by the [SE-EDU initiative](https://se-education.org).
+
+### Libraries Used
+
+- [JavaFX](https://openjfx.io/)
+- [Jackson](https://github.com/FasterXML/jackson)
+- [JUnit5](https://github.com/junit-team/junit5)
diff --git a/build.gradle b/build.gradle
index be2d2905dde..9309846fef4 100644
--- a/build.gradle
+++ b/build.gradle
@@ -8,8 +8,8 @@ plugins {
mainClassName = 'seedu.address.Main'
-sourceCompatibility = JavaVersion.VERSION_11
-targetCompatibility = JavaVersion.VERSION_11
+sourceCompatibility = 11
+targetCompatibility = 11
repositories {
mavenCentral()
@@ -56,6 +56,12 @@ dependencies {
implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'win'
implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'mac'
implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'linux'
+ implementation group: 'org.openjfx', name: 'javafx-web', version: javaFxVersion, classifier: 'win'
+ implementation group: 'org.openjfx', name: 'javafx-web', version: javaFxVersion, classifier: 'mac'
+ implementation group: 'org.openjfx', name: 'javafx-web', version: javaFxVersion, classifier: 'linux'
+ implementation group: 'org.openjfx', name: 'javafx-media', version: javaFxVersion, classifier: 'win'
+ implementation group: 'org.openjfx', name: 'javafx-media', version: javaFxVersion, classifier: 'mac'
+ implementation group: 'org.openjfx', name: 'javafx-media', version: javaFxVersion, classifier: 'linux'
implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.7.0'
implementation group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: '2.7.4'
diff --git a/docs/AboutUs.md b/docs/AboutUs.md
index 1c9514e966a..534ddfd89cc 100644
--- a/docs/AboutUs.md
+++ b/docs/AboutUs.md
@@ -5,55 +5,55 @@ title: About Us
We are a team based in the [School of Computing, National University of Singapore](http://www.comp.nus.edu.sg).
-You can reach us at the email `seer[at]comp.nus.edu.sg`
-
## Project team
-### John Doe
+### Siew Hui Zhuan
-
+
-[[homepage](http://www.comp.nus.edu.sg/~damithch)]
-[[github](https://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[homepage](https://huizhuansam.github.io)]
+[[github](https://github.com/huizhuansam)]
+[[portfolio](team/huizhuansam.md)]
-* Role: Project Advisor
+- Role: Scheduling and Tracking, Deliverables and Deadlines
+- Responsibilities: User assistance, command syntax
-### Jane Doe
+### Kishendran Vendar Kon
-
+
-[[github](http://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](https://github.com/KishendranVendarKon)]
+[[portfolio](team/kishendranvendarkon.md)]
-* Role: Team Lead
-* Responsibilities: UI
+- Role: Testing
+- Responsibilities: In charge of `Storage` component
-### Johnny Doe
+### Lee Zheng Han
-
+
-[[github](http://github.com/johndoe)] [[portfolio](team/johndoe.md)]
+[[github](https://github.com/zhenghanlee)]
+[[portfolio](team/zhenghanlee.md)]
-* Role: Developer
-* Responsibilities: Data
+- Role: Documentation, VSCode Expert
+- Responsibility: Search by categories
-### Jean Doe
+### Loh Xian Ze, Bryan
-
+
-[[github](http://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](https://github.com/anonymxtrix)]
+[[portfolio](team/anonymxtrix.md)]
-* Role: Developer
-* Responsibilities: Dev Ops + Threading
+- Role: Code Quality, Git Expert
+- Responsibility: Logic
-### James Doe
+### Zhou Jiahao
-
+
-[[github](http://github.com/johndoe)]
-[[portfolio](team/johndoe.md)]
+[[github](https://github.com/Zhou-Jiahao-1998)]
+[[portfolio](team/zhou-jiahao-1998.md)]
-* Role: Developer
-* Responsibilities: UI
+- Role: Integration
+- Responsibility: Search by categories
diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md
index 46eae8ee565..b789153d694 100644
--- a/docs/DeveloperGuide.md
+++ b/docs/DeveloperGuide.md
@@ -121,7 +121,7 @@ How the parsing works:
The `Model` component,
-* stores the address book data i.e., all `Person` objects (which are contained in a `UniquePersonList` object).
+* stores the data i.e., all `Person` objects (which are contained in a `UniquePersonList` object).
* stores the currently 'selected' `Person` objects (e.g., results of a search query) as a separate _filtered_ list which is exposed to outsiders as an unmodifiable `ObservableList` that can be 'observed' e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change.
* stores a `UserPref` object that represents the user’s preferences. This is exposed to the outside as a `ReadOnlyUserPref` objects.
* does not depend on any of the other three components (as the `Model` represents data entities of the domain, they should make sense on their own without depending on other components)
@@ -257,13 +257,14 @@ _{Explain here how the data archiving feature will be implemented}_
**Target user profile**:
-* has a need to manage a significant number of contacts
+* handles large volumes of internal and external communications
* prefer desktop apps over other types
* can type fast
* prefers typing to mouse interactions
* is reasonably comfortable using CLI apps
+* requires fast manipulation and precise handling of contact data
-**Value proposition**: manage contacts faster than a typical mouse/GUI driven app
+**Value proposition**: manage contacts faster than a typical mouse/GUI driven app, and minimise tedious and repetitive tasks such as data entry, email blasts, and mail merge
### User stories
@@ -272,12 +273,14 @@ Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unli
| 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 |
+| `* * *` | new user | get help | refer to instructions when I forget how to use the App |
+| `* * *` | new user | batch import contacts | quickly get started |
+| `* * *` | user | search for a specific field | filter my result easily |
+| `* * *` | user | update contact details | the information stays updated |
+| `* * *` | user | purge all data | easily start over |
+| `* * *` | careless user | have case-insensitive commands | speed up my typing |
+| `*` | careless user | be warned about incorrect data format | minimise errors |
+| `*` | with incomplete contact data | have autofill suggestions | make the contact data complete |
*{More to be added}*
@@ -285,43 +288,52 @@ Priorities: High (must have) - `* * *`, Medium (nice to have) - `* *`, Low (unli
(For all use cases below, the **System** is the `AddressBook` and the **Actor** is the `user`, unless specified otherwise)
-**Use case: Delete a person**
+**Use case: Batch Import**
**MSS**
-1. User requests to list persons
-2. AddressBook shows a list of persons
-3. User requests to delete a specific person in the list
-4. AddressBook deletes the person
+1. User requests to batch import
+2. AddressBook shows file selection window
+3. User selects the file
+4. AddressBook adds the data
Use case ends.
**Extensions**
-* 2a. The list is empty.
+* 3a. The file is not in the correct format.
Use case ends.
-* 3a. The given index is invalid.
+**Use case: Filter by fields**
- * 3a1. AddressBook shows an error message.
+**MSS**
+
+1. User inputs filter requirement
+2. AddressBook shows matching results
+
+ Use case ends.
- Use case resumes at step 2.
+**Extensions**
+
+* 1a. The command is not in the correct format.
+
+ Use case ends.
*{More to be added}*
### Non-Functional Requirements
-1. Should work on any _mainstream OS_ as long as it has Java `11` or above installed.
-2. Should be able to hold up to 1000 persons without a noticeable sluggishness in performance for typical usage.
-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.
+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.
+3. Should be able to import up to 1000 persons without a noticeable sluggishness in performance.
+4. A user with above average typing speed for regular English text (i.e. not code, not system admin commands) should be able to accomplish most of the tasks faster using commands than using the mouse.
*{More to be added}*
### Glossary
* **Mainstream OS**: Windows, Linux, Unix, OS-X
-* **Private contact detail**: A contact detail that is not meant to be shared with others
--------------------------------------------------------------------------------------------------------------------
diff --git a/docs/Gemfile b/docs/Gemfile
index 999a7099d8d..71470c27332 100644
--- a/docs/Gemfile
+++ b/docs/Gemfile
@@ -7,3 +7,5 @@ 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", "~> 1.7"
diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock
index 397c4d044f8..18216fab0ca 100644
--- a/docs/Gemfile.lock
+++ b/docs/Gemfile.lock
@@ -1,7 +1,7 @@
GEM
remote: https://rubygems.org/
specs:
- activesupport (6.0.3.1)
+ activesupport (6.0.4.1)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
@@ -16,86 +16,102 @@ GEM
colorator (1.1.0)
commonmarker (0.17.13)
ruby-enum (~> 0.5)
- concurrent-ruby (1.1.6)
- dnsruby (1.61.3)
- addressable (~> 2.5)
- em-websocket (0.5.1)
+ concurrent-ruby (1.1.9)
+ dnsruby (1.61.7)
+ simpleidn (~> 0.1)
+ em-websocket (0.5.2)
eventmachine (>= 0.12.9)
http_parser.rb (~> 0.6.0)
- ethon (0.12.0)
- ffi (>= 1.3.0)
+ ethon (0.14.0)
+ ffi (>= 1.15.0)
eventmachine (1.2.7)
- eventmachine (1.2.7-x64-mingw32)
- execjs (2.7.0)
- faraday (1.0.1)
+ execjs (2.8.1)
+ faraday (1.8.0)
+ faraday-em_http (~> 1.0)
+ faraday-em_synchrony (~> 1.0)
+ faraday-excon (~> 1.1)
+ faraday-httpclient (~> 1.0.1)
+ faraday-net_http (~> 1.0)
+ faraday-net_http_persistent (~> 1.1)
+ faraday-patron (~> 1.0)
+ faraday-rack (~> 1.0)
multipart-post (>= 1.2, < 3)
- ffi (1.12.2)
- ffi (1.12.2-x64-mingw32)
+ ruby2_keywords (>= 0.0.4)
+ faraday-em_http (1.0.0)
+ faraday-em_synchrony (1.0.0)
+ faraday-excon (1.1.0)
+ faraday-httpclient (1.0.1)
+ faraday-net_http (1.0.1)
+ faraday-net_http_persistent (1.2.0)
+ faraday-patron (1.0.0)
+ faraday-rack (1.0.0)
+ ffi (1.15.4)
forwardable-extended (2.6.0)
gemoji (3.0.1)
- github-pages (204)
- github-pages-health-check (= 1.16.1)
- jekyll (= 3.8.5)
+ github-pages (220)
+ github-pages-health-check (= 1.17.9)
+ jekyll (= 3.9.0)
jekyll-avatar (= 0.7.0)
jekyll-coffeescript (= 1.1.1)
jekyll-commonmark-ghpages (= 0.1.6)
jekyll-default-layout (= 0.1.4)
- jekyll-feed (= 0.13.0)
+ jekyll-feed (= 0.15.1)
jekyll-gist (= 1.5.0)
jekyll-github-metadata (= 2.13.0)
- jekyll-mentions (= 1.5.1)
+ jekyll-mentions (= 1.6.0)
jekyll-optional-front-matter (= 0.3.2)
jekyll-paginate (= 1.1.0)
jekyll-readme-index (= 0.3.0)
- jekyll-redirect-from (= 0.15.0)
+ jekyll-redirect-from (= 0.16.0)
jekyll-relative-links (= 0.6.1)
- jekyll-remote-theme (= 0.4.1)
+ jekyll-remote-theme (= 0.4.3)
jekyll-sass-converter (= 1.5.2)
- jekyll-seo-tag (= 2.6.1)
+ jekyll-seo-tag (= 2.7.1)
jekyll-sitemap (= 1.4.0)
jekyll-swiss (= 1.0.0)
- jekyll-theme-architect (= 0.1.1)
- jekyll-theme-cayman (= 0.1.1)
- jekyll-theme-dinky (= 0.1.1)
- jekyll-theme-hacker (= 0.1.1)
- jekyll-theme-leap-day (= 0.1.1)
- jekyll-theme-merlot (= 0.1.1)
- jekyll-theme-midnight (= 0.1.1)
- jekyll-theme-minimal (= 0.1.1)
- jekyll-theme-modernist (= 0.1.1)
- jekyll-theme-primer (= 0.5.4)
- jekyll-theme-slate (= 0.1.1)
- jekyll-theme-tactile (= 0.1.1)
- jekyll-theme-time-machine (= 0.1.1)
+ jekyll-theme-architect (= 0.2.0)
+ jekyll-theme-cayman (= 0.2.0)
+ jekyll-theme-dinky (= 0.2.0)
+ jekyll-theme-hacker (= 0.2.0)
+ jekyll-theme-leap-day (= 0.2.0)
+ jekyll-theme-merlot (= 0.2.0)
+ jekyll-theme-midnight (= 0.2.0)
+ jekyll-theme-minimal (= 0.2.0)
+ jekyll-theme-modernist (= 0.2.0)
+ jekyll-theme-primer (= 0.6.0)
+ jekyll-theme-slate (= 0.2.0)
+ jekyll-theme-tactile (= 0.2.0)
+ jekyll-theme-time-machine (= 0.2.0)
jekyll-titles-from-headings (= 0.5.3)
- jemoji (= 0.11.1)
- kramdown (= 1.17.0)
+ jemoji (= 0.12.0)
+ kramdown (= 2.3.1)
+ kramdown-parser-gfm (= 1.1.0)
liquid (= 4.0.3)
mercenary (~> 0.3)
minima (= 2.5.1)
nokogiri (>= 1.10.4, < 2.0)
- rouge (= 3.13.0)
+ rouge (= 3.26.0)
terminal-table (~> 1.4)
- github-pages-health-check (1.16.1)
+ github-pages-health-check (1.17.9)
addressable (~> 2.3)
dnsruby (~> 1.60)
octokit (~> 4.0)
- public_suffix (~> 3.0)
+ public_suffix (>= 3.0, < 5.0)
typhoeus (~> 1.3)
- html-pipeline (2.12.3)
+ html-pipeline (2.14.0)
activesupport (>= 2)
nokogiri (>= 1.4)
http_parser.rb (0.6.0)
i18n (0.9.5)
concurrent-ruby (~> 1.0)
- jekyll (3.8.5)
+ jekyll (3.9.0)
addressable (~> 2.4)
colorator (~> 1.0)
em-websocket (~> 0.5)
i18n (~> 0.7)
jekyll-sass-converter (~> 1.0)
jekyll-watch (~> 2.0)
- kramdown (~> 1.14)
+ kramdown (>= 1.17, < 3)
liquid (~> 4.0)
mercenary (~> 0.3.3)
pathutil (~> 0.9)
@@ -115,14 +131,14 @@ GEM
rouge (>= 2.0, < 4.0)
jekyll-default-layout (0.1.4)
jekyll (~> 3.0)
- jekyll-feed (0.13.0)
+ jekyll-feed (0.15.1)
jekyll (>= 3.7, < 5.0)
jekyll-gist (1.5.0)
octokit (~> 4.2)
jekyll-github-metadata (2.13.0)
jekyll (>= 3.4, < 5.0)
octokit (~> 4.0, != 4.4.0)
- jekyll-mentions (1.5.1)
+ jekyll-mentions (1.6.0)
html-pipeline (~> 2.3)
jekyll (>= 3.7, < 5.0)
jekyll-optional-front-matter (0.3.2)
@@ -130,101 +146,107 @@ GEM
jekyll-paginate (1.1.0)
jekyll-readme-index (0.3.0)
jekyll (>= 3.0, < 5.0)
- jekyll-redirect-from (0.15.0)
+ jekyll-redirect-from (0.16.0)
jekyll (>= 3.3, < 5.0)
jekyll-relative-links (0.6.1)
jekyll (>= 3.3, < 5.0)
- jekyll-remote-theme (0.4.1)
+ jekyll-remote-theme (0.4.3)
addressable (~> 2.0)
jekyll (>= 3.5, < 5.0)
- rubyzip (>= 1.3.0)
+ jekyll-sass-converter (>= 1.0, <= 3.0.0, != 2.0.0)
+ rubyzip (>= 1.3.0, < 3.0)
jekyll-sass-converter (1.5.2)
sass (~> 3.4)
- jekyll-seo-tag (2.6.1)
- jekyll (>= 3.3, < 5.0)
+ jekyll-seo-tag (2.7.1)
+ jekyll (>= 3.8, < 5.0)
jekyll-sitemap (1.4.0)
jekyll (>= 3.7, < 5.0)
jekyll-swiss (1.0.0)
- jekyll-theme-architect (0.1.1)
- jekyll (~> 3.5)
+ jekyll-theme-architect (0.2.0)
+ jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0)
- jekyll-theme-cayman (0.1.1)
- jekyll (~> 3.5)
+ jekyll-theme-cayman (0.2.0)
+ jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0)
- jekyll-theme-dinky (0.1.1)
- jekyll (~> 3.5)
+ jekyll-theme-dinky (0.2.0)
+ jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0)
- jekyll-theme-hacker (0.1.1)
- jekyll (~> 3.5)
+ jekyll-theme-hacker (0.2.0)
+ jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0)
- jekyll-theme-leap-day (0.1.1)
- jekyll (~> 3.5)
+ jekyll-theme-leap-day (0.2.0)
+ jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0)
- jekyll-theme-merlot (0.1.1)
- jekyll (~> 3.5)
+ jekyll-theme-merlot (0.2.0)
+ jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0)
- jekyll-theme-midnight (0.1.1)
- jekyll (~> 3.5)
+ jekyll-theme-midnight (0.2.0)
+ jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0)
- jekyll-theme-minimal (0.1.1)
- jekyll (~> 3.5)
+ jekyll-theme-minimal (0.2.0)
+ jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0)
- jekyll-theme-modernist (0.1.1)
- jekyll (~> 3.5)
+ jekyll-theme-modernist (0.2.0)
+ jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0)
- jekyll-theme-primer (0.5.4)
+ jekyll-theme-primer (0.6.0)
jekyll (> 3.5, < 5.0)
jekyll-github-metadata (~> 2.9)
jekyll-seo-tag (~> 2.0)
- jekyll-theme-slate (0.1.1)
- jekyll (~> 3.5)
+ jekyll-theme-slate (0.2.0)
+ jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0)
- jekyll-theme-tactile (0.1.1)
- jekyll (~> 3.5)
+ jekyll-theme-tactile (0.2.0)
+ jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0)
- jekyll-theme-time-machine (0.1.1)
- jekyll (~> 3.5)
+ jekyll-theme-time-machine (0.2.0)
+ jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0)
jekyll-titles-from-headings (0.5.3)
jekyll (>= 3.3, < 5.0)
jekyll-watch (2.2.1)
listen (~> 3.0)
- jemoji (0.11.1)
+ jemoji (0.12.0)
gemoji (~> 3.0)
html-pipeline (~> 2.2)
jekyll (>= 3.0, < 5.0)
- kramdown (1.17.0)
+ kramdown (2.3.1)
+ rexml
+ kramdown-parser-gfm (1.1.0)
+ kramdown (~> 2.0)
liquid (4.0.3)
- listen (3.2.1)
+ listen (3.7.0)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
mercenary (0.3.6)
- mini_portile2 (2.5.1)
+ mini_portile2 (2.6.1)
minima (2.5.1)
jekyll (>= 3.5, < 5.0)
jekyll-feed (~> 0.9)
jekyll-seo-tag (~> 2.1)
- minitest (5.14.1)
+ minitest (5.14.4)
multipart-post (2.1.1)
- nokogiri (1.11.5)
- mini_portile2 (~> 2.5.0)
+ nokogiri (1.12.5)
+ mini_portile2 (~> 2.6.1)
racc (~> 1.4)
- nokogiri (1.11.5-x64-mingw32)
+ nokogiri (1.12.5-x86_64-darwin)
racc (~> 1.4)
- octokit (4.18.0)
+ octokit (4.21.0)
faraday (>= 0.9)
sawyer (~> 0.8.0, >= 0.5.3)
pathutil (0.16.2)
forwardable-extended (~> 2.6)
- public_suffix (3.1.1)
+ public_suffix (4.0.6)
racc (1.5.2)
- rb-fsevent (0.10.4)
+ rb-fsevent (0.11.0)
rb-inotify (0.10.1)
ffi (~> 1.0)
- rouge (3.13.0)
- ruby-enum (0.8.0)
+ rexml (3.2.5)
+ rouge (3.26.0)
+ ruby-enum (0.9.0)
i18n
- rubyzip (2.3.0)
+ ruby2_keywords (0.0.5)
+ rubyzip (2.3.2)
safe_yaml (1.0.5)
sass (3.7.4)
sass-listen (~> 4.0.0)
@@ -234,23 +256,30 @@ GEM
sawyer (0.8.2)
addressable (>= 2.3.5)
faraday (> 0.8, < 2.0)
+ simpleidn (0.2.1)
+ unf (~> 0.1.4)
terminal-table (1.8.0)
unicode-display_width (~> 1.1, >= 1.1.1)
thread_safe (0.3.6)
typhoeus (1.4.0)
ethon (>= 0.9.0)
- tzinfo (1.2.7)
+ tzinfo (1.2.9)
thread_safe (~> 0.1)
- unicode-display_width (1.7.0)
- zeitwerk (2.3.0)
+ unf (0.1.4)
+ unf_ext
+ unf_ext (0.0.8)
+ unicode-display_width (1.8.0)
+ webrick (1.7.0)
+ zeitwerk (2.4.2)
PLATFORMS
ruby
- x64-mingw32
+ x86_64-darwin-19
DEPENDENCIES
github-pages
jekyll
+ webrick (~> 1.7)
BUNDLED WITH
- 2.1.4
+ 2.2.28
diff --git a/docs/Search.html b/docs/Search.html
new file mode 100644
index 00000000000..2d9bcb91254
--- /dev/null
+++ b/docs/Search.html
@@ -0,0 +1,22 @@
+---
+title: Search
+description: "Search this site"
+layout: page
+permalink: /search/
+tipue_search_active: true
+exclude_from_search: true
+---
+
+
+
+
+
+
diff --git a/docs/UserGuide.md b/docs/UserGuide.md
index 3716f3ca8a4..8a515c979da 100644
--- a/docs/UserGuide.md
+++ b/docs/UserGuide.md
@@ -3,20 +3,35 @@ layout: page
title: User Guide
---
-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.
+NUSpam is a desktop app for managing contacts **targeted at marketers who require fast manipulation and precise handling of contact data.** It enables marketers to more easily manage and make use of email and phone leads, and **minimise tedious and repetitive tasks** such as data entry, email blasts, and mail merge.
+
+- [Quick start](#quick-start)
+- [Features](#features)
+ - [Viewing help: `help`](#viewing-help-help)
+ - [Adding a person: `add`](#adding-a-person-add)
+ - [Batch importing contacts: `import`](#batch-importing-contacts-import)
+ - [Listing all persons: `list`](#listing-all-persons-list)
+ - [Editing a person: `edit`](#editing-a-person-edit)
+ - [Locating persons by name: `find`](#locating-persons-find)
+ - [Deleting a person: `delete`](#deleting-a-person-delete)
+ - [Clearing all entries: `clear`](#clearing-all-entries-clear)
+ - [Exiting the program: `exit`](#exiting-the-program-exit)
+ - [Saving the data](#saving-the-data)
+ - [Editing the data file](#editing-the-data-file)
+- [Controls](#controls)
+ - [Navigating Previously Entered Commands](#navigating-previously-entered-commands)
+- [FAQ](#faq)
+- [Command Summary](#command-summary)
-* Table of Contents
-{:toc}
-
---------------------------------------------------------------------------------------------------------------------
+---
## Quick start
1. Ensure you have Java `11` or above installed in your Computer.
-1. Download the latest `addressbook.jar` from [here](https://github.com/se-edu/addressbook-level3/releases).
+1. Download the latest `NUSpam.jar` (Coming Soon).
-1. Copy the file to the folder you want to use as the _home folder_ for your AddressBook.
+1. Copy the file to the folder you want to use as the _home folder_ for your NUSpam.
1. Double-click the file to start the app. The GUI similar to the below should appear in a few seconds. Note how the app contains some sample data.

@@ -24,133 +39,175 @@ AddressBook Level 3 (AB3) is a **desktop app for managing contacts, optimized fo
1. Type the command in the command box and press Enter to execute it. e.g. typing **`help`** and pressing Enter will open the help window.
Some example commands you can try:
- * **`list`** : Lists all contacts.
+ - `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.
+ - `add -n "John Doe" -p "+659875432" -e "johnd@example.com"` : Adds a contact named `John Doe` to the Address Book.
- * **`delete`**`3` : Deletes the 3rd contact shown in the current list.
+ - `delete 3` : Deletes the 3rd contact shown in the current list.
- * **`clear`** : Deletes all contacts.
+ - `clear` : Deletes all contacts.
- * **`exit`** : Exits the app.
+ - `exit` : Exits the app.
1. Refer to the [Features](#features) below for details of each command.
---------------------------------------------------------------------------------------------------------------------
+---
## Features
-**:information_source: Notes about the command format:**
+> **:information_source: Notes about the command format:**
+>
+> All command inputs follows the following format:
+>
+> ` "" "" ...`
+>
+> > Examples:
+> >
+> > `clear`
+> >
+> > `find --name "John"`
+> >
+> > `edit "1" --phone "91234567" -e "johndoe@example.com"`
+>
+> > Note:
+> >
+> > All flags will have a long version and a short version that can be used. The long version will be prefixed with
+> > `--` while the short versions will be prefixed with `-`. (Eg. `--phone` and `-p`)
+
+
-* 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`.
+### Viewing help: `help`
-* 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`.
+Displays a window containing documentation for command syntax and format.
-* 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.
+
-* 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.
+_(Referenced from macOS Preview help window)_
-* If a parameter is expected only once in the command but you specified it multiple times, only the last occurrence of the parameter will be taken.
- e.g. if you specify `p/12341234 p/56785678`, only `p/56785678` will be taken.
+Format: `help (--edit/-e) (--import/-i) (--add/-a) (--exit/-x) (--delete/-d) (--find/-f) (--clear/-c) (--list/-l)`
-* 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`.
+- The command can accept up to 1 optional argument.
+- By supplying the optional argument, the program displays the relevant documentation for the command.
+- Supplying 0 optional arguments will display the table of contents of the documentation with hyperlinks to the documentation of the commands.
-
+### Adding a person: `add`
+
+Adds a person to the address book.
-### Viewing help : `help`
+Format: `add (-n/--name) "[NAME]" (-p/--phone) "[PHONE]" (-e/--email) "[EMAIL]" (-a/--address) "[ADDRESS]" (-t/--tag) "[TAG]"`
-Shows a message explaning how to access the help page.
+- At least the name field must be provided.
-
+Examples:
-Format: `help`
+- `add -n "John Doe" -p "+6501234567" -e "johndoe@example.com" -a "NUS School of Computing" -t "undergraduate,computer science"` adds a contact with name of `John Doe`, phone number `+6501234567`, email `johndoe@example.com`, address `NUS School of Computing`, tags `undergraduate` and `computer science`.
+- `add -n "Jane Deer" -t "woman"` adds a contact with the name of `Jane Deer` and tag of `woman`.
+### Batch importing contacts: `import`
-### Adding a person: `add`
+Imports all contacts from a selected _csv_ file. Calling the command will open a file browser to help select the file.
+
+Format: `import`
-Adds a person to the address book.
+Example:
-Format: `add n/NAME p/PHONE_NUMBER e/EMAIL a/ADDRESS [t/TAG]…`
+
-
:bulb: **Tip:**
-A person can have any number of tags (including 0)
-
+- Select `importTemplate.csv` file.
+- Click open to import contacts.
-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`
+Note:
+- `.csv` file must have corresponding **headers**:
+ - name
+ - phone
+ - email
+ - address
+ - tags(optional)
+- Addresses containing **commas (,)** should be wrapped in **"double quotes"**.
+- Multiple tags should be seperated via **single whitespace**.
+- Make sure to save the spreadsheet data as **`.csv`** and not **`.csv UTF-8`**.
+- A template `importTemplate.csv` can be found in the default directory of the file browser.
-### Listing all persons : `list`
+Sneak peek:
+
+
+
+### Listing all persons: `list`
Shows a list of all persons in the address book.
Format: `list`
-### Editing a person : `edit`
+### Editing a person: `edit`
Edits an existing person in the address book.
-Format: `edit INDEX [n/NAME] [p/PHONE] [e/EMAIL] [a/ADDRESS] [t/TAG]…`
+Format: `edit "[INDEX]" (-n/--name) "[NAME]" (-p/--phone) "[PHONE]" (-e/--email) "[EMAIL]" (-a/--address) "[ADDRESS]" (-t/--tag) "[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.
+- 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 ie. adding of tags is not cumulative.
+- You can remove all the person’s tags by typing `-t` without specifying any tags after it.
Examples:
-* `edit 1 p/91234567 e/johndoe@example.com` Edits the phone number and email address of the 1st person to be `91234567` and `johndoe@example.com` respectively.
-* `edit 2 n/Betsy Crower t/` Edits the name of the 2nd person to be `Betsy Crower` and clears all existing tags.
-### Locating persons by name: `find`
+- `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.
+
+### Locating persons: `find`
-Finds persons whose names contain any of the given keywords.
+Finds persons whose name, phone number, email, address and/or tag contain contains any of the given keywords.
-Format: `find KEYWORD [MORE_KEYWORDS]`
+Format: `find (-n/--name) "[NAME]" (-p/--phone) "[PHONE]" (-e/--email) "[EMAIL]" (-a/--address) "[ADDRESS]" (-t/--tag) "[TAG]"`
-* 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).
+- At least one of the optional fields must be provided.
+- 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 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`
Examples:
-* `find John` returns `john` and `John Doe`
-* `find alex david` returns `Alex Yeoh`, `David Li`
+
+- `find John` returns `john` and `John Doe`
+- `find alex david` returns `Alex Yeoh`, `David Li`

-### Deleting a person : `delete`
+### Deleting a person: `delete`
+
+Deletes the person of choice from the address book.
+
+Format: `delete "UID1,UID2,..."`
+
+- Deletes a specific user(s) based on the User ID.
+- The number of UID in the input is arbitrary.
+- At least one User ID must be provided.
-Deletes the specified person from the address book.
+Examples:
+
+- `delete "1,2"` deletes two person with UID 1 and 2 in the address book.
-Format: `delete INDEX`
+Format: `delete -a"`
-* Deletes the person at the specified `INDEX`.
-* The index refers to the index number shown in the displayed person list.
-* The index **must be a positive integer** 1, 2, 3, …
+- Deletes ALL users in the current scope.
+- A warning will pop up for further confirmation.
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`
+- `find Betsy` followed by `delete -a` deletes ALL person in the results of the `find` command.
+
+### Clearing all entries: `clear`
Clears all entries from the address book.
Format: `clear`
-### Exiting the program : `exit`
+### Exiting the program: `exit`
-Exits the program.
+Shuts down and exits the program.
Format: `exit`
@@ -170,23 +227,35 @@ If your changes to the data file makes its format invalid, AddressBook will disc
_Details coming soon ..._
---------------------------------------------------------------------------------------------------------------------
+---
+
+## Controls
+
+In order to improve your experience when using the app, there are a few features that were added.
+
+### Navigating Previously Entered Commands
+
+Use the ↑ and ↓ arrow keys to navigate between previously entered commands.
+
+---
## FAQ
**Q**: How do I transfer my data to another Computer?
**A**: Install the app in the other computer and overwrite the empty data file it creates with the file that contains the data of your previous AddressBook home folder.
---------------------------------------------------------------------------------------------------------------------
+---
## 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, Examples |
+| ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| **Add** | `add (-n/--name) "[NAME]" (-p/--phone) "[PHONE]" ...` e.g., `add -n "James Ho" -p "22224444" -e "jamesho@example.com" -a "123, Clementi Rd, 1234665" -t "friend"` |
+| **Clear** | `clear` |
+| **Delete** | `delete "UID1,UID2,..."` e.g., `delete "3,2,7"` |
+| **Edit** | `edit "[INDEX]" (-n/--name) "[NAME]" (-p/--phone) "[PHONE]"…` e.g., `edit "2" -n "James Lee" -e "jameslee@example.com"` |
+| **Exit** | `exit` |
+| **Find** | `find (-n/--name) "[NAME]" (-p/--phone) "[PHONE]" (-e/--email) "[EMAIL]" (-a/--address) "[ADDRESS]" (-t/--tag) "[TAG]"` e.g., `find -n "James Jake"` |
+| **Help** | `help (--edit/-e) (--import/-i) (--add/-a) (--exit/-x) (--delete/-d) (--find/-f) (--clear/-c) (--list/-l)` e.g., `help -e` |
+| **Import** | `import` |
+| **List** | `list` |
diff --git a/docs/_config.yml b/docs/_config.yml
index 6bd245d8f4e..ae61f19a5c1 100644
--- a/docs/_config.yml
+++ b/docs/_config.yml
@@ -1,15 +1,20 @@
-title: "AB-3"
+title: "NUSpam"
theme: minima
header_pages:
- UserGuide.md
- DeveloperGuide.md
- AboutUs.md
+ - Search.html
markdown: kramdown
-repository: "se-edu/addressbook-level3"
+repository: "AY2122S1-CS2103T-W13-2/tp"
github_icon: "images/github-icon.png"
plugins:
- jemoji
+
+tipue_search:
+ include:
+ pages: true
diff --git a/docs/_includes/head.html b/docs/_includes/head.html
index 83ac5326933..ed9ebf6a3ce 100644
--- a/docs/_includes/head.html
+++ b/docs/_includes/head.html
@@ -7,6 +7,15 @@
{%- include custom-head.html -%}
+ {% if page.tipue_search_active or layout.tipue_search_active %}
+
+
+
+
+
+
+ {% endif %}
+
{{page.title}}
diff --git a/docs/_sass/minima/_base.scss b/docs/_sass/minima/_base.scss
index 0d3f6e80ced..ac83665359c 100644
--- a/docs/_sass/minima/_base.scss
+++ b/docs/_sass/minima/_base.scss
@@ -288,7 +288,7 @@ table {
text-align: center;
}
.site-header:before {
- content: "AB-3";
+ content: "NUSpam";
font-size: 32px;
}
}
diff --git a/docs/assets/templates/importTemplate.csv b/docs/assets/templates/importTemplate.csv
new file mode 100644
index 00000000000..57389d85923
--- /dev/null
+++ b/docs/assets/templates/importTemplate.csv
@@ -0,0 +1,4 @@
+name,phone,tags,address,email
+Adam,81234567,,"ABC, Street",adam@test.com
+Beth,620400,friend,123 Drive,beth123@eg.edu
+Charlie,90005000,mentor colleague,Oak Lane,Ch4rle5@test.org
diff --git a/docs/assets/tipuesearch/css/normalize.css b/docs/assets/tipuesearch/css/normalize.css
new file mode 100644
index 00000000000..9b77e0eb4d9
--- /dev/null
+++ b/docs/assets/tipuesearch/css/normalize.css
@@ -0,0 +1,461 @@
+/*! normalize.css v5.0.0 | MIT License | github.com/necolas/normalize.css */
+
+/**
+ * 1. Change the default font family in all browsers (opinionated).
+ * 2. Correct the line height in all browsers.
+ * 3. Prevent adjustments of font size after orientation changes in
+ * IE on Windows Phone and in iOS.
+ */
+
+/* Document
+ ========================================================================== */
+
+html {
+ font-family: sans-serif; /* 1 */
+ line-height: 1.15; /* 2 */
+ -ms-text-size-adjust: 100%; /* 3 */
+ -webkit-text-size-adjust: 100%; /* 3 */
+}
+
+/* Sections
+ ========================================================================== */
+
+/**
+ * Remove the margin in all browsers (opinionated).
+ */
+
+body {
+ margin: 0;
+}
+
+/**
+ * Add the correct display in IE 9-.
+ */
+
+article,
+aside,
+footer,
+header,
+nav,
+section {
+ display: block;
+}
+
+/**
+ * Correct the font size and margin on `h1` elements within `section` and
+ * `article` contexts in Chrome, Firefox, and Safari.
+ */
+
+h1 {
+ font-size: 2em;
+ margin: 0.67em 0;
+}
+
+/* Grouping content
+ ========================================================================== */
+
+/**
+ * Add the correct display in IE 9-.
+ * 1. Add the correct display in IE.
+ */
+
+figcaption,
+figure,
+main { /* 1 */
+ display: block;
+}
+
+/**
+ * Add the correct margin in IE 8.
+ */
+
+figure {
+ margin: 1em 40px;
+}
+
+/**
+ * 1. Add the correct box sizing in Firefox.
+ * 2. Show the overflow in Edge and IE.
+ */
+
+hr {
+ box-sizing: content-box; /* 1 */
+ height: 0; /* 1 */
+ overflow: visible; /* 2 */
+}
+
+/**
+ * 1. Correct the inheritance and scaling of font size in all browsers.
+ * 2. Correct the odd `em` font sizing in all browsers.
+ */
+
+pre {
+ font-family: monospace, monospace; /* 1 */
+ font-size: 1em; /* 2 */
+}
+
+/* Text-level semantics
+ ========================================================================== */
+
+/**
+ * 1. Remove the gray background on active links in IE 10.
+ * 2. Remove gaps in links underline in iOS 8+ and Safari 8+.
+ */
+
+a {
+ background-color: transparent; /* 1 */
+ -webkit-text-decoration-skip: objects; /* 2 */
+}
+
+/**
+ * Remove the outline on focused links when they are also active or hovered
+ * in all browsers (opinionated).
+ */
+
+a:active,
+a:hover {
+ outline-width: 0;
+}
+
+/**
+ * 1. Remove the bottom border in Firefox 39-.
+ * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
+ */
+
+abbr[title] {
+ border-bottom: none; /* 1 */
+ text-decoration: underline; /* 2 */
+ text-decoration: underline dotted; /* 2 */
+}
+
+/**
+ * Prevent the duplicate application of `bolder` by the next rule in Safari 6.
+ */
+
+b,
+strong {
+ font-weight: inherit;
+}
+
+/**
+ * Add the correct font weight in Chrome, Edge, and Safari.
+ */
+
+b,
+strong {
+ font-weight: bolder;
+}
+
+/**
+ * 1. Correct the inheritance and scaling of font size in all browsers.
+ * 2. Correct the odd `em` font sizing in all browsers.
+ */
+
+code,
+kbd,
+samp {
+ font-family: monospace, monospace; /* 1 */
+ font-size: 1em; /* 2 */
+}
+
+/**
+ * Add the correct font style in Android 4.3-.
+ */
+
+dfn {
+ font-style: italic;
+}
+
+/**
+ * Add the correct background and color in IE 9-.
+ */
+
+mark {
+ background-color: #ff0;
+ color: #000;
+}
+
+/**
+ * Add the correct font size in all browsers.
+ */
+
+small {
+ font-size: 80%;
+}
+
+/**
+ * Prevent `sub` and `sup` elements from affecting the line height in
+ * all browsers.
+ */
+
+sub,
+sup {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline;
+}
+
+sub {
+ bottom: -0.25em;
+}
+
+sup {
+ top: -0.5em;
+}
+
+/* Embedded content
+ ========================================================================== */
+
+/**
+ * Add the correct display in IE 9-.
+ */
+
+audio,
+video {
+ display: inline-block;
+}
+
+/**
+ * Add the correct display in iOS 4-7.
+ */
+
+audio:not([controls]) {
+ display: none;
+ height: 0;
+}
+
+/**
+ * Remove the border on images inside links in IE 10-.
+ */
+
+img {
+ border-style: none;
+}
+
+/**
+ * Hide the overflow in IE.
+ */
+
+svg:not(:root) {
+ overflow: hidden;
+}
+
+/* Forms
+ ========================================================================== */
+
+/**
+ * 1. Change the font styles in all browsers (opinionated).
+ * 2. Remove the margin in Firefox and Safari.
+ */
+
+button,
+input,
+optgroup,
+select,
+textarea {
+ font-family: sans-serif; /* 1 */
+ font-size: 100%; /* 1 */
+ line-height: 1.15; /* 1 */
+ margin: 0; /* 2 */
+}
+
+/**
+ * Show the overflow in IE.
+ * 1. Show the overflow in Edge.
+ */
+
+button,
+input { /* 1 */
+ overflow: visible;
+}
+
+/**
+ * Remove the inheritance of text transform in Edge, Firefox, and IE.
+ * 1. Remove the inheritance of text transform in Firefox.
+ */
+
+button,
+select { /* 1 */
+ text-transform: none;
+}
+
+/**
+ * 1. Prevent a WebKit bug where (2) destroys native `audio` and `video`
+ * controls in Android 4.
+ * 2. Correct the inability to style clickable types in iOS and Safari.
+ */
+
+button,
+html [type="button"], /* 1 */
+[type="reset"],
+[type="submit"] {
+ -webkit-appearance: button; /* 2 */
+}
+
+/**
+ * Remove the inner border and padding in Firefox.
+ */
+
+button::-moz-focus-inner,
+[type="button"]::-moz-focus-inner,
+[type="reset"]::-moz-focus-inner,
+[type="submit"]::-moz-focus-inner {
+ border-style: none;
+ padding: 0;
+}
+
+/**
+ * Restore the focus styles unset by the previous rule.
+ */
+
+button:-moz-focusring,
+[type="button"]:-moz-focusring,
+[type="reset"]:-moz-focusring,
+[type="submit"]:-moz-focusring {
+ outline: 1px dotted ButtonText;
+}
+
+/**
+ * Change the border, margin, and padding in all browsers (opinionated).
+ */
+
+fieldset {
+ border: 1px solid #c0c0c0;
+ margin: 0 2px;
+ padding: 0.35em 0.625em 0.75em;
+}
+
+/**
+ * 1. Correct the text wrapping in Edge and IE.
+ * 2. Correct the color inheritance from `fieldset` elements in IE.
+ * 3. Remove the padding so developers are not caught out when they zero out
+ * `fieldset` elements in all browsers.
+ */
+
+legend {
+ box-sizing: border-box; /* 1 */
+ color: inherit; /* 2 */
+ display: table; /* 1 */
+ max-width: 100%; /* 1 */
+ padding: 0; /* 3 */
+ white-space: normal; /* 1 */
+}
+
+/**
+ * 1. Add the correct display in IE 9-.
+ * 2. Add the correct vertical alignment in Chrome, Firefox, and Opera.
+ */
+
+progress {
+ display: inline-block; /* 1 */
+ vertical-align: baseline; /* 2 */
+}
+
+/**
+ * Remove the default vertical scrollbar in IE.
+ */
+
+textarea {
+ overflow: auto;
+}
+
+/**
+ * 1. Add the correct box sizing in IE 10-.
+ * 2. Remove the padding in IE 10-.
+ */
+
+[type="checkbox"],
+[type="radio"] {
+ box-sizing: border-box; /* 1 */
+ padding: 0; /* 2 */
+}
+
+/**
+ * Correct the cursor style of increment and decrement buttons in Chrome.
+ */
+
+[type="number"]::-webkit-inner-spin-button,
+[type="number"]::-webkit-outer-spin-button {
+ height: auto;
+}
+
+/**
+ * 1. Correct the odd appearance in Chrome and Safari.
+ * 2. Correct the outline style in Safari.
+ */
+
+[type="search"] {
+ -webkit-appearance: textfield; /* 1 */
+ outline-offset: -2px; /* 2 */
+}
+
+/**
+ * Remove the inner padding and cancel buttons in Chrome and Safari on macOS.
+ */
+
+[type="search"]::-webkit-search-cancel-button,
+[type="search"]::-webkit-search-decoration {
+ -webkit-appearance: none;
+}
+
+/**
+ * 1. Correct the inability to style clickable types in iOS and Safari.
+ * 2. Change font properties to `inherit` in Safari.
+ */
+
+::-webkit-file-upload-button {
+ -webkit-appearance: button; /* 1 */
+ font: inherit; /* 2 */
+}
+
+/* Interactive
+ ========================================================================== */
+
+/*
+ * Add the correct display in IE 9-.
+ * 1. Add the correct display in Edge, IE, and Firefox.
+ */
+
+details, /* 1 */
+menu {
+ display: block;
+}
+
+/*
+ * Add the correct display in all browsers.
+ */
+
+summary {
+ display: list-item;
+}
+
+/* Scripting
+ ========================================================================== */
+
+/**
+ * Add the correct display in IE 9-.
+ */
+
+canvas {
+ display: inline-block;
+}
+
+/**
+ * Add the correct display in IE.
+ */
+
+template {
+ display: none;
+}
+
+/* Hidden
+ ========================================================================== */
+
+/**
+ * Add the correct display in IE 10-.
+ */
+
+[hidden] {
+ display: none;
+}
diff --git a/docs/assets/tipuesearch/css/tipuesearch.css b/docs/assets/tipuesearch/css/tipuesearch.css
new file mode 100755
index 00000000000..56b5ee3667e
--- /dev/null
+++ b/docs/assets/tipuesearch/css/tipuesearch.css
@@ -0,0 +1,210 @@
+/*
+Tipue Search 6.1
+Copyright (c) 2017 Tipue
+Tipue Search is released under the MIT License
+http://www.tipue.com/search
+*/
+
+/* fonts */
+
+#tipue_search_input,
+#tipue_search_foot_boxes {
+ font: 300 14px/1 Roboto, sans-serif;
+}
+#tipue_search_results_count,
+#tipue_search_warning,
+.tipue_search_content_url,
+.tipue_search_content_debug,
+.tipue_search_related_text {
+ font: 300 14px/1.7 Roboto, sans-serif;
+}
+.tipue_search_content_title {
+ font: 100 26px/1.7 Roboto, sans-serif;
+}
+.tipue_search_content_text,
+.tipue_search_related_title {
+ font: 300 15px/1.7 Roboto, sans-serif;
+}
+.tipue_search_content_bold,
+.tipue_search_related_bold {
+ font-weight: 400;
+}
+
+/* search box */
+
+#tipue_search_input {
+ color: #333;
+ max-width: 210px;
+ padding: 17px;
+ border: 1px solid #e3e3e3;
+ border-radius: 0;
+ -moz-appearance: none;
+ -webkit-appearance: none;
+ box-shadow: none;
+ outline: 0;
+ margin: 0;
+}
+.tipue_search_icon {
+ width: 24px;
+ height: 24px;
+}
+.tipue_search_left {
+ float: left;
+ padding: 15px 9px 0 0;
+}
+.tipue_search_right {
+ float: left;
+}
+
+/* search results */
+
+#tipue_search_content {
+ max-width: 750px;
+ padding-top: 15px;
+ margin: 0;
+}
+#tipue_search_results_count {
+ color: #333;
+}
+#tipue_search_warning {
+ color: #333;
+ margin: 7px 0;
+}
+#tipue_search_warning a {
+ color: #5396ea;
+ text-decoration: none;
+}
+#tipue_search_warning a:hover {
+ color: #555;
+}
+.tipue_search_content_title {
+ color: #666;
+ margin-top: 21px;
+}
+.tipue_search_content_title a {
+ color: #666;
+ text-decoration: none;
+}
+.tipue_search_content_title a:hover {
+ color: #666;
+}
+.tipue_search_content_url {
+ word-wrap: break-word;
+ hyphens: auto;
+}
+.tipue_search_content_url a,
+.tipue_search_related_text a {
+ color: #5396ea;
+ text-decoration: none;
+}
+.tipue_search_content_url a:hover,
+.tipue_search_related_text a:hover,
+.tipue_search_related_before,
+.tipue_search_related_after {
+ color: #555;
+}
+.tipue_search_content_text {
+ color: #333;
+ word-wrap: break-word;
+ hyphens: auto;
+ margin-top: 5px;
+}
+.tipue_search_content_bold {
+ color: #333;
+}
+.tipue_search_content_debug {
+ color: #333;
+ margin: 5px 0;
+}
+.tipue_search_related_title {
+ color: #333;
+ margin: 26px 0 7px 0;
+}
+.tipue_search_related_cols {
+ -webkit-columns: 230px 2;
+ -moz-columns: 230px 2;
+ columns: 230px 2;
+}
+
+#tipue_search_foot {
+ margin: 51px 0 21px 0;
+}
+#tipue_search_foot_boxes {
+ padding: 0;
+ margin: 0;
+ cursor: pointer;
+}
+#tipue_search_foot_boxes li {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ display: inline;
+}
+#tipue_search_foot_boxes li a {
+ padding: 10px 17px 11px 17px;
+ background-color: #fff;
+ border: 1px solid #e3e3e3;
+ border-radius: 1px;
+ color: #333;
+ margin-right: 7px;
+ text-decoration: none;
+ text-align: center;
+}
+#tipue_search_foot_boxes li.current {
+ padding: 10px 17px 11px 17px;
+ background: #f6f6f6;
+ border: 1px solid #e3e3e3;
+ border-radius: 1px;
+ color: #333;
+ margin-right: 7px;
+ text-align: center;
+}
+#tipue_search_foot_boxes li a:hover {
+ background: #f6f6f6;
+}
+
+/* spinner */
+
+.tipue_search_spinner {
+ width: 50px;
+ height: 28px;
+}
+.tipue_search_spinner > div {
+ background-color: #e3e3e3;
+ height: 100%;
+ width: 2px;
+ display: inline-block;
+ margin-right: 2px;
+ -webkit-animation: stretchdelay 1.2s infinite ease-in-out;
+ animation: stretchdelay 1.2s infinite ease-in-out;
+}
+.tipue_search_spinner .tipue_search_rect2 {
+ -webkit-animation-delay: -1.1s;
+ animation-delay: -1.1s;
+}
+.tipue_search_spinner .tipue_search_rect3 {
+ -webkit-animation-delay: -1s;
+ animation-delay: -1s;
+}
+@-webkit-keyframes stretchdelay {
+ 0%,
+ 40%,
+ 100% {
+ -webkit-transform: scaleY(0.4);
+ }
+ 20% {
+ -webkit-transform: scaleY(1);
+ }
+}
+@keyframes stretchdelay {
+ 0%,
+ 40%,
+ 100% {
+ transform: scaleY(0.4);
+ -webkit-transform: scaleY(0.4);
+ }
+ 20% {
+ transform: scaleY(1);
+ -webkit-transform: scaleY(1);
+ }
+}
diff --git a/docs/assets/tipuesearch/search.png b/docs/assets/tipuesearch/search.png
new file mode 100644
index 00000000000..b96a4a0db39
Binary files /dev/null and b/docs/assets/tipuesearch/search.png differ
diff --git a/docs/assets/tipuesearch/tipuesearch.min.js b/docs/assets/tipuesearch/tipuesearch.min.js
new file mode 100644
index 00000000000..c5e3cf85d8b
--- /dev/null
+++ b/docs/assets/tipuesearch/tipuesearch.min.js
@@ -0,0 +1,540 @@
+(function ($) {
+ $.fn.tipuesearch = function (options) {
+ var set = $.extend(
+ {
+ contentLocation: "tipuesearch/tipuesearch_content.json",
+ contextBuffer: 60,
+ contextLength: 60,
+ contextStart: 90,
+ debug: false,
+ descriptiveWords: 25,
+ highlightTerms: true,
+ liveContent: "*",
+ liveDescription: "*",
+ minimumLength: 3,
+ mode: "static",
+ newWindow: false,
+ show: 9,
+ showContext: true,
+ showRelated: true,
+ showTime: true,
+ showTitleCount: true,
+ showURL: true,
+ wholeWords: true,
+ },
+ options
+ );
+ return this.each(function () {
+ var tipuesearch_in = { pages: [] };
+ $.ajaxSetup({ async: false });
+ var tipuesearch_t_c = 0;
+ $("#tipue_search_content")
+ .hide()
+ .html(
+ '
'
+ )
+ .show();
+ if (set.mode == "live") {
+ for (var i = 0; i < tipuesearch_pages.length; i++) {
+ $.get(tipuesearch_pages[i]).done(function (html) {
+ var cont = $(set.liveContent, html).text();
+ cont = cont.replace(/\s+/g, " ");
+ var desc = $(set.liveDescription, html).text();
+ desc = desc.replace(/\s+/g, " ");
+ var t_1 = html.toLowerCase().indexOf("");
+ var t_2 = html.toLowerCase().indexOf("", t_1 + 7);
+ if (t_1 != -1 && t_2 != -1) {
+ var tit = html.slice(t_1 + 7, t_2);
+ } else {
+ var tit = tipuesearch_string_1;
+ }
+ tipuesearch_in.pages.push({
+ title: tit,
+ text: desc,
+ tags: cont,
+ url: tipuesearch_pages[i],
+ });
+ });
+ }
+ }
+ if (set.mode == "json") {
+ $.getJSON(set.contentLocation).done(function (json) {
+ tipuesearch_in = $.extend({}, json);
+ });
+ }
+ if (set.mode == "static") {
+ tipuesearch_in = $.extend({}, tipuesearch);
+ }
+ var tipue_search_w = "";
+ if (set.newWindow) {
+ tipue_search_w = ' target="_blank"';
+ }
+ function getURLP(name) {
+ var _locSearch = location.search;
+ var _splitted = new RegExp(
+ "[?|&]" + name + "=" + "([^&;]+?)(&|#|;|$)"
+ ).exec(_locSearch) || [, ""];
+ var searchString = _splitted[1].replace(/\+/g, "%20");
+ try {
+ searchString = decodeURIComponent(searchString);
+ } catch (e) {
+ searchString = unescape(searchString);
+ }
+ return searchString || null;
+ }
+ if (getURLP("q")) {
+ $("#tipue_search_input").val(getURLP("q"));
+ getTipueSearch(0, true);
+ }
+ $(this).keyup(function (event) {
+ if (event.keyCode == "13") {
+ getTipueSearch(0, true);
+ }
+ });
+ function getTipueSearch(start, replace) {
+ var out = "";
+ var show_replace = false;
+ var show_stop = false;
+ var standard = true;
+ var c = 0;
+ found = [];
+ var d_o = $("#tipue_search_input").val();
+ var d = d_o.toLowerCase();
+ d = $.trim(d);
+ if (
+ (d.match('^"') && d.match('"$')) ||
+ (d.match("^'") && d.match("'$"))
+ ) {
+ standard = false;
+ }
+ var d_w = d.split(" ");
+ if (standard) {
+ d = "";
+ for (var i = 0; i < d_w.length; i++) {
+ var a_w = true;
+ for (var f = 0; f < tipuesearch_stop_words.length; f++) {
+ if (d_w[i] == tipuesearch_stop_words[f]) {
+ a_w = false;
+ show_stop = true;
+ }
+ }
+ if (a_w) {
+ d = d + " " + d_w[i];
+ }
+ }
+ d = $.trim(d);
+ d_w = d.split(" ");
+ } else {
+ d = d.substring(1, d.length - 1);
+ }
+ if (d.length >= set.minimumLength) {
+ if (standard) {
+ if (replace) {
+ var d_r = d;
+ for (var i = 0; i < d_w.length; i++) {
+ for (var f = 0; f < tipuesearch_replace.words.length; f++) {
+ if (d_w[i] == tipuesearch_replace.words[f].word) {
+ d = d.replace(
+ d_w[i],
+ tipuesearch_replace.words[f].replace_with
+ );
+ show_replace = true;
+ }
+ }
+ }
+ d_w = d.split(" ");
+ }
+ var d_t = d;
+ for (var i = 0; i < d_w.length; i++) {
+ for (var f = 0; f < tipuesearch_stem.words.length; f++) {
+ if (d_w[i] == tipuesearch_stem.words[f].word) {
+ d_t = d_t + " " + tipuesearch_stem.words[f].stem;
+ }
+ }
+ }
+ d_w = d_t.split(" ");
+ for (var i = 0; i < tipuesearch_in.pages.length; i++) {
+ var score = 0;
+ var s_t = tipuesearch_in.pages[i].text;
+ for (var f = 0; f < d_w.length; f++) {
+ if (set.wholeWords) {
+ var pat = new RegExp("\\b" + d_w[f] + "\\b", "gi");
+ } else {
+ var pat = new RegExp(d_w[f], "gi");
+ }
+ if (tipuesearch_in.pages[i].title.search(pat) != -1) {
+ var m_c = tipuesearch_in.pages[i].title.match(pat).length;
+ score += 20 * m_c;
+ }
+ if (tipuesearch_in.pages[i].text.search(pat) != -1) {
+ var m_c = tipuesearch_in.pages[i].text.match(pat).length;
+ score += 20 * m_c;
+ }
+ if (tipuesearch_in.pages[i].tags.search(pat) != -1) {
+ var m_c = tipuesearch_in.pages[i].tags.match(pat).length;
+ score += 10 * m_c;
+ }
+ if (tipuesearch_in.pages[i].url.search(pat) != -1) {
+ score += 20;
+ }
+ if (score != 0) {
+ for (var e = 0; e < tipuesearch_weight.weight.length; e++) {
+ if (
+ tipuesearch_in.pages[i].url ==
+ tipuesearch_weight.weight[e].url
+ ) {
+ score += tipuesearch_weight.weight[e].score;
+ }
+ }
+ }
+ if (d_w[f].match("^-")) {
+ pat = new RegExp(d_w[f].substring(1), "i");
+ if (
+ tipuesearch_in.pages[i].title.search(pat) != -1 ||
+ tipuesearch_in.pages[i].text.search(pat) != -1 ||
+ tipuesearch_in.pages[i].tags.search(pat) != -1
+ ) {
+ score = 0;
+ }
+ }
+ }
+ if (score != 0) {
+ found.push({
+ score: score,
+ title: tipuesearch_in.pages[i].title,
+ desc: s_t,
+ url: tipuesearch_in.pages[i].url,
+ });
+ c++;
+ }
+ }
+ } else {
+ for (var i = 0; i < tipuesearch_in.pages.length; i++) {
+ var score = 0;
+ var s_t = tipuesearch_in.pages[i].text;
+ var pat = new RegExp(d, "gi");
+ if (tipuesearch_in.pages[i].title.search(pat) != -1) {
+ var m_c = tipuesearch_in.pages[i].title.match(pat).length;
+ score += 20 * m_c;
+ }
+ if (tipuesearch_in.pages[i].text.search(pat) != -1) {
+ var m_c = tipuesearch_in.pages[i].text.match(pat).length;
+ score += 20 * m_c;
+ }
+ if (tipuesearch_in.pages[i].tags.search(pat) != -1) {
+ var m_c = tipuesearch_in.pages[i].tags.match(pat).length;
+ score += 10 * m_c;
+ }
+ if (tipuesearch_in.pages[i].url.search(pat) != -1) {
+ score += 20;
+ }
+ if (score != 0) {
+ for (var e = 0; e < tipuesearch_weight.weight.length; e++) {
+ if (
+ tipuesearch_in.pages[i].url ==
+ tipuesearch_weight.weight[e].url
+ ) {
+ score += tipuesearch_weight.weight[e].score;
+ }
+ }
+ }
+ if (score != 0) {
+ found.push({
+ score: score,
+ title: tipuesearch_in.pages[i].title,
+ desc: s_t,
+ url: tipuesearch_in.pages[i].url,
+ });
+ c++;
+ }
+ }
+ }
+ if (c != 0) {
+ if (set.showTitleCount && tipuesearch_t_c == 0) {
+ var title = document.title;
+ document.title = "(" + c + ") " + title;
+ tipuesearch_t_c++;
+ }
+ if (show_replace) {
+ out +=
+ '