diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index fd8c44d086..133b0e7f2b 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -31,20 +31,4 @@ jobs: java-package: jdk+fx - name: Build and check with Gradle - run: ./gradlew check - - - name: Perform IO redirection test (*NIX) - if: runner.os == 'Linux' - working-directory: ${{ github.workspace }}/text-ui-test - run: ./runtest.sh - - - name: Perform IO redirection test (MacOS) - if: always() && runner.os == 'macOS' - working-directory: ${{ github.workspace }}/text-ui-test - run: ./runtest.sh - - - name: Perform IO redirection test (Windows) - if: always() && runner.os == 'Windows' - working-directory: ${{ github.workspace }}/text-ui-test - shell: cmd - run: runtest.bat \ No newline at end of file + run: ./gradlew check \ No newline at end of file diff --git a/.gitignore b/.gitignore index f69985ef1f..7f2309d3eb 100644 --- a/.gitignore +++ b/.gitignore @@ -13,5 +13,8 @@ src/main/resources/docs/ *.iml bin/ +# Project specific /text-ui-test/ACTUAL.txt -text-ui-test/EXPECTED-UNIX.TXT +/text-ui-test/EXPECTED-UNIX.TXT +/data/ +/logs/ diff --git a/README.md b/README.md index 698b938529..c91b95fb89 100644 --- a/README.md +++ b/README.md @@ -62,3 +62,43 @@ Steps for publishing documentation to the public: 1. Scroll down to the `GitHub Pages` section. 1. Set the `source` as `master branch /docs folder`. 1. Optionally, use the `choose a theme` button to choose a theme for your documentation. + +## Workflow + +The workflow will go like this: +* Synchronise your local repo with the team repo. +* Make a separate branch for your work session. +* Commit and push your work to the corresponding branch on your remote repo. +* Make a pull request to merge your remote repo's work to the team repo and resolve merge conflicts. + +### Setting up for each work session + +* `git fetch upstream`, `git rebase upstream/master` + * The command means to fetch from the team repo (upstream) and then rebase master. + * Your local master should be synchronised with the upstream master now. +* `git switch -c ` + * Make a new branch for your local work (to preserve master's functionality). + * `git checkout -b ` does the same thing. + +### Pushing and merging your work after each work session + +* First, `git add .` if you want to stage all files or `git add ` if you want to add specific files. +* `git commit -m 'commit message here'` followed by `git push origin `. + * Git will create the corresponding branch on your remote repo and push your commits there. +* Merge your work into the team repo's master with a pull request over Github's interface. + * Do not confirm merge! Let the rest of the team view the pull request first before we confirm that it can be merged. + * Any merge conflicts should be resolved AFTER we okay the merge. + * After we all okay-ed the merge, the merge can continue and your work is complete. + +### Rolling back + +* First off, you can bookmark [this website](https://ohshitgit.com/) because you will need it at some point. +* Undoing a local commit: Do `git revert HEAD`. `git revert` works by bringing your previous commit in as a new commit to undo what you did so far. + * `HEAD` refers to your current commit (which is the one you want to undo). + * If you want to revert back to __BEFORE__ a specific commit, use `git log` and find the commit hash (a long string of characters but you only need the first 6 or so) and do `git revert `. +* Undoing a push to remote: Do `git push -f origin :`. + * This forces a push of the `` commit, which is the one you want to revert __to__, to the specified remote branch in ``. Use `git log` to find the hash. + * Alternatively, you can undo the local commit first (as in point 1), then `git push -f origin master:` instead of finding a specific commit. +* Hard reset: + * First, try doing `git fetch` then `git reset --hard origin/`. This gets your remote's latest commits (which shouldn't include your mistakes) and then resets your working directory to match the latest commit on your remote. __ALL WORK ON LOCAL THAT IS NOT ALSO ON REMOTE IS LOST!__ + * If that doesn't work, delete everything in your repo except the .git folder, download from the Github repo page (green button on top right of file window), put everything in the same folder, then `git add *`, `git commit`. diff --git a/build.gradle b/build.gradle index b0c5528fb5..05722516d4 100644 --- a/build.gradle +++ b/build.gradle @@ -10,8 +10,11 @@ repositories { } dependencies { + implementation 'com.alibaba:fastjson:1.2.12' + implementation 'com.google.code.gson:gson:2.8.6' testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.5.0' testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.5.0' + implementation group: 'org.fusesource.jansi', name: 'jansi', version: '1.18' } test { @@ -28,12 +31,25 @@ test { } } +sourceSets { + main { + resources { + srcDirs "src/main/resources" + } + } +} + application { - mainClassName = "seedu.duke.Duke" + mainClassName = "seedu.ravi.Ravi" +} + +java { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 } shadowJar { - archiveBaseName = "duke" + archiveBaseName = "ravi" archiveClassifier = null } @@ -42,5 +58,6 @@ checkstyle { } run{ + enableAssertions = true standardInput = System.in } diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index 7e1ce222a9..3e8c66bccc 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -38,11 +38,11 @@ - - - - - + + + + + @@ -184,7 +184,7 @@ - + @@ -199,6 +199,10 @@ value="COMMA, SEMI, POST_INC, POST_DEC, DOT, ELLIPSIS, METHOD_REF"/> + + + @@ -230,9 +234,9 @@ - - - + + + diff --git a/docs/AboutUs.md b/docs/AboutUs.md index 0f072953ea..6faed5bc4c 100644 --- a/docs/AboutUs.md +++ b/docs/AboutUs.md @@ -2,8 +2,8 @@ Display | Name | Github Profile | Portfolio --------|:----:|:--------------:|:---------: -![](https://via.placeholder.com/100.png?text=Photo) | John Doe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Don Joe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Ron John | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | John Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) -![](https://via.placeholder.com/100.png?text=Photo) | Don Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md) +![](https://github.com/tobiasceg.png) | Tan Jian Hui Tobias | [Github](https://github.com/tobiasceg) | [Portfolio](https://ay2021s1-cs2113t-t09-2.github.io/tp/team/tobiasceg.html) +![](https://github.com/f0fz.png) | Sim Jun You | [Github](https://github.com/f0fz) | [Portfolio](https://ay2021s1-cs2113t-t09-2.github.io/tp/team/f0fz.html) +![](https://github.com/amalinasani.png) | Amalina | [Github](https://github.com/amalinasani) | [Portfolio](https://ay2021s1-cs2113t-t09-2.github.io/tp/team/amalinasani.html) +![](https://github.com/aseanseen.png) | Sean Lim | [Github](https://github.com/Aseanseen) | [Portfolio](https://ay2021s1-cs2113t-t09-2.github.io/tp/team/aseanseen.html) +![](https://github.com/wangqinNick.png) | Wang Qin | [Github](https://github.com/wangqinNick) | [Portfolio](https://ay2021s1-cs2113t-t09-2.github.io/tp/team/wangqinNick.html) diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md index 0ec3db103d..7e39a7e1b3 100644 --- a/docs/DeveloperGuide.md +++ b/docs/DeveloperGuide.md @@ -1,34 +1,983 @@ -# Developer Guide +# Developer Guide for ra.VI -## Design & implementation + +## Table of Contents +[1 **Setting up**](#1-setting-up)
+  [1.1 Software Prerequisites](#11-software-prerequisites)
+  [1.2 Setting up the work environment](#12-setting-up-the-work-environment)
+  [1.3 Verifying the setup](#13-verifying-the-setup)
+  [1.4 Configure coding style](#14-configure-coding-style)
+[2 **Design**](#2-design)
+  [2.1 Architecture](#21-architecture)
+    [2.1.1 Main Classes and Main Command Loop](#211-main-classes-and-main-command-loop)
+    [2.1.2 Command Family](#212-command-family)
+    [2.1.3 Data Family](#213-data-family)
+    [2.1.4 Parser Family](#214-parser-family)
+    [2.1.5 Timetable Family](#215-timetable-family)
+  [2.2 Implementation](#22-implementation)
+    [2.2.1 Add/Delete Feature](#221-adddelete-feature)
+    [2.2.2 List Feature](#222-list-feature)
+    [2.2.3 Cap Feature](#223-cap-feature)
+    [2.2.4 Grade Feature](#224-grade-feature)
+    [2.2.5 Undo the Previous Command](#225-undo-feature)
+    [2.2.6 Timetable Feature](#226-timetable-feature)
+      [2.2.6.1 Add lesson/s to timetable](#2261-add-lessons-to-timetable)
+      [2.2.6.2 Delete lesson/s from timetable](#2262-delete-lessons-from-timetable)
+      [2.2.6.3 View the timetable](#2263-view-the-timetable)
+      [2.2.6.4 Filter the timetable](#2264-filter-the-timetable)
+      [2.2.6.5 Reset the timetable](#2265-reset-the-timetable)
+    [2.2.7 [Proposed] Notes Feature](#227-proposed-notes-feature)
+      [2.2.7.1 Add notes](#2271-add-notes)
+      [2.2.7.2 Viewing list of notes](#2272-viewing-list-of-notes)
+      [2.2.7.3 Delete a note](#2273-delete-a-note)
+      [2.2.7.4 View notes](#2274-view-notes)
+    [2.2.8 Colored Output](#228-colored-output)
+[3 Appendix A: Product Scope](#3-appendix-a-product-scope)
+  [3.1 Target user profile](#31-target-user-profile)
+  [3.2 Value proposition](#32-value-proposition)
+[4 Appendix B: User Stories](#4-appendix-b-user-stories)
+[5 Appendix C: Non-Functional Requirements](#5-appendix-c-non-functional-requirements)
+[6 Appendix D: Glossary](#6-appendix-d-glossary)
+[7 Appendix E: Instructions for manual testing](#7-appendix-e-instructions-for-manual-testing)
+  [7.1 Task](#71-task)
+    [7.1.1 Adding a task](#711-adding-a-task)
+    [7.1.2 Deleting a task](#712-deleting-a-task)
+    [7.1.3 Editing a task](#713-editing-a-task)
+    [7.1.4 Marking a task as done](#714-marking-a-task-as-done)
+    [7.1.5 Viewing the task list](#715-viewing-the-task-list)
+    [7.1.6 Viewing task summary](#716-viewing-task-summary)
+  [7.2 Module](#72-module)
+    [7.2.1 Adding a module](#721-adding-a-module)
+    [7.2.2 Deleting a module](#722-deleting-a-module)
+    [7.2.3 Editing a module](#723-editing-a-module)
+    [7.2.4 Viewing the module list](#724-viewing-the-module-list)
+  [7.3 Viewing help messages and prompts](#73-viewing-help-messages-and-prompts)
+  [7.4 Timetable](#74-timetable)
+    [7.4.1 Amending the timetable](#741-amending-the-timetable)
+    [7.4.2 Viewing the timetable](#742-viewing-the-timetable)
+    [7.4.3 Filtering the timetable](#743-filtering-the-timetable)
+    [7.4.4 Resetting the timetable](#744-resetting-the-timetable)
+  [7.5 Calculating the Accumulated Cap after the current semester](#75-calculating-the-accumulated-cap-after-the-current-semester)
+  [7.6 Grading an existing module in module list](#76-grading-an-existing-module-in-module-list)
+  [7.7 Undo the previous command](#77-undo-the-previous-command)
+  [7.8 Saving data](#78-saving-data)
+ -{Describe the design and implementation of the product. Use UML diagrams and short code snippets where applicable.} +---- + +## 1 Setting up +The following section describes how to set up ra.VI on your own computer. -## Product scope -### Target user profile +### 1.1 Software Prerequisites -{Describe the target user profile} +1. **JDK** 11 +2. **IntelliJ** IDEA -### Value proposition +### 1.2 Setting up the work environment -{Describe the value proposition: what problem does it solve?} +1. **Fork** this repo onto your GitHub account. **Clone** it onto your computer. +2. Open IntelliJ. Close any existing projects if you are not at the welcome page. +3. Ensure it is set to the correct JDK version. + a. `Configure` > `Project Structure for New Projects` > Select Java 11 under Project SDK. +4. Click `Open or Import` to open the cloned repo. +5. If necessary, locate the `build.gradle` file and select it. Click OK. -## User Stories +### 1.3 Verifying the setup + +1. Run the program by selecting the `run` Gradle task at the top right and running it. +2. Test the program by trying to run commands. +3. Additionally, select the `test` Gradle task and run it. Check that all the tests pass. + +### 1.4 Configure coding style + +ra.VI's code uses the Gradle Checkstyle plugin. +It is advised to change [IntelliJ's built-in code style +options](https://se-education.org/guides/tutorials/intellijCodeStyle.html) to match the requirements. + +The checkstyle configurations is in `/config/checkstyle/` by default. Here is some information on [how to use the +Checkstyle plugin with IntelliJ IDEA](https://se-education.org/guides/tutorials/checkstyle.html). + +---- + +## 2 Design + +### 2.1 Architecture + +#### 2.1.1 Main Classes and Main Command Loop + +This is a class diagram of the top-level of ra.Vi. +The classes depicted here are those which are direct dependencies of the main class `Ravi`. +The various dependencies of the classes depicted here are not shown to avoid cluttering, and are described in later +sections. + +![UML class diagram for Main Class](https://github.com/AY2021S1-CS2113T-T09-2/tp/blob/master/docs/diagrams/MainClassDiagram.png?raw=true) + +The main class holds the main loop. +Most classes used by the main class are static in nature and do not need to be instantiated. + +`Executor` can be viewed as a simple layer of abstraction on top of `Command`, `CommandResult`, `StateManager`, +`TimeTableManager`, `InputOutputManager` to facilitate the execution of user commands, while reducing the dependencies +of the main class. `Command` is a dependency of `Parser` as `Parser` creates `Command` objects to return to the main +loop. + +![Sequence diagram 1 for Main loop](https://github.com/AY2021S1-CS2113T-T09-2/tp/blob/master/docs/diagrams/MainSequenceDiagram.png?raw=true) + +This sequence diagram shows the activity of the main class, `Ravi`. When it starts, it first adds the shutdown hook to +handle both unexpected and normal shutdowns. + +`start()` and `runCommandLoopUntilExitCommand()` are referenced in sequence diagrams below. + +Following that, `Ravi` calls the `run()` function, which is just a wrapper for the two methods `start()` and +`runCommandLoopUntilExitCommand()`. `start()` may throw an exception while trying to load the NUSMods data; if it cannot +load the NUSMods data, `run()` will show the error message to the user using `TextUi` then return +to `main()`, where `main()` terminates and ra.VI shuts down. + +After `start()` runs successfully, `runCommandLoopUntilExitCommand()` will run until the user gives the exit command, +`bye`. Subsequently, `run()` will return, `main()` will terminate, and ra.VI shuts down. + +The shutdown hook runs right before ra.VI shuts down (i.e. when `main()` terminates or when the process is shut down via +any other means other than `SIGKILL`). It prints a shutdown message as described in the diagram to assure the user that +their data is saved. + +![Sequence diagram 2 for Main loop](https://github.com/AY2021S1-CS2113T-T09-2/tp/blob/master/docs/diagrams/MainSequenceDiagramStartSd.png?raw=true) + +This sequence diagram holds the reference for `start()`. + +`TextUi` is initialised with a new `Scanner` object set to `System.in` to get user input. + +`InputOutputManager` is initialised, which makes it load all user data files and NUSMods data. It will return the +results of the load (i.e. success or failure) which will be displayed by `TextUi` later on. As mentioned earlier, if +it fails to load NUSMods data (when resource file is corrupted and there is no Internet connection), it will throw an +exception so that ra.VI terminates. + +`StateManager` is initialised, creating the empty stacks of 'snapshots' as well as pushing the first snapshot (which is +the starting state) to the stack. + +`TimeTableManager` is initialised. The user is required to input the **current NUS week**. +* If it is currently before or exactly Week 6 of the semester, the user should input the actual week number. +* If it's currently recess week, the user should input "7". +* If it's currently after recess week, the user should input the current week number plus one (to account for +recess week). +There is a validation loop to catch invalid user input. + +![Sequence diagram 3 for Main loop](https://github.com/AY2021S1-CS2113T-T09-2/tp/blob/master/docs/diagrams/MainSequenceDiagramLoopSd.png?raw=true) + +The main loop is contained in the `runCommandLoopUntilExitCommand()` method. +The main loop follows the following steps: +1. Get the user input as a string. +2. Send the user input to `Executor`. +2. `Executor` parses the input using `Parser` and gets a `Command` object. +3. It then executes the `Command` object with the `execute()` method. This will do the necessary work and return a +`CommandResult` object. +4. If any data was changed, `Executor` runs `StateManager`'s `saveState()` to facilitate undo commands, and +`InputOutputManager`'s `save()` to save all user data as a measure against unexpected shutdowns. +5. Finally, use the `CommandResult` object to show the result of the `Command` to the user using `TextUi`. + +> :exclamation: Note that the `Executor` class wraps the `InputOutputManager` class + +#### 2.1.2 Command Family + +The Command family of classes are nearly all derived from the abstract `Command` class, except for +`CommandResult` and `PromptType`. All `Command` classes belong to the `Command` package. This is shown in the diagram +below. + +![UML class diagram for Command Family Classes](https://github.com/AY2021S1-CS2113T-T09-2/tp/blob/master/docs/diagrams/CommandClassDiagram.png?raw=true) + +`PromptType` indicates the functionality of the `Command` object. The most useful type is `EDIT`, which indicates to +StateManager that there has been a change in state. + +The `Command` classes carry information about the user's command. There is one class for each exact user command. The +`execute()` function of the `Command` class generates a `CommandResult`, which holds the reply to the user. This is +shown in the diagram below. + +![UML sequence diagram for Command Classes](https://github.com/AY2021S1-CS2113T-T09-2/tp/blob/master/docs/diagrams/CommandSequenceDiagram.png?raw=true) + +#### 2.1.3 Data Family + +The Data family of classes consists of all the abstracted data types required for our features, such as +`Task`, `Module`, and their respective Managers. All Data classes exist in the `data` package, and the classes +in charge of saving and loading like `InputOutputManager` are in the storage subpackage. + +![UML class diagram for Data Family Classes](https://github.com/AY2021S1-CS2113T-T09-2/tp/blob/master/docs/diagrams/DataClassDiagram.png?raw=true) + +`Lesson`, `Task`, and `Module` are the base level abstractions, with their respective Managers containing the logic +to store and manipulate instances of these objects in a meaningful way. `InputOutputManager` reads and writes +information from the various Managers in order to save and load. `State` and `StateManager` are specifically for undo +functionality. They do not interact directly with the rest of the Data family. + +`LessonFilter` is the only interface in the data package. It allows for flexible creation of filters for powerful user +filtering of lessons via lambda functions. For example, the user can choose to filter only lectures on Mondays before +2PM. + +Since there is no `Command` to save or load, `InputOutputManager` is not a dependency of `Command`. All the other +Managers, however, are dependencies of `Command` as there are commands for using/manipulating each one of them. +`InputOutputManager` and `Command` are then dependencies of the main class `Ravi`. + +ra.VI loads the user saves granularly to prevent any errors in loading one file from affecting the rest. The full +sequence diagram is below, separated into three sections. + +![UML sequence diagram for Loading Data](https://github.com/AY2021S1-CS2113T-T09-2/tp/blob/master/docs/diagrams/DataSequenceDiagram.png?raw=true) + +The above is the main loading diagram. ra.VI tries to load each save file separately. The tasks, modules, and timetable +save files are handled in the same way. The NUSMods save file is handled in a different way as it is possible to load +from the NUSMods API or the prepackaged NUSMods resource file in the JAR release. + +![UML sequence diagram for Loading Data (Normal data)](https://github.com/AY2021S1-CS2113T-T09-2/tp/blob/master/docs/diagrams/DataSequenceDiagramDataSd.png?raw=true) + +`InputOutputManager` uses the `File` and `Decoder` classes to read from the file and decode the contents into the data +objects (using FastJSON). Depending on whether the file exists or whether exceptions are thrown, the status code is +updated and returned accordingly. + +> :exclamation: The data classes may have seemingly unused getters and setters. This is intended, as FastJSON needs +> them to be present in order to handle the conversion between JSON strings and Java objects. + +![UML sequence diagram for Loading Data (NUSMods)](https://github.com/AY2021S1-CS2113T-T09-2/tp/blob/master/docs/diagrams/DataSequenceDiagramNusModsSd.png?raw=true) + +For NUSMods, the same principles apply. However, there is a chain of try-catch blocks to serve as fallbacks if one +loading measure fails. + +1. Try to load from the data directory. The NUSMods data is saved in the data directory to serve as a cached, most +up-to-date version of the data for faster and more accurate data. +2. Failing that, try to load from the NUSMods API. This is slightly slower and requries the user to have an internet +access. +3. Failing both of the above, try to load from the JAR resource file. The JAR release will hold a version of the +NUSMods data that we stored in case of these situations. This version may be out of date, however, but it's the next +best option available. +4. Failing all the above, `InputOutputManager` will throw an exception that causes ra.VI to shut down. There will be +a message prompting the user to re-download the JAR release if they can do so, as it is likely that the JAR file is +corrupted in some way. + +#### 2.1.4 Parser Family + +The Parser family of classes consists of the main `Parser` class and the `xCommandParser` subclasses. The main `Parser` class +first determines the main `Command` in the user `Command` string. If it is one of the 10 commands with a `xCommandParser` +subclass, then `Parser` delegates the remaining work to the subclass due to the complicated logic involved. Otherwise, it +handles the logic itself. + +**Parser "subclasses" do not inherit from the `Parser` class.** They serve to organise the code that would otherwise all +be placed in the `Parser` class. + +`Parser` will create a `Command` object, no matter whether the user `Command` is valid or not (if it is not, then an +`IncorrectCommand` object is created). This `Command` object passes back to the main class `Ravi` for execution. + +![UML class diagram for Parser Family Classes](https://github.com/AY2021S1-CS2113T-T09-2/tp/blob/master/docs/diagrams/ParserClassDiagram.png?raw=true) + +#### 2.1.5 Timetable Family + +The Timetable Family of classes is an example of a _cross-family_ family of classes from the `Data` and `Command` +families, and consists of the `TimeTableCommand` and `TimeTableCommandParser` classes, as well as `TimeTableManager` and +`TimeTable` themselves. Extending from the abstract `TimeTableCommand` class are the `TimeTableAddCommand`, +`TimeTableDeleteCommand`, `TimeTableViewCommand`, and `TimeTableResetCommand` classes. + +![Class diagram for TimeTable Family Classes](https://github.com/AY2021S1-CS2113T-T09-2/tp/blob/master/docs/diagrams/TimeTableClassDiagram.png?raw=true) + +**This is a good representation of how the other data classes (`Task`, `Module`) work as well.** The `Command` objects +call the methods held in the Manager classes to perform work on the stored user data. There are the classic getters and +setters, as well as more elaborate adding, deleting, editing, and viewing methods with logic for validation. + +Upon the first start up of ra.VI, `TimeTableManager.initialise()` will be run. This will no longer run again in future +sessions as long as the user does not tamper with or delete the files in the created data folder, or use ra.VI elsewhere. + +The `TimeTable` is created based on the user's initial input, with an appropriate number of `LessonManagers`. +The point of entry for this feature will be at `TimeTableCommandParser`, which will decide which of the commands +to return through `parseTimeTableCommand()`. If the `TimeTableCommand` is returned and executed, the +`TimeTableManager` will carry out the associated commands, adding, deleting or viewing the lessons in the timetable. + + +---- + + +### 2.2 Implementation + +This section serves to **provide an overview of how certain features are implemented**, not provide a comprehensive +explanation of all features in ra.VI. + +#### 2.2.1 Add/Delete Feature + +This feature is facilitated by the `TaskManager`, `ModuleManager` classes. +Extending from the abstract `Command` class are the `AddModuleCommand` and `AddTaskCommand` classes. This feature implements +the following operations: +* Add tasks - Add a task to the task list through `TaskManager.add()` +* Add modules - Add a module to the module list through `ModuleManager.add()` +* Delete tasks - Deletes a task from the task list through `TaskManager.delete()` +* Delete modules - Deletes a module from the module list through `ModuleManager.delete()` + +![Sequence diagram for AddCommand](https://github.com/AY2021S1-CS2113T-T09-2/tp/blob/master/docs/diagrams/AddCommandSequenceDiagram.png?raw=true) + +As seen from the sequence diagram above, this is the flow of an add command. This flow is similar to that of a delete command with the naming being the only difference.\ +`AddCommand` is an abstract class, inheriting from it are `AddTaskCommand` and `AddModuleCommand`.\ +The `AddCommandParser` decides to create either `AddModuleCommand`, `AddTaskCommand` or `IncorrectCommand` objects +based on the user input.\ +Each of these have an `execute()` function that creates a `CommandResult` object that shows the user the result of +the `Command` through `TextUi`, using `showOutputToUser()` + +Given below is an example usage scenario and how the add feature behaves at each step. + +1. The user launches the application for the first time. + +2. The user inputs `add -m CS2101` into ra.VI, as the user wants to note down a module named ‘CS2101’ and add it to their module list.\ +`TextUi` receives the input as a string. `Parser` and `AddCommandParser` parse the string before creating an `AddModuleCommand`. + +3. The `AddModuleCommand` is executed, returning a `CommandResult` containing a success message if the module has been successfully added.\ +Otherwise, an exception message will be shown explaining the exception to the user.\ +Common reasons for failure include: + +* Wrong command format\ +e.g. `add --t task`\ +e.g. `add -t task --by 2-10-2020 1400`\ +e.g. `add -m Fake Mod`\ +e.g. `add -t task -by 2nd Jan` +* Module already exists in module list\ +e.g. `add -m CS1010` but the module list already contains `CS1010` + + + + +#### 2.2.2 List Feature + +This feature is facilitated by the `TaskManager` and `ModuleManager` classes. +It extends from the abstract `Command` class. +This feature implements the following operations: +* List tasks - List all tasks in the task list through `TaskManager.list()` +* List modules - List all modules in the module map through `ModuleManager.list()` + +![Sequence diagram for List Feature in Command class](https://github.com/AY2021S1-CS2113T-T09-2/tp/blob/master/docs/diagrams/ListCommandSequenceDiagram.png?raw=true) + +As seen from the sequence diagram above, this is the flow of `ListCommand`. +`ListCommandParser` class calls `ListCommand(1)`, `ListCommand(0)`, or throws an `InvalidParameterException()` +based on the user input. + +`ListCommand` has an `execute()` method. Depending on the type of entry, `ListCommand` calls `list()` method of +`TaskManager` if it is "TASK", or `list()` method of `ModuleManager` if it is "MODULE". + +If output is null, `ListCommand` calls `CommandResult(MESSAGE_LIST_EMPTY)`, creating a `CommandResult` object. +Else, `ListCommand` calls `CommandResult(MESSAGE_LIST_PRINTED + output)`, creating a `CommandResult` object. + +`ListCommand` returns `CommandResult`. + +Given below is an example usage scenario and how the list feature behaves at each step. +1. The user launches the application for the first time. +2. The user inputs `add -t Read book` into ra.VI, adding the task to the task list in TaskManager. The user keys in +multiple other tasks of the following: +* `add -t Return book -by 2-10-2020 1400` +* `add -t Meeting` + +3. The user inputs `add -m CS2113T` into ra.VI, adding the module to the module map in ModuleManager. The user keys in +multiple other modules of the following: +* `add -m CS2101` +* `add -m CG2271` + +4. The user inputs `list -t`. The `CommandResult` returns +``` +Here's your list: + +1. return a book [x] +2. read a book [x], by 07:00PM, Sunday, 02 Feb 2020 +``` +5. The user inputs `list -m`. The `CommandResult` returns +``` +Here's your list: + +1. CS1010: Programming Methodology (0.0MC) (Grade: No grade yet) +2. CS3235: Computer Security (0.0MC) (Grade: No grade yet) +``` + + + + +#### 2.2.3 CAP Feature +This feature is facilitated by `ModuleManager` and `Module` class +It extends `Command` and runs through the `ModuleManager`, checking every `Module`'s grade and module credit. +* Calculate user's CAP - Uses a formula to calculate the user's current cap. + +![Sequence diagram for Cap Feature in Command class](https://github.com/AY2021S1-CS2113T-T09-2/tp/blob/master/docs/diagrams/CapCommandSequenceDiagram.png?raw=true) + +As seen from the sequence diagram above, this is the flow of a CAP command. +The `CapCommandParser` parses the user's input and calls the `CapCommand` constructor. +When `CapCommand` executes, a `CommandResult` object is created that calculates the user's current cap after taking into +account the user's current modules and the users's total MC taken based on the modules graded. + +Given below is an example usage scenario and how the CAP feature behaves at each step. + +1. The user launches the application for the first time. + +2. The user inputs `add -m CS2101` into ra.VI, as the user adds a module they are taking into the `ModuleManager`. +The user keys in as many modules into ra.VI as they are taking. + +3. Once the user attains a grade for the modules keyed in, they input `grade CS2101 4 A-` (4 MCs, A grade) to record the +grade for their module. They does this for all the other modules they have taken. + +4. Once every module in the `ModuleManager` has been graded, they inputs `cap` to calculate their accumulative +CAP after attaining their new grades. + +5. The `CommandResult` returns the success message to show the user their current CAP after attaining their grades. + +#### 2.2.4 Grade Feature +This feature is facilitated by `ModuleManager` and `Module` classes. +It extends `Command` and is stored internally inside `Module` as a `grade` and `moduleCredit`. +* Grading a module - assigns a grade and MC number to a specific module present in the module list. + +![Sequence diagram for Grade Feature in Command class](https://github.com/AY2021S1-CS2113T-T09-2/tp/blob/master/docs/diagrams/GradeCommandSequenceDiagram.png?raw=true) + +As seen from the sequence diagram above, this is the flow of a Grade command. +The `GradeCommandParser` parses the user's input, and assigns the relevant attributes in the `GradeCommand` constructor, +such as `moduleCredit` and `grade`. When `GradeCommand` executes,a `CommandResult` object is created that shows +the user the result of the `Command` through `TextUi`, using `showOutputToUser()`. + +Given below is an example usage scenario and how the grade feature behaves at each step. + +1. The user launches the application. The user inputs `add -m CS2101` into ra.VI, as the user wants to note down +a module named ‘CS2101’ and add it to their module list. + +2. The user inputs `grade CS2101 4 A+`. The `Parser` parses and allocates the user input to `GradeCommand`. +`GradeCommand.execute()` is called and `ModuleManager` checks if such a module exists in the user’s module list, +then checks if the input grade is valid according to the NUS grading schematic. Finally, it assigns the specific module +with the grade and module credits. + +3. The `CommandResult` returns the success message to show the user that their module has successfully been graded. +Otherwise, an exception message will be shown regarding the exception caught. + + + +#### 2.2.5 Undo Feature +This feature is facilitated by `State` and `StateManager` classes. + +* `GradeCommand.testgrade(stringGrade)` - checks if the input grade is valid according to NUS grading schematic +* `GradeCommand.grade(moduleModule)` - assigns the specific module present in the module list, the grade and moduleCredit attributes. + +![Sequence diagram for Undo Feature](https://github.com/AY2021S1-CS2113T-T09-2/tp/blob/master/docs/diagrams/UndoCommandSequenceDiagram.png?raw=true) + +As seen from the sequence diagram above, this is the flow of an Undo command. +The Parser parses the user's input, and construct the default UndoCommand. +When the Undo Command object executes, the `undo()` method in the StateManager class will be called. +In the StateManager, the previous copies of the data are encoded as Json and stored in a stack. +When the `undo()` is called, the StateManager will pops the top copy in the stack. +After that, the StateManager class will notify TaskManager and Module Manager to load from the encoded saved copies. To do that, it will facilitate the load methods, `loadMods()` `loadTasks()` from TaskManager and ModuleManager to set the data. + +Given below is an example usage scenario and how the undo feature behaves at each step. + +1. The user launches the application. The user inputs `add -m CS2101` into ra.VI, as the user wants to note down +a module named ‘CS2101’ and add it to their module list. This input is received by the Ui ,which processes it into +a string. The parser parses the string and allocates it to the AddCommand where it is added to the list of modules. + +2. The user finds the module just added is wrong. Thus, he wants to undo the previous `add -m CS2101` command. + +3. The user inputs `undo` into ra.VI. The input is received by the Ui, which then passes the input to Parser and parsed to an Undo command. + +4. Then the execution process of the Undo command will makes the method calls demonstrate above in the diagram. + +5. More importantly, the Undo command only works for those 'data-changed' operations. Those operations refer to 'add', 'delete', 'edit' commands. + + + + +#### 2.2.6 Timetable Feature + +This feature is facilitated by the `TimeTableManager` class and `TimeTableCommand` class. +Extending from the abstract `TimeTableCommand` class are the `TimeTableAddCommand`, `TimeTableDeleteCommand`, +`TimeTableViewCommand` and `TimeTableResetCommand` classes. +* Add a lesson - Add a lesson to the timetable through `TimeTableManager.addLesson()` +* Delete a lesson - Delete all associated lessons from the timetable through `TimeTableManager.deleteLesson()` +* View today's timetable - List all lessons for today through `TimeTableManager.getSpecificDayLessons()` +* View this week's timetable - List all lessons in this week through `TimeTableManager.getSpecifiedWeekLessons()` +* Reset timetable - Reset the whole timetable through `TimeTableManager.initialiseTimetable()` + +##### 2.2.6.1 Add lesson/s to timetable + +Given below is an example scenario to add a lesson to the timetable and how the timetable feature behaves at each step. + +1. The user launches the application for the first time. ra.VI asks for the current NUS week. This input is parsed and +initialises the `TimeTableManager`. + +2. The user inputs `add -m CS2101`, as the user wants to note down a module named `CS2101` and add it to their module list. + +3. The user inputs `timetable -add CS2101 TUESDAY 0800 1000 LECTURE 1`. This means the user wants to add a `CS2101 LECTURE` +that occurs once a week on `TUESDAY 0800 1000`. This `Command` will be parsed and eventually returns a `TimeTableAddCommand`. + +4. The `TimeTableAddCommand` is executed, returning a `CommandResult` containing a success message if the lesson has +been successfully added. Otherwise, an exception message will be shown explaining the exception to the user.\ +Common reasons for failure include: + +* Wrong command format\ +e.g. `timetable -add CS2101 TUE 0800 1000 LECTURE 1`\ +e.g. `timetable -add CS2101 TUESDAY 8am 10am LECTURE 1`\ +e.g. `timetable -add CS2101 TUESDAY 0800 1000 NONSENSE 1`\ +e.g. `timetable -add CS2101 TUESDAY 0800 1000 LECTURE 5` +* Module does not exist in module list\ +e.g. `timetable -add CS2101 TUESDAY 0800 1000 LECTURE 1` but the module list does not contain `CS2101`. Available modules can be found by entering `list -m` +e.g. `timetable -add BAD TUESDAY 0800 1000 LECTURE 1` but the module list does not contain `BAD` and `BAD` is not a valid NUS module. + +##### 2.2.6.2 Delete lesson/s from timetable + +Given below is an example scenario to delete a lesson from the timetable and how the timetable feature behaves at each step. + +1. The user launches the application for the first time. ra.VI asks for the current NUS week. This input is parsed +and initialises the `TimeTableManager`. + +2. The user inputs `add -m CS2101`, as the user wants to note down a module named `CS2101` and add it to their module list. + +3. The user inputs `timetable -add CS2101 TUESDAY 0800 1000 LECTURE 1`. This means the user wants to add a +`CS2101 LECTURE` that occurs once a week on `TUESDAY 0800 1000`. This `Command` will be parsed and eventually returns a +`TimeTableAddCommand`. + +4. The user inputs `timetable -del TUESDAY 1`. This means the user wants to delete the `CS2101 TUESDAY 0800 1000 LECTURE` +lessons. The `1` at the end reflects lessons on index `1` on `TUESDAY` as reflected by `timetable -day` or `timetable -week`. +This `Command` will be parsed and eventually returns a `TimeTableDeleteCommand`. + +5. The `TimeTableDeleteCommand` is executed, returning a `CommandResult` containing a success message if the lessons +have been successfully deleted. Otherwise, an exception message will be shown explaining the exception to the user. +Common reasons for failure include: + +* Wrong Command format\ +e.g. `timetable -del TUE 1`. +* Lesson does not exist in the timetable\ +e.g. `timetable -del TUESDAY 5` but the timetable does not contain a lesson/s on `TUESDAY` at index `5`. Current +lessons can be found by entering `timetable -day` or `timetable -week`. + +##### 2.2.6.3 View the timetable + +Given below is an example scenario to view the timetable for the day. + +1. The user adds a lesson to the timetable for today, for e.g. `timetable -add CS2101 TUESDAY 0800 1000 LECTURE 1`. + +2. The user inputs `timetable -day`. + +3. The timetable for the day is shown to the user. The user is able to see the Tuesday CS2101 lecture that was +previously added in step 1. + +##### 2.2.6.4 Filter the timetable + +Given below is an example scenario to filter the timetable for CS2101 LECTURE. + +1. The user adds a lesson to the timetable for today, for e.g. `timetable -add CS2101 TUESDAY 0800 1000 LECTURE 1`. + +2. The user inputs `timetable -filter CS2101 - - - LECTURE` + +3. All CS2101 lectures in the timetable are shown to the user. The user is able to see the CS2101 weekly lectures that were previously added in step 1. + +* Wrong Command format\ +e.g. `timetable -filter` + +##### 2.2.6.5 Reset the timetable + +Given below is an example scenario to reset the timetable. + +1. The user inputs `timetable -reset`. + +2. ra.VI will ask for the current NUS week. This input is parsed and re-initialises the `TimeTableManager` with a new `Timetable`. + + + + +#### 2.2.7 [Proposed] Notes Feature + +![Class diagram for Notes Feature in Command class](https://github.com/AY2021S1-CS2113T-T09-2/tp/blob/master/docs/diagrams/NotesClassDiagram.png?raw=true) + +The proposed notes feature is facilitated by the `NotesManager` class and abstract `NotesCommand` class +Extending from the abstract `NotesCommand` class are the `NotesAddCommand`, `NotesListCommand`, `NotesDeleteCommand`, +and `NotesViewCommand` classes. + +It implements the following operations: +* `NotesManager.addNote()` - Add a note +* `NoteManager.listNote()` - View the list of notes and their indexes +* `NoteManager.deleteNote()` - Delete a note +* `NoteManager.viewNote()` - View a particular note + +##### 2.2.7.1 Add notes + +Given below is an example scenario to add a note and how the notes feature behave at each step + +Step 1. The user inputs `note -add Orbital Mechanics: Application of ballistics and celestial mechanics`, as the user wants to add a note. +Step 2. This input is parsed by `NotesCommandParser` and it returns `NotesAddCommand`. +Step 3. `NotesAddCommand` is executed, returning a `CommandResult` containing a success message if the note has been +added successfully. Otherwise, an error message will be shown explaining the error to the user. + +##### 2.2.7.2 Viewing list of notes + +Given below is an example scenario to view the list of notes and how the notes feature behaves at each step. + +Step 1. The user inputs `note -list` as the user wants to view the list of notes. +Step 2. This input is parsed by `NotesCommandParser` and it returns `NotesListCommand`. +Step 3. `NotesListCommand` is executed, returning a `CommandResult` containing the list of notes and their indexes. +Otherwise, an error message will be shown explaining the error to the user. + +##### 2.2.7.3 Delete a note + +Given below is an example scenario to delete a note and how the notes feature behaves at each step. + +Step 1. The user inputs `note -del 1` as the user wants to delete the note with index 1. +Step 2. This input is parsed by `NotesCommandParser` and it returns `NotesDeleteCommand`. +Step 3. `NotesDeleteCommand` is executed, returning a `CommandResult` containing a success message if the note has been +deleted successfully. Otherwise, an error message will be shown explaining the error to the user. + +* Currently available notes and their indexes can be found by entering `notes -list` + +##### 2.2.7.4 View notes + +Given below is an example scenario to view a particular note in the list +Step 1. The user inputs `note -view 1` as the user wants to view the note with index 1. +Step 2. This input is parsed by NotesCommandParser and it returns `NotesDeleteCommand`. +Step 3. `NotesViewCommand` is executed, returning a `CommandResult` containing the note if the note has been shown +successfully. Otherwise, an error message will be shown explaining the error to the user. + + + + +#### 2.2.8 Colored Output +The output of ra.VI is colored to improve readability and draw attention to important parts of messages. To color +ra.VI's output, we used the [JANSI library](https://github.com/fusesource/jansi) which uses ANSI escape codes to color +printed messages on the terminal. As ANSI escape codes are universally supported on most terminals, we do not foresee +major compatibility issues with the mainstream OSes. + +We use JANSI's `ansi().render()` to wrap ra.VI's output in `TextUi`'s `outputToUser` function. So, we gain the ability +to color (and otherwise decorate) ra.VI's text using JANSI's formatting standards. + +An example: To make `"Hello"` red, we change it to `"@|red Hello|@"`. + +> :exclamation: The extra characters cause some difficulties in centering text, so `centerString(String s)` in +> `TextHelper` is designed to remove these formatting artifacts and center the text properly. However, +> `centerString(int width, String s)` does not remove the JANSI artifacts and hence should not be used with JANSI. + +---- + +## 3 Appendix A: Product scope +### 3.1 Target user profile + +The target user profile for ra.VI is described by the following: +* A student of NUS (a freshman in particular). +* Has a need to manage their school related tasks, classes and notes. +* Prefers desktop apps over other types. +* Types fast. +* Prefers typing to mouse interactions. +* Reasonably comfortable using CLI apps. + +### 3.2 Value proposition + +A common problem amongst freshmen is the inability to organise all the incoming information. +NUS places a focus on taking responsibility for your own learning, so it might be a tough transition from tertiary education. +A lot of students miss lessons, assignments, and even exams, just because they're struggling to adapt to the new +environment. + +ra.VI helps students to manage their school-related information in a compact, stripped-down interface that does not +bombard them with too much information. +When you receive your modules and lessons, simply enter them into ra.VI as they arrive. ra.VI will keep track of all of it +for you. +You can create tasks, give them deadlines, and tag them to certain modules. You can see all of your tasks and deadlines at a glance. +You can even write and save your notes in ra.VI, uncluttering your work environment even further. + +ra.VI is even integrated with NUSMods, bringing its comprehensive library of information to your fingertips. +All the above features are wrapped in a compact, no-frills command-line interface. No confusing menus and dropdowns +to distract you; only simple commands to give you what you want. + + + +---- + + + +## 4 Appendix B: User Stories |Version| As a ... | I want to ... | So that I can ...| |--------|----------|---------------|------------------| |v1.0|new user|see usage instructions|refer to them when I forget how to use the application| -|v2.0|user|find a to-do item by name|locate a to-do without having to go through the entire list| +|v1.0|user|save and load my information|store all my school related data in the application| +|v1.0|user|add tasks to the application|keep track of all my tasks| +|v1.0|user|add deadlines for tasks to the application|keep track of when I need to complete the tasks| +|v1.0|user|add modules to the application|keep track of them during the school term| +|v1.0|user|delete tasks from the application|keep track of new tasks| +|v1.0|user|delete modules from the application|keep track of new modules| +|v1.0|user|edit task descriptions|make changes or updates to my tasks| +|v1.0|user|edit module code|make changes to module codes in the list| +|v1.0|user|mark task as done|update the completion status of my tasks| +|v1.0|user|view my task list|be aware of the tasks I have added to my list| +|v1.0|user|view my module list|be aware of the modules I have added to my list| +|v2.0|user|receive help easily|use ra.VI efficiently| +|v2.0|user|add lessons to my timetable|view my timetable with a simple command| +|v2.0|user|delete lessons from my timetable|view my accurate timetable with a simple command| +|v2.0|user|view my timetable quickly|be aware of my classes and prepare for them quickly| +|v2.0|user|filter the lessons in my timetable |be aware of specific classes and prepare for them quickly| +|v2.0|user|view a summary of my tasks|be aware of my tasks and work on them as needed| +|v2.0|user|grade my modules|keep track of my grades for respective modules| +|v2.0|user|calculate my accumulative cap|keep track of my progress in university| +|v2.0|user|undo unintended commands|make amends quickly| +|v2.1|user|reset my timetable|prepare for another semester| + +---- + +## 5 Appendix C: Non-Functional Requirements + +* Should work on any mainstream OS with Java 11 or above installed. +* 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. + +---- + +## 6 Appendix D: Glossary + +* IntelliJ - An Integrated Development Environment (IDE) designed for Java software development. +* CLI - Command Line Interface +* UML - Unified Modeling Language +* Terminal - Any operating system shell with a command-line interface. +* Mainstream OS - Windows, mainstream distributions of Linux, and macOS. + + + +---- + +## 7 Appendix E: Instructions for manual testing + +Given below are instructions to test the app manually. + +1. Download the latest version of `ra.VI` from [here](https://github.com/AY2021S1-CS2113T-T09-2/tp/releases/tag/v2.0) and copy it into an empty folder. +2. Open a new terminal window and navigate to the same directory where `ravi.jar` is located. +3. Enter the command `java -jar ravi.jar` into the terminal window to launch the application. The application should now be running. +4. Enter the command `help` to get a list of all available commands and its usages. +5. For a detailed list on available features, refer to the [user guide](https://github.com/AY2021S1-CS2113T-T09-2/tp/blob/master/docs/UserGuide.md). +6. Simply enter `bye` to terminate and exit the application. + +### 7.1 Task +#### 7.1.1 Adding a task +1. Adding a task without deadline + 1. Test case: `add -t read a book`\ + Expected: Task `read a book` will be added to the task list. Details of the success of the added task will be shown. + 2. Test case: `add -t `\ + Expected: As there is no task to add, details of the associated error message will be shown. +2. Adding a task with deadline + 1. Test case: `add -t read a book -by 20-10-2020 1800`\ + Expected: Task `read a book` will be added to the task list. Additionally, the deadline + will be added to the task. Details of the added task is shown in the status message. + 2. Test case: `add -t read a book -by 20/20/2020`\ + Expected: Invalid deadline `20/20/2020` will not allow the task to be added to the task list. Details of the + associated error message will be shown. + +#### 7.1.2 Deleting a task +1. Deleting a task + 1. Test case: `del -t 1` where `task` is index `0` in the task list.\ + Expected: The DeleteCommandParser parses `1` and converts it to index `0` in the task list. + As task `task` is the index `0` in the task list, `task` will be deleted from the task list. + 2. Test case: `del -t 10` where there is no task of index `9` in the task list.\ + Expected: The DeleteCommandParser parses `10` and converts it to index `9` in the task list. + As there is no task of index `9` in the task list, the deletion will give an error. + Details of the associated error message will be shown. + +#### 7.1.3 Editing a task +1. Editing a task + 1. Test case: `edit -t 3 read a book`, where task index `3` has already been added previously into the task list.\ + Expected: As the task at index `3` is in the task list, the task description will be edited and changed to `read a book`. + Details of the success of the edit task will be shown. + 2. Test case: `edit -t 10 meet girlfriend`, where there is no task `10` in the task list.\ + Expected: As there is no such task in the task list, an error will be given to the user. Details of the associated error + message will be shown. + +#### 7.1.4 Marking a task as done +1. Marking a task as done + 1. Test case: `done 1`, where `task` is index `0` in the task list.\ + Expected: The DoneCommandParser parses `1` and converts it to index `0` in the task list. + As task `task` is the index `0` in the task list, `task` will be marked as done. + 2. Test case: `done 10`, where there is no task of index `9` in the task list.\ + Expected: The DoneCommandParser parses `10` and converts it to index `9` in the task list. + As there is no task of index `9` in the task list, an error is thrown. Details of the associated error message will be shown. + +#### 7.1.5 Viewing the task list +1. Viewing the task list + 1. Test case: `list -t`, with the tasks "read book" and "buy stuff" in the task list.\ + Expected: A list containing the two tasks will be shown. + 2. Test case: `list -t` when no tasks have been added.\ + Expected: As there are no tasks in the list, a message signifying the empty list is shown. + +### 7.1.6 Viewing task summary +1. Viewing the task summary + 1. Test case: + `summary`, when the list contains + ``` + 1. Read a book [x] + 2. Return book [x], by 06:00PM, Tuesday, 20 Oct 2020 + 3. meeting [√], by 08:00PM, Thursday, 22 Oct 2020 + ``` + Expected: The task summary will be shown, each task belonging to their respective categories. + +### 7.2 Module +#### 7.2.1 Adding a module +1. Adding a module + 1. Test case: `add -m CS2113T`\ + Expected: Module `CS2113T` will be checked against the NUS module list. + Since `CS2113T` is a valid module, it will be added to the module list. Details of the success of the added module will be shown. + 2. Test case: `add -m Fake Mod`\ + Expected: As there is no such module `Fake Mod` in the NUS module list, it will not be added to the module list. + Details of the associated error message will be shown. + +#### 7.2.2 Deleting a module +1. Deleting a module + 1. Test case: `del -m CS2113T` where `CS2113T` has been previously added to the module list.\ + Expected: As module `CS2113T` is in the module list, `CS2113T` will be deleted from the module list. + Details of the success of the deleted module will be shown. + 2. Test case: `del -m 0` where there is no module `0` in the module list.\ + Expected: As there is no such module in the module list, the deletion will give an error. + Details of the associated error message will be shown. + +#### 7.2.3 Editing a module +1. Editing a module + 1. Test case: `edit -m CG2271 GER1000`, where module `CG2271` has already been added previously into the module list.\ + Expected: As `CG2271` is in the module list, the module will be edited and changed to `GER1000`. Details of the success + of the edit module will be shown. + 2. Test case: `edit -m ACC1101 GER1000`, where there is no module `ACC1101` in the module list.\ + Expected: As there is no such module in the module list, an error will be given to the user. Details of the associated + error message will be shown. + +#### 7.2.4 Viewing the module list +1. Viewing the module list + 1. Test case: `list -m`, with the modules "CS2113T" and "CS2101" in the module list.\ + Expected: A list containing the two module codes, MCs, and grades associated will be shown. + 2. Test case: `list -m` when no modules have been added.\ + Expected: As there are no modules in the list, a message signifying the empty list is shown. + +### 7.3 Viewing help messages and prompts +1. Viewing the help message for a specific command + 1. Test case: `help add`\ + Expected: A help message containing the `add` command format and examples of its usage is shown. + 2. Test case: `add CS2101`\ + Expected: As this is an incorrect command format, a help message containing the correct format is shown. A prompt message suggesting the use of `help` is also shown. + +### 7.4 Timetable +#### 7.4.1 Amending the timetable +1. Adding a lesson + 1. Test case: `timetable -add CS2113T MONDAY 1200 1400 LECTURE 0` where `CS2113T` is a module in module list.\ + Expected: The TimeTableCommandParser parses the lesson parameters, `CS2113T` is the associated module, + `MONDAY 1200 1400 LECTURE` reflects that the lesson is a lecture on Monday from 12pm to 2pm. `0` indicates + that this lesson only occurs once. Since `CS2113T` is a valid module in the module list, the lesson will be added + to the timetable. Details of the success of the added lesson will be shown. +2. Deleting a lesson + 1. Test case: `timetable -del MONDAY 0` where the only lesson on MONDAY is a CS2113T lecture from 12pm to 2pm.\ + Expected: The TimeTableCommandParser parses the lesson parameters, and searches for a lesson/s of index `0` on + `MONDAY`. However, the timetable does not contain such lesson/s. Details of the associated error message will be shown. + +#### 7.4.2 Viewing the timetable +1. Timetable for the day + 1. Test case: `timetable -day`\ + Expected: If there are no lessons for today, this information is shown to the user. Otherwise, the lessons for today + are shown to the user. +2. Timetable for the week + 1. Test case: `timetable -week`\ + Expected: The lessons for Monday to Sunday of this week are shown to the user. + +#### 7.4.3 Filtering the timetable +1. Filter all lessons + 1. Test case: `timetable -filter CS2113T - - - -`, which filters CS2113T lessons only.\ + Expected: All CS2113T lessons are shown to the user. + 2. Test case: `timetable -filter CS2113T - - - LECTURE`, which filters CS2113T **lectures** only.\ + Expected: All CS2113T lectures are shown to the user. + 3. Test case: `timetable -filter CS2113T MONDAY 1200 2000 LECTURE`, which filters CS2113T lectures **on Monday + between 1200 and 2000** only.\ + Expected: All CS2113T lectures on Monday between 1200 and 2000 are shown to the user. + +#### 7.4.4 Resetting the timetable +1. Reset the timetable + 1. Test case: `timetable -reset`\ + Expected: TimeTableManager clears and reinitialises the timetable. The user is prompted to input the current week for reinitialisation. + +### 7.5 Calculating the Accumulated Cap after the current semester +1. Calculate the Cap: + 1. Test case: `cap`, where the modules in module list has already been graded individually.\ + Excepted: Each module in `ModuleManager` will be checked for its `moduleCredit` and `grade`. + Using the CAP formula, the user's most updated CAP will be calculated and shown to user. + +### 7.6 Grading an existing module in module list +1. Grade the module: + 1. Test case: `grade CS2101 4 A+`, where the module `CS2101` has been previously added to the module list.\ + Expected: Module `CS2101` will be checked if its inside ModuleManager. + Since `CS2101` exists then the attributes of `4` and `A+` which are module credit and grade, + will be added to the Module. + +### 7.7 Undo the previous command +**Do note that `undo` will only undo the last command that edited the data files, namely commands with a `PromptType` of `EDIT`.** +1. Undo: + 1. Test case: `undo`, after the user has input `add -t finish work`.\ + Expected: The task `finish work` is added to the task list. As the AddTaskCommand has a `PromptType` of `EDIT`, the addition of the task: `finish work` to the task list will be undone. Details of the successful undo will be shown. + 2. Test case: `undo`, without any prior commands with a `PromptType` of `EDIT` since the program launch.\ + Expected: Due to the fact that there have been no commands with a `PromptType` of `EDIT`, nothing will be undone and details of the associated error message will be shown. + +### 7.8 Saving data +**Do note that if you exit the application without entering `bye`, ra.VI will still be able to retrieve data that was +amended during that session. However, this is not a recommended way to use ra.VI.**\ +**Tampering with the files created by ra.VI, through any other application, may also cause ra.VI to malfunction and is +strongly discouraged.** +1. Add tasks and modules, then exit + 1. Test case: `add -t task 1`, `add -m CS1010`, `bye`\ + Expected: `user_task_data.json` and `user_mod_data.json` should be created in `/data/` with a JSON + representation of the task and module. +2. Loading tasks and modules + 1. Test case: Run ra.VI again after the first test case, then run `list -t` and `list -m`.\ + Expected: `task 1` should be shown in the task list, and `CS1010` should be shown in the module list. + +---- + + + +## The Graphical User Interface V3.0 +**The graphical user interface and its related features are supposed to released in the next iteration v3.0** +**Thus, the GUI is currently still a separate branch. The professor asks me to attach the GUI features here to fulfill my contribution to the DG** +**The following are some features implemented in the GUI branch** + +### Top level classes + +This is a class diagram of the top-level of ra.Vi GUI version. +The classes depicted here are those which are direct dependencies of the main class `Ravi`. +The various dependencies of the classes depicted here are not shown to avoid cluttering, and are described in later +sections. + +![UML class diagram for Main Class](https://github.com/AY2021S1-CS2113T-T09-2/tp/blob/master/docs/diagrams/MainClassDiagramGUI.png?raw=true) + + +#### Command Family + +The Command family of classes in GUI branch are regarded as the supplement for the master branch (CLI). +The Command family of classes are nearly all derived from the abstract `Command` class, except for +`CommandResult` and `PromptType`. All `Command` classes belong to the `Command` package. This is shown in the diagram +below. +![UML class diagram for Command Family Classes](https://github.com/AY2021S1-CS2113T-T09-2/tp/blob/master/docs/diagrams/CommandClassDiagramGUI.png?raw=true) + + +#### Graphical User Interface Features +The graphical user interface is designed to help user to have a more intuitive concept of the modules and tasks. +The `MainStage` class implements the `Initializable` class. +The DirectoryTree object is created when the `showDirectoryTree()` method is called in the `MainStage` class. +The DailyTaskWindow object is created when the `showDailyTask()` method is called in the `MainStage` class. -## Non-Functional Requirements +### Feature explanation +#### General Add Feature +This feature is facilitated by the ModuleManager and TaskManager classes. +This is the general version of add feature. +The Parser class will parse the general AddCommand to AddModuleCommand or AddTaskCommand according to the user current level. +If the user is at the root level, the general AddCommand will be parsed to AddModuleCommand. +If the user is at the Module level, the general AddCommand will be parsed to AddTaskCommand. -{Give non-functional requirements} +#### Change directory Feature +This feature is facilitated by the `DirectoryTraverser` classes. +It extends from the abstract `Command` class. +This feature implements the following operations: +* Change to a specific directory (module/task) +* Jump out of the the current directory (module/task) -## Glossary +Given below is an example scenario to show how the change directory feature behaves at each step. +Suppose the user is currently at the `root` level. +The user inputs cd `CS2113T`, to move to the module CS2113T directory. +The ChangeDirectoryCommand object will first examine if the user has specify the targeted directory. +If the user does not specify the target directory: +The method `findNextDirectory("CS2113T")` in DirectoryTraverse class will be called, to examine the validity of the userInput directory name `CS2113T`. +If the userInput directory name is valid, then the `traverseDown()` or `traverseUp()` method in the DirectoryTraverse class will be called. +If the userInput directory name is invalid, a `DataNotFoundException` will be thrown. +However, there is another boundary case, where the user tries to traverse beyond the boundary levels, such as the root level and task levels. +Then another exception `DirectoryTraversalOutOfBoundsException` will be thrown. +If the user like the example, has specified the directory CS2113T: +The `traverseTo(CS2113T)` method in the `DirectoryTraverse` class will be called to set the `currentDirectoryLevel` attribute to the specified the directory. -* *glossary item* - Definition +#### Week Command Feature +This feature works with the GUI components to create a upcoming week table for users. A window will pop out and the task number on the each day of the upcoming week will be listed. +It extends from the abstract `Command` class. -## Instructions for manual testing +#### Directory Command Feature +This feature works with the GUI components to create a module-list table for users. A window will pop out and all module with related tasks will be listed. +It extends from the abstract `Command` class. -{Give instructions on how to do a manual product testing e.g., how to load sample data to be used for testing} + diff --git a/docs/README.md b/docs/README.md index bbcc99c1e7..a67e4bce96 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,6 +1,10 @@ -# Duke +# ra.VI -{Give product intro here} +Hello! Thank you for choosing **ra.VI**. + +**Repository Assistant with a Versatile Interface (ra.VI)** is a desktop app for managing tasks, deadlines, and notes, 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, **ra.VI** can manage your tasks faster than traditional GUI apps. Useful links: * [User Guide](UserGuide.md) diff --git a/docs/UserGuide.md b/docs/UserGuide.md index abd9fbe891..9bbe6a708e 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -1,42 +1,807 @@ -# User Guide +# ra.VI User Guide + +Welcome to the ra.VI User Guide! Choose a section from the table of contents on the left, or simply start reading from the introduction. This User Guide will give you step-by-step instructions to start your journey in planning out your NUS life. + +--- ## Introduction -{Give a product intro} +Repository Assistant with a Versatile Interface (ra.VI) is a desktop app for managing tasks, deadlines, and timetable, optimised for use via a Command Line Interface (CLI). If you can type fast, ra.VI can manage your tasks and timetable faster than traditional GUI apps. + +This user guide aims to provide you with a clear documentation of ra.VI's features. In addition, the quick start guide provides an start-to-end setup process to begin tracking your tasks, modules, and lessons with ra.VI! + +--- + +### Product Overview + +ra.VI is targeted at you - the NUS freshman. As a freshman, there are many documents and new procedures that you must get familiar with. This may be daunting for you but ra.VI will provide you with the assistance you need. + +By helping you keep track of your tasks and deadlines, you will be able to keep on top of deadlines. +Moreover, the timetable feature helps you to schedule your lessons, allowing you to be more prepared for lessons. + +Adding on, ra.VI also allows you to keep track of your CAP, so that you can keep tabs on how well you are doing, motivating you towards that elusive CAP 5.0. + +--- + +### How to use this Guide + +This user guide will give you a step-by-guide tutorial on how to use each of the commands provided in ra.VI. To aid this, this guide is written with specific formatting to help you understand how to use ra.VI better. + +`Grey highlighted font` like this indicate a command or a keyword. For example, `help` or `list -t`. + +Keywords like `` and `` are surrounded by angle brackets ("<" and ">"), and they indicate the positions of extra information you need to provide to the command. For example, `add -m ` means that you need to fill in the module code you want in the place of the ``. It would look something like `add -m CS2113T`. + +We also have some special text boxes to help you understand how to use ra.VI! + +```tip +This box shows you information that isn't necessary, but will be helpful. +``` + +```note +This box shows you useful information that you will need to know. +``` + +```warning +This box tells you about things you need to be alert about. If you're not careful, you might end up with an error! +``` + +--- + +### Keywords + +#### Command-Line Interface + +The Command-Line Interface (or CLI for short) is a type of user interface which lets a user control a computer program like ra.VI. Instead of the Graphical User Interface (GUI) with buttons and menus like you are probably used to, the CLI is entirely text-based. This makes it less intuitive but far faster to use, especially if you are a fast typer! + +#### Tasks + +A task refers to something that you would like to get done. This refers to reading a book or doing an assignment. Tasks can be created with or without a deadline. + +#### Deadline + +A deadline refers to a date and time associated with a task. This is in the format: `DAY-MONTH-YEAR TIME_24H`, e.g. `23-12-2020 1400` or `1-2-2000 0800`. + +#### Modules + +A module refers to a module taken under NUS. Entered modules will be checked against the list of NUS modules taken from [NUSMods](https://nusmods.com/timetable/sem-1). + +#### Module Code + +A module code refers to the **official** module code of the module you are trying to refer to. As with modules, ra.VI will be taking reference from [NUSMods](https://nusmods.com/timetable/sem-1). + +#### CAP + +CAP refers to Cumulative Average Point, which is the [grading system used by NUS](http://www.nus.edu.sg/registrar/academic-information-policies/graduate/modular-system). The CAP will be calculated based on your modules and the grades you have assigned to them. + +#### Done + +Any task can be marked as “done”. This will signify completion of the task so that you can get an easy view of any remaining tasks. + +#### Timetable + +The timetable holds all the lessons you take. It allows you to manage the lessons for the modules that you are taking. + +#### NUS Week Number + +NUS’s semesters last for 6 weeks, followed by Recess Week, then another 6 weeks, and finally Reading Week for a total of 14 weeks. When you first use ra.VI, you will be asked to tell ra.VI the current NUS week number. After setting the timetable up the first time, you do not need to go through the set up again. + +#### Lesson Type + +Some commands have a `lesson_type` field for you to specify a certain type of lesson. Here are the accepted values:\ +`TUTORIAL`, `LECTURE`, `SEMINAR`, `LAB`, `RECITATION`, `SESSION`. + +```warning +Similar to the `day` field, this format must be followed exactly! It has to be fully spelled out as shown here, and entirely in uppercase. +``` + +#### Repeat + +`repeat` is a field to specify how often lessons should repeat. +* `0` - Does not repeat. +* `1` - Repeats every week. +* `2` - Repeats every **even** week. +* `3` - Repeats every **odd** week. + +#### Day + +Some commands have a `day` field for you to specify a certain day. Here are the accepted values:\ +`MONDAY`, `TUESDAY`, `WEDNESDAY`, `THURSDAY`, `FRIDAY`, `SATURDAY`, `SUNDAY`. + +```warning +This format must be followed exactly! Fully spelled out in uppercase. `Monday`, `Mon`, `monday` are examples of what will **not** work. If you want to specify Monday, only `MONDAY` will work. +``` + +#### Time + +Some commands require you to enter a time. The `time` field requires the hours and minutes of the time you want to specify, in the [24H format](https://en.wikipedia.org/wiki/24-hour_clock). For example, 9AM would be `0900` and 2:15PM would be `1415`. + +#### Deadline + +Some commands require you to enter a date and time for a deadline. The date portion should have the day, month, and year written in numbers and separated with dashes. + +For example, 30 December 2020 would be `30-12-2020`. The time portion is the same as described in the [Time](#time) explanation above. A full deadline of “15 February 2021 3:30AM” would be `15-02-2021 0330`. + +#### Undo + +Some commands edit your tasks, modules, and lessons. All commands that edit your information can be undone! Here’s a list: +* Adding / deleting / editing tasks. +* Completing tasks. +* Adding / deleting / editing modules. +* Adding / deleting / editing lessons to / from the timetable. +* Resetting the timetable. +* Grading a module. + +--- + +### ra.VI’s Interface + +![Interface with arrows and labels](images/interface/1.png) + +ra.VI is a CLI application, which means you control it entirely with text commands. This is the start screen of ra.VI, after you've used it at least once and initialised ra.VI with the current NUS week number. ra.VI shows you the loading statuses of your data in the welcome message. Your data can either be successfully loaded, skipped (if you have no data), or corrupted if something is wrong with the file. + +```note +All your data is saved in the `data` folder that will be created when ra.VI first runs! There will be 4 save files: +* `mod_data.json` +* `task_data.json` +* `timetable_data.json` +* `nus_mod_data.json` + +If any of these files are corrupted (unreadable by ra.VI), ra.VI will rename them with a ".bak" at the end to indicate that it is no longer in use as a save file. For example, "mod_data.json" would become "mod_data.json.bak". +``` + +![Initialisation interface with arrows and labels](images/interface/2.png) + +This is what you should first see when you launch ra.VI. As you can see from the picture, all the data files' statuses are "skipped" since you have no data saved. It's your first time using ra.VI after all! ra.VI also tells you that it has downloaded the latest data from NUSMods to provide you with useful module information. + +![Command prompt interface explanation](images/interface/3.png) + +ra.VI will “talk” to you with lines of text, as you can see from the diagram. Your previous command entered will be shown on top of the **output** (the result) for that command. You will always be able to type in the next command at the bottom of the window, as shown in the image. + +Just type in whatever command you wish to use with the appropriate syntax and press the Enter key. It's really that simple! + +--- ## Quick Start -{Give steps to get started quickly} +New to using ra.VI? Here's how to get ra.VI up and functional in a few simple steps. 1. Ensure that you have Java 11 or above installed. -1. Down the latest version of `Duke` from [here](http://link.to/duke). +2. Download the latest version of `ra.VI` from [here](https://github.com/AY2021S1-CS2113T-T09-2/tp/releases/tag/v2.1). +3. Copy the file to the folder you want to use as the home folder for `ra.VI`.\ +![Jar file in folder](images/quickstart/1.png){:height="50%" width="50%"} +4. Use your terminal of choice (like Command Prompt or Powershell on Windows, or Terminal on macOS) in the folder from step 3 and enter `java -jar ravi.jar`.\ +![Console with start jar command](images/quickstart/2.png) +5. ra.VI will be launched, and you will be greeted with the welcome screen!\ +![Welcome screen](images/quickstart/3.png) +6. Enter the current NUS week number as prompted. You will then see the prompt for your command.\ +![Command Prompt](images/quickstart/4.png) +7. Type the command in the command prompt and press the Enter key to execute it. + 1. For example, typing `help` and pressing the Enter key will show you the help message, with a list of all of ra.VI’s commands. +8. Refer to the Features below for details of each command, or refer to the command summary for a quick look at all possible commands. + +```warning +It is highly recommended that you have a working internet connection when you first launch ra.VI, as ra.vI will try to download the latest data from NUSMods the first time you use it. If it is not possible, ra.VI has some backup NUSMods data that it can use that is bundled with it, but it may be prone to inaccuracies as it cannot be updated as frequently. +``` + +--- + +## Features + +### Tasks + +Tasks are the one of the main features of ra.VI. Every modern student has tasks to do, and ra.VI helps you to manage your to-do list. This section will show you all you need to know about managing your tasks with ra.VI. + +#### Adding a task (Sean) +You can add a task into ra.VI to keep you on top of your tasks. + +**Format:** +`add -t [-by ]` + +**Example Usage:** +Let’s say you have a task to "read Chapter 1". +To add a task into ra.VI: +1. Type `add -t`, followed by your task name, `read Chapter 1`. +2. The full command would be `add -t read Chapter 1`. +3. Then, simply press the Enter key to execute it. + +Now, let’s say you have to add a deadline `30-12-2020 1800` (i.e. 30th of December 2020, 6pm). +1. You can add this optional deadline to the task by adding `-by`, followed by the deadline for your task, but don’t forget to press enter to execute! +2. The full command would be `add -t read Chapter 1 -by 30-12-2020 1800`. + +**Outcome:** +ra.VI will display the message saying that your task has been added successfully! What you would expect to see is shown below. + +```note +After you add your task, you may want to check if it is there. You will learn how to view your tasks using the `list -t` command later on! +``` + +|Example Commands|Expected Output| +|--------------|--------------| +|`add -t read Chapter 1`|![Add Task](images/addtask/1.png)| +|`add -t read Chapter 1 -by 30-12-2020 1800`|![Add Task W Deadline](images/addtask/2.png)| +|`add -t read Chapter 1 -by 30-12-2020 800`|![Add Task W Wrong Deadline](images/addtask/3.png)| + +#### Listing all tasks (Amalina) +You have a whole list of tasks now, but you need a way to view them. ra.VI can help with that. + +**Format:** +`list -t` + +**Example Usage:** +To view your task list: +1. Type `list -t`. That is the full command. +2. Then, simply press the Enter key to execute it. + +**Outcome:** +ra.VI will display the list of tasks and their indexes. + +```tip +You will need the task indexes for `del`, `edit`, and `done` commands! +``` + +|Example Commands|Context|Expected Output| +|--------------|----|--------------| +|`list -t`|With one task in your list|![List Task](images/listtask/1.png)| + +#### Deleting a task (Tobias) +If your teacher cancels that last minute assignment, ra.VI can help remove a task from your task list. + +**Format:** +`del -t ` + +**Example Usage:** +Let’s say you have a task "read Chapter 1" of index `1` (seen from your `list -t` command), and you would like to remove it from your list. +To delete a task from ra.VI: +1. Type `del -t`, followed by the task index of the task you want to delete, `1`. +2. The full command would be `del -t 1`. +3. Then, simply press the Enter key to execute it. + +**Outcome:** +ra.VI will display the message saying that your task has been deleted successfully! + +```note +After you delete your task, you may want to check if it is there. You will be able to view your tasks using the `list` command earlier! +``` + +|Example Commands|Expected Output| +|--------------|--------------| +|`del -t 1`|![Delete Task](images/deletetask/1.png)| +|`del -t 0`|![Delete Task wrong index](images/deletetask/2.png)| + +#### Marking a task as done (Amalina) +Already completed your assignments or finished your revision? You can mark your tasks as completed with ra.VI. + +**Format:** +`done ` + +**Example Usage:** +Let’s say you have a task "return book" of index `1` (seen from your `list -t` command), and you have completed it. +To mark a task as done: +1. Type `done`, followed by the task index of the task you want to delete, `1`. +2. The full command would be `done 1`. +3. Then, simply press the Enter key to execute it. + +**Outcome:** +ra.VI will display the message saying that your task has been marked done! Your task will now be marked with a tick. + +|Example Commands|Expected Output| +|--------------|--------------| +|`done 1`|![Done Task](images/donetask/1.png)| +|`done 0`|![Delete Task wrong index](images/donetask/2.png)| + +#### Editing a task description (Amalina) +Put "CS2113 homework" instead of "CS2113T homework"? You can edit the task descriptions and deadlines of existing tasks. + +**Format:** +`edit -t [-by ]` + +**Example Usage:** +Let’s say you have a task called "Team Project", with task index `1` (seen from your `list -t` command), and you want to change the description to "Individual Project" instead. +To edit a task’s description: +1. Type `edit -t`, followed by the task index of the task you want to edit, `1`, and the new task description, `Individual Project`. +2. The full command would be `edit -t 1 Individual Project`. +3. Then, simply press the Enter key to execute it. + +Additionally, let’s say you want to add/edit the deadline of your task to `30-12-2020 1800` (i.e. 30th of December 2020, 6pm). +1. You can add this optional deadline to the task by adding `-by`, followed by the deadline for your task. +2. The full command would be `edit -t 1 Individual Project -by 30-12-2020 1800`. + +**Outcome:** +ra.VI will display the message saying that your task has been edited successfully! Your task will now have the new description + +```tip +You can find the index of the tasks by using `list -t`. +``` + +|Example Commands|Context|Expected Output| +|--------------|----------|--------------| +|`edit -t 1 Individual Project`|You have a task "Team Project" at index 1 in the list|![Edit Task](images/edittask/1.png)| +|`edit -t 1 Individual Project -by 30-12-2020 1800`|You have a task "Team Project" at index 1 in the list|![Edit Task](images/edittask/2.png)| + +#### Viewing task summary (Jun You) +If you have too many tasks to keep track of, you can use this command to sort your commands into 3 categories: +1. Incomplete tasks with deadlines. These tasks will be sorted with the most pressing deadline on top. +2. Incomplete tasks without deadlines. +3. Completed tasks (with or without deadlines). + +**Format:** +`summary` + +**Example Usage:** +To view your task summary: +1. Type `summary`. +2. Then, simply press the Enter key to execute it. + +**Outcome:** +ra.VI will display a neat summary of all your tasks, grouped into three categories. The three categories are “Incomplete tasks with deadline”, “Incomplete tasks with no deadline” and “Completed tasks”. + +```tip +Your "Incomplete tasks with deadlines" will be sorted by date, with the current closest deadline at the top and the furthest deadline at the bottom. +``` + +|Example Commands|Context|Expected Output| +|--------------|----------|--------------| +|`summary`|You have 2 tasks with a deadline, 1 task without deadline, and one completed task|![Edit Task](images/summary/1.png)| + +--- + +### Modules -## Features +Modules are the one of the main features of ra.VI. Every NUS student takes modules, and ra.VI helps you to manage all of your modules. This section will show you all you need to know about managing your modules with ra.VI. -{Give detailed description of each feature} +#### Adding a module (Sean) +You can add a module that you are currently taking into ra.VI. -### Adding a todo: `todo` -Adds a new item to the list of todo items. +**Format:** +`add -m ` -Format: `todo n/TODO_NAME d/DEADLINE` +**Example Usage:** +Let’s say you are taking the module CS1010 Programming Methodology. -* The `DEADLINE` can be in a natural language format. -* The `TODO_NAME` cannot contain punctuation. +To add a module into ra.VI: +1. Type `add -m`, followed by your module, `CS1010`. +2. The full command would be `add -m CS1010`. +3. Then, simply press the Enter key to execute it. -Example of usage: +**Outcome:** +ra.VI will display the message saying that your module has been added successfully! +What you would expect to see is shown below. -`todo n/Write the rest of the User Guide d/next week` +```note +After you add your module, you may want to check if it is there. You will learn how to view your modules using the `list` command later on! +``` -`todo n/Refactor the User Guide to remove passive voice d/13/04/2020` +```warning +You will only be able to add modules that are offered at NUS. +``` + +|Example Commands|Expected Output| +|--------------|--------------| +|`add -m CS1010`|![Add CS1010](images/addmodule/1.PNG)| +|`add -m CS2113T`|![Add CS2113T](images/addmodule/2.PNG)| +|`add -m CS`|![Add CS](images/addmodule/3.PNG)| + +#### Listing all modules (Amalina) +You have a whole list of modules now, but you need a way to view them. ra.VI can help with that. + +**Format:** +`list -m` + +**Example Usage:** +To view your module list: +1. Type `list -m`. That is the full command. +2. Then, simply press the Enter key to execute it. + +**Outcome:** +ra.VI will display the list of modules with their modular credits and attained grades, which we will talk about in our `grade` command later on! + +|Example Commands|Context|Expected Output| +|--------------|----------|--------------| +|`list -m`|With CS1010 in your list|![List CS1010](images/listmodule/1.PNG)| + +#### Deleting a module (Tobias) +Even if you have unintentionally added the wrong module, ra.VI can delete it for you. + +**Format:** +`del -m ` + +**Example Usage:** +Let’s say you have a module CS1010 in your list (seen from your `list -m` command), and you would like to remove it from your list. +To delete a module from ra.VI: +1. Type `del -m`, followed by the module code of the module you want to delete, `CS1010`. +2. The full command would be `del -m CS1010`. +3. Then, simply press the Enter key to execute it. + +**Outcome:** +ra.VI will display the message saying that your module has been deleted successfully! + +```tip +After you delete your module, you may want to check if it is still there. You will be able to view your modules using the `list` command earlier! +``` + +|Example Commands|Context|Expected Output| +|--------------|----------|--------------| +|`del -m CS1010`|CS1010 is a module in your module list|![Delete CS1010 Success](images/delmodule/1.PNG)| +|`del -m CS2113T`|CS2113T is not in your module list|![Delete CS2113T Failure](images/delmodule/2.PNG)| + +#### Editing a module (Amalina) +Put CS2113 instead of CS2101? You can edit the module code of specific modules in your module list. + +**Format:** +`edit -m ` + +**Example Usage:** +Let’s say you have a module CS2113 in your module list (seen from your `list -t` command). + +To edit a module: +1. Type `edit -m`, followed by the module code you want to edit, `CS2113`, and the new module code, `CS2101`. +2. The full command would be `edit -m CS2113 CS2101`. +3. Then, simply press the Enter key to execute it. + +**Outcome:** +ra.VI will display the message saying that your module has been edited successfully! + +```tip +You can check your module list by using `list -m` to check if the module has been edited correctly. +``` + +|Example Commands|Context|Expected Output| +|--------------|----------|--------------| +|`edit -m CS2113 CS2101`|You have `CS2113` in your module list|![Edit Module](images/editmodule/1.png)| +|`edit -m CG2271 CS2101`|You do not have `CG2271` in your module list|![Edit Missing Module](images/editmodule/2.PNG)| + +#### Grade an existing module (Tobias) +Assign a grade and its relevant module credits to a module in ra.VI. + +**Format:** + `grade ` + +```note +* ra.VI will accept both _lowercase_ and _uppercase_. ie `A+` or `a+`. +* Relevant module information, such as the number of module credits for the relevant module, can be found at [NUSMods](https://nusmods.com/modules). +* If you have [SU-ed your module](http://www.nus.edu.sg/registrar/academic-activities/satisfactory-unsatisfactory-(s-u)-option), use `CS` or `CU` as the grade accordingly. +``` + +**Example Usage.** +Let’s say it is the end of the semester and results are out. You got an A+ for your CS1010, great job! To add the grade into ra.VI: +1. Type `grade` into the command box, followed by the module code of the module to be graded, `CS1010`. +2. Then, type in the respective module credits, `4`, and the grade achieved for that module, `A+`. +3. The full command would be `grade CS2101 4 A+`. +4. Then, simply press the Enter key to execute it. + +**Outcome:** +ra.VI will display the message saying that your module has been successfully graded! + +```warning +* Please ensure that the grade assigned is compliant with the [NUS grade schematic](http://www.nus.edu.sg/registrar/academic-information-policies/non-graduating/modular-system) +* The module to be graded must first **exist** in the list of modules, to be assigned a grade. +``` + +|Example Commands|Context|Expected Output| +|--------------|----------|--------------| +|`grade CS2101 4 A+`|CS2101 has been successfully graded|![Grade CS2101 Success](images/grademodule/1.PNG)| +|`grade ACC1002 4 C+`|ACC1002 is not in your module list|![Grade ACC1002 Failure](images/grademodule/2.PNG)| + + +#### Calculate your current CAP (Tobias) +Curious to know your current CAP before, during or after the semester? +You have the flexibility of calculating your current CAP at any time. + +**Format:** +`cap` + +```note +Please ensure the relevant modules in the module list have been graded, for ra.VI to calculate your CAP accurately. However, CAP is calculated only by considering the modules that you have entered a grade for. +``` + +**Example Usage:** +With all of the relevant modules in the module list graded, you may calculate your current CAP by executing the `cap` command. + +To calculate your current CAP: +1. Simply type in the command `cap` +2. The full command would be `cap`. +3. Then simply press the Enter key to execute it. + +**Outcome:** +Based on the grades that you have given to each module in the module list, ra.VI will display the calculated CAP. + +|Example Commands|Context|Expected Output| +|--------------|----------|--------------| +|`cap`|CAP calculated successfully|![CAP calculated Success](images/cap/1.PNG)| + +--- + +### Timetable +Every NUS student has lessons to take, whether they are lectures, labs or tutorials, just to name a few. These lessons are usually at regular intervals throughout the semester. ra.VI will help you arrange your lessons into a timetable, allowing you to view all of your lessons in one place. + +#### Adding a lesson (Jun You) +Every student has lessons. Too many lessons, even. Let ra.VI help you keep track of them all with this command. + +**Format:** +`timetable -add ` + +```warning +These fields must follow this order strictly, and also must follow certain requirements. You can check the [Keywords](#keywords) section above for details on these fields! + +For `module_code`, the module code must be in your module list. See your module list with `list -m`. + +The format for `start_time` and `end_time` are both explained in the "Time" section of the [Keywords](#keywords) section above. `start_time` must be chronologically before `end_time`. For example, `1800 1700` is not accepted, but `1700 1800` is accepted. +``` + +**Example Usage:** +Let’s say you have a lecture for CS2101 at 8AM to 10AM on every Tuesday, and you would like to add it to your timetable. +To add a lesson to your timetable: +1. Type `timetable -add`, followed by the lesson’s details, `CS2101 TUESDAY 0800 1000 LECTURE 1`. +2. The full command would be `timetable -add CS2101 TUESDAY 0800 1000 LECTURE 1`. +3. Then, simply press the Enter key to execute it. + +**Outcome:** +ra.VI will display a message saying that your lesson has been added! + +|Example Commands|Context|Expected Output| +|--------------|----------|--------------| +|`timetable -add CS2101 TUESDAY 0800 1000 LECTURE 1`|CS2101 is in your module list|![Timetable add CS2101 Success](images/timetableadd/1.png)| +|`timetable -add CS1010 WEDNESDAY 1200 1400 LECTURE 2`|CS1010 is not in your module list|![Timetable add CS1010 Failure](images/timetableadd/2.png)| +|`timetable -add CS2113T TUESDAY 0800 1000 LECTURE 2`|Overlapping lesson times|![Timetable add Overlap Failure](images/timetableadd/3.png)| +|`timetable -add CS1010 THURSDAY LECTURE 0`|Missing parameters|![Timetable add Missing Parameters Failure](images/timetableadd/4.png)| + +#### Viewing your timetable (Jun You) +Now that you have your lessons in your timetable, you can view them too! + +**Format:** +`timetable -day` or `timetable -week` + +**Example Usage:** +To view your day’s timetable: +1. Type `timetable -day`. That is the full command. +2. Then, simply press the Enter key to execute it. + +To view the current week’s timetable: +1. Type `timetable -week`. That is the full command. +2. Then, simply press the Enter key to execute it. + +**Outcome:** +ra.VI will display your timetable, containing the lessons and their indexes, for the day or week! + +|Example Commands|Context|Expected Output| +|--------------|----------|--------------| +|`timetable -day`|View day’s timetable|![Timetable view day](images/timetableday/1.JPG)| +|`timetable -week`|View week’s timetable|![Timetable view week](images/timetableweek/1.PNG)| + +#### Deleting a lesson (Jun You) +Entered the wrong lessons to your timetable? ra.VI can help ypu delete them. + +**Format:** +`timetable -del ` + +**Example Usage:** +Let’s say that you have a lesson on Tuesday, with the index of `1`. +To remove a lesson from your timetable: +1. Type `timetable -del`, followed by the lesson’s details, `TUESDAY 1`. +2. The full command would be `timetable -del TUESDAY 1`. +3. Then, simply press the Enter key to execute it. + +**Outcome:** +ra.VI will display a message saying that your lesson has been deleted. + +```tip +You will need the lesson indexes for `timetable -del`! Use `timetable -day` or `timetable -week` to see the lesson’s index. +``` + +|Example Commands|Context|Expected Output| +|--------------|----------|--------------| +|`timetable -del MONDAY 1`|Lesson on Monday with an index of 1|![Timetable Del Success](images/timetabledel/1.PNG)| +|`timetable -del FRIDAY 3`|No lessons on Friday with an index of 3|![Timetable Del Failure](images/timetabledel/2.PNG)| + +#### Filtering lessons in your timetable (Jun You) + +If you have a cluttered timetable and would only like to view certain lessons out of all of your lessons, ra.VI can filter them out for you. + +**Format:** +`timetable -filter ` + +**Example Usage:** +Let’s say that you want to see all your lessons on Thursday this week. To filter out these lessons from your timetable: +1. Type `timetable -filter`, followed by the lesson’s details, `- THURSDAY - - -`. +2. The full command would be `timetable -filter - THURSDAY - - -`. +3. Then, simply press the Enter key to execute it. + +**Outcome:** +ra.VI will display a message saying that your lesson has been deleted. + +```tip +Confused by the `-` symbol? If you want to skip using certain criteria, you can use a dash (`-`) in the place of that field! For example, if you only want to filter all lessons on Monday, you could do `timetable -filter - MONDAY - - -`, only filling in the `day` field and using `-` to ignore the other fields. **Any combination of fields is possible!** + +Need help with understanding the fields such as module, day, and so on? Refer to the [Keywords](#keywords) section to find out more! +``` + +**For some context,** here is the timetable without any filtering: + +![Timetable before filter](images/timetablefilter/1.png){:height="75%" width="75%"} + +|Example Commands|Context|Expected Output| +|--------------|----------|--------------| +|`timetable -filter - THURSDAY - - -`|All lessons on Thursday|![Timetable filter with existing lesson](images/timetablefilter/2.png){:height="75%" width="75%"}| +|`timetable -filter - - 1200 - -`|All lessons after noon on any day|![Timetable filter with existing lesson](images/timetablefilter/3.png){:height="75%" width="75%"}| +|`timetable -filter - - - - TUTORIAL`|All tutorials|![Timetable filter with all tutorials](images/timetablefilter/4.png){:height="75%" width="75%"}| +|`timetable -filter CS2222 - 0800 1000 -`|No such module in the module list|![Timetable filter with error](images/timetablefilter/5.png){:height="75%" width="75%"}| + +#### Resetting your timetable (Sean) +As you move to the next semester, you can still continue to use ra.VI. In fact, we would appreciate it if you could use ra.VI all the way until your graduation! + +**Format:** +`timetable -reset` + +**Example Usage:** +Let’s say that it is the start of a new semester and you would like to start with a new timetable. + +To reset your timetable: +1. Type `timetable -reset`. That is the full command. +2. Then, simply press the Enter key to execute it. + +**Outcome:** +ra.VI will prompt you for the current NUS week, just like when you used ra.VI for the first time. Once that is completed, ra.VI will display a message saying that your timetable has been reset. + +```warning +Once you reset your timetable and exit ra.VI, there is no going back! You can only undo your timetable reset before you exit ra.VI, so do make sure that you truly want to reset your timetable and that you will not lose any valuable information. +``` + +|Example Commands|Expected Output| +|--------------|--------------| +|`timetable -reset`|![Reset the timetable](images/timetablereset/1.JPG){:height="75%" width="75%"}| + +--- + +### Undo (Sean) +Deleted a task when you didn’t mean to? Accidentally reset your timetable? You can undo your previous action! + +**Format:** +`undo` + +**Example Usage:** +Let’s say you have accidentally deleted an important task. +To undo an action: +1. Type `undo`. That is the full command. +2. Then, simply press the Enter key to execute it. + +**Outcome:** +ra.VI will undo the command and display a success message with the details of the undone command! + +```tip +Refer to the [Undo](#undo) in the [Keywords](#keywords) section above for the list of commands that can be undone. +``` + +|Example Commands|Context|Expected Output| +|--------------|----------|--------------| +|`undo`|You have previously entered a command that can be undone|![bye success](images/undo/1.png)| +|`undo`|You just launched ra.VI and did not change any data with commands|![bye failure](images/undo/2.png)| + +--- + +### Exit (Sean) +Done using ra.VI? You can save your data and safely exit with this command. + +**Format:** +`bye` + +**Example Usage:** +To exit ra.VI: +1. Type `bye`. That is the full command. +2. Then, simply press the Enter key to execute it. + +**Outcome:** +ra.VI saves all data and says goodbye to you before shutting down! + +|Example Commands|Expected Output| +|--------------|--------------| +|`bye`|![bye success](images/bye/1.png)| + +--- ## FAQ -**Q**: How do I transfer my data to another computer? +**Q**: Can I use ra.VI on operating system other than Windows?\ +**A**: Yes. ra.VI is compatible with Windows, macOS and Linux. + +**Q**: Can I use ra.VI throughout my time in NUS?\ +**A**: Yes! In fact, we strongly encourage using ra.VI for your time at NUS. ra.VI is robust enough to handle the trials of time, since it continually gets the latest information from NUSMods, has a simple yet timeless data management system, and can easily work across semesters. -**A**: {your answer here} +**Q**: How do I transfer my data to another computer?\ +**A**: Zip the folder where you have installed ra.VI on and transfer the zip file to the other computer. Unzip the folder on the new computer, and you are good to go! + +**Q**: Can I edit the files created by ra.VI?\ +**A**: It is not advised to edit the files created by ra.VI with any other software. However, any advanced user with knowledge of the [JSON](https://en.wikipedia.org/wiki/JSON) format can try their hand at manually editing the save files. (However, we **do not recommend this** and we will **not be liable for any damages done**. Consider yourself warned.) + +**Q**: Can I force close ra.VI?\ +**A**: It is not advised to force close ra.VI. If you decide to do so, the changes made during that current session may get corrupted. To close ra.VI, please enter `bye`. + +--- ## Command Summary -{Give a 'cheat sheet' of commands here} +| Function | Command | +|--------|---------------------------------------| +| Add a task | `add -t [-by ]`| +| Delete a task | `del -t ` | +| Edit a task | `edit -t [-by ]` | +| Mark task as done | `done ` | +| List all tasks | `list -t` | +| View task summary | `summary` | +| Add a module | `add -m ` | +| Delete a module | `del -m ` | +| Edit a module | `edit -m ` | +| List all modules | `list -m` | +| Grade and allocate MCs to a module | `grade ` | +| Calculate CAP | `cap` | +| Add a lesson | `timetable -add ` | +| Delete a lesson | `timetable -del ` | +| View today's timetable | `timetable -day` | +| View current week's timetable | `timetable -week` | +| Filter the timetable | `timetable -filter ` | +| Reset the timetable | `timetable -reset` | +| Undo previous change | `undo` | +| Get help for commands | `help` | +| Get detailed help message for each command | `help ` | +| Exit ra.VI | `bye` | + +--- + +## v3.0 Graphical User Interface (Wang Qin) + +### Change Directory Command `cd` +Traverse to the target directory. + +**Note:** +All the modules and tasks are treated as directories, like the folders in the Window OS. +To create a task related to Module CS2101, the user need to go into the Directory CS2101, to create the task. +Format: `cd ` + `cd ..` + +Example of usage: +* `cd CS2101` +* `cd ..` + +Example of output: +* `CS2101` +* `Root` + +### 6.2 General Add `add` +The generic way to add a module or a task to the system. + +**Note:** +There are two types of add commands in the system: add a module and add a task. +The general add command combines and simplifies the above two command. +The ra.VI system could parse the general add command to different add commands according to the user current directory level. +Format: `add ` +Example of usage: +* `add CS2101` +* `add read a book` + +Example of output: +* Module has been added +* Task has been added + +### 6.3 Undo `undo` +Recover the data from the previous "Data-changed" operations. + +**Note:** +"Data-changed" operations refer to Add, Edit, Delete operations only. + +Example of usage: +1. `add -m CS2113T` +2. `undo` + +Example of output: +* Undo Successfully + +### 6.4 Week Command `week` +A window will pop out and the task number on the each day of the upcoming week will be listed. + +Example of usage: +* `week` + +### 6.5 Directory Command `dir` +A window will pop out and all module with related tasks will be listed. -* Add todo `todo n/TODO_NAME d/DEADLINE` +Example of usage: +* `dir` diff --git a/docs/_config.yml b/docs/_config.yml new file mode 100644 index 0000000000..bd8077d7c1 --- /dev/null +++ b/docs/_config.yml @@ -0,0 +1,31 @@ +title: "ra.VI" +description: "Repository Assistant with a Versatile Interface" +remote_theme: rundocs/jekyll-rtd-theme + +markdown: kramdown + +plugins: +- jemoji +- jekyll-avatar +- jekyll-mentions + +kramdown: + auto_ids: true + +translate: + # shortcodes + danger: + note: + tip: + warning: + # 404 + not_found: + # copyright + revision: + # search + searching: + search: + search_docs: + search_results: + search_results_found: # the "#" in this translate will replaced with results size! + search_results_not_found: diff --git a/docs/diagrams/AddCommandSequenceDiagram.png b/docs/diagrams/AddCommandSequenceDiagram.png new file mode 100644 index 0000000000..a02910005a Binary files /dev/null and b/docs/diagrams/AddCommandSequenceDiagram.png differ diff --git a/docs/diagrams/CapCommandSequenceDiagram.png b/docs/diagrams/CapCommandSequenceDiagram.png new file mode 100644 index 0000000000..18adc43fe6 Binary files /dev/null and b/docs/diagrams/CapCommandSequenceDiagram.png differ diff --git a/docs/diagrams/CommandClassDiagram.png b/docs/diagrams/CommandClassDiagram.png new file mode 100644 index 0000000000..c6f9032e47 Binary files /dev/null and b/docs/diagrams/CommandClassDiagram.png differ diff --git a/docs/diagrams/CommandClassDiagramGUI.png b/docs/diagrams/CommandClassDiagramGUI.png new file mode 100644 index 0000000000..be67047585 Binary files /dev/null and b/docs/diagrams/CommandClassDiagramGUI.png differ diff --git a/docs/diagrams/CommandSequenceDiagram.png b/docs/diagrams/CommandSequenceDiagram.png new file mode 100644 index 0000000000..b23b20650f Binary files /dev/null and b/docs/diagrams/CommandSequenceDiagram.png differ diff --git a/docs/diagrams/DataClassDiagram.png b/docs/diagrams/DataClassDiagram.png new file mode 100644 index 0000000000..e7dff2b09d Binary files /dev/null and b/docs/diagrams/DataClassDiagram.png differ diff --git a/docs/diagrams/DataClassDiagramGUI.png b/docs/diagrams/DataClassDiagramGUI.png new file mode 100644 index 0000000000..4a74667245 Binary files /dev/null and b/docs/diagrams/DataClassDiagramGUI.png differ diff --git a/docs/diagrams/DataSequenceDiagram.png b/docs/diagrams/DataSequenceDiagram.png new file mode 100644 index 0000000000..a0a651a01a Binary files /dev/null and b/docs/diagrams/DataSequenceDiagram.png differ diff --git a/docs/diagrams/DataSequenceDiagramDataSd.png b/docs/diagrams/DataSequenceDiagramDataSd.png new file mode 100644 index 0000000000..d535e0089b Binary files /dev/null and b/docs/diagrams/DataSequenceDiagramDataSd.png differ diff --git a/docs/diagrams/DataSequenceDiagramNusModsSd.png b/docs/diagrams/DataSequenceDiagramNusModsSd.png new file mode 100644 index 0000000000..951f5170ae Binary files /dev/null and b/docs/diagrams/DataSequenceDiagramNusModsSd.png differ diff --git a/docs/diagrams/GradeCommandSequenceDiagram.png b/docs/diagrams/GradeCommandSequenceDiagram.png new file mode 100644 index 0000000000..0c4b04d13c Binary files /dev/null and b/docs/diagrams/GradeCommandSequenceDiagram.png differ diff --git a/docs/diagrams/ListCommandSequenceDiagram.png b/docs/diagrams/ListCommandSequenceDiagram.png new file mode 100644 index 0000000000..9fd3fc6252 Binary files /dev/null and b/docs/diagrams/ListCommandSequenceDiagram.png differ diff --git a/docs/diagrams/MainClassDiagram.png b/docs/diagrams/MainClassDiagram.png new file mode 100644 index 0000000000..aaf84a1bdd Binary files /dev/null and b/docs/diagrams/MainClassDiagram.png differ diff --git a/docs/diagrams/MainClassDiagramGUI.png b/docs/diagrams/MainClassDiagramGUI.png new file mode 100644 index 0000000000..4fc865d378 Binary files /dev/null and b/docs/diagrams/MainClassDiagramGUI.png differ diff --git a/docs/diagrams/MainSequenceDiagram.png b/docs/diagrams/MainSequenceDiagram.png new file mode 100644 index 0000000000..4fdaee987e Binary files /dev/null and b/docs/diagrams/MainSequenceDiagram.png differ diff --git a/docs/diagrams/MainSequenceDiagramLoopSd.png b/docs/diagrams/MainSequenceDiagramLoopSd.png new file mode 100644 index 0000000000..ea83e51ee6 Binary files /dev/null and b/docs/diagrams/MainSequenceDiagramLoopSd.png differ diff --git a/docs/diagrams/MainSequenceDiagramStartSd.png b/docs/diagrams/MainSequenceDiagramStartSd.png new file mode 100644 index 0000000000..962ad9edd4 Binary files /dev/null and b/docs/diagrams/MainSequenceDiagramStartSd.png differ diff --git a/docs/diagrams/NotesClassDiagram.png b/docs/diagrams/NotesClassDiagram.png new file mode 100644 index 0000000000..07f9b02c4b Binary files /dev/null and b/docs/diagrams/NotesClassDiagram.png differ diff --git a/docs/diagrams/ParserClassDiagram.png b/docs/diagrams/ParserClassDiagram.png new file mode 100644 index 0000000000..eaa18f6903 Binary files /dev/null and b/docs/diagrams/ParserClassDiagram.png differ diff --git a/docs/diagrams/ParserClassDiagramGUI.png b/docs/diagrams/ParserClassDiagramGUI.png new file mode 100644 index 0000000000..b8ac0f5112 Binary files /dev/null and b/docs/diagrams/ParserClassDiagramGUI.png differ diff --git a/docs/diagrams/TimeTableClassDiagram.png b/docs/diagrams/TimeTableClassDiagram.png new file mode 100644 index 0000000000..7d0cb79a9d Binary files /dev/null and b/docs/diagrams/TimeTableClassDiagram.png differ diff --git a/docs/diagrams/UML/AddCommandSequenceDiagram.puml b/docs/diagrams/UML/AddCommandSequenceDiagram.puml new file mode 100644 index 0000000000..77618143f6 --- /dev/null +++ b/docs/diagrams/UML/AddCommandSequenceDiagram.puml @@ -0,0 +1,25 @@ +@startuml +-> ":AddCommandParser": prepareAddCommand() +activate ":AddCommandParser" +alt MODULE_PREFIX + create ":AddModuleCommand" + ":AddCommandParser" -> ":AddModuleCommand": <> getAddCommand() + activate ":AddModuleCommand" + ":AddCommandParser" <-- ":AddModuleCommand": AddModuleCommand + deactivate ":AddModuleCommand" +else TASK_PREFIX + create ":AddTaskCommand" + ":AddCommandParser" -> ":AddTaskCommand": <> getAddCommand() + activate ":AddTaskCommand" + ":AddCommandParser" <-- ":AddTaskCommand": AddTaskCommand + deactivate ":AddTaskCommand" +else UNKNOWN_PREFIX + create ":IncorrectCommand" + ":AddCommandParser" -> ":IncorrectCommand": <> + activate ":IncorrectCommand" + ":AddCommandParser" <-- ":IncorrectCommand" + deactivate ":IncorrectCommand" +end +<-- ":AddCommandParser": Command +destroy ":AddCommandParser" +@enduml \ No newline at end of file diff --git a/docs/diagrams/UML/CapCommandSequenceDiagram.puml b/docs/diagrams/UML/CapCommandSequenceDiagram.puml new file mode 100644 index 0000000000..2f342d76c2 --- /dev/null +++ b/docs/diagrams/UML/CapCommandSequenceDiagram.puml @@ -0,0 +1,25 @@ +@startuml + +-> ":CapCommandParser" ++ : CapCommand() + ":CapCommandParser" -> ":CapCommand" ** : <> + activate ":CapCommand" + return +<-- ":CapCommandParser" !! : CapCommand + +-> ":CapCommand" ++ : execute() + ":CapCommand" -> ":CapCommand" ++ : calculateCap() + ||| + participant ":ModuleManager" as MM << Class >> + ":CapCommand" -> MM ++ : getModuleMap() + return moduleList + ||| + ":CapCommand" -> ":CapCommand" ++ : gradeConvert(moduleList) + return mcGrade + ||| + return CAP + + create ":CommandResult" + ":CapCommand" -> ":CommandResult" ++ : <> + return CommandResult +<-- ":CapCommand" !! : CommandResult +@enduml \ No newline at end of file diff --git a/docs/diagrams/UML/CommandClassDiagram.puml b/docs/diagrams/UML/CommandClassDiagram.puml new file mode 100644 index 0000000000..98ceddeda8 --- /dev/null +++ b/docs/diagrams/UML/CommandClassDiagram.puml @@ -0,0 +1,76 @@ +@startuml + +hide circle +skinparam classAttributeIconSize 0 + +abstract class "{abstract} \n Command" { + PromptType getPromptType() + void setPromptType() + CommandResult execute() +} + +class CommandResult { + String feedbackToUser + Boolean isError + Boolean isExit +} + +abstract class "{abstract} \n AddCommand" +class AddModuleCommand +class AddTaskCommand + +abstract class "{abstract} \n DeleteCommand" +class DeleteModuleCommand +class DeleteTaskCommand + +abstract class "{abstract} \n EditCommand" +class EditModuleCommand +class EditTaskCommand + +abstract class "{abstract} \n TimeTableCommand" +class TimeTableAddCommand +class TimeTableDeleteCommand +class TimeTableViewCommand + +class DoneCommand +class UndoCommand +class HelpCommand +class ListCommand +class ExitCommand +class IncorrectCommand +enum "<> \n PromptType" { + WARNING, + INFORMATIVE, + NONE, + EDIT +} + +"{abstract} \n Command" <|- HelpCommand +"{abstract} \n Command" <|- ListCommand +"{abstract} \n Command" <|- ExitCommand +"{abstract} \n Command" <|-- "{abstract} \n DeleteCommand" +"{abstract} \n Command" <|-- "{abstract} \n AddCommand" +"{abstract} \n EditCommand" ---|> "{abstract} \n Command" +DoneCommand -|> "{abstract} \n Command" +UndoCommand -|> "{abstract} \n Command" +IncorrectCommand -|> "{abstract} \n Command" +"{abstract} \n TimeTableCommand" ---|> "{abstract} \n Command" + +"<> \n PromptType" ---* "1" "{abstract} \n Command" + +"{abstract} \n Command" -- CommandResult : returns + +"{abstract} \n AddCommand" <|-- AddModuleCommand +"{abstract} \n AddCommand" <|-- AddTaskCommand + +"{abstract} \n DeleteCommand" <|-- DeleteModuleCommand +"{abstract} \n DeleteCommand" <|-- DeleteTaskCommand + +EditModuleCommand --|> "{abstract} \n EditCommand" +EditTaskCommand --|> "{abstract} \n EditCommand" + +TimeTableAddCommand --|> "{abstract} \n TimeTableCommand" +TimeTableDeleteCommand --|> "{abstract} \n TimeTableCommand" +TimeTableViewCommand --|> "{abstract} \n TimeTableCommand" + +@enduml \ No newline at end of file diff --git a/docs/diagrams/UML/CommandSequenceDiagram.puml b/docs/diagrams/UML/CommandSequenceDiagram.puml new file mode 100644 index 0000000000..ad1f90aa94 --- /dev/null +++ b/docs/diagrams/UML/CommandSequenceDiagram.puml @@ -0,0 +1,12 @@ +@startuml +-> ":Command": execute() +activate ":Command" +create ":CommandResult" +":Command" -> ":CommandResult": <> +activate ":CommandResult" +":Command" <-- ":CommandResult": CommandResult +deactivate ":CommandResult" +<-- ":Command": CommandResult +deactivate ":Command" +destroy ":Command" +@enduml \ No newline at end of file diff --git a/docs/diagrams/UML/DataClassDiagram.puml b/docs/diagrams/UML/DataClassDiagram.puml new file mode 100644 index 0000000000..aa228d3554 --- /dev/null +++ b/docs/diagrams/UML/DataClassDiagram.puml @@ -0,0 +1,82 @@ +@startuml + +hide circle +skinparam classAttributeIconSize 0 + +package storage { + class InputOutputManager + class Decoder + class Encoder + + InputOutputManager ..> Decoder + InputOutputManager ..> Encoder +} + +class Module { + String moduleCode + String title +} +class ModuleManager { + HashMap modulesMap + HashMap nusModsMap +} +ModuleManager *-- "*" Module : Any number of modules +InputOutputManager ...> ModuleManager + +class TimeTable { + HashMap semesterMap +} +class TimeTableManager { + TimeTable timetable +} +TimeTableManager *-- "1" TimeTable : Only one timetable +TimeTable *-- "1..13" LessonManager : One for each week + +class Task { + String name + LocalDateTime deadline + boolean isDone +} +class TaskManager { + ArrayList tasksList +} +TaskManager *-- "*" Task : Any number of tasks +InputOutputManager ..> TaskManager + +class State { + String encodedSavedList + String encodedSavedMap +} +class StateManager { + Stack undoStack + Stack redoStack +} +StateManager *-down- "*" State : Stores a stack + +class Lesson { + String moduleCode + String description + LessonType lessonType + DayOfWeek day + LocalTime startTime + LocalTime endTime +} +class LessonManager { + HashMap> lessonMap +} +interface "<> \n LessonFilter" +enum "<> \n LessonType" { + TUTORIAL, + LECTURE, + SEMINAR, + LAB, + RECITATION, + SESSION +} +LessonManager *-- "*" Lesson : Any number of\nlessons in a week +LessonManager ..> "<> \n LessonType" +LessonManager ..> "<> \n LessonFilter" : used, not\nimplemented +InputOutputManager ..> TimeTableManager + + +@enduml \ No newline at end of file diff --git a/docs/diagrams/UML/DataSequenceDiagram.puml b/docs/diagrams/UML/DataSequenceDiagram.puml new file mode 100644 index 0000000000..861ea6325d --- /dev/null +++ b/docs/diagrams/UML/DataSequenceDiagram.puml @@ -0,0 +1,38 @@ +@startuml + +participant ":InputOutputManager" as IO << Class >> +participant ":java.io.File" as File << Class >> + +-> IO ++ : tryLoadX() +note right : tryLoadMods(),\ntryLoadTasks(),\ntryLoadTimetable() +||| +opt if save folder does not exist + IO -> File ++ : Make folder + ||| + IO <-- File -- + + IO -> IO ++ : tryLoadNusMods() + IO <-- IO -- : Status code + + ||| +else if save folder exists + IO -> IO ++ : tryLoadMods() + ref over IO : Try to load data + IO <-- IO -- : Status code + ||| + IO -> IO ++ : tryLoadTasks() + ref over IO : Try to load data + IO <-- IO -- : Status code + ||| + IO -> IO ++ : tryLoadTimetable() + ref over IO : Try to load data + IO <-- IO -- : Status code + ||| + IO -> IO ++ : tryLoadNusMods() + ref over IO : Try to load NUSMods data + IO <-- IO -- : Status code +end opt +<-- IO -- : Return status code + + +@enduml \ No newline at end of file diff --git a/docs/diagrams/UML/DataSequenceDiagramDataSd.puml b/docs/diagrams/UML/DataSequenceDiagramDataSd.puml new file mode 100644 index 0000000000..1c64245974 --- /dev/null +++ b/docs/diagrams/UML/DataSequenceDiagramDataSd.puml @@ -0,0 +1,42 @@ +@startuml +mainframe sd Try to load data + +participant ":InputOutputManager" as IO << Class >> +participant ":java.io.File" as File << Class >> +participant ":Decoder" as Dec << Class >> +participant ":Manager" as Man << Class >> + +-> IO ++ : tryLoad() +||| +group try + IO -> File ++ : Check file exists + IO <-- File -- : Boolean: file exists + ||| + alt if file exists + ||| + IO -> IO ++ : Enter if block + IO -> File ++ : Read file + IO <-- File -- : File contents as string + IO -> Dec ++ : Decode file string + IO <-- Dec -- : Instances of X + IO -> Man ++ : Save X objects into xManager + IO <-- Man -- + IO <-- IO -- : 'Success' status code + ||| + else if file doesn't exist + ||| + IO -> IO ++ : Enter else block + IO <-- IO -- : 'Skipped' status code + ||| + end alt + ||| +else catch if file is corrupted + ||| + IO -> IO ++ : Enter catch block + IO -> File ++ : Rename the file + IO <-- File -- + IO <-- IO -- : 'Corrupted' status code + ||| +end group +<-- IO -- : Return status code +@enduml \ No newline at end of file diff --git a/docs/diagrams/UML/DataSequenceDiagramNusModsSd.puml b/docs/diagrams/UML/DataSequenceDiagramNusModsSd.puml new file mode 100644 index 0000000000..8834cee829 --- /dev/null +++ b/docs/diagrams/UML/DataSequenceDiagramNusModsSd.puml @@ -0,0 +1,40 @@ +@startuml +mainframe sd Try to load NUSMods + +participant ":InputOutputManager" as IO << Class >> +participant ":java.io.File" as File << Class >> +participant ":Decoder" as Dec << Class >> +participant ":ModuleManager" as Man << Class >> + +-> IO ++ : tryLoadNusMods() +||| +group try + ||| + IO -> File ++ : Read file + IO <-- File -- : File contents string + IO -> Dec ++ : Decode contents + IO <-- Dec -- : Module objects (of mods on NUSMods) + IO <-- IO : Update status code: 'Read from data dir' + ||| +else catch couldn't load from data directory + group try + IO -> Dec ++ : Read from NUSMods API and decode + IO <-- Dec -- : Module objects (of mods on NUSMods) + IO <-- IO : Update status code: 'Read from NUSMods API' + ||| + else catch couldn't load from NUSMods API (online) + group try + IO -> Dec ++ : Read from JAR resource file and decode + IO <- Dec -- : Module objects (of mods on NUSMods) + IO <-- IO : Update status code: 'Read from JAR resource file' + ||| + else catch couldn't load from JAR resource file + <-- IO : Throw exception since\nNUSMods could not be loaded.\nThis exception will halt ra.VI + end group + end group +end group +||| +IO -> Man ++ : Save NUSMods into ModuleManager +IO <-- Man -- +<-- IO -- : Return status code +@enduml \ No newline at end of file diff --git a/docs/diagrams/UML/GradeCommandSequenceDiagram.puml b/docs/diagrams/UML/GradeCommandSequenceDiagram.puml new file mode 100644 index 0000000000..3a067e515a --- /dev/null +++ b/docs/diagrams/UML/GradeCommandSequenceDiagram.puml @@ -0,0 +1,29 @@ +@startuml + +-> ":GradeCommandParser" ++: prepareGradeCommand() + ":GradeCommandParser" -> ":GradeCommand" ** : <> GradeCommand(module,moduleCredit,grade) + activate ":GradeCommand" + return GradeCommand +<-- ":GradeCommandParser" !! : GradeCommand + +-> ":GradeCommand" ++ : execute() + participant ":ModuleManager" as MM << Class >> + ":GradeCommand" -> MM ++ : getModule() + ":GradeCommand" <-- MM -- :moduleToBeGraded + ||| + ":GradeCommand" -> ":GradeCommand" ++ : grade(moduleToBeGraded) + alt testGrade(grade) + ":GradeCommand" -> MM ++ : grade(module,grade,moduleCredit) + ||| + ":GradeCommand" <-- MM -- + else + <-- ":GradeCommand" : InvalidGradeException() + end + ":GradeCommand" <-- ":GradeCommand" -- + + ":GradeCommand" -> ":CommandResult" ** : <> + activate ":CommandResult" + ":GradeCommand" <-- ":CommandResult" --: CommandResult +<-- ":GradeCommand" !! : CommandResult + +@enduml \ No newline at end of file diff --git a/docs/diagrams/UML/ListCommandSequenceDiagram.puml b/docs/diagrams/UML/ListCommandSequenceDiagram.puml new file mode 100644 index 0000000000..158ae37b99 --- /dev/null +++ b/docs/diagrams/UML/ListCommandSequenceDiagram.puml @@ -0,0 +1,57 @@ +@startuml +-> ":ListCommandParser": getListCommand() +activate ":ListCommandParser" +alt MODULE_PREFIX + create ":ListCommand" + ":ListCommandParser" -> ":ListCommand": ListCommand(1) + activate ":ListCommand" + ":ListCommandParser" <-- ":ListCommand": + deactivate ":ListCommand" +else TASK_PREFIX + create ":ListCommand" + ":ListCommandParser" -> ":ListCommand": ListCommand(0) + activate ":ListCommand" + ":ListCommandParser" <-- ":ListCommand": + deactivate ":ListCommand" +else else + create ":InvalidParameterException" + ":ListCommandParser" -> ":InvalidParameterException": InvalidParameterException() + activate ":InvalidParameterException" + ":ListCommandParser" <-- ":InvalidParameterException" + deactivate ":InvalidParameterException" +end +<-- ":ListCommandParser": ListCommand +destroy ":ListCommandParser" + +-> ":ListCommand": execute() +activate ":ListCommand" + alt TASK + create ":TaskManager" + ":ListCommand" -> ":TaskManager": list() + activate ":TaskManager" + ":ListCommand" <-- ":TaskManager": output + deactivate ":TaskManager" + else MODULE + create ":ModuleManager" + ":ListCommand" -> ":ModuleManager": list() + activate ":ModuleManager" + ":ListCommand" <-- ":ModuleManager": output + deactivate ":ModuleManager" + end + + alt output null + create ":CommandResult" + ":ListCommand" -> ":CommandResult": CommandResult(MESSAGE_LIST_EMPTY) + activate ":CommandResult" + ":ListCommand" <-- ":CommandResult": CommandResult + deactivate ":CommandResult" + else else + create ":CommandResult" + ":ListCommand" -> ":CommandResult": CommandResult(MESSAGE_LIST_PRINTED + output) + activate ":CommandResult" + ":ListCommand" <-- ":CommandResult": CommandResult + deactivate ":CommandResult" + end +<-- ":ListCommand": CommandResult +destroy ":ListCommand" +@enduml \ No newline at end of file diff --git a/docs/diagrams/UML/MainClassDiagram.puml b/docs/diagrams/UML/MainClassDiagram.puml new file mode 100644 index 0000000000..bb550c2276 --- /dev/null +++ b/docs/diagrams/UML/MainClassDiagram.puml @@ -0,0 +1,39 @@ +@startuml + +hide circle +skinparam classAttributeIconSize 0 + +class Executor +class Scanner + +package parser { + class Parser +} + +package command { + class Command + class CommandResult +} + +package data { + class InputOutputManager + class StateManager +} + +package ui { + class TextUi { + Scanner in + } +} + +Ravi ..> ui +Ravi ..> Executor + +Executor ...> data +Executor ..> command +Executor .> parser +parser ...> command + +TextUi "1" *-- Scanner + +@enduml \ No newline at end of file diff --git a/docs/diagrams/UML/MainSequenceDiagram.puml b/docs/diagrams/UML/MainSequenceDiagram.puml new file mode 100644 index 0000000000..dc11f92b60 --- /dev/null +++ b/docs/diagrams/UML/MainSequenceDiagram.puml @@ -0,0 +1,42 @@ +@startuml + +participant ":Ravi" as Ravi << Class >> +participant ":Executor" as Ex << Class >> + +create Ravi +activate Ravi +-> Ravi: main() +Ravi -> Ravi ++ : Add shutdown hook +return +||| +Ravi -> Ravi ++ : run() + ||| + Ravi -> Ex ++ : Initialise Executor + ref over Ex: initialise() + Ravi <-- Ex -- + opt Could not load NUSMods + ||| + <- Ravi : Terminate program here + end opt + ||| + Ravi -> Ex ++ : Start command loop + ref over Ex: startCommandLoop() + Ravi <-- Ex -- + ||| +return + +<- Ravi -- : exit main() + +-> Ravi ++ : Shutdown hook +Ravi -> Ravi ++ : Print "saving" message +note right + Saving is actually done in Executor. + This is just to assure the user that + ra.VI has shut down properly (if they + used Ctrl-C to shut down ra.VI) +end note +return +return Completed shutdown +destroy Ravi + +@enduml \ No newline at end of file diff --git a/docs/diagrams/UML/MainSequenceDiagramLoopSd.puml b/docs/diagrams/UML/MainSequenceDiagramLoopSd.puml new file mode 100644 index 0000000000..8937f1b560 --- /dev/null +++ b/docs/diagrams/UML/MainSequenceDiagramLoopSd.puml @@ -0,0 +1,49 @@ +@startuml +mainframe sd startCommandLoop() + +participant ":Executor" as Ex << Class >> +participant ":TextUi" as Ui << Class >> +participant ":Parser" as P << Class >> +participant ":InputOutputManager" as IO << Class >> +participant ":StateManager" as State << Class >> + +-> Ex ++ : startCommandLoop() + +loop do while Exit command not received + + Ex -> Ui ++ : Get user input + ||| + return User input string + + Ex -> Ex ++ : executeCommand() + Ex -> P ++ : Parse user input + P -> ":Command" ** : Construct relevant\nCommand + activate ":Command" + ":Command" -> ":CommandResult" ** : Construct\nCommandResult + activate ":CommandResult" + return CommandResult object + return Command object + return Command object + + Ex -> ":Command" ++ : Execute Command + return CommandResult object + destroy ":Command" + ||| + + opt If user made changes to data + Ex -> IO ++ : Save data + return + + Ex -> State ++ : Save state + return + end opt + return CommandResult object + + Ex -> Ui ++ : Show CommandResult to user + ||| + return + +end loop +return + +@enduml \ No newline at end of file diff --git a/docs/diagrams/UML/MainSequenceDiagramStartSd.puml b/docs/diagrams/UML/MainSequenceDiagramStartSd.puml new file mode 100644 index 0000000000..4cb93297dd --- /dev/null +++ b/docs/diagrams/UML/MainSequenceDiagramStartSd.puml @@ -0,0 +1,37 @@ +@startuml +mainframe sd start() + +participant ":Ravi" as Ravi << Class >> +participant ":TextUi" as Ui << Class >> +participant ":InputOutputManager" as IO << Class >> +participant ":StateManager" as State << Class >> +participant ":TimeTableManager" as TT << Class >> + +-> Ravi ++ : start() + +Ravi -> Ui ++ : Initializes Scanner +||| +return + +Ravi -> IO ++ : Initialization +||| +return Returns loading status + +Ravi -> State ++ : Initialization +||| +return + +Ravi -> Ui ++ : Show welcome message\nwith loading status +||| +return + +loop while TimeTableManager not initialised + Ravi -> TT ++ : Initialization + TT -> Ui ++ : Try to get week number from user + return + return +end loop + +return + +@enduml \ No newline at end of file diff --git a/docs/diagrams/UML/NotesClassDiagram.puml b/docs/diagrams/UML/NotesClassDiagram.puml new file mode 100644 index 0000000000..3dd81a4c77 --- /dev/null +++ b/docs/diagrams/UML/NotesClassDiagram.puml @@ -0,0 +1,78 @@ +@startuml + +hide circle +skinparam classAttributeIconSize 0 + +class NotesAddCommand +class NotesDeleteCommand +class NotesListCommand +class NotesViewCommand +class NotesManager +class Note + +class "NotesCommandParser" { + + {static} parseNotesCommand() + - {static} parseNotesAddCommand() + - {static} parseNotesDeleteCommand() + - {static} parseNotesViewCommand() + - {static} parseNotesListCommand() +} + +class NotesManager { + notes: ArrayList + + addNote() + + listNote() + + deleteNote() + + viewNote() +} + +class Note { + - note: String +} + +abstract class "{abstract} \n Command " { + + execute() +} + +abstract class "{abstract} \n NotesCommand " { + + execute() +} + +class IncorrectCommand { + + execute() +} + +class NotesAddCommand { + + execute() +} + +class NotesDeleteCommand { + + execute() +} + +class NotesListCommand { + + execute() +} + +class NotesViewCommand { + + execute() +} + +Note --* "*" NotesManager +NotesManager <.. "{abstract} \n NotesCommand " + +"{abstract} \n NotesCommand " --|> "{abstract} \n Command " +IncorrectCommand --|> "{abstract} \n Command " + +"{abstract} \n NotesCommand " <|-- NotesListCommand + NotesDeleteCommand --|> "{abstract} \n NotesCommand " +"{abstract} \n NotesCommand " <|-- NotesViewCommand +NotesAddCommand --|> "{abstract} \n NotesCommand " + + + +NotesCommandParser ..> IncorrectCommand +NotesCommandParser ..> "{abstract} \n NotesCommand " + + +@enduml \ No newline at end of file diff --git a/docs/diagrams/UML/ParserClassDiagram.puml b/docs/diagrams/UML/ParserClassDiagram.puml new file mode 100644 index 0000000000..8ac7a71e7a --- /dev/null +++ b/docs/diagrams/UML/ParserClassDiagram.puml @@ -0,0 +1,33 @@ +@startuml + +hide circle +skinparam classAttributeIconSize 0 + +abstract class "{abstract} \n Command" +package parser { + class Parser + class AddCommandParser + class DeleteCommandParser + class DoneCommandParser + class EditCommandParser + class ListCommandParser + class CapCommandParser + class GradeCommandParser + class HelpCommandParser + class LessonParser + class TimeTableCommandParser +} +parser .left.> "{abstract} \n Command" : All Parser classes\ngenerate Command objects + +Parser .left.> AddCommandParser : All Parser "subclasses" do not\ninherit from Parser +Parser .right.> HelpCommandParser +Parser ..> DeleteCommandParser +Parser ...> DoneCommandParser +Parser ....> EditCommandParser +Parser ...> ListCommandParser +Parser ..> CapCommandParser +Parser ....> GradeCommandParser +Parser ...> LessonParser +Parser ....> TimeTableCommandParser + +@enduml \ No newline at end of file diff --git a/docs/diagrams/UML/TimeTableClassDiagram.puml b/docs/diagrams/UML/TimeTableClassDiagram.puml new file mode 100644 index 0000000000..c1f467c3f8 --- /dev/null +++ b/docs/diagrams/UML/TimeTableClassDiagram.puml @@ -0,0 +1,87 @@ +@startuml + +hide circle +skinparam classAttributeIconSize 0 + +class TimeTableAddCommand +class TimeTableDeleteCommand +class TimeTableViewCommand +class Lesson { + - moduleCode: String + - lessonType: LessonType + - day: DayOfWeek + - startTime: LocalTime + - endTime: LocalTime + - hiddenId: String +} + +class "TimeTableCommandParser" { + + {static} parseTimeTableCommand() + - {static} parseTimeTableAddCommand() + - {static} parseTimeTableDeleteCommand() + - {static} parseTimeTableViewCommand() +} + +abstract class "{abstract} \n TimeTableCommand" { + + execute() +} + +abstract class "{abstract} \n Command" { + + execute() +} + +class TimeTable { +} + +class TimeTableAddCommand { + + execute() +} + +class TimeTableViewCommand { + + execute() +} + +class TimeTableDeleteCommand { + + execute() +} + +class TimeTableResetCommand { + + execute() +} + +class IncorrectCommand { + + execute() +} + +class LessonManager { + + addLesson() + + deleteLessonById() + + getDayLessonList(): ArrayList +} + +class TimeTableManager { + + {static} initialise() + + {static} addLesson() + + {static} deleteLesson() + + {static} getSpecificDayLessons(): ArrayList + + {static} getSpecifiedWeekLessons(): ArrayList> +} + +"{abstract} \n TimeTableCommand" --|> "{abstract} \n Command" +IncorrectCommand --|> "{abstract} \n Command" + +"TimeTableCommandParser" ..> "{abstract} \n TimeTableCommand" +"TimeTableCommandParser" ..> IncorrectCommand + +TimeTableAddCommand -|> "{abstract} \n TimeTableCommand" +"{abstract} \n TimeTableCommand" <|-- TimeTableDeleteCommand +TimeTableViewCommand --|> "{abstract} \n TimeTableCommand" +"{abstract} \n TimeTableCommand" <|-- TimeTableResetCommand + +TimeTableManager *-- "1" TimeTable +TimeTable o-- "1..13" LessonManager +LessonManager o-- "*" Lesson + +TimeTableManager <... "{abstract} \n TimeTableCommand" + +@enduml \ No newline at end of file diff --git a/docs/diagrams/UndoCommandSequenceDiagram.png b/docs/diagrams/UndoCommandSequenceDiagram.png new file mode 100644 index 0000000000..ff5584efa1 Binary files /dev/null and b/docs/diagrams/UndoCommandSequenceDiagram.png differ diff --git a/docs/images/addmodule/1.PNG b/docs/images/addmodule/1.PNG new file mode 100644 index 0000000000..c3ae06d405 Binary files /dev/null and b/docs/images/addmodule/1.PNG differ diff --git a/docs/images/addmodule/2.PNG b/docs/images/addmodule/2.PNG new file mode 100644 index 0000000000..2f764f9f6b Binary files /dev/null and b/docs/images/addmodule/2.PNG differ diff --git a/docs/images/addmodule/3.PNG b/docs/images/addmodule/3.PNG new file mode 100644 index 0000000000..b4f19cd778 Binary files /dev/null and b/docs/images/addmodule/3.PNG differ diff --git a/docs/images/addtask/1.png b/docs/images/addtask/1.png new file mode 100644 index 0000000000..0034839da3 Binary files /dev/null and b/docs/images/addtask/1.png differ diff --git a/docs/images/addtask/2.png b/docs/images/addtask/2.png new file mode 100644 index 0000000000..6357d3c3cb Binary files /dev/null and b/docs/images/addtask/2.png differ diff --git a/docs/images/addtask/3.png b/docs/images/addtask/3.png new file mode 100644 index 0000000000..68e3ded709 Binary files /dev/null and b/docs/images/addtask/3.png differ diff --git a/docs/images/bye/1.png b/docs/images/bye/1.png new file mode 100644 index 0000000000..719fef4aee Binary files /dev/null and b/docs/images/bye/1.png differ diff --git a/docs/images/cap/1.PNG b/docs/images/cap/1.PNG new file mode 100644 index 0000000000..a53ef9cd81 Binary files /dev/null and b/docs/images/cap/1.PNG differ diff --git a/docs/images/deletetask/1.png b/docs/images/deletetask/1.png new file mode 100644 index 0000000000..8d3cfd616f Binary files /dev/null and b/docs/images/deletetask/1.png differ diff --git a/docs/images/deletetask/2.png b/docs/images/deletetask/2.png new file mode 100644 index 0000000000..8d12a050c8 Binary files /dev/null and b/docs/images/deletetask/2.png differ diff --git a/docs/images/delmodule/1.PNG b/docs/images/delmodule/1.PNG new file mode 100644 index 0000000000..43ae01c132 Binary files /dev/null and b/docs/images/delmodule/1.PNG differ diff --git a/docs/images/delmodule/2.PNG b/docs/images/delmodule/2.PNG new file mode 100644 index 0000000000..13f77c272d Binary files /dev/null and b/docs/images/delmodule/2.PNG differ diff --git a/docs/images/donetask/1.png b/docs/images/donetask/1.png new file mode 100644 index 0000000000..f8771da2fd Binary files /dev/null and b/docs/images/donetask/1.png differ diff --git a/docs/images/donetask/2.png b/docs/images/donetask/2.png new file mode 100644 index 0000000000..a3be2b450d Binary files /dev/null and b/docs/images/donetask/2.png differ diff --git a/docs/images/editmodule/1.png b/docs/images/editmodule/1.png new file mode 100644 index 0000000000..d795dab2da Binary files /dev/null and b/docs/images/editmodule/1.png differ diff --git a/docs/images/editmodule/2.PNG b/docs/images/editmodule/2.PNG new file mode 100644 index 0000000000..85a8e64578 Binary files /dev/null and b/docs/images/editmodule/2.PNG differ diff --git a/docs/images/edittask/1.png b/docs/images/edittask/1.png new file mode 100644 index 0000000000..c0817a7274 Binary files /dev/null and b/docs/images/edittask/1.png differ diff --git a/docs/images/edittask/2.png b/docs/images/edittask/2.png new file mode 100644 index 0000000000..1dde0cede1 Binary files /dev/null and b/docs/images/edittask/2.png differ diff --git a/docs/images/grademodule/1.PNG b/docs/images/grademodule/1.PNG new file mode 100644 index 0000000000..136448d44a Binary files /dev/null and b/docs/images/grademodule/1.PNG differ diff --git a/docs/images/grademodule/2.PNG b/docs/images/grademodule/2.PNG new file mode 100644 index 0000000000..36c04b3f1d Binary files /dev/null and b/docs/images/grademodule/2.PNG differ diff --git a/docs/images/interface/1.png b/docs/images/interface/1.png new file mode 100644 index 0000000000..23eb64625f Binary files /dev/null and b/docs/images/interface/1.png differ diff --git a/docs/images/interface/2.png b/docs/images/interface/2.png new file mode 100644 index 0000000000..7cadc752cd Binary files /dev/null and b/docs/images/interface/2.png differ diff --git a/docs/images/interface/3.png b/docs/images/interface/3.png new file mode 100644 index 0000000000..4701cbb55b Binary files /dev/null and b/docs/images/interface/3.png differ diff --git a/docs/images/listmodule/1.PNG b/docs/images/listmodule/1.PNG new file mode 100644 index 0000000000..a6a5687a09 Binary files /dev/null and b/docs/images/listmodule/1.PNG differ diff --git a/docs/images/listtask/1.png b/docs/images/listtask/1.png new file mode 100644 index 0000000000..f8ac59c09a Binary files /dev/null and b/docs/images/listtask/1.png differ diff --git a/docs/images/quickstart/1.png b/docs/images/quickstart/1.png new file mode 100644 index 0000000000..460c942ec9 Binary files /dev/null and b/docs/images/quickstart/1.png differ diff --git a/docs/images/quickstart/2.png b/docs/images/quickstart/2.png new file mode 100644 index 0000000000..63b6236a0a Binary files /dev/null and b/docs/images/quickstart/2.png differ diff --git a/docs/images/quickstart/3.png b/docs/images/quickstart/3.png new file mode 100644 index 0000000000..32628453a0 Binary files /dev/null and b/docs/images/quickstart/3.png differ diff --git a/docs/images/quickstart/4.png b/docs/images/quickstart/4.png new file mode 100644 index 0000000000..fbd6826e01 Binary files /dev/null and b/docs/images/quickstart/4.png differ diff --git a/docs/images/ravi.jpeg b/docs/images/ravi.jpeg new file mode 100644 index 0000000000..008d1b3c17 Binary files /dev/null and b/docs/images/ravi.jpeg differ diff --git a/docs/images/summary/1.png b/docs/images/summary/1.png new file mode 100644 index 0000000000..2881cbf296 Binary files /dev/null and b/docs/images/summary/1.png differ diff --git a/docs/images/timetableadd/1.png b/docs/images/timetableadd/1.png new file mode 100644 index 0000000000..117214f9bb Binary files /dev/null and b/docs/images/timetableadd/1.png differ diff --git a/docs/images/timetableadd/2.png b/docs/images/timetableadd/2.png new file mode 100644 index 0000000000..aa1f06068b Binary files /dev/null and b/docs/images/timetableadd/2.png differ diff --git a/docs/images/timetableadd/3.png b/docs/images/timetableadd/3.png new file mode 100644 index 0000000000..5c5361f64a Binary files /dev/null and b/docs/images/timetableadd/3.png differ diff --git a/docs/images/timetableadd/4.png b/docs/images/timetableadd/4.png new file mode 100644 index 0000000000..fdaa81bbce Binary files /dev/null and b/docs/images/timetableadd/4.png differ diff --git a/docs/images/timetableday/1.JPG b/docs/images/timetableday/1.JPG new file mode 100644 index 0000000000..627b6b20e9 Binary files /dev/null and b/docs/images/timetableday/1.JPG differ diff --git a/docs/images/timetabledel/1.PNG b/docs/images/timetabledel/1.PNG new file mode 100644 index 0000000000..3e3ee8e65b Binary files /dev/null and b/docs/images/timetabledel/1.PNG differ diff --git a/docs/images/timetabledel/2.PNG b/docs/images/timetabledel/2.PNG new file mode 100644 index 0000000000..4ebdf0b97c Binary files /dev/null and b/docs/images/timetabledel/2.PNG differ diff --git a/docs/images/timetablefilter/1.png b/docs/images/timetablefilter/1.png new file mode 100644 index 0000000000..2b6fd45dd4 Binary files /dev/null and b/docs/images/timetablefilter/1.png differ diff --git a/docs/images/timetablefilter/2.png b/docs/images/timetablefilter/2.png new file mode 100644 index 0000000000..87eeacc119 Binary files /dev/null and b/docs/images/timetablefilter/2.png differ diff --git a/docs/images/timetablefilter/3.png b/docs/images/timetablefilter/3.png new file mode 100644 index 0000000000..896d6f57ee Binary files /dev/null and b/docs/images/timetablefilter/3.png differ diff --git a/docs/images/timetablefilter/4.png b/docs/images/timetablefilter/4.png new file mode 100644 index 0000000000..d8de3dbd01 Binary files /dev/null and b/docs/images/timetablefilter/4.png differ diff --git a/docs/images/timetablefilter/5.png b/docs/images/timetablefilter/5.png new file mode 100644 index 0000000000..169ef0e8a1 Binary files /dev/null and b/docs/images/timetablefilter/5.png differ diff --git a/docs/images/timetablereset/1.JPG b/docs/images/timetablereset/1.JPG new file mode 100644 index 0000000000..1b356d9888 Binary files /dev/null and b/docs/images/timetablereset/1.JPG differ diff --git a/docs/images/timetableweek/1.PNG b/docs/images/timetableweek/1.PNG new file mode 100644 index 0000000000..f78513754d Binary files /dev/null and b/docs/images/timetableweek/1.PNG differ diff --git a/docs/images/undo/1.png b/docs/images/undo/1.png new file mode 100644 index 0000000000..9f15f88283 Binary files /dev/null and b/docs/images/undo/1.png differ diff --git a/docs/images/undo/2.png b/docs/images/undo/2.png new file mode 100644 index 0000000000..11a3ffb544 Binary files /dev/null and b/docs/images/undo/2.png differ diff --git a/docs/team/amalinasani.md b/docs/team/amalinasani.md new file mode 100644 index 0000000000..a8b2845faa --- /dev/null +++ b/docs/team/amalinasani.md @@ -0,0 +1,59 @@ +# Amalina Sani's Project Portfolio Page +## CS2113T Project: ra.VI +Repository assistant with a Versatile Interface (ra.VI) is a desktop app for managing tasks, deadlines, and timetables, optimized for use via a Command Line Interface (CLI). +Ra.VI aims to help freshmen ease into and adapt to their new university schedules. + +### Summary of Contributions +#### Features +* **Done Feature**: Added the ability to mark a task as done in ra.VI. ([\#38](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/38)) + * What it does: Allows the user to mark a task in the task list as done. + * Justification: This feature is integral to the product so that the user can update the completion status of tasks. + * Highlights: This enhancement ties in with the `summary` command, in which the tasks will be listed according to completion status. + +* **List Feature**: Added the ability to list all added tasks and modules in ra.VI. ([\#38](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/38)) + * What it does: Allows the user to view the list of tasks or modules. + * Justification: This feature is integral to the product so that the user can view all the tasks and modules that has been added at a quick glance. + * Highlights: This enhancement affects existing commands as the task index from `list` is required as a parameter for `done` and `edit` commands. + +* **Help Feature**: Added the ability to view the list of all available commands, and help messages for each command. ([\#39](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/39), [\#107](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/107)) + * What it does: A general help message allows the user to view the list of all available commands and its functions. + Detailed help messages for each command allows the user to view the command's format and example usage. A prompt to use `help` is also shown to the user when the user inputs an incorrect command. + * Justification: This feature is important in providing seamless assistance for the usage of ra.VI. It assists the user in navigating all the features and commands of the application. + * Highlights: The implementation of this feature was challenging as a unique help message had to be integrated into each existing command. + +* **Summary Feature**: Added the ability to view a task summary in collaboration with [Jun You](https://github.com/AY2021S1-CS2113T-T09-2/tp/tree/master/docs/team/f0fz.md). ([\#93](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/93)) + * What it does: Allows the user to view a task summary, categorising tasks into "Incomplete tasks with deadlines", "Incomplete tasks without deadlines", and "Completed tasks". + * Justification: This feature is important in providing the user with a brief, categorised list of tasks for quick viewing. + +* **View Timetable Feature**: Added the ability to view the timetable for the day or week in collaboration with [Sean Lim](https://github.com/AY2021S1-CS2113T-T09-2/tp/tree/master/docs/team/aseanseen.md). ([\#120](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/120)) + * What it does: Allows the user to view the timetable, listing all lessons and lesson times for the day or week. + * Justification: This feature is important in providing the user with a brief, day-to-day timetable of lessons for quick viewing. + +* **Reset Timetable Feature**: Added the ability to reset the timetable. ([\#230](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/230)) + * What it does: Allows the user to clear and reinitisialise the timetable. + * Justification: This feature is necessary for the user to populate the timetable with new lessons in preparation for a new semester. + +#### Code contributed [RepoSense link](https://nus-cs2113-ay2021s1.github.io/tp-dashboard/#breakdown=true&search=amalinasani&sort=groupTitle&sortWithin=title&since=2020-09-27&timeframe=commit&mergegroup=&groupSelect=groupByRepos&checkedFileTypes=docs~functional-code~test-code~other) + +#### Documentation + * User Guide: + * Added documentation for the features `help`, `add`, `edit`, `del`, `list`, `done`, `bye` [\#106](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/106) + * Added a command summary table [\#132](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/132) + * Added documentation for the features `timetable -reset` [\#240](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/240) + + * Developer Guide: + * Added instructions for manual testing. [\#128](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/128) + * Added implementation details and sequence diagram for the `list` feature. [\#133](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/133) + * Added documentation for `timetable -reset` [\#240](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/240) + * Added user stories for existing features and manual testing steps for `list`, `help`, and `summary` commands. [\#251](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/251) + * Added implementation details and class diagram for the proposed `notes` feature [\#257](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/257) + +#### Project management +* Added and managed issues for milestones v1.0, v2.0, v2.1. + +#### Enhancements to existing features + * Wrote additional tests for `help`,`done`,`list` commands to increase coverage. ([\#79](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/79), [\#252](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/252)) + * Solve issues surfaced from bug bounty. ([\#233](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/233)) + +#### Community + * Reported bugs and suggestions for other teams in the class (Examples: [1](https://github.com/AY2021S1-CS2113T-T12-2/tp/issues/226), [2](https://github.com/AY2021S1-CS2113T-T12-2/tp/issues/225), [3](https://github.com/AY2021S1-CS2113T-T12-2/tp/issues/224), [4](https://github.com/nus-cs2113-AY2021S1/tp/pull/36/files/8b45df880852c7cd42988080fb263f72f22a6328)) diff --git a/docs/team/aseanseen.md b/docs/team/aseanseen.md new file mode 100644 index 0000000000..f5ad30de74 --- /dev/null +++ b/docs/team/aseanseen.md @@ -0,0 +1,37 @@ +### Sean Lim Zhi Xiang - Project Portfolio Page +#### CS2113T Project: ra.VI +Repository Assistant with a Versatile Interface (ra.VI) is a desktop app for NUS freshmen, helping them manage tasks, deadlines, and their timetable. It is optimized for use via a Command Line Interface (CLI). +#### My contributions +#### Features implemented: +* **New Feature**: Added the timetable feature [#101](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/101) [#118](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/118) + * What it does: Allows the user to manage their lessons in their timetable. This includes adding, deleting, viewing and filtering. + * Highlights: This feature was challenging due to the Time element. Therefore, we had to be very careful during our implementation, creating a robust data structure to handle the timetable. + * In-depth contribution: + * Implemented the parsing of the timetable commands. + * Implemented the `TimeTableManager` to handle the lessons from the timetable. + * Implemented the commands to add and delete lessons from the timetable. + * Credits: [Jun You](https://ay2021s1-cs2113t-t09-2.github.io/tp/team/f0fz.html) +* **New Feature**: Added add/delete tasks and modules feature [#17](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/17) [#35](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/35) [#54](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/54) + * What it does: Allows the user to manage their tasks and modules. This includes adding, deleting and handling of deadlines. + * Credits: Implemented with adaptations from my [iP](https://github.com/Aseanseen/ip) +* **New Feature**: Added main class and exit command [#40](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/40) [#53](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/53) + * Credits: Implemented with adaptations from my [iP](https://github.com/Aseanseen/ip) and [AddressBook (Level 2)](https://se-education.org/addressbook-level2/). +* **Code contributed**: [RepoSense Link](https://nus-cs2113-ay2021s1.github.io/tp-dashboard/#breakdown=true&search=aseanseen) +* **Enhancements**: + * After a successful undo command, show the user the command that was undone. [#241](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/241) + +#### Contributions to team-based tasks +* **Project Management**: + * Managed releases `v1.0` - `v2.1` (3 releases) on Github +* **Documentation**: + * Developer Guide: + * Added documentation for the `timetable`, `add`, `delete` features. [#96](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/96) [#97](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/97) [#122](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/122) [#136](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/136) + * Added class diagrams for `Command`, `TimeTable`. [#122](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/122) [#127](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/127) [#136](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/136) [#244](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/244) + * Added sequence diagram for `AddCommand`. [#110](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/110) + * User Guide: + * Added documentation for the Introduction. [#116](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/116) [#235](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/235) + * Added documentation for the FAQ. [#235](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/235) + * Added documentation for the `timetable` feature. [#116](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/116) +* **Review / mentoring contributions**: + * PRs reviewed (with non-trivial review comments): [#242](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/242) [#29](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/29) [#106](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/106) [#44](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/44) [#226](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/226) [#238](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/238) + * Reported bugs and suggestions for other teams' tp (examples: [1](https://github.com/Aseanseen/ped/issues), [2](https://github.com/AY2021S1-CS2113T-T09-4/tp/issues/282), [3](https://github.com/AY2021S1-CS2113T-T09-4/tp/issues/289), [4](https://github.com/AY2021S1-CS2113T-T09-4/tp/issues/288)) \ No newline at end of file diff --git a/docs/team/f0fz.md b/docs/team/f0fz.md new file mode 100644 index 0000000000..83b47e2093 --- /dev/null +++ b/docs/team/f0fz.md @@ -0,0 +1,66 @@ +# Sim Jun You - Project Portfolio Page + +## Overview + +Repository Assistant with a Versatile Interface (ra.VI) is a desktop app for managing tasks, deadlines, and timetable, +optimized for use via a Command Line Interface (CLI). It is written in Java and is built to run on Java 11 on Linux, Mac +and Windows machines. + +### Summary of Contributions +#### Code contributed + +[RepoSense link here.](https://nus-cs2113-ay2021s1.github.io/tp-dashboard/#breakdown=true&search=f0fz) + +#### Features implemented + +* Built the entire `data` package, excluding State and StateManager. + * Built the user-based data classes such as `Lesson`, `Module`, `Task`, and their respective "Managers". Also, + maintained and made tests for them to ensure reliability. + * Created a modular system where each atomic data item (like `Lesson`, `Task`, etc.) are stored in progressively + larger "Managers" (`LessonManager`, etc.) which can be held in even larger "Managers" + (i.e. `TimeTableManager` > `TimeTable` > `LessonManager` > `Lesson`). +* Built the entire `storage` package that allows ra.VI to save and load. Integrated `InputOutputManager` +into the main codebase for seamless saving and loading when ra.VI starts/exits. + * Created a granular and robust system for saving and loading, with multiple fallbacks and comprehensive error + handling. + * Maintained the package, and was in charge of fixing all bugs for saving and loading. + * Was not the one who first implemented FastJSON usage, but took over its implementation and maintenance. Also, + did not write the HTTP functions that call the NUSMods API. +* Implemented the logging feature, which improved our ability to debug ra.VI during the development process. + +#### Enhancements + +* Assisted in resolving bugs and adding functionality to many other areas, like the various Commands and Parser classes +as well as the main class. Some examples: + * Made adding, editing, and deleting tasks/modules/lessons show the results of the change. + * Reduced dependencies in the main class by packaging all dependencies needed to execute a command into the + `Executor` class, following the Single Responsibility Principle. + * Added the shutdown hook to catch unexpected shutdowns. + * Improved the `CommandResult` class to make it more useful and output-friendly. + * Worked heavily on the `TextUi` class to improve formatting and created the helper class `TextHelper` to decrease + bloat and to follow the Single Responsibility Principle. +* Polished the user interface formatting as well as each message to make it cleaner and easier to read. + +#### Contributions to documentation + +* DG: + * Wrote the following sections: Setting Up, Value Proposition, Implementation. + * Added class diagrams for the Main Class, and the Command/Data/Parser/TimeTable Family Classes. + * Added sequence diagram for the main loop. + +* UG: + * Polished and proofread some sections of the UG. + +#### Contributions to team-based tasks + +* Did general code enhancements (cleanups, refactoring). +* Introduced the use of PlantUML for our UML diagrams. +* Documented non-feature-specific portions in our DG. + +#### Review/mentoring contributions + +* PRs reviewed (with non-trivial review comments): #13 #17 #44 #57 #76 #106 #107 #231 #235 #243 + +#### Contributions beyond the project team + +* Reviewed and gave [detailed issues](https://github.com/f0fz/ped/issues) for other teams' projects \ No newline at end of file diff --git a/docs/team/johndoe.md b/docs/team/johndoe.md deleted file mode 100644 index ab75b391b8..0000000000 --- a/docs/team/johndoe.md +++ /dev/null @@ -1,6 +0,0 @@ -# John Doe - Project Portfolio Page - -## Overview - - -### Summary of Contributions diff --git a/docs/team/tobiasceg.md b/docs/team/tobiasceg.md new file mode 100644 index 0000000000..840854a516 --- /dev/null +++ b/docs/team/tobiasceg.md @@ -0,0 +1,58 @@ +# Tan Jian Hui Tobias - Project Portfolio Page + +# CS2113T Project: ra.VI + +The Repository Assistant with a Versatile Interface is a user-friendly desktop application for managing task,deadline +,modules and planning of timetable via a Command Line Interface (CLI). ra.VI aims to help freshmen of Universities to +better integrate and manage their hectic schedule. + +## Overview of my contributions to the project. + +### Features implemented: + * Added and Managed the parser commands (excluding timetable parser). + * What it does: Parses the user's input using java REGEX to parse and filter specific words and phrases, calling the + relevant constructors to ensure that the subsequent command executes with the appropriate arguments. + * Justification: There is a specific parser command for each respective command in ra.VI , each and every parser has + its very own specialised REGEX format as the different commands require their own specific variables to execute and achieve + the desired results + * Highlights: This filter affects almost every command in ra.VI as the user's raw input has to be parsed to ensure that + the relevant desired inputs by the user are captured by the program and executed correctly. Most important and general + exceptions are caught and filtered by the parser class. + * Credits: Special thanks to teammates, [Sean Lim](https://github.com/AY2021S1-CS2113T-T09-2/tp/tree/master/docs/team/aseanseen.md) and [Jun You](https://github.com/AY2021S1-CS2113T-T09-2/tp/tree/master/docs/team/f0fz.md) for the assistance in debugging and correcting the REGEX used, as + it is a relatively new and unknown area of java to tackle, thus a lot of problems and bugs were found making parser successful. + + * Added and Managed the grade and cap command. + * What it does: Allows the user to grade modules that have been previously input and keyed into their personalised module list, + thus allowing them to assign its module credits and the grade achieved by the user on the module. Subsequently, the user is able + to calculate their new Cumulative Average Point (CAP) after grading all their respective modules. + * Justification: This enhancement improves the product in a way that allows users to not only keep track of the modules taken, but + also add the relevant details such as the module credit and grade attained for that specific module. Therefore, allowing the + user to calculate and keep track of their new CAP after the semester has ended. + * Highlights: This enhancement affects and compliments existing commands adding additional attributes of existing modules in + module manager and subsequently consolidating the relevant attributes, to calculate the user's CAP. Multiple grades and scenarios + had to be taken into account to ensure that the CAP calculated was as accurate as possible. + +* **Code Contribution**: [RepoSense Link](https://nus-cs2113-ay2021s1.github.io/tp-dashboard/#breakdown=true&search=tobiasceg) + +* **Project management**: + * Assisted in release `v1.0 - v2.1` (3 releases) on GitHub + +* **Enhancements to existing features**: + * Split Parser to handle individual commands separately (Pull request [\#78](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/78)) + * Added option for `CS/CU` for Cap command (Pull request [\#243](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/243)) + * Wrote additional tests for existing features to increase coverage. (Pull request [\#119](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/119), [\#59](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/59)) + +### Contributions to Documentation: + * **User Guide**: + * Added Documentation for the features `Cap` and `Grade`. (Pull request [\#99](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/99), [\#115](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/115)) + * Solved issues raised after bug bounties (Pull request [\#238](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/238)) + * Added in certain cosmetic tweaks to existing documentation of features and tables (Pull request [\#225](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/225)) + + * **Developer Guide**: + * Added Documentation for the features `Cap` and `Grade` including their respective sequence diagrams. (Pull request [\#99](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/99)), [\#112](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/112)) + * Enhancement in certain cosmetic areas to existing documentation of features and tables (Pull request [\#129](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/129)) + +### Community Contributions: + * PRs reviewed: [\#237](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/237), [\#242](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/242) + + diff --git a/docs/team/wangqinNick.md b/docs/team/wangqinNick.md new file mode 100644 index 0000000000..0ad7b89166 --- /dev/null +++ b/docs/team/wangqinNick.md @@ -0,0 +1,100 @@ +# [Wang Qin] - Project Portfolio Page + +## Overview +Repository Assistant with a Versatile Interface (ra.VI) is a desktop app for managing tasks, deadlines, and timetable, optimized for use via a Command Line Interface (CLI). It is written in Java and is built to run on Java 11 on Linux, Mac and Windows machines. + +## My contributions +### Features implemented for Individual GUI Team Project: + +* **New Feature**: Added the Graphical User Interface to the project + * What it does: Allows user to have more intuitive concepts about the modules and related tasks. + * Justification: The GUI is done by myself, thus due to the limited of time and human resources, it could only do limited features. + * Highlights: 1. Different kinds of pop up windows and notifications are added. + 2. The GUI is implemented with the console parts (console screen and console). + * In-depth contribution: + * Created a MainStage for the basic view. + * Besides the MainStage, different kinds of pop-up components will be shown when the user clicks some buttons. + * Add different kinds of interactions. For example, when the user hangs the mouse over a section, some windows will also be shown. + +* **New Feature**: Added Directory System feature + * What it does: The Directory System treats all the modules as directories. + * Justification: It follows the UNIX style. + * Highlights: 1. The directory level hierarchy is 'Root -> Module -> Task' + * In-depth contribution: + * Users could traverse through modules and root by using Change Directory command. + * The traversing is facilitated by the traverse stack. This stack is used to store the level of directories. + +* **New Feature**: Traverse previous commands feature. + * What it does: Use the Up/Down arrow on the keyboard to traverse previous input commands in the GUI. + * Justification: Users (students) would like to input a previous command. Like our terminal or CMD, the UP/DOWN arrow on the keyboard is used to traverse. + * Highlights: 1. Add the event listener to catch the key press action. + * In-depth contribution: + * Add a CommandManager class to manage the history of all commands. + +### Features implemented for Team CLI Team Project: + +* **New Feature**: Added Edit task feature [#44](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/44) + * What it does: Allows users (students) to edit existing tasks. + * Justification: Users (students) may make some mistakes when adding tasks, like entering the wrong task description. This feature allows them to edit the task description. + * Highlights: N.A. + +* **New Feature**: Added Undo feature [#77](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/77) + * What it does: Recover the previous operation. + * Justification: The undo command could only recover the previous data-changed operations. The User could undo as many times as he wants. + * Highlights: 1. All commands are classified into "Edit", "Info" types. + 2. Add the State class to save the copy of all data after user input "Data-Changed" operations. + 3. Add the State Manager class to manage the saving states. + * In-depth contribution: + * Add encoder function to encoder the Module and Task objects to Json strings when saving. + * Add decoder function to decode the Json strings back to Module and Task objects when loading. + +* **New Feature**: Module Loader feature [#28](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/28) + * What it does: Allow the program load all module information when it starts. + * Justification: The module information is provided by NUSMODS. + * Highlights: Add the IoManager class to load modules when the program starts. + * In-depth contribution: + * Parse the Json file (module information) to the Module object. + * Once all modules are parsed, save them to the HashMap that stores the moduleMap. + + +* **New Feature**: Added Undo feature [#77](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/77) + * What it does: Recover the previous operation. + * Justification: The undo command could only recover the previous data-changed operations. The User could undo as many times as he wants. + * Highlights: 1. All commands are classified into "Edit", "Info" types. + 2. Add the State class to save the copy of all data after user input "Data-Changed" operations. + 3. Add the State Manager class to manage the saving states. + * In-depth contribution: + * Add encoder function to encoder the Module and Task objects to Json strings when saving. + * Add decoder function to decode the Json strings back to Module and Task objects when loading. + + +#### Code contributed +* **Code contributed**: [RepoSense Link](https://nus-cs2113-ay2021s1.github.io/tp-dashboard/#breakdown=true&search=wangqinNick) +* **Code contributed For Individual Team Project**: The Graphical User Interface branch. [GUI Branch link](https://github.com/wangqinNick/tp/tree/branch-iptp) + + +#### Contributions to documentation +#### Contributions to the DG +* **Developer Guide**: + * Added documentation for the `editTask`, `undo` features. [#96] + * Added class diagrams for `State`, `StateManager`. + * Added sequence diagram for `editTask`, `undo`. + +### Contributions to team-based tasks +* **Project Management**: + * Managed individual releases `v3.0` (1 releases) on Github + +##### Review/mentoring contributions +* **Review/mentoring contributions**: + * PRs reviewed (with non-trivial review comments): [#26](https://github.com/AY2021S1-CS2113T-T09-2/tp/pull/26) + +##### Contributions beyond the project team +* **Individual Team Project**: + * The Graphical User Interface branch. [GUI Branch link](https://github.com/wangqinNick/tp/tree/branch-iptp) + +#### [Optional] Contributions to the User Guide (Extracts) +* **User Guide**: + * Added documentation for the Conclusion. + * Added documentation for the FAQ. + * Added documentation for the Graphical User Interface v3.0. + * Added documentation for the `undo` feature. diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index b7c8c5dbf5..192bd14dc0 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ +#Mon Sep 28 00:10:37 CST 2020 +distributionUrl=https\://services.gradle.org/distributions/gradle-6.2-all.zip distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.2-bin.zip -zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME diff --git a/src/main/java/seedu/duke/Duke.java b/src/main/java/seedu/duke/Duke.java deleted file mode 100644 index 5c74e68d59..0000000000 --- a/src/main/java/seedu/duke/Duke.java +++ /dev/null @@ -1,21 +0,0 @@ -package seedu.duke; - -import java.util.Scanner; - -public class Duke { - /** - * Main entry-point for the java.duke.Duke application. - */ - public static void main(String[] args) { - String logo = " ____ _ \n" - + "| _ \\ _ _| | _____ \n" - + "| | | | | | | |/ / _ \\\n" - + "| |_| | |_| | < __/\n" - + "|____/ \\__,_|_|\\_\\___|\n"; - System.out.println("Hello from\n" + logo); - System.out.println("What is your name?"); - - Scanner in = new Scanner(System.in); - System.out.println("Hello " + in.nextLine()); - } -} diff --git a/src/main/java/seedu/ravi/Executor.java b/src/main/java/seedu/ravi/Executor.java new file mode 100644 index 0000000000..f74bb9fb12 --- /dev/null +++ b/src/main/java/seedu/ravi/Executor.java @@ -0,0 +1,60 @@ +package seedu.ravi; + +import seedu.ravi.command.Command; +import seedu.ravi.command.CommandResult; +import seedu.ravi.command.PromptType; +import seedu.ravi.data.StateManager; +import seedu.ravi.data.TimeTableManager; +import seedu.ravi.data.storage.InputOutputManager; +import seedu.ravi.exception.NusModsNotLoadedException; +import seedu.ravi.parser.Parser; +import seedu.ravi.ui.TextUi; + +public class Executor { + /** + * Executes command. + * + * @param userInput The input from the user to be parsed and executed as a command + * @return commandResult that contains the execute output information + */ + public static CommandResult executeCommand(String userInput) { + Command command = new Parser().parseCommand(userInput); + CommandResult result = command.execute(); + + if (command.getPromptType() == PromptType.EDIT) { + StateManager.saveState(userInput); + InputOutputManager.save(); + } + + return result; + } + + /** + * Initialises all classes that need to be initialised. + * + * @throws NusModsNotLoadedException + * If the InputOutputManager cannot load any NUSMods data + */ + public static void initialise() throws NusModsNotLoadedException { + int loadStatus = InputOutputManager.start(); + StateManager.initialise(); + TextUi.showWelcomeMessage(loadStatus); + InputOutputManager.saveNusMods(); + while (!TimeTableManager.isInitialised()) { + TimeTableManager.initialiseTimetable(); + } + } + + /** + * Carries out the command loop and exits when result.isExit is true. + */ + public static void startCommandLoop() { + CommandResult result; + String userInput; + do { + userInput = TextUi.getUserCommand(); + result = Executor.executeCommand(userInput); // Saves state too + TextUi.showResultToUser(result); + } while (!result.isExit); + } +} diff --git a/src/main/java/seedu/ravi/Ravi.java b/src/main/java/seedu/ravi/Ravi.java new file mode 100644 index 0000000000..6c4980b404 --- /dev/null +++ b/src/main/java/seedu/ravi/Ravi.java @@ -0,0 +1,68 @@ +package seedu.ravi; + +import org.fusesource.jansi.AnsiConsole; +import java.io.FileNotFoundException; +import java.util.NoSuchElementException; +import java.util.Scanner; + +import seedu.ravi.command.IncorrectCommand; +import seedu.ravi.exception.NusModsNotLoadedException; +import seedu.ravi.ui.TextUi; + +import static seedu.ravi.util.ExceptionMessage.MESSAGE_NUS_MODS_NOT_LOADED; +import static seedu.ravi.util.Message.MESSAGE_SHUTDOWN; + +public class Ravi { + private static final RaviLogger logger = new RaviLogger(Ravi.class.getName()); + + /** + * Entry-point for the java.ravi.Ravi application. + * + * @param args arguments passed to the program. + * @throws FileNotFoundException exception is thrown if the file is not found. + */ + public static void main(String[] args) { + AnsiConsole.systemInstall(); + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + logger.getLogger().info("PROGRAM TERMINATED SUCCESSFULLY"); + System.out.println(); + TextUi.outputToUser(MESSAGE_SHUTDOWN); + AnsiConsole.systemUninstall(); + })); + + run(args); + } + + /** + * Sets up the storage, loads up the data from the storage file and prints the welcome message. + * + * @param args + * From the command line + * @throws NusModsNotLoadedException + * When no NUSMods data can be loaded + */ + private static void start(String[] args) throws NusModsNotLoadedException { + TextUi.initialiseTextUi(new Scanner(System.in)); + Executor.initialise(); + logger.getLogger().info("Initialised scanner, UI, and IO"); + } + + /** + * Runs the program until termination. + * + * @param args arguments passed to the program. + */ + public static void run(String[] args) { + logger.getLogger().info("STARTING PROGRAM..."); + try { + start(args); + logger.getLogger().info("ENTERING COMMAND LOOP"); + Executor.startCommandLoop(); + } catch (NusModsNotLoadedException e) { + // Show NUSMods not loaded error message if NUSMods not loaded and crash! + TextUi.showResultToUser(new IncorrectCommand(MESSAGE_NUS_MODS_NOT_LOADED).execute()); + } catch (NoSuchElementException ignored) { + // User has entered ctrl-c + } + } +} diff --git a/src/main/java/seedu/ravi/RaviLogger.java b/src/main/java/seedu/ravi/RaviLogger.java new file mode 100644 index 0000000000..14279d4cb1 --- /dev/null +++ b/src/main/java/seedu/ravi/RaviLogger.java @@ -0,0 +1,113 @@ +package seedu.ravi; + +import java.io.IOException; +import java.util.logging.FileHandler; +import java.util.logging.LogRecord; +import java.util.logging.Logger; +import java.util.logging.Level; +import java.io.File; +import java.util.logging.SimpleFormatter; + +public class RaviLogger { + private Logger raviLogger; // One logger for each instance + + // The following are shared across all RaviLogger instances + private static FileHandler logFile; + private static String logFileName = null; + private static final String LOG_PATH = "./logs/"; + private static final String LOG_NAME = "session_"; + private static final String LOG_EXT = ".log"; + private static final Level LOGGING_LEVEL = Level.INFO; // CHANGE LOGGING LEVEL HERE! + + private static final SimpleFormatter FORMATTER = new SimpleFormatter() { + private static final String formatE = "%1$s - %2$s:%n[%3$-7s] %4$s%n%5$s%n%n"; + private static final String format = "%1$s - %2$s:%n[%3$-7s] %4$s%n%n"; + @Override + public synchronized String format(LogRecord lr) { + if (lr.getThrown() != null) { + return String.format(formatE, + lr.getSourceClassName(), + lr.getSourceMethodName(), + lr.getLevel().getLocalizedName(), + lr.getMessage(), + lr.getThrown() + ); + } else { + return String.format(format, + lr.getSourceClassName(), + lr.getSourceMethodName(), + lr.getLevel().getLocalizedName(), + lr.getMessage() + ); + } + } + }; + + public RaviLogger(String className) { + try { + raviLogger = Logger.getLogger(className); + if (logFileName == null) { + globalSetup(); + logFile = new FileHandler(logFileName); + } + raviLogger.setUseParentHandlers(false); // Stop it from logging from console... + raviLogger.addHandler(logFile); // Make it log to file instead + raviLogger.setLevel(LOGGING_LEVEL); + logFile.setFormatter(FORMATTER); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public Logger getLogger() { + return raviLogger; + } + + private static void globalSetup() { + try { + preparePath(); + logFileName = prepareFile(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static void preparePath() { + File logFolder = new File(LOG_PATH); + if (!logFolder.exists()) { + logFolder.mkdir(); + } + } + + public static String prepareFile() throws IOException { + int sessionNum = 1; + String currentLogFileName = LOG_PATH + LOG_NAME + sessionNum + LOG_EXT; + File logFile = new File(currentLogFileName); + while (logFile.exists()) { + sessionNum++; + currentLogFileName = LOG_PATH + LOG_NAME + sessionNum + LOG_EXT; + logFile = new File(currentLogFileName); + } + if (sessionNum >= 2) { + try { + deletePreviousLogs(); + } catch (NullPointerException e) { + // do nothing + } + sessionNum = 0; + currentLogFileName = LOG_PATH + LOG_NAME + sessionNum + LOG_EXT; + logFile = new File(currentLogFileName); + } + logFile.createNewFile(); + return currentLogFileName; + } + + public static void deletePreviousLogs() throws NullPointerException { + File logFolder = new File(LOG_PATH); + for (File file: logFolder.listFiles()) { + if (!file.isDirectory()) { + file.delete(); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/seedu/ravi/command/Command.java b/src/main/java/seedu/ravi/command/Command.java new file mode 100644 index 0000000000..2a0d4171b2 --- /dev/null +++ b/src/main/java/seedu/ravi/command/Command.java @@ -0,0 +1,25 @@ +package seedu.ravi.command; + +import static seedu.ravi.command.PromptType.NONE; + +public abstract class Command { + protected PromptType promptType = NONE; + + public PromptType getPromptType() { + return promptType; + } + + public void setPromptType(PromptType promptType) { + this.promptType = promptType; + } + + /** + * Executes the command. + * + * @return + * The result of the execution + */ + public abstract CommandResult execute(); + + +} \ No newline at end of file diff --git a/src/main/java/seedu/ravi/command/CommandResult.java b/src/main/java/seedu/ravi/command/CommandResult.java new file mode 100644 index 0000000000..f787677bab --- /dev/null +++ b/src/main/java/seedu/ravi/command/CommandResult.java @@ -0,0 +1,25 @@ +package seedu.ravi.command; + +public class CommandResult { + public final String feedbackToUser; + public final boolean isError; + public final boolean isExit; + + public CommandResult(String feedbackToUser) { + this.feedbackToUser = feedbackToUser; + this.isError = false; + this.isExit = false; + } + + public CommandResult(String feedbackToUser, boolean isError) { + this.feedbackToUser = feedbackToUser; + this.isError = isError; + this.isExit = false; + } + + public CommandResult(String feedbackToUser, boolean isError, boolean isExit) { + this.feedbackToUser = feedbackToUser; + this.isError = isError; + this.isExit = isExit; + } +} diff --git a/src/main/java/seedu/ravi/command/ExitCommand.java b/src/main/java/seedu/ravi/command/ExitCommand.java new file mode 100644 index 0000000000..94bfb0d50c --- /dev/null +++ b/src/main/java/seedu/ravi/command/ExitCommand.java @@ -0,0 +1,16 @@ +//@@author aseanseen + +package seedu.ravi.command; + +import static seedu.ravi.util.Message.MESSAGE_GOODBYE; + +public class ExitCommand extends Command { + public static final String COMMAND_WORD = "bye"; + public static final String HELP = "Exit ra.VI and saves all changes." + + "\n\t@|bold,blue,BG_BLACK Format:|@ " + COMMAND_WORD; + + @Override + public CommandResult execute() { + return new CommandResult(MESSAGE_GOODBYE, false, true); + } +} diff --git a/src/main/java/seedu/ravi/command/IncorrectCommand.java b/src/main/java/seedu/ravi/command/IncorrectCommand.java new file mode 100644 index 0000000000..d97fe1afe8 --- /dev/null +++ b/src/main/java/seedu/ravi/command/IncorrectCommand.java @@ -0,0 +1,26 @@ +package seedu.ravi.command; + +/** + *

Invalid Command

+ * A Command that is determined to be invalid. + * @see Command + */ +public class IncorrectCommand extends Command { + private final String feedbackToUser; // Message to be shown to the user + + public IncorrectCommand(String message) { + this.feedbackToUser = message; + } + + /** + * Executes the Invalid Command to show the message to the user due to an invalid + * command. + * + * @return The Command Result of the execution + * @see CommandResult + */ + @Override + public CommandResult execute() { + return new CommandResult(feedbackToUser, true); + } +} diff --git a/src/main/java/seedu/ravi/command/PromptType.java b/src/main/java/seedu/ravi/command/PromptType.java new file mode 100644 index 0000000000..e3851e660e --- /dev/null +++ b/src/main/java/seedu/ravi/command/PromptType.java @@ -0,0 +1,15 @@ +package seedu.ravi.command; + +/** + * Indicates the type of user commands and corresponding command results. + * WARNING: the command results a waring message + * INFORMATIVE: the command results a help message + * EDIT: the command is a EDIT command + * NONE: the command is a basic command + */ +public enum PromptType { + WARNING, + INFORMATIVE, + NONE, + EDIT +} diff --git a/src/main/java/seedu/ravi/command/add/AddCommand.java b/src/main/java/seedu/ravi/command/add/AddCommand.java new file mode 100644 index 0000000000..847eab3821 --- /dev/null +++ b/src/main/java/seedu/ravi/command/add/AddCommand.java @@ -0,0 +1,15 @@ +//@@author aseanseen + +package seedu.ravi.command.add; + +import seedu.ravi.command.Command; +import seedu.ravi.ui.TextUi; + +public abstract class AddCommand extends Command { + public static final String COMMAND_WORD = "add"; + public static final String FORMAT_ADD_MODULE = COMMAND_WORD + " -m "; + public static final String FORMAT_ADD_TASK = COMMAND_WORD + " -t [-by ]"; + public static final String FORMAT = FORMAT_ADD_TASK + "\n" + FORMAT_ADD_MODULE; + public static final String PROMPT_HELP = TextUi.getCommandHelpMessage(COMMAND_WORD); + public static final String HELP = AddTaskCommand.HELP + AddModuleCommand.HELP; +} \ No newline at end of file diff --git a/src/main/java/seedu/ravi/command/add/AddModuleCommand.java b/src/main/java/seedu/ravi/command/add/AddModuleCommand.java new file mode 100644 index 0000000000..5cca45823c --- /dev/null +++ b/src/main/java/seedu/ravi/command/add/AddModuleCommand.java @@ -0,0 +1,65 @@ +//@@author aseanseen + +package seedu.ravi.command.add; + +import seedu.ravi.command.CommandResult; +import seedu.ravi.command.PromptType; +import seedu.ravi.data.Module; +import seedu.ravi.data.ModuleManager; +import seedu.ravi.exception.DuplicateModuleException; +import seedu.ravi.exception.ModuleNotFoundException; +import seedu.ravi.exception.ModuleNotProvidedException; + +import static seedu.ravi.util.ExceptionMessage.MESSAGE_DUPLICATE_MODULE; +import static seedu.ravi.util.ExceptionMessage.MESSAGE_MODULE_NOT_PROVIDED; +import static seedu.ravi.util.Message.MESSAGE_ADD_MODULE_SUCCESS; + +public class AddModuleCommand extends AddCommand { + private final String module; + public static final String FORMAT = COMMAND_WORD + " -m "; + public static final String HELP = "Add a module from NUSMods to the scheduler." + + "\n\t@|bold,blue,BG_BLACK Format:|@ " + FORMAT + + "\n\t@|bold,blue,BG_BLACK Example usage:|@ add -m CS2113T"; + + /** + * Constructs AddModuleCommand. + * + * @param module Module code to be added. + */ + public AddModuleCommand(String module) { + this.module = module.toUpperCase(); + setPromptType(PromptType.EDIT); + } + + /** + * Add the Module to the module list. + * + * @param module Module code to be added. + * @throws DuplicateModuleException if the module is already in the list + */ + private Module addModule(String module) throws + DuplicateModuleException, ModuleNotProvidedException, ModuleNotFoundException { + ModuleManager.add(module); + return ModuleManager.getModule(module); + } + + /** + * Executes the AddModuleCommand to add the module to the module list. + * + * @return CommandResult containing acknowledgement of the add module or messages from exceptions. + */ + @Override + public CommandResult execute() { + try { + Module newModule = addModule(module); + return new CommandResult(String.format(MESSAGE_ADD_MODULE_SUCCESS, newModule.toString())); + } catch (DuplicateModuleException e) { + return new CommandResult(MESSAGE_DUPLICATE_MODULE, true); + } catch (ModuleNotProvidedException e) { + return new CommandResult(MESSAGE_MODULE_NOT_PROVIDED, true); + } catch (ModuleNotFoundException e) { + // should not happen + return new CommandResult("AddModuleCommand caught ModuleNotFoundException", true); + } + } +} diff --git a/src/main/java/seedu/ravi/command/add/AddTaskCommand.java b/src/main/java/seedu/ravi/command/add/AddTaskCommand.java new file mode 100644 index 0000000000..7f31cb27ec --- /dev/null +++ b/src/main/java/seedu/ravi/command/add/AddTaskCommand.java @@ -0,0 +1,96 @@ +//@@author aseanseen + +package seedu.ravi.command.add; + +import seedu.ravi.command.CommandResult; +import seedu.ravi.command.PromptType; +import seedu.ravi.data.Task; +import seedu.ravi.data.TaskManager; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; + +import static seedu.ravi.util.Message.MESSAGE_ADD_TASK_SUCCESS; + +public class AddTaskCommand extends AddCommand { + private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d-M-yyyy HHmm"); + private final String desc; + private LocalDateTime dateTimeOfDeadline; + public static final String FORMAT = COMMAND_WORD + " -t [-by ]"; + public static final String HELP = "Add a task to the scheduler." + + "\n\t@|bold,blue,BG_BLACK Format:|@ " + FORMAT + + "\n\t@|bold,blue,BG_BLACK Example usage:|@ add -t Read Book" + + "\n\t add -t Return Book -by 30-12-2020 1800\n\n"; + + /** + * Constructs AddTaskCommand without the deadline. + * + * @param desc Description of the entry. + * @throws DateTimeParseException If the deadline does not follow the DateTime format. + */ + public AddTaskCommand(String desc) { + this.desc = desc; + setPromptType(PromptType.EDIT); + } + + /** + * Constructs AddTaskCommand and tests the format of the deadline. + * + * @param desc Description of the entry. + * @param deadline Deadline of the task to be added. + * @throws DateTimeParseException If the deadline does not follow the DateTime format. + */ + public AddTaskCommand(String desc, String deadline) throws DateTimeParseException { + this.desc = desc; + if (deadline != null) { + dateTimeOfDeadline = testDeadline(deadline); + } + setPromptType(PromptType.EDIT); + } + + /** + * Test if the deadline of the task follows the DateTimeFormatter. + * + * @param deadline LocalDateTime deadline. + * @throws DateTimeParseException if the deadline does not follow format. + */ + private LocalDateTime testDeadline(String deadline) throws DateTimeParseException { + LocalDateTime dateTimeOfDeadline; + dateTimeOfDeadline = LocalDateTime.parse(deadline, formatter); + return dateTimeOfDeadline; + } + + /** + * Add the Task with deadline to the task list. + * + * @param desc Description of the task to be added. + * @param dateTimeOfDeadline LocalDateTime of the deadline. + * @return newTask The new task object that was added. + */ + private Task addTask(String desc, LocalDateTime dateTimeOfDeadline) { + Task newTask; + // Option for user to input a deadline + if (dateTimeOfDeadline == null) { + newTask = new Task(desc); + } else { + newTask = new Task(desc, dateTimeOfDeadline); + } + TaskManager.add(newTask); + return newTask; + } + + /** + * Executes the AddTaskCommand to add the task to the task list. + * + * @return CommandResult containing acknowledgement of the add task or messages from exceptions. + */ + @Override + public CommandResult execute() { + String message; + Task addedTask = addTask(desc, dateTimeOfDeadline); + + message = String.format(MESSAGE_ADD_TASK_SUCCESS, addedTask.toString()); + return new CommandResult(message); + } +} diff --git a/src/main/java/seedu/ravi/command/cap/CapCommand.java b/src/main/java/seedu/ravi/command/cap/CapCommand.java new file mode 100644 index 0000000000..0e2bf7ccfd --- /dev/null +++ b/src/main/java/seedu/ravi/command/cap/CapCommand.java @@ -0,0 +1,138 @@ +//@@author tobiasceg + +package seedu.ravi.command.cap; + +import seedu.ravi.command.Command; +import seedu.ravi.command.CommandResult; +import seedu.ravi.data.ModuleManager; +import seedu.ravi.exception.InvalidCapCalculatedException; +import seedu.ravi.exception.ModuleNotFoundException; +import seedu.ravi.ui.TextUi; + +import static seedu.ravi.util.ExceptionMessage.MESSAGE_INVALID_CAP_ATTAINED; +import static seedu.ravi.util.ExceptionMessage.MESSAGE_MODULE_NOT_FOUND; +import static seedu.ravi.util.Message.MESSAGE_CAP_DISPLAY; + +public class CapCommand extends Command { + public static final String COMMAND_WORD = "cap"; + public static final String FORMAT = COMMAND_WORD + " "; + public static final String PROMPT_HELP = TextUi.getCommandHelpMessage(COMMAND_WORD); + public static final String HELP = "Calculate your CAP." + + "\n\t@|bold,blue,BG_BLACK Format:|@ " + FORMAT + + "\n\t@|bold,blue,BG_BLACK Example usage:|@ cap 20 4.5"; + + private static double cap = 0.0; + private static final double SUMMCGRADE = 20; + private static final double SUMMC = 4; + + /** + * Enum for the grading schematic of NUS. + */ + private enum GradeSchematic { + A_PLUS("A+", 5.0), + A("A", 5.0), + A_MINUS("A-", 4.5), + B_PLUS("B+", 4.0), + B("B", 3.5), + B_MINUS("B-", 3.0), + C_PLUS("C+", 2.5), + C("C", 2.0), + D_PLUS("D+", 1.5), + D("D", 1.0), + F("F", 0.0), + CS("CS", -2.0), + CU("CU", -3.0); + + private final String symbol; + private final double value; + + GradeSchematic(String symbol, double value) { + this.symbol = symbol; + this.value = value; + } + } + + /** + * Converts the grade assigned to a module the value by using the enum. + * + * @param grade + * grade assigned to module + * @return + * the value of the grade + */ + private double gradeConvert(String grade) { + double score = 0.0; + if (grade.equals("No grade yet")) { + score = -1.0; + return score; + } + for (GradeSchematic g : GradeSchematic.values()) { + if (grade.equals(g.symbol)) { + score = g.value; + } + } + return score; + } + + /** + * Calculates the cap of the user. + * + * @return + * cap of the user + * @throws InvalidCapCalculatedException + * When the attained cap is unimaginable + * @throws ModuleNotFoundException + * When the module called isn't found + */ + private double calculateCap() throws InvalidCapCalculatedException, ModuleNotFoundException { + String[] moduleList = ModuleManager.getModCodeList(); + double mcGrade; + double sumMcGrade = 0; + double sumMc = 0; + double gradeValue; + int numberOfCsCuModules = 0; + int numberOfModules = 0; + + for (String i : moduleList) { + numberOfModules++; + gradeValue = gradeConvert(ModuleManager.getModule(i).getModuleGrade()); + + if (gradeValue != -1.0) { + if (gradeValue >= 0) { + sumMc += ModuleManager.getModule(i).getModuleCredit(); + mcGrade = ModuleManager.getModule(i).getModuleCredit() + * gradeValue; + sumMcGrade += mcGrade; + } else { + numberOfCsCuModules++; + } + } + } + if (numberOfCsCuModules == numberOfModules) { + sumMcGrade = SUMMCGRADE; + sumMc = SUMMC; + } + + cap = sumMcGrade / sumMc; + + if (cap < 0 || cap > 5.0 || isNan(cap)) { + throw new InvalidCapCalculatedException(); + } + return cap; + } + + private boolean isNan(double cap) { + return cap != cap; + } + + @Override + public CommandResult execute() { + try { + return new CommandResult(String.format("%s%.2f\n", MESSAGE_CAP_DISPLAY, calculateCap())); + } catch (InvalidCapCalculatedException e) { + return new CommandResult(MESSAGE_INVALID_CAP_ATTAINED, true); + } catch (ModuleNotFoundException e) { + return new CommandResult(MESSAGE_MODULE_NOT_FOUND, true); + } + } +} diff --git a/src/main/java/seedu/ravi/command/delete/DeleteCommand.java b/src/main/java/seedu/ravi/command/delete/DeleteCommand.java new file mode 100644 index 0000000000..aa21330a56 --- /dev/null +++ b/src/main/java/seedu/ravi/command/delete/DeleteCommand.java @@ -0,0 +1,15 @@ +//@@author aseanseen + +package seedu.ravi.command.delete; + +import seedu.ravi.command.Command; +import seedu.ravi.ui.TextUi; + +public abstract class DeleteCommand extends Command { + public static final String COMMAND_WORD = "del"; + public static final String FORMAT_DELETE_TASK = DeleteCommand.COMMAND_WORD + " -t" + " "; + public static final String FORMAT_DELETE_MODULE = DeleteCommand.COMMAND_WORD + " -m" + " "; + public static final String FORMAT = FORMAT_DELETE_TASK + "\n" + FORMAT_DELETE_MODULE; + public static final String PROMPT_HELP = TextUi.getCommandHelpMessage(COMMAND_WORD); + public static final String HELP = DeleteTaskCommand.HELP + DeleteModuleCommand.HELP; +} diff --git a/src/main/java/seedu/ravi/command/delete/DeleteModuleCommand.java b/src/main/java/seedu/ravi/command/delete/DeleteModuleCommand.java new file mode 100644 index 0000000000..02d547744d --- /dev/null +++ b/src/main/java/seedu/ravi/command/delete/DeleteModuleCommand.java @@ -0,0 +1,57 @@ +//@@author aseanseen + +package seedu.ravi.command.delete; + +import seedu.ravi.command.CommandResult; +import seedu.ravi.command.PromptType; +import seedu.ravi.data.Module; +import seedu.ravi.data.ModuleManager; +import seedu.ravi.exception.ModuleNotFoundException; + +import static seedu.ravi.util.ExceptionMessage.MESSAGE_MODULE_NOT_FOUND; +import static seedu.ravi.util.Message.MESSAGE_DELETE_MODULE_SUCCESS; + +public class DeleteModuleCommand extends DeleteCommand { + private final String moduleCode; + public static final String FORMAT = DeleteCommand.COMMAND_WORD + " -m" + " "; + public static final String HELP = "Delete a module from the scheduler." + + "\n\t@|bold,blue,BG_BLACK Format:|@ " + FORMAT + + "\n\t@|bold,blue,BG_BLACK Example usage:|@ del -m CS2113T"; + + /** + * Constructor to delete module from module list. + * + * @param moduleCode Module code to be deleted. + */ + public DeleteModuleCommand(String moduleCode) { + this.moduleCode = moduleCode.toUpperCase(); + setPromptType(PromptType.EDIT); + } + + /** + * Deletes the module from the module list. + * + * @param moduleCode Module code to be deleted. + * @throws ModuleNotFoundException If the module is not found in the module list. + */ + private Module deleteModule(String moduleCode) throws ModuleNotFoundException { + Module deletedModule = ModuleManager.getModule(moduleCode); + ModuleManager.delete(moduleCode); + return deletedModule; + } + + /** + * Executes the DeleteModuleCommand to delete the module from the module list. + * + * @return CommandResult containing acknowledgement of the delete or errors. + */ + @Override + public CommandResult execute() { + try { + Module deletedMod = deleteModule(moduleCode); + return new CommandResult(String.format(MESSAGE_DELETE_MODULE_SUCCESS, deletedMod.toString())); + } catch (ModuleNotFoundException e) { + return new CommandResult(MESSAGE_MODULE_NOT_FOUND, true); + } + } +} diff --git a/src/main/java/seedu/ravi/command/delete/DeleteTaskCommand.java b/src/main/java/seedu/ravi/command/delete/DeleteTaskCommand.java new file mode 100644 index 0000000000..f6697aa4dd --- /dev/null +++ b/src/main/java/seedu/ravi/command/delete/DeleteTaskCommand.java @@ -0,0 +1,56 @@ +//@@author aseanseen + +package seedu.ravi.command.delete; + +import seedu.ravi.command.CommandResult; +import seedu.ravi.command.PromptType; +import seedu.ravi.data.Task; +import seedu.ravi.data.TaskManager; + +import static seedu.ravi.util.ExceptionMessage.MESSAGE_TASK_NOT_FOUND; +import static seedu.ravi.util.Message.MESSAGE_DELETE_TASK_SUCCESS; + +public class DeleteTaskCommand extends DeleteCommand { + private final int taskId; + public static final String FORMAT = DeleteCommand.COMMAND_WORD + " -t" + " "; + public static final String HELP = "Delete a task from the scheduler." + + "\n\t@|bold,blue,BG_BLACK Format:|@ " + FORMAT + + "\n\t@|bold,blue,BG_BLACK Example usage:|@ del -t 1\n\n"; + + /** + * Constructor to delete task from task list. + * + * @param taskId ID of the task to be deleted. + */ + public DeleteTaskCommand(int taskId) { + this.taskId = taskId; + setPromptType(PromptType.EDIT); + } + + /** + * Deletes the task from the task list. + * + * @param taskId ID of the task to be deleted. + * @throws TaskManager.TaskNotFoundException If the task is not found in the task list. + */ + private Task deleteTask(int taskId) throws TaskManager.TaskNotFoundException { + Task deletedTask = TaskManager.getTask(taskId); + TaskManager.delete(taskId); + return deletedTask; + } + + /** + * Executes the DeleteTaskCommand to delete the task from the task list. + * + * @return CommandResult containing acknowledgement of the delete or errors. + */ + @Override + public CommandResult execute() { + try { + Task deletedTask = deleteTask(taskId); + return new CommandResult(String.format(MESSAGE_DELETE_TASK_SUCCESS, deletedTask.toString())); + } catch (TaskManager.TaskNotFoundException e) { + return new CommandResult(MESSAGE_TASK_NOT_FOUND, true); + } + } +} diff --git a/src/main/java/seedu/ravi/command/done/DoneCommand.java b/src/main/java/seedu/ravi/command/done/DoneCommand.java new file mode 100644 index 0000000000..9d98ff63c8 --- /dev/null +++ b/src/main/java/seedu/ravi/command/done/DoneCommand.java @@ -0,0 +1,52 @@ +package seedu.ravi.command.done; + +import seedu.ravi.command.Command; +import seedu.ravi.command.CommandResult; +import seedu.ravi.command.PromptType; +import seedu.ravi.data.Task; +import seedu.ravi.data.TaskManager; +import seedu.ravi.ui.TextUi; + +import static seedu.ravi.util.ExceptionMessage.MESSAGE_TASK_NOT_FOUND; +import static seedu.ravi.util.Message.MESSAGE_DONE_TASK_SUCCESS; + +//@@author amalinasani +public class DoneCommand extends Command { + private final int taskId; + public static final String COMMAND_WORD = "done"; + public static final String FORMAT = COMMAND_WORD + " "; + public static final String HELP = "Mark a task as done." + + "\n\t@|bold,blue,BG_BLACK Format:|@ " + FORMAT + + "\n\t@|bold,blue,BG_BLACK Example usage:|@ done 1"; + public static final String PROMPT_HELP = TextUi.getCommandHelpMessage(COMMAND_WORD); + + public DoneCommand(int taskId) { + this.taskId = taskId; + setPromptType(PromptType.EDIT); + } + + /** + * Marks the task from the task list as done. + * + * @param taskId id of task. + * @throws TaskManager.TaskNotFoundException If the task is not found in the task list. + */ + private Task doneTask(int taskId) throws TaskManager.TaskNotFoundException { + return TaskManager.done(taskId); + } + + /** + * Marks the task from the task list as done. + * + * @return CommandResult containing acknowledgement of marking task as done. + */ + @Override + public CommandResult execute() { + try { + Task completedTask = doneTask(taskId); + return new CommandResult(String.format(MESSAGE_DONE_TASK_SUCCESS, completedTask)); + } catch (TaskManager.TaskNotFoundException e) { + return new CommandResult(MESSAGE_TASK_NOT_FOUND, true); + } + } +} diff --git a/src/main/java/seedu/ravi/command/edit/EditCommand.java b/src/main/java/seedu/ravi/command/edit/EditCommand.java new file mode 100644 index 0000000000..78675900b2 --- /dev/null +++ b/src/main/java/seedu/ravi/command/edit/EditCommand.java @@ -0,0 +1,13 @@ +package seedu.ravi.command.edit; + +import seedu.ravi.command.Command; +import seedu.ravi.ui.TextUi; + +public abstract class EditCommand extends Command { + public static final String COMMAND_WORD = "edit"; + public static final String FORMAT_EDIT_TASK = COMMAND_WORD + " -t [-by ]"; + public static final String FORMAT_EDIT_MODULE = COMMAND_WORD + " -m "; + public static final String FORMAT = FORMAT_EDIT_TASK + "\n" + FORMAT_EDIT_MODULE; + public static final String PROMPT_HELP = TextUi.getCommandHelpMessage(COMMAND_WORD); + public static final String HELP = EditTaskCommand.HELP + EditModuleCommand.HELP; +} diff --git a/src/main/java/seedu/ravi/command/edit/EditModuleCommand.java b/src/main/java/seedu/ravi/command/edit/EditModuleCommand.java new file mode 100644 index 0000000000..83f7e3aba3 --- /dev/null +++ b/src/main/java/seedu/ravi/command/edit/EditModuleCommand.java @@ -0,0 +1,69 @@ +package seedu.ravi.command.edit; + +import seedu.ravi.command.CommandResult; +import seedu.ravi.command.PromptType; +import seedu.ravi.data.Module; +import seedu.ravi.data.ModuleManager; +import seedu.ravi.exception.DuplicateModuleException; +import seedu.ravi.exception.ModuleNotFoundException; +import seedu.ravi.exception.ModuleNotProvidedException; + +import java.util.regex.Pattern; + +import static seedu.ravi.util.ExceptionMessage.MESSAGE_DUPLICATE_MODULE; +import static seedu.ravi.util.ExceptionMessage.MESSAGE_MODULE_NOT_FOUND; +import static seedu.ravi.util.ExceptionMessage.MESSAGE_MODULE_NOT_PROVIDED; +import static seedu.ravi.util.Message.MESSAGE_EDIT_MODULE_SUCCESS; + +public class EditModuleCommand extends EditCommand { + public static final String FORMAT = EditCommand.COMMAND_WORD + " -m" + " "; + public static final String HELP = "Edit a module code from the module list." + + "\n\t@|bold,blue,BG_BLACK Format:|@ " + FORMAT + + "\n\t@|bold,blue,BG_BLACK Example usage:|@ edit -m CS2113 CS2113T"; + public static final Pattern REGEX_FORMAT = Pattern.compile( + "(?(edit)) -m(?(?:\\s+\\w\\S*))(?(?:\\s+\\w\\S*))" + ); + + private final String oldModuleCode; + private final String newModuleCode; + + /** + * Constructs the command to edit a module. + * + * @param oldModuleCode + * The module code of the module to be edited + * @param newModuleCode + * The new module code for the module if any + */ + public EditModuleCommand(String oldModuleCode, String newModuleCode) { + this.oldModuleCode = oldModuleCode.toUpperCase(); + this.newModuleCode = newModuleCode.toUpperCase(); + setPromptType(PromptType.EDIT); + } + + /** + * Executes the Edit Module Command to edit a Module with the module code + * from the Module List. + * + * @return The Command Result of the execution + * @see Module + * @see ModuleManager + * @see CommandResult + */ + @Override + public CommandResult execute() { + try { + Module oldModule = ModuleManager.getModule(oldModuleCode); + Module editedModule = ModuleManager.edit(newModuleCode, oldModuleCode); + String message = String.format( + MESSAGE_EDIT_MODULE_SUCCESS, oldModule.toString(), editedModule.toString()); + return new CommandResult(message); + } catch (ModuleNotProvidedException e) { + return new CommandResult(MESSAGE_MODULE_NOT_PROVIDED, true); + } catch (DuplicateModuleException e) { + return new CommandResult(MESSAGE_DUPLICATE_MODULE, true); + } catch (ModuleNotFoundException e) { + return new CommandResult(MESSAGE_MODULE_NOT_FOUND, true); + } + } +} \ No newline at end of file diff --git a/src/main/java/seedu/ravi/command/edit/EditTaskCommand.java b/src/main/java/seedu/ravi/command/edit/EditTaskCommand.java new file mode 100644 index 0000000000..4d3dee619b --- /dev/null +++ b/src/main/java/seedu/ravi/command/edit/EditTaskCommand.java @@ -0,0 +1,95 @@ +package seedu.ravi.command.edit; + +import seedu.ravi.command.CommandResult; +import seedu.ravi.command.PromptType; +import seedu.ravi.data.Task; +import seedu.ravi.data.TaskManager; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; + +import static seedu.ravi.util.ExceptionMessage.MESSAGE_NO_EDIT_TASK; +import static seedu.ravi.util.Message.MESSAGE_EDIT_TASK_SUCCESS; + + +public class EditTaskCommand extends EditCommand { + private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d-M-yyyy HHmm"); + private final int taskId; + private final String newTaskDescription; + private LocalDateTime dateTimeOfDeadline; + public static final String FORMAT = EditCommand.COMMAND_WORD + " -t [-by ]"; + public static final String HELP = "Edit a task description from the task list." + + "\n\t@|bold,blue,BG_BLACK Format:|@ " + FORMAT + + "\n\t@|bold,blue,BG_BLACK Example usage:|@ edit -t 1 Project meeting" + + "\n\t@|bold,blue,BG_BLACK Example usage:|@ edit -t 1 Project meeting -by" + + " 30-12-2020 1200\n\n"; + + /** + * Constructs the command to edit a task. + * + * @param taskId + * The ID of the task to be edited + * @param newTaskDescription + * The new description of the task if any + */ + public EditTaskCommand(int taskId, String newTaskDescription) { + this.taskId = taskId; + this.newTaskDescription = newTaskDescription; + this.dateTimeOfDeadline = null; + setPromptType(PromptType.EDIT); + } + + /** + * Constructs AddTaskCommand and tests the format of the deadline. + * + * @param taskId + * The ID of the task to be edited + * @param newTaskDescription + * The new description of the task if any + * @param deadline + * The new deadline of the task if any + * @throws DateTimeParseException + * If the deadline does not follow the DateTime format. + */ + public EditTaskCommand(int taskId, String newTaskDescription, String deadline) throws DateTimeParseException { + this.taskId = taskId; + this.newTaskDescription = newTaskDescription; + if (deadline != null) { + dateTimeOfDeadline = testDeadline(deadline); + } + setPromptType(PromptType.EDIT); + } + + /** + * Test if the deadline of the task follows the DateTimeFormatter. + * + * @param deadline LocalDateTime deadline. + * @throws DateTimeParseException if the deadline does not follow format. + */ + private LocalDateTime testDeadline(String deadline) throws DateTimeParseException { + LocalDateTime dateTimeOfDeadline; + dateTimeOfDeadline = LocalDateTime.parse(deadline, formatter); + return dateTimeOfDeadline; + } + + protected Task edit() throws TaskManager.TaskNotFoundException { + if (dateTimeOfDeadline == null) { + return TaskManager.edit(taskId, newTaskDescription); + } else { + return TaskManager.edit(taskId, newTaskDescription, dateTimeOfDeadline); + } + } + + @Override + public CommandResult execute() { + try { + String oldTask = TaskManager.getTask(taskId).toString(); + Task editedTask = edit(); + return new CommandResult(String.format( + MESSAGE_EDIT_TASK_SUCCESS, oldTask, editedTask.toString())); + } catch (TaskManager.TaskNotFoundException e) { + return new CommandResult(MESSAGE_NO_EDIT_TASK, true); + } + } +} diff --git a/src/main/java/seedu/ravi/command/grade/GradeCommand.java b/src/main/java/seedu/ravi/command/grade/GradeCommand.java new file mode 100644 index 0000000000..2a4adc0d58 --- /dev/null +++ b/src/main/java/seedu/ravi/command/grade/GradeCommand.java @@ -0,0 +1,97 @@ +//@@author tobiasceg + +package seedu.ravi.command.grade; + +import seedu.ravi.command.Command; +import seedu.ravi.command.CommandResult; +import seedu.ravi.command.PromptType; +import seedu.ravi.data.Module; +import seedu.ravi.data.ModuleManager; +import seedu.ravi.exception.InvalidGradeException; +import seedu.ravi.exception.ModuleNotFoundException; +import seedu.ravi.ui.TextUi; + +import static seedu.ravi.util.ExceptionMessage.MESSAGE_INVALID_GRADE; +import static seedu.ravi.util.ExceptionMessage.MESSAGE_MODULE_NOT_FOUND; +import static seedu.ravi.util.Message.MESSAGE_GRADE_MODULE_SUCCESS; + + +public class GradeCommand extends Command { + private final String moduleGraded; + private final double moduleCredit; + private final String grade; + public static final String COMMAND_WORD = "grade"; + public static final String FORMAT = COMMAND_WORD + " "; + public static final String PROMPT_HELP = TextUi.getCommandHelpMessage(COMMAND_WORD); + public static final String HELP = "Grades and allocates the Module Credit to the Module." + + "\n\t@|bold,blue,BG_BLACK Format:|@ " + FORMAT + + "\n\t@|bold,blue,BG_BLACK Example usage:|@ grade CS2113T 4 A+"; + + /** + * Constructs GradeCommand. + * + * @param moduleGraded + * Module to be graded. + * @param moduleCredit + * Modular credits of the module to be graded. + * @param grade + * Grade attained by user for the specific module. + */ + public GradeCommand(String moduleGraded, double moduleCredit, String grade) { + this.moduleGraded = moduleGraded.toUpperCase(); + this.moduleCredit = moduleCredit; + this.grade = grade.toUpperCase(); + setPromptType(PromptType.EDIT); + } + + /** + * Tests if the input grade by the user is valid grade. + * + * @param grade + * grade input by user + */ + private boolean testGrade(String grade) { + String[] validGrades = {"A+", "A", "A-", "B+", "B-", "B", "C+", "C", "D+", "D", "F", "CS", "CU"}; + for (String i: validGrades) { + if (grade.equals(i)) { + return true; + } + } + return false; + } + + + /** + * Grades and allocates the Module Credit to the Module. + * + * @throws InvalidGradeException + * If the grade isn't recognised by the NUS grading schematic + */ + private Module grade() throws InvalidGradeException, ModuleNotFoundException { + if (testGrade(grade)) { + ModuleManager.grade(moduleGraded, grade, moduleCredit); + } else { + throw new InvalidGradeException(); + } + return ModuleManager.getModule(moduleGraded); + } + + /** + * Executes the Grade Module Command to grade a Module with the module code + * from the Module List. + * + * @return The Command Result of the execution + */ + @Override + public CommandResult execute() { + try { + Module moduleGraded = grade(); + return new CommandResult(String.format( + MESSAGE_GRADE_MODULE_SUCCESS, moduleGraded.toString())); + } catch (InvalidGradeException e) { + return new CommandResult(MESSAGE_INVALID_GRADE, true); + } catch (ModuleNotFoundException e) { + return new CommandResult(MESSAGE_MODULE_NOT_FOUND, true); + } + } +} diff --git a/src/main/java/seedu/ravi/command/help/HelpCommand.java b/src/main/java/seedu/ravi/command/help/HelpCommand.java new file mode 100644 index 0000000000..ba5448a4cd --- /dev/null +++ b/src/main/java/seedu/ravi/command/help/HelpCommand.java @@ -0,0 +1,90 @@ +package seedu.ravi.command.help; + +import seedu.ravi.command.Command; +import seedu.ravi.command.CommandResult; +import seedu.ravi.command.ExitCommand; +import seedu.ravi.command.add.AddCommand; +import seedu.ravi.command.cap.CapCommand; +import seedu.ravi.command.delete.DeleteCommand; +import seedu.ravi.command.done.DoneCommand; +import seedu.ravi.command.edit.EditCommand; +import seedu.ravi.command.grade.GradeCommand; +import seedu.ravi.command.list.ListCommand; +import seedu.ravi.command.misc.UndoCommand; +import seedu.ravi.command.summary.SummaryCommand; +import seedu.ravi.command.timetable.TimeTableCommand; +import seedu.ravi.ui.TextUi; + +import static seedu.ravi.util.ExceptionMessage.MESSAGE_INVALID_HELP_COMMAND; + +//@@author amalinasani +public class HelpCommand extends Command { + private String commandType; + public static final String COMMAND_WORD = "help"; + public static final String FORMAT = COMMAND_WORD + " []"; + public static final String HELP = "View command information." + + "\n\t@|bold,blue,BG_BLACK Format:|@ " + FORMAT + + "\n\t@|bold,blue,BG_BLACK Example usage:|@ help" + + "\n\t help add"; + + public HelpCommand(String commandType) { + this.commandType = commandType; + } + + /** + * Prints help message. + * + * @return CommandResult containing help message for that command + */ + @Override + public CommandResult execute() { + String output = TextUi.getCommandList(); + + if (commandType == null) { + return new CommandResult(output); + } + + switch (commandType) { + case AddCommand.COMMAND_WORD: + output = AddCommand.HELP; + break; + case CapCommand.COMMAND_WORD: + output = CapCommand.HELP; + break; + case DeleteCommand.COMMAND_WORD: + output = DeleteCommand.HELP; + break; + case DoneCommand.COMMAND_WORD: + output = DoneCommand.HELP; + break; + case EditCommand.COMMAND_WORD: + output = EditCommand.HELP; + break; + case GradeCommand.COMMAND_WORD: + output = GradeCommand.HELP; + break; + case HelpCommand.COMMAND_WORD: + output = HelpCommand.HELP; + break; + case ListCommand.COMMAND_WORD: + output = ListCommand.HELP; + break; + case UndoCommand.COMMAND_WORD: + output = UndoCommand.HELP; + break; + case TimeTableCommand.COMMAND_WORD: + output = TimeTableCommand.HELP; + break; + case SummaryCommand.COMMAND_WORD: + output = SummaryCommand.HELP; + break; + case ExitCommand.COMMAND_WORD: + output = ExitCommand.HELP; + break; + default: + output = MESSAGE_INVALID_HELP_COMMAND; + return new CommandResult(output, true); + } + return new CommandResult(output); + } +} \ No newline at end of file diff --git a/src/main/java/seedu/ravi/command/list/ListCommand.java b/src/main/java/seedu/ravi/command/list/ListCommand.java new file mode 100644 index 0000000000..c383dd2fe7 --- /dev/null +++ b/src/main/java/seedu/ravi/command/list/ListCommand.java @@ -0,0 +1,56 @@ +package seedu.ravi.command.list; + +import seedu.ravi.command.Command; +import seedu.ravi.command.CommandResult; +import seedu.ravi.command.PromptType; +import seedu.ravi.data.ModuleManager; +import seedu.ravi.data.TaskManager; +import seedu.ravi.parser.Parser; +import seedu.ravi.ui.TextUi; + +import static seedu.ravi.util.ExceptionMessage.MESSAGE_LIST_EMPTY; +import static seedu.ravi.util.Message.MESSAGE_LIST_PRINTED; + +//@@author amalinasani +public class ListCommand extends Command { + private final Parser.TypeOfEntries typeOfEntry; + public static final String COMMAND_WORD = "list"; + public static final String FORMAT_TASK = COMMAND_WORD + " -t"; + public static final String FORMAT_MODULE = COMMAND_WORD + " -m"; + public static final String FORMAT = FORMAT_TASK + "\n" + FORMAT_MODULE; + public static final String HELP = "List all tasks in the task list." + + "\n\t@|bold,blue,BG_BLACK Format:|@ " + FORMAT_TASK + + "\n\nList all modules in the module list." + + "\n\t@|bold,blue,BG_BLACK Format:|@ " + FORMAT_MODULE; + public static final String PROMPT_HELP = TextUi.getCommandHelpMessage(COMMAND_WORD); + + public ListCommand(Parser.TypeOfEntries typeOfEntry) { + this.typeOfEntry = typeOfEntry; + setPromptType(PromptType.INFORMATIVE); + } + + /** + * Lists the tasks/modules from their respective lists. + * + * @return CommandResult containing list of tasks/modules + */ + @Override + public CommandResult execute() { + String output = ""; + switch (typeOfEntry) { + case TASK: + output = TaskManager.list(); + break; + case MODULE: + output = ModuleManager.list(); + break; + default: + break; + } + if (output != null) { + return new CommandResult(MESSAGE_LIST_PRINTED + output); + } else { + return new CommandResult(MESSAGE_LIST_EMPTY); + } + } +} diff --git a/src/main/java/seedu/ravi/command/misc/UndoCommand.java b/src/main/java/seedu/ravi/command/misc/UndoCommand.java new file mode 100644 index 0000000000..6a07a83e8a --- /dev/null +++ b/src/main/java/seedu/ravi/command/misc/UndoCommand.java @@ -0,0 +1,32 @@ +package seedu.ravi.command.misc; + +import seedu.ravi.command.Command; +import seedu.ravi.command.CommandResult; +import seedu.ravi.command.PromptType; +import seedu.ravi.data.StateManager; + +import java.io.IOException; +import java.util.EmptyStackException; + +import static seedu.ravi.util.Message.MESSAGE_UNDO_AT_BEGINNING; +import static seedu.ravi.util.Message.MESSAGE_UNDO_SUCCESS; + +public class UndoCommand extends Command { + public static final String COMMAND_WORD = "undo"; + public static final String HELP = "Undo last action." + + "\n\t@|bold,blue,BG_BLACK Format:|@ " + COMMAND_WORD; + + public UndoCommand() { + this.promptType = PromptType.EDIT; + } + + @Override + public CommandResult execute() { + try { + String lastCommand = StateManager.undo(); + return new CommandResult(String.format(MESSAGE_UNDO_SUCCESS, lastCommand)); + } catch (EmptyStackException | IOException e) { + return new CommandResult(MESSAGE_UNDO_AT_BEGINNING, true); + } + } +} diff --git a/src/main/java/seedu/ravi/command/summary/SummaryCommand.java b/src/main/java/seedu/ravi/command/summary/SummaryCommand.java new file mode 100644 index 0000000000..e3172611a0 --- /dev/null +++ b/src/main/java/seedu/ravi/command/summary/SummaryCommand.java @@ -0,0 +1,26 @@ +package seedu.ravi.command.summary; + +import seedu.ravi.command.Command; +import seedu.ravi.command.CommandResult; +import seedu.ravi.data.TaskManager; + +import static seedu.ravi.util.Message.MESSAGE_SUMMARY_PRINTED; + +//@@author amalinasani +public class SummaryCommand extends Command { + public static final String COMMAND_WORD = "summary"; + public static final String HELP = "View task summary." + + "\n\t@|bold,blue,BG_BLACK Format:|@ " + COMMAND_WORD; + + /** + * Lists the tasks from respective lists in summaryLists. + * + * @return CommandResult containing task summary message + */ + @Override + public CommandResult execute() { + String output = TaskManager.getSummary(); + return new CommandResult(MESSAGE_SUMMARY_PRINTED + output); + + } +} diff --git a/src/main/java/seedu/ravi/command/timetable/TimeTableAddCommand.java b/src/main/java/seedu/ravi/command/timetable/TimeTableAddCommand.java new file mode 100644 index 0000000000..81ebe0978b --- /dev/null +++ b/src/main/java/seedu/ravi/command/timetable/TimeTableAddCommand.java @@ -0,0 +1,81 @@ +//@@author aseanseen + +package seedu.ravi.command.timetable; + +import seedu.ravi.command.CommandResult; +import seedu.ravi.command.PromptType; +import seedu.ravi.data.Lesson; +import seedu.ravi.data.TimeTableManager; +import seedu.ravi.exception.LessonInvalidTimeException; +import seedu.ravi.exception.LessonOverlapException; +import seedu.ravi.exception.ModuleNotFoundException; +import seedu.ravi.exception.RepeatFrequencyInvalidException; + +import static seedu.ravi.util.ExceptionMessage.MESSAGE_LESSON_INVALID_TIME; +import static seedu.ravi.util.ExceptionMessage.MESSAGE_LESSON_OVERLAP; +import static seedu.ravi.util.ExceptionMessage.MESSAGE_REPEAT_FREQUENCY_UNKNOWN; +import static seedu.ravi.util.ExceptionMessage.MESSAGE_MODULE_NOT_FOUND; +import static seedu.ravi.util.Message.MESSAGE_ADD_LESSON_SUCCESS; + +public class TimeTableAddCommand extends TimeTableCommand { + private final Lesson newLesson; + private final int repeatFreq; + + public TimeTableAddCommand(Lesson newLesson, int repeatFreq) { + this.newLesson = newLesson; + this.repeatFreq = repeatFreq; + setPromptType(PromptType.EDIT); + } + + /** + * Method runs during execution. Adds the lesson to the timetable. + * + * @throws LessonInvalidTimeException + * When the lesson overlaps with an existing lesson. + * @throws RepeatFrequencyInvalidException + * When the repeat parameter given by the user is not from 0 - 3. + * @throws ModuleNotFoundException + * When the module associated with the Lesson to be added is not in the module list. + * @throws LessonOverlapException + * When the Lesson to be added overlaps with an existing lesson. + */ + public void addLessonToTimeTable() throws LessonInvalidTimeException, RepeatFrequencyInvalidException, + ModuleNotFoundException, LessonOverlapException { + if (repeatFreq < 0 || repeatFreq > 3) { + throw new RepeatFrequencyInvalidException(); + } + TimeTableManager.addLesson(newLesson, repeatFreq); + } + + public String parseRepeatFreq() { + switch (repeatFreq) { + case 0: + return "this week only."; + case 1: + return "every week."; + case 2: + return "every even week."; + case 3: + return "every odd week."; + default: + return "error!"; + } + } + + @Override + public CommandResult execute() { + try { + addLessonToTimeTable(); + return new CommandResult( + String.format(MESSAGE_ADD_LESSON_SUCCESS, newLesson.toString(), parseRepeatFreq())); + } catch (LessonInvalidTimeException e) { + return new CommandResult(MESSAGE_LESSON_INVALID_TIME, true); + } catch (RepeatFrequencyInvalidException e) { + return new CommandResult(MESSAGE_REPEAT_FREQUENCY_UNKNOWN, true); + } catch (ModuleNotFoundException e) { + return new CommandResult(MESSAGE_MODULE_NOT_FOUND, true); + } catch (LessonOverlapException e) { + return new CommandResult(String.format(MESSAGE_LESSON_OVERLAP, e.overlapLessonStr), true); + } + } +} diff --git a/src/main/java/seedu/ravi/command/timetable/TimeTableCommand.java b/src/main/java/seedu/ravi/command/timetable/TimeTableCommand.java new file mode 100644 index 0000000000..3d1039eba0 --- /dev/null +++ b/src/main/java/seedu/ravi/command/timetable/TimeTableCommand.java @@ -0,0 +1,48 @@ +//@@author aseanseen + +package seedu.ravi.command.timetable; + +import seedu.ravi.command.Command; +import seedu.ravi.ui.TextUi; + +public abstract class TimeTableCommand extends Command { + public static final String COMMAND_WORD = "timetable"; + public static final String TIMETABLE_DAY_VIEW_FORMAT = COMMAND_WORD + " -day"; + public static final String TIMETABLE_WEEK_VIEW_FORMAT = COMMAND_WORD + " -week"; + public static final String TIMETABLE_LESSON_ADD_USER_FORMAT = COMMAND_WORD + + " -add ... " + + "\n\t\t... "; + public static final String TIMETABLE_LESSON_DELETE_USER_FORMAT = COMMAND_WORD + " -del "; + public static final String TIMETABLE_LESSON_FILTER_USER_FORMAT = COMMAND_WORD + + " -filter ... " + + "\n\t\t... "; + public static final String FORMAT = TIMETABLE_LESSON_ADD_USER_FORMAT + + "\n" + TIMETABLE_LESSON_DELETE_USER_FORMAT + + "\n" + TIMETABLE_DAY_VIEW_FORMAT + + "\n" + TIMETABLE_WEEK_VIEW_FORMAT; + public static final String HELP = + "View day's timetable" + + "\n\t@|bold,blue,BG_BLACK Format:|@ " + TIMETABLE_DAY_VIEW_FORMAT + + "\n\nView week's timetable" + + "\n\t@|bold,blue,BG_BLACK Format:|@ " + TIMETABLE_WEEK_VIEW_FORMAT + + "\n\nAdd a lesson to the timetable." + + "\n\t@|bold,blue,BG_BLACK Format:|@ " + TIMETABLE_LESSON_ADD_USER_FORMAT + + "\n\t 0: Once" + + "\n\t 1: Once a week" + + "\n\t 2: Even weeks" + + "\n\t 3: Odd weeks" + + "\n\t@|bold,blue,BG_BLACK Example usage:|@ timetable -add CS2101 TUESDAY 0800 1000 LECTURE 1" + + "\n\nRemove a lesson from the timetable." + + "\n\t@|bold,blue,BG_BLACK Format:|@ " + TIMETABLE_LESSON_DELETE_USER_FORMAT + + "\n\t@|bold,blue,BG_BLACK Example usage:|@ timetable -del MONDAY 2" + + "\n\nFilter out lessons from the timetable based on certain criteria." + + "\n\tUse '-' to signify no criteria for that property." + + "\n\t@|bold,blue,BG_BLACK Format:|@ " + TIMETABLE_LESSON_FILTER_USER_FORMAT + + "\n\t@|bold,blue,BG_BLACK Example usage:|@" + + "\n\t\t- Any CS1010 lesson after 1000 on any day:" + + "\n\t\t- timetable -filter CS1010 - 1000 - -" + + "\n\t\t- Any lecture on Monday before 1200:" + + "\n\t\t- timetable -filter - MONDAY - 1200 LECTURE"; + + public static final String PROMPT_HELP = TextUi.getCommandHelpMessage(COMMAND_WORD); +} diff --git a/src/main/java/seedu/ravi/command/timetable/TimeTableDeleteCommand.java b/src/main/java/seedu/ravi/command/timetable/TimeTableDeleteCommand.java new file mode 100644 index 0000000000..21797279a6 --- /dev/null +++ b/src/main/java/seedu/ravi/command/timetable/TimeTableDeleteCommand.java @@ -0,0 +1,46 @@ +//@@author aseanseen + +package seedu.ravi.command.timetable; + +import seedu.ravi.command.CommandResult; +import seedu.ravi.command.PromptType; +import seedu.ravi.data.Lesson; +import seedu.ravi.data.TimeTableManager; + +import java.time.DayOfWeek; + +import static seedu.ravi.util.ExceptionMessage.MESSAGE_LESSON_NOT_FOUND; +import static seedu.ravi.util.Message.MESSAGE_DELETE_LESSON_SUCCESS; + +public class TimeTableDeleteCommand extends TimeTableCommand { + private final DayOfWeek dayOfWeek; + private final int lessonIndexToDelete; + + public TimeTableDeleteCommand(DayOfWeek dayOfWeek, int lessonIndexToDelete) { + this.dayOfWeek = dayOfWeek; + this.lessonIndexToDelete = lessonIndexToDelete; + setPromptType(PromptType.EDIT); + } + + /** + * Method runs during execution. Deletes the lesson from the timetable. + * + * @return + * The deleted lesson object. + * @throws IndexOutOfBoundsException + * When the index given by the user is out of bounds. + */ + public Lesson removeLessonFromTimeTable() throws IndexOutOfBoundsException { + return TimeTableManager.deleteLesson(dayOfWeek, lessonIndexToDelete); + } + + @Override + public CommandResult execute() { + try { + Lesson deletedLesson = removeLessonFromTimeTable(); + return new CommandResult(String.format(MESSAGE_DELETE_LESSON_SUCCESS, deletedLesson.toString())); + } catch (IndexOutOfBoundsException e) { + return new CommandResult(MESSAGE_LESSON_NOT_FOUND, true); + } + } +} diff --git a/src/main/java/seedu/ravi/command/timetable/TimeTableFilterCommand.java b/src/main/java/seedu/ravi/command/timetable/TimeTableFilterCommand.java new file mode 100644 index 0000000000..ef5df9ab97 --- /dev/null +++ b/src/main/java/seedu/ravi/command/timetable/TimeTableFilterCommand.java @@ -0,0 +1,41 @@ +package seedu.ravi.command.timetable; + +import seedu.ravi.command.CommandResult; +import seedu.ravi.data.Lesson; +import seedu.ravi.data.LessonFilter; +import seedu.ravi.data.TimeTableManager; +import seedu.ravi.ui.TextUi; + +import java.time.DayOfWeek; +import java.time.LocalDate; +import java.util.ArrayList; + +import static java.time.temporal.TemporalAdjusters.previousOrSame; +import static seedu.ravi.data.TimeTableManager.getCurrNusWeekStr; + +public class TimeTableFilterCommand extends TimeTableCommand { + private final ArrayList filterList; + private final LocalDate now = LocalDate.now(); + + public TimeTableFilterCommand(ArrayList filterList) { + this.filterList = filterList; + } + + public String getFilteredWeekTimetable() { + ArrayList> weekLessons = TimeTableManager.filterWeekWithFilterList(filterList); + StringBuilder out = new StringBuilder(); + LocalDate dateIterator = now.with(previousOrSame(DayOfWeek.MONDAY)); + out.append("Current NUS Week: " + getCurrNusWeekStr() + "\n"); + for (ArrayList dayLesson : weekLessons) { + out.append(TextUi.printDayTimetable(dateIterator, dayLesson)); + dateIterator = dateIterator.plusDays(1); + } + + return out.toString(); + } + + @Override + public CommandResult execute() { + return new CommandResult(getFilteredWeekTimetable()); + } +} diff --git a/src/main/java/seedu/ravi/command/timetable/TimeTableResetCommand.java b/src/main/java/seedu/ravi/command/timetable/TimeTableResetCommand.java new file mode 100644 index 0000000000..2edfea9d5e --- /dev/null +++ b/src/main/java/seedu/ravi/command/timetable/TimeTableResetCommand.java @@ -0,0 +1,23 @@ +package seedu.ravi.command.timetable; + +import seedu.ravi.command.CommandResult; +import seedu.ravi.command.PromptType; +import seedu.ravi.data.TimeTableManager; + +import static seedu.ravi.util.Message.MESSAGE_TIMETABLE_RESET; + +//@@author amalinasani +public class TimeTableResetCommand extends TimeTableCommand { + public TimeTableResetCommand() { + setPromptType(PromptType.EDIT); + } + + @Override + public CommandResult execute() { + if (TimeTableManager.isInitialised()) { + TimeTableManager.clearTimeTable(); + } + TimeTableManager.initialiseTimetable(); + return new CommandResult(MESSAGE_TIMETABLE_RESET); + } +} diff --git a/src/main/java/seedu/ravi/command/timetable/TimeTableViewCommand.java b/src/main/java/seedu/ravi/command/timetable/TimeTableViewCommand.java new file mode 100644 index 0000000000..7275ea6213 --- /dev/null +++ b/src/main/java/seedu/ravi/command/timetable/TimeTableViewCommand.java @@ -0,0 +1,54 @@ +package seedu.ravi.command.timetable; + +import seedu.ravi.command.CommandResult; +import seedu.ravi.data.Lesson; +import seedu.ravi.ui.TextUi; + +import java.time.DayOfWeek; +import java.time.LocalDate; +import static java.time.temporal.TemporalAdjusters.previousOrSame; +import java.util.ArrayList; + +import static seedu.ravi.data.TimeTableManager.getCurrWeekNum; +import static seedu.ravi.data.TimeTableManager.getCurrNusWeekStr; +import static seedu.ravi.data.TimeTableManager.getSpecificDayLessons; +import static seedu.ravi.data.TimeTableManager.getSpecifiedWeekLessons; + +//@@author amalinasani +public class TimeTableViewCommand extends TimeTableCommand { + private final int numOfDays; + private final LocalDate now = LocalDate.now(); + + public TimeTableViewCommand(int numOfDays) { + this.numOfDays = numOfDays; + } + + public String generateDayTimeTable() { + ArrayList lessonList; + lessonList = getSpecificDayLessons(now.getDayOfWeek()); + return "Current NUS Week: " + getCurrNusWeekStr() + "\n" + TextUi.printDayTimetable(now, lessonList); + } + + public String generateWeekTimeTable() { + int currentWeek = getCurrWeekNum(); + ArrayList> weekLessons = getSpecifiedWeekLessons(currentWeek); + StringBuilder out = new StringBuilder(); + LocalDate dateIterator = now.with(previousOrSame(DayOfWeek.MONDAY)); + out.append("Current NUS Week: " + getCurrNusWeekStr() + "\n"); + for (ArrayList dayLesson : weekLessons) { + out.append(TextUi.printDayTimetable(dateIterator, dayLesson)); + dateIterator = dateIterator.plusDays(1); + } + + return out.toString(); + } + + @Override + public CommandResult execute() { + if (numOfDays == 1) { + return new CommandResult(generateDayTimeTable()); + } else { + return new CommandResult(generateWeekTimeTable()); + } + } +} diff --git a/src/main/java/seedu/ravi/data/Lesson.java b/src/main/java/seedu/ravi/data/Lesson.java new file mode 100644 index 0000000000..7886976eb6 --- /dev/null +++ b/src/main/java/seedu/ravi/data/Lesson.java @@ -0,0 +1,168 @@ +package seedu.ravi.data; + +import seedu.ravi.exception.LessonInvalidTimeException; + +import java.time.DayOfWeek; +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; +import java.util.UUID; + +public class Lesson { + private String moduleCode; + private LessonType lessonType; + private DayOfWeek day; + private LocalTime startTime; + private LocalTime endTime; + private String hiddenId; + + public Lesson(String moduleCode, LessonType lessonType, DayOfWeek day, LocalTime startTime, LocalTime endTime) + throws LessonInvalidTimeException { + if (startTime.isAfter(endTime) || startTime.equals(endTime)) { + throw new LessonInvalidTimeException(); + } + + this.moduleCode = moduleCode; + this.lessonType = lessonType; + this.day = day; + this.startTime = startTime; + this.endTime = endTime; + } + + public String getModuleCode() { + return moduleCode; + } + + public LocalTime getStartTime() { + return startTime; + } + + public LocalTime getEndTime() { + return endTime; + } + + public DayOfWeek getDay() { + return day; + } + + public LessonType getLessonType() { + return lessonType; + } + + /** + * Generates the unique hiddenId for each instance of this Lesson class. + * No two instances of Lesson class should share a hiddenId. + */ + public void generateHiddenId() { + hiddenId = UUID.randomUUID().toString(); + } + + public String getHiddenId() { + return hiddenId; + } + + /** + * Checks if 'this' lesson is after otherLesson. + * @param otherLesson + * The other lesson object to check against + * @return + * Whether 'this' lesson is after otherLesson + */ + public boolean isAfter(Lesson otherLesson) { + return otherLesson.getEndTime().isBefore(startTime) || otherLesson.getEndTime().equals(startTime); + } + + /** + * Checks if 'this' lesson is before otherLesson. + * @param otherLesson + * The other lesson object to check against + * @return + * Whether 'this' lesson is before otherLesson + */ + public boolean isBefore(Lesson otherLesson) { + return otherLesson.getStartTime().isAfter(endTime) || otherLesson.getStartTime().equals(endTime); + } + + /** + * Checks for time period overlap with the specified Lesson. + * + * @param otherLesson + * The specified lesson + * @return + * Whether their start and end times overlap + */ + public boolean checkOverlap(Lesson otherLesson) { + if (otherLesson.getDay() != day) { + return false; + } + // lessons are constructed with valid start-end times + // for NO OVERLAP, (isAfter ^ isBefore) is true + // so OVERLAP is just (isAfter == isBefore) + return isAfter(otherLesson) == isBefore(otherLesson); + } + + /** + * Generates string based on lesson type. + * + * @return + * String of lesson type + */ + public String getLessonTypeString() { + switch (lessonType) { + case LECTURE: + return "Lecture"; + case TUTORIAL: + return "Tutorial"; + case LAB: + return "Lab"; + case SEMINAR: + return "Seminar"; + case RECITATION: + return "Recitation"; + default: + return "Session"; + } + } + + /** + * Creates string representation of lesson. + * e.g. CS1010 Lecture: MONDAY 1400-1500 + * + * @return + * String representation of lesson + */ + public String toString() { + DateTimeFormatter time = DateTimeFormatter.ofPattern("Hmm"); + return String.format("%s %s: %s %s-%s", moduleCode, getLessonTypeString(), + day.toString(), startTime.format(time), endTime.format(time)); + } + + // vvv Required for fastJSON, not used otherwise vvv + public Lesson() { + + } + + public void setModuleCode(String moduleCode) { + this.moduleCode = moduleCode; + } + + public void setStartTime(LocalTime startTime) { + this.startTime = startTime; + } + + public void setEndTime(LocalTime endTime) { + this.endTime = endTime; + } + + public void setDay(DayOfWeek day) { + this.day = day; + } + + public void setLessonType(LessonType lessonType) { + this.lessonType = lessonType; + } + + public void setHiddenId(String hiddenId) { + this.hiddenId = hiddenId; + } + // ^^^ Required for fastJSON, not used otherwise ^^^ +} diff --git a/src/main/java/seedu/ravi/data/LessonFilter.java b/src/main/java/seedu/ravi/data/LessonFilter.java new file mode 100644 index 0000000000..5dd84f2aff --- /dev/null +++ b/src/main/java/seedu/ravi/data/LessonFilter.java @@ -0,0 +1,5 @@ +package seedu.ravi.data; + +public interface LessonFilter { + boolean filter(Lesson l); +} diff --git a/src/main/java/seedu/ravi/data/LessonManager.java b/src/main/java/seedu/ravi/data/LessonManager.java new file mode 100644 index 0000000000..b7aacf5e13 --- /dev/null +++ b/src/main/java/seedu/ravi/data/LessonManager.java @@ -0,0 +1,159 @@ +package seedu.ravi.data; + +import seedu.ravi.RaviLogger; +import seedu.ravi.exception.LessonInvalidTimeException; +import seedu.ravi.exception.LessonNotFoundException; + +import java.time.DayOfWeek; +import java.util.ArrayList; +import java.util.HashMap; + +public class LessonManager { + private HashMap> lessonMap = new HashMap<>(); + private static final RaviLogger logger = new RaviLogger(LessonManager.class.getName()); + + /** + * Initialise the lessonMap upon construction. + */ + public LessonManager() { + for (DayOfWeek eachDay : DayOfWeek.values()) { + lessonMap.put(eachDay, new ArrayList<>()); + } + } + + /** + * Inserts a Lesson object in the correct position in the correct ArrayList in lessonMap, based on its day and time. + * + * @param newLesson + * The new Lesson object + * @throws LessonInvalidTimeException + * When the new lesson overlaps with an existing lesson + */ + public void addLesson(Lesson newLesson) throws LessonInvalidTimeException { + DayOfWeek lessonDay = newLesson.getDay(); + logger.getLogger().info("Trying to add lesson: " + newLesson.toString()); + + // if lessonMap is not initialised yet... + if (lessonMap.keySet().size() == 0) { + logger.getLogger().info("Adding to uninitialised lessonMap"); + lessonMap.get(lessonDay).add(newLesson); + return; + } + + int indexToInsertNewLesson = -1; + for (int i = 0; i < lessonMap.get(lessonDay).size(); i++) { + Lesson eachLesson = lessonMap.get(lessonDay).get(i); + if (newLesson.checkOverlap(eachLesson)) { + logger.getLogger().warning("New lesson overlaps with the lesson: " + eachLesson.toString()); + throw new LessonInvalidTimeException(); + } + // insert before the lesson which starts right after newLesson + // each day ArrayList in lessonMap is hence always sorted due to addLesson's logic + if (eachLesson.isAfter(newLesson)) { + logger.getLogger().info("Lesson inserted at index " + i); + indexToInsertNewLesson = i; + break; + } + } + + if (indexToInsertNewLesson == -1) { // lesson is the latest lesson in the day + logger.getLogger().info("Lesson inserted at index " + lessonMap.get(lessonDay).size()); + lessonMap.get(lessonDay).add(newLesson); + } else { + logger.getLogger().info("Lesson inserted at index " + indexToInsertNewLesson); + lessonMap.get(lessonDay).add(indexToInsertNewLesson, newLesson); + } + } + + // required for fastJSON, not used otherwise + public void addLesson(DayOfWeek day, Lesson lesson) { + lessonMap.get(day).add(lesson); + } + + /** + * Removes the lesson at lessonIndex on the given day. + * + * @param day + * The specified day + * @param lessonIndex + * The index of the lesson to be removed + * @throws LessonNotFoundException + * When the lesson to be removed does not exist in the lesson map + */ + public void removeLesson(DayOfWeek day, int lessonIndex) throws LessonNotFoundException { + if (!lessonMap.containsKey(day)) { + logger.getLogger().warning("lessonMap does not contain day: " + day); + throw new LessonNotFoundException(); + } + if (lessonIndex < 0 || lessonIndex >= lessonMap.get(day).size()) { + logger.getLogger().warning("The lesson index is out of bounds; size is: " + lessonMap.get(day).size()); + throw new LessonNotFoundException(); + } + lessonMap.get(day).remove(lessonIndex); + } + + /** + * Removes the lesson at lessonIndex on the given day. + * + * @param day + * The specified day + * @param id + * The hiddenId of the lesson to be removed + */ + public void removeLessonById(DayOfWeek day, String id) { + if (!lessonMap.containsKey(day)) { + logger.getLogger().warning("lessonMap does not contain day: " + day); + return; + } + for (int i = 0; i < lessonMap.get(day).size(); i++) { + if (lessonMap.get(day).get(i).getHiddenId().equals(id)) { + lessonMap.get(day).remove(i); + logger.getLogger().info("Lesson removed at index: " + i); + return; + } + } + } + + /** + * Returns the ArrayList of lessons on the given day. + * + * @param day + * The specified day + * @return + * The ArrayList of lessons on that day + */ + public ArrayList getDayLessonList(DayOfWeek day) { + return lessonMap.get(day); + } + + public int getLessonCountOnDay(DayOfWeek day) { + return lessonMap.get(day).size(); + } + + public int countTotalLessons() { + int numLessons = 0; + for (ArrayList eachDay : lessonMap.values()) { + numLessons += eachDay.size(); + } + return numLessons; + } + + /** + * Resets lessonMap to blank state. + */ + public void clearAllLessons() { + for (DayOfWeek eachDay : DayOfWeek.values()) { + lessonMap.put(eachDay, new ArrayList<>()); + } + } + + // required for fastJSON, not used otherwise + public HashMap> getLessonMap() { + return lessonMap; + } + + // required for fastJSON, not used otherwise + public void setLessonMap(HashMap> lessonMap) { + this.lessonMap = lessonMap; + } +} diff --git a/src/main/java/seedu/ravi/data/LessonType.java b/src/main/java/seedu/ravi/data/LessonType.java new file mode 100644 index 0000000000..351e450695 --- /dev/null +++ b/src/main/java/seedu/ravi/data/LessonType.java @@ -0,0 +1,10 @@ +package seedu.ravi.data; + +public enum LessonType { + TUTORIAL, + LECTURE, + SEMINAR, + LAB, + RECITATION, + SESSION +} diff --git a/src/main/java/seedu/ravi/data/Module.java b/src/main/java/seedu/ravi/data/Module.java new file mode 100644 index 0000000000..19a3dfab17 --- /dev/null +++ b/src/main/java/seedu/ravi/data/Module.java @@ -0,0 +1,90 @@ +package seedu.ravi.data; + +import seedu.ravi.directory.Directory; +import seedu.ravi.directory.DirectoryLevel; + +public class Module extends Directory { + private String moduleCode; + private String grade; + private double moduleCredit; + private String title; + + public Module() { + } + + public Module(String moduleCode) { + this.moduleCode = moduleCode; + } + + public String getModuleCode() { + return moduleCode; + } + + public void setModuleCode(String moduleCode) { + this.moduleCode = moduleCode; + } + + public String getModuleGrade() { + if (grade == null) { + return "No grade yet"; + } + return grade; + } + + public void setModuleGrade(String grade) { + this.grade = grade; + } + + public double getModuleCredit() { + return moduleCredit; + } + + public void setModuleCredit(double moduleCredit) { + this.moduleCredit = moduleCredit; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public boolean isSameModule(Module checkModule) { + String moduleCode = checkModule.getModuleCode(); + String moduleTitle = checkModule.getTitle(); + return this.moduleCode.equalsIgnoreCase(moduleCode) && this.title.equalsIgnoreCase(moduleTitle); + } + + public String toString() { + String format = "%s: %s (%sMC) (Grade: %s)"; + return String.format(format, getModuleCode(), getTitle(), getModuleCredit(), getModuleGrade()); + } + + @Override + public Directory getParent() { + return null; + } + + @Override + public DirectoryLevel getLevel() { + return null; + } +} + +//import seedu.ravi.directory.Directory; +//import seedu.ravi.directory.DirectoryLevel; +// +//public class Module extends Directory { +// +// @Override +// public Directory getParent() { +// return null; +// } +// +// @Override +// public DirectoryLevel getLevel() { +// return null; +// } +//} diff --git a/src/main/java/seedu/ravi/data/ModuleManager.java b/src/main/java/seedu/ravi/data/ModuleManager.java new file mode 100644 index 0000000000..6845c636df --- /dev/null +++ b/src/main/java/seedu/ravi/data/ModuleManager.java @@ -0,0 +1,223 @@ +package seedu.ravi.data; + +import seedu.ravi.RaviLogger; +import seedu.ravi.exception.DuplicateModuleException; +import seedu.ravi.exception.ModuleNotFoundException; +import seedu.ravi.exception.ModuleNotProvidedException; +import seedu.ravi.ui.TextUi; + +import java.util.HashMap; + + +public class ModuleManager { + private static final RaviLogger logger = new RaviLogger(ModuleManager.class.getName()); + + private static HashMap modulesMap = new HashMap<>(); + // modulesMap is the main module list. Maps module code to module object. + private static HashMap nusModsMap = new HashMap<>(); + // nusModsMap is the module list containing the Module objects created from NUSMods' JSON file of modules. + + /** + * Finds a module with the specified module code in the Module List. + * + * @param moduleCode + * The module code of the module to be found + * @return + * The found module with the specified module code + * @throws ModuleNotFoundException + * If the module is not found in the Module List + */ + public static Module getModule(String moduleCode) throws ModuleNotFoundException { + logger.getLogger().info("Retrieving module with code: " + moduleCode); + for (Module module : modulesMap.values()) { + if (module.getModuleCode().equalsIgnoreCase(moduleCode)) { + return module; + } + } + logger.getLogger().warning("Can't retrieve module because it doesn't exist!"); + throw new ModuleNotFoundException(); + } + + /** + * Edits a module in the Module List by replacing the old module object with a new one. + * + * @param newModuleCode + * The new module code of the new module that replaces the old one. + * @param oldModuleCode + * The module code of the module to be edited. + * @return + * The module object after editing. + * @throws ModuleNotProvidedException + * If there is no module with the new module code offered by NUS + * @throws DuplicateModuleException + * If there are duplicate modules with the same module code as the new module code in the Module List + * @throws ModuleNotFoundException + * If the old module is not found + */ + public static Module edit(String newModuleCode, String oldModuleCode) + throws ModuleNotProvidedException, DuplicateModuleException, ModuleNotFoundException { + logger.getLogger().info("Editing module at old module code: " + oldModuleCode); + if (!doesContainMod(oldModuleCode)) { + logger.getLogger().warning("Old module code not found!"); + throw new ModuleNotFoundException(); + } + add(newModuleCode); + Module oldModule = getModule(oldModuleCode); + if (oldModule.getModuleCredit() != 0 && oldModule.getModuleGrade() != null) { + grade(newModuleCode, oldModule.getModuleGrade(), oldModule.getModuleCredit()); + } + delete(oldModuleCode); + return getModule(newModuleCode); + } + + /** + * Checks if the module to be graded is in the moduleMap and assigns the grade to the module. + * + * @param moduleCode + * Module code of the module to be graded + * @param grade + * The grade to be assigned + * @param moduleCredit + * The module's assigned module credit + * @throws ModuleNotFoundException + * If there is no such module in the user's module list + */ + public static void grade(String moduleCode, String grade, double moduleCredit) throws ModuleNotFoundException { + if (doesContainMod(moduleCode)) { + getModule(moduleCode).setModuleGrade(grade); + getModule(moduleCode).setModuleCredit(moduleCredit); + } else { + throw new ModuleNotFoundException(); + } + } + + /** + * Checks for duplicates of the same module code in the Module List. + * @param moduleCode + * The module code to check + * @return + * TRUE if there exists a duplicate, and FALSE otherwise + */ + public static boolean doesContainMod(String moduleCode) { + for (String eachCode : modulesMap.keySet()) { + if (eachCode.equalsIgnoreCase(moduleCode)) { + return true; + } + } + return false; + } + + /** + * Adds a module to the Module List. Uses the module code to grab the module object from the NUSMods list. + * @param moduleCode + * The module code string of the module to add to the module list + * @throws DuplicateModuleException + * When the module to be added already exists in the module list + * @throws ModuleNotProvidedException + * When the module to be added is not a valid NUS module + */ + public static void add(String moduleCode) throws DuplicateModuleException, ModuleNotProvidedException { + logger.getLogger().info("Adding module with code: " + moduleCode); + if (doesContainMod(moduleCode)) { + logger.getLogger().warning("Can't add module because it already exists!"); + throw new DuplicateModuleException(); + } + Module verifiedNusMod = getNusModule(moduleCode); + modulesMap.put(moduleCode, verifiedNusMod); + } + + /** + * Removes a module from the Module List using the module code. + * @param moduleCode + * The module code of the module to remove from the module list + * @throws ModuleNotFoundException + * When the module to be deleted is not in the module list + */ + public static void delete(String moduleCode) throws ModuleNotFoundException { + logger.getLogger().info("Deleting module with code: " + moduleCode); + if (!doesContainMod(moduleCode)) { + logger.getLogger().warning("Can't delete module because it doesn't exist!"); + throw new ModuleNotFoundException(); + } + modulesMap.remove(moduleCode); + } + + /** + * Finds a module with the specified module code in the NUSMods Module List. + * + * @param moduleCode + * The module code of the module to be found + * @return + * The found module with the specified module code + * @throws ModuleNotProvidedException + * If the module is not found in the Module List + */ + public static Module getNusModule(String moduleCode) throws ModuleNotProvidedException { + for (Module module : nusModsMap.values()) { + if (module.getModuleCode().equalsIgnoreCase(moduleCode)) { + return module; + } + } + throw new ModuleNotProvidedException(); + } + + public static String[] getModCodeList() { + return modulesMap.keySet().toArray(new String[0]); + } + + + public static String[] getNusModCodeList() { + return nusModsMap.keySet().toArray(new String[0]); + } + + //@@author amalinasani + /** + * List modules in the module map. + * + * @return + * The formatted module list from TextUi or null if list is empty + */ + public static String list() { + if (modulesMap.size() > 0) { + return TextUi.getIndexModuleList(modulesMap); + } else { + return null; + } + } + + //@@author + /** + * Loads the file loaded module map into ModuleManager's own module map. + * + * @param loadedModulesMap the loaded module map from file + */ + public static void loadMods(HashMap loadedModulesMap) { + modulesMap = loadedModulesMap; + } + + /** + * Loads the file loaded module map into ModuleManager's own module map. + * + * @param loadedModulesMap the loaded module map from file + */ + public static void loadNusMods(HashMap loadedModulesMap) { + nusModsMap = loadedModulesMap; + } + + /** + * Clears all modules in modulesMap. + */ + public static void clearModules() { + modulesMap = new HashMap<>(); + } + + /** + * Returns the modules in the system. + * + * @return modulesMap + */ + public static HashMap getModulesMap() { + return modulesMap; + } + +} diff --git a/src/main/java/seedu/ravi/data/State.java b/src/main/java/seedu/ravi/data/State.java new file mode 100644 index 0000000000..d23cc40582 --- /dev/null +++ b/src/main/java/seedu/ravi/data/State.java @@ -0,0 +1,34 @@ +package seedu.ravi.data; + +import java.util.ArrayList; + +public class State { + private final String encodedSavedList; + private final String encodedSavedMap; + private final ArrayList commandArrayList; + private final String encodedTimeTable; + + public State(String encodedSavedList, String encodedSavedMap, ArrayList commandArrayList, + String encodedTimeTable) { + this.encodedSavedList = encodedSavedList; + this.encodedSavedMap = encodedSavedMap; + this.commandArrayList = commandArrayList; + this.encodedTimeTable = encodedTimeTable; + } + + public String getEncodedSavedList() { + return encodedSavedList; + } + + public String getEncodedSavedMap() { + return encodedSavedMap; + } + + public ArrayList getEditTypeCommandArrayList() { + return commandArrayList; + } + + public String getEncodedTimeTable() { + return encodedTimeTable; + } +} diff --git a/src/main/java/seedu/ravi/data/StateManager.java b/src/main/java/seedu/ravi/data/StateManager.java new file mode 100644 index 0000000000..f31680120d --- /dev/null +++ b/src/main/java/seedu/ravi/data/StateManager.java @@ -0,0 +1,217 @@ +package seedu.ravi.data; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.EmptyStackException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Stack; + +public class StateManager { + private static Stack undoStack = new Stack<>(); + private static Stack redoStack = new Stack<>(); + private static ArrayList editTypeCommandArrayList = new ArrayList<>(); + + /** + * Initialises the screen shot manager with its first screen shot of the starting list. + */ + public static void initialise() { + //for Junit Test only + undoStack = new Stack<>(); + redoStack = new Stack<>(); + + State screenShot = toJson(); + assert undoStack.isEmpty() : "Undo stack should be empty!"; + assert redoStack.isEmpty() : "Redo stack should be empty!"; + undoStack.push(screenShot); + } + + /** + * Returns and pops the top state. + * + * @return the last state. + * @throws EmptyStackException stack is empty. + */ + private static State popPreviousScreenShot() throws EmptyStackException { + // There should be at least 2 screen shots to allow undo + if (undoStack.size() < 2) { + throw new EmptyStackException(); + } + var currentState = undoStack.pop(); + editTypeCommandArrayList = currentState.getEditTypeCommandArrayList(); + redoStack.push(currentState); + return undoStack.peek(); + } + + /** + * Returns the last state without pop it. + * + * @return the last state. + */ + private static State peekPreviousScreenShot() { + return undoStack.peek(); + } + + /** + * Reverts to the previous changed state of the list. + * + * @return The last edit type command entered by the user. + * @throws IOException exception is thrown when error occurred during IO operation. + * @throws EmptyStackException exception is thrown when user trying to undo at the initial state. + */ + public static String undo() throws IOException, EmptyStackException { + var previousState = popPreviousScreenShot(); + + var encodedSavedList = previousState.getEncodedSavedList(); + var encodedSavedMap = previousState.getEncodedSavedMap(); + var encodedTimeTable = previousState.getEncodedTimeTable(); + + var stream1 = new ByteArrayInputStream(encodedSavedList.getBytes()); + var bufferedReader1 = new BufferedReader(new InputStreamReader(stream1)); + + var stream2 = new ByteArrayInputStream(encodedSavedMap.getBytes()); + var bufferedReader2 = new BufferedReader(new InputStreamReader(stream2)); + + var stream3 = new ByteArrayInputStream(encodedTimeTable.getBytes()); + var bufferedReader3 = new BufferedReader(new InputStreamReader(stream3)); + + Task[] readList1 = new Gson().fromJson(bufferedReader1, Task[].class); + TaskManager.loadTasks(getDecodedTaskList(readList1)); + + Type type = new TypeToken>(){}.getType(); + HashMap map = new Gson().fromJson(bufferedReader2, type); + ModuleManager.loadMods(map); + + Type type2 = new TypeToken(){}.getType(); + TimeTable map2 = new Gson().fromJson(bufferedReader3, type2); + TimeTableManager.loadTimeTable(map2); + + bufferedReader1.close(); + bufferedReader2.close(); + bufferedReader3.close(); + + String lastCommand = editTypeCommandArrayList.remove(editTypeCommandArrayList.size() - 1); + String[] arrOfLastCommand = lastCommand.split("\\s+"); + String out; + // Special case to find tasks + if (arrOfLastCommand[1].equals("-t")) { + out = String.join(" ", arrOfLastCommand[0], arrOfLastCommand[1]); + String substring = lastCommand.substring(lastCommand.indexOf(arrOfLastCommand[2])); + out += " " + substring; + } else { + out = String.join(" ", arrOfLastCommand); + } + return out; + } + + /** + * Saves the moduleList as a string if it was changed. + * + * @param editTypeCommand The edit type command entered by the user. + */ + public static void saveState(String editTypeCommand) { + editTypeCommandArrayList.add(editTypeCommand); + State screenShot = toJson(); + undoStack.push(screenShot); + /* + if (getUndoStackSize() == 0) { + undoStack.push(screenShot); + return; + } + var previousScreenShot = peekPreviousScreenShot(); + var previousEncodedSavedList = previousScreenShot.getEncodedSavedList(); + if (!previousEncodedSavedList.equals(encodedSavedList)) { + undoStack.push(screenShot); + if (!redoStack.isEmpty()) { + redoStack.clear(); + } + } + + */ + } + + private static State toJson() { + var gson = new GsonBuilder().create(); + var encodedSavedList = gson.toJson(TaskManager.getTaskList()); + var encodedSavedMap = gson.toJson(ModuleManager.getModulesMap()); + var encodedSavedTimeTable = gson.toJson(TimeTableManager.getTimeTable()); + return new State(encodedSavedList, encodedSavedMap, editTypeCommandArrayList, encodedSavedTimeTable); + } + + /** + * Return the task list read from Json file. + * + * @param readList the task array read from Json file + * @return the task list parsed from readList array + */ + public static ArrayList getDecodedTaskList(Task[] readList) { + ArrayList tempTaskList = new ArrayList<>(); + for (Task task : readList) { + tempTaskList.add(new Task(task.getName(), task.retrieveDeadline(), task.getStatus())); + } + return tempTaskList; + } + + /* + + + /** + * Return the number of states store in th stack. + * + * @return the stack size + */ + private static int getUndoStackSize() { + return undoStack.size(); + } + + /** + * Return the task list read from Json file. + * + * @param readList the module map read from Json file + * @return the task list parsed from readList array + */ + public static ArrayList getDecodedModuleList(Module[] readList) { + ArrayList temp = new ArrayList<>(); + for (Module module : readList) { + temp.add(new Module(module.getModuleCode())); + } + return temp; + } + + /** + * Parse map to list. + * + * @return module list + */ + public static ArrayList parseModuleList() { + ArrayList moduleArrayList = new ArrayList<>(); + Iterator it = ModuleManager.getModulesMap().keySet().iterator(); + while (it.hasNext()) { + String key = it.next(); + moduleArrayList.add(ModuleManager.getModulesMap().get(key)); + } + return moduleArrayList; + } + + /** + * Parse list to map. + * @param moduleArrayList module list + * @return module map + */ + public static HashMap parseModuleMap(ArrayList moduleArrayList) { + HashMap map = new HashMap<>(); + for (Module module: moduleArrayList + ) { + map.put(module.getModuleCode(), module); + } + return map; + } +} diff --git a/src/main/java/seedu/ravi/data/Task.java b/src/main/java/seedu/ravi/data/Task.java new file mode 100644 index 0000000000..e74db29878 --- /dev/null +++ b/src/main/java/seedu/ravi/data/Task.java @@ -0,0 +1,111 @@ +package seedu.ravi.data; + +import seedu.ravi.util.Message; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +public class Task { + private String name; + private LocalDateTime deadline = null; + private boolean isDone; + + public Task() { + } + + public Task(String name) { + this.name = name; + this.isDone = false; + } + + public Task(String name, boolean isDone) { + this.name = name; + this.isDone = isDone; + } + + public Task(String name, LocalDateTime dateTimeOfDeadline) { + this.name = name; + this.deadline = dateTimeOfDeadline; + this.isDone = false; + } + + public Task(String name, LocalDateTime dateTimeOfDeadline, boolean isDone) { + this.name = name; + this.deadline = dateTimeOfDeadline; + this.isDone = isDone; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public boolean getStatus() { + return isDone; + } + + public void setStatus(boolean status) { + this.isDone = status; + } + + // For use within codebase + public LocalDateTime retrieveDeadline() { + return deadline; + } + + // For FastJSON use + public LocalDateTime getDeadline() { + if (deadline == null) { + return LocalDateTime.of(1, 1, 1, 0, 0); + } + return deadline; + } + + // For FastJSON use + public void setDeadline(LocalDateTime deadline) { + if (deadline.isEqual(LocalDateTime.of(1, 1, 1, 0, 0))) { + this.deadline = null; + } else { + this.deadline = deadline; + } + } + + //@@author amalinasani + public String generateStatusIcon() { + if (this.isDone) { + return Message.ICON_DONE; + } else { + return Message.ICON_NOT_DONE; + } + } + + //@@author + public String toString() { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("hh:mma, EEEE, dd MMM yyyy"); + if (retrieveDeadline() == null) { + return getName() + " [" + generateStatusIcon() + "]"; + } else { + return getName() + " [" + generateStatusIcon() + "]," + " by " + retrieveDeadline().format(formatter); + } + } +} + + + +//import seedu.ravi.directory.Directory; +//import seedu.ravi.directory.DirectoryLevel; +// +//public class Task extends Directory { +// @Override +// public Directory getParent() { +// return null; +// } +// +// @Override +// public DirectoryLevel getLevel() { +// return null; +// } +//} diff --git a/src/main/java/seedu/ravi/data/TaskManager.java b/src/main/java/seedu/ravi/data/TaskManager.java new file mode 100644 index 0000000000..b526975761 --- /dev/null +++ b/src/main/java/seedu/ravi/data/TaskManager.java @@ -0,0 +1,215 @@ +package seedu.ravi.data; + +import seedu.ravi.exception.DataNotFoundException; +import seedu.ravi.ui.TextUi; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Comparator; + +public class TaskManager { + private static ArrayList tasksList = new ArrayList<>(); // Main task list. + + /** + * Finds a task with the specified task index (id) in the Task List. + * + * @param taskId + * The index of the task to be found + * @return + * The found task with the specified task index + * @throws TaskNotFoundException + * If the task is not found in the Task List + */ + public static Task getTask(int taskId) throws TaskNotFoundException { + if (taskId < 0 || taskId > tasksList.size() - 1) { + throw new TaskNotFoundException(); + } + return tasksList.get(taskId); + } + + /** + * Edits a task in the Task List. + * + * @param taskId + * The index of the task in the Task List + * @param editedTaskDesc + * The edited task description string + * @return + * The task object after editing + * @throws TaskNotFoundException + * If there is no task found with that ID + */ + public static Task edit(int taskId, String editedTaskDesc) throws TaskNotFoundException { + if (taskId < 0 || taskId > tasksList.size() - 1) { + throw new TaskNotFoundException(); + } + tasksList.get(taskId).setName(editedTaskDesc); + return tasksList.get(taskId); + } + + /** + * Edits a task in the Task List. + * + * @param taskId + * The index of the task in the Task List. + * @param editedTaskDesc + * The edited task description string + * @param deadline + * The edited deadline + * @return + * The task object after editing + * @throws TaskNotFoundException + * If there is no task found with that ID + */ + public static Task edit(int taskId, String editedTaskDesc, LocalDateTime deadline) throws TaskNotFoundException { + if (taskId < 0 || taskId > tasksList.size() - 1) { + throw new TaskNotFoundException(); + } + tasksList.get(taskId).setName(editedTaskDesc); + tasksList.get(taskId).setDeadline(deadline); + return tasksList.get(taskId); + } + + /** + * Adds a task to the Task List. + * @param newTask + * The task object to add to the task list + */ + public static void add(Task newTask) { + tasksList.add(newTask); + } + + /** + * Removes a task from the Task List using the task index (id). + * @param taskId + * The index of the task to be deleted + * @throws TaskNotFoundException + * When the task to be removed is not in the task list + */ + public static void delete(int taskId) throws TaskNotFoundException { + if (taskId < 0 || taskId > tasksList.size() - 1) { + throw new TaskNotFoundException(); + } + tasksList.remove(taskId); + } + + //@@author amalinasani + /** + * Marks a task from the Task List as done using the task index (id). + * @param taskId + * The index of the task to be marked done + * @return + * The task object marked as done + * @throws TaskNotFoundException + * When the task to be removed is not in the task list + */ + public static Task done(int taskId) throws TaskNotFoundException { + Task task; + if (taskId < 0 || taskId > tasksList.size() - 1) { + throw new TaskNotFoundException(); + } + task = getTask(taskId); + task.setStatus(true); + return task; + } + + //@@author + /** + * Generate an ordered ArrayList of ArrayLists. + * First ArrayList contains a list of uncompleted tasks with deadlines, sorted by deadlines. + * Second ArrayList contains a list of uncompleted tasks without deadlines. + * Last ArrayList contains a list of completed tasks. + * + * @return + * The ArrayList of ArrayLists mentioned above. + */ + public static ArrayList> summary() { + ArrayList> summaryLists = new ArrayList<>(); + ArrayList incompleteTasksDated = new ArrayList<>(); + ArrayList incompleteTasksUndated = new ArrayList<>(); + ArrayList completedTasks = new ArrayList<>(); + + for (Task eachTask : tasksList) { + if (eachTask.getStatus()) { + completedTasks.add(eachTask); + } else if (eachTask.retrieveDeadline() == null) { + incompleteTasksUndated.add(eachTask); + } else { + incompleteTasksDated.add(eachTask); + } + } + + Comparator compareByDeadline = Comparator.comparing(Task::retrieveDeadline); + incompleteTasksDated.sort(compareByDeadline); + + // Do not change the adding order! + summaryLists.add(incompleteTasksDated); + summaryLists.add(incompleteTasksUndated); + summaryLists.add(completedTasks); + return summaryLists; + } + + //@@author amalinasani + /** + * Gets Task summary. + * + * @return + * The message containing the task summary + */ + public static String getSummary() { + ArrayList> summaryLists = summary(); + return TextUi.getSummaryList(summaryLists); + } + + /** + * Gets Task List. + * + * @return tasksList + */ + public static ArrayList getTaskList() { + return tasksList; + } + + /** + * Prints all tasks in task list. + * + * @return + * The formatted task list from TextUi or null if list is empty + */ + public static String list() { + if (getTaskList().size() > 0) { + return TextUi.getIndexTaskList(tasksList); + } else { + return null; + } + } + + //@@author + /** + * Loads the file loaded task list into TaskManager's own task list. + * + * @param loadedTasksList the loaded task list from file + */ + public static void loadTasks(ArrayList loadedTasksList) { + tasksList = loadedTasksList; + } + + /** + * Returns the number of tasks. + * + * @return the number of tasks + */ + public static int getTaskCount() { + return tasksList.size(); + } + + /** + * Clears the current task list. + */ + public static void clear() { + tasksList = new ArrayList<>(); + } + + public static class TaskNotFoundException extends DataNotFoundException { + } +} \ No newline at end of file diff --git a/src/main/java/seedu/ravi/data/TimeTable.java b/src/main/java/seedu/ravi/data/TimeTable.java new file mode 100644 index 0000000000..3f75c51957 --- /dev/null +++ b/src/main/java/seedu/ravi/data/TimeTable.java @@ -0,0 +1,79 @@ +package seedu.ravi.data; + +import java.time.DayOfWeek; +import java.util.HashMap; + +public class TimeTable { + private HashMap semesterMap = new HashMap<>(); + private int semStartWeekNum; + private int semEndWeekNum; + private int semRecessWeekNum; + + public TimeTable() { + + } + + public void initWeek(int weekNum) { + semesterMap.put(weekNum, new LessonManager()); + } + + public int getSemEndWeekNum() { + return semEndWeekNum; + } + + public int getSemRecessWeekNum() { + return semRecessWeekNum; + } + + public int getSemStartWeekNum() { + return semStartWeekNum; + } + + public int countLessonManagers() { + return semesterMap.size(); + } + + public LessonManager getLessonManagerOfWeek(int weekNum) { + return semesterMap.get(weekNum); + } + + public void deleteLessonById(DayOfWeek dayOfWeek, String id) { + for (LessonManager eachWeek : semesterMap.values()) { + eachWeek.removeLessonById(dayOfWeek, id); + } + } + + public int countWeekLessons(int week) { + return semesterMap.get(week).countTotalLessons(); + } + + public int countTimetableLessons() { + int totalLessonNum = 0; + for (LessonManager eachWeek : semesterMap.values()) { + totalLessonNum += eachWeek.countTotalLessons(); + } + return totalLessonNum; + } + + // required for fastJSON, not used otherwise + public HashMap getSemesterMap() { + return semesterMap; + } + + // required for fastJSON, not used otherwise + public void setSemesterMap(HashMap semesterMap) { + this.semesterMap = semesterMap; + } + + public void setSemEndWeekNum(int semEndWeekNum) { + this.semEndWeekNum = semEndWeekNum; + } + + public void setSemRecessWeekNum(int semRecessWeekNum) { + this.semRecessWeekNum = semRecessWeekNum; + } + + public void setSemStartWeekNum(int semStartWeekNum) { + this.semStartWeekNum = semStartWeekNum; + } +} diff --git a/src/main/java/seedu/ravi/data/TimeTableManager.java b/src/main/java/seedu/ravi/data/TimeTableManager.java new file mode 100644 index 0000000000..5abb817614 --- /dev/null +++ b/src/main/java/seedu/ravi/data/TimeTableManager.java @@ -0,0 +1,387 @@ +//@@author aseanseen + +package seedu.ravi.data; + +import seedu.ravi.RaviLogger; +import seedu.ravi.exception.LessonInvalidTimeException; +import seedu.ravi.exception.LessonOverlapException; +import seedu.ravi.exception.TimeTableInitialiseException; +import seedu.ravi.exception.ModuleNotFoundException; +import seedu.ravi.ui.TextUi; + +import java.time.DayOfWeek; +import java.time.LocalDateTime; +import java.time.temporal.ChronoField; +import java.util.ArrayList; +import java.util.NoSuchElementException; + +import static seedu.ravi.util.ExceptionMessage.TIMETABLE_NOT_INITIALISED; + +public class TimeTableManager { + private static TimeTable timetable = new TimeTable(); + private static final RaviLogger logger = new RaviLogger(TimeTableManager.class.getName()); + private static boolean isInitialised; + + /** + * Initialise the semesterMap when it is empty. + * Takes in the current week number in order to initialise. + * + * @param userCurrWeekNum + * The current nus week number. + * @throws TimeTableInitialiseException + * when the userCurrWeekNum is not accepted. + */ + public static void initialise(int userCurrWeekNum) throws TimeTableInitialiseException { + logger.getLogger().info("Initialising timetable with user input: " + userCurrWeekNum); + LocalDateTime now = LocalDateTime.now(); + // One sem has 13 weeks of lessons + if (userCurrWeekNum > 0 && userCurrWeekNum < 15) { + // e.g. Current week is 45, NUS week 2 + // semStartWeekNum is NUS week 1 + // therefore, semStartWeekNum = 45 - (2 - 1) = 44 + timetable.setSemStartWeekNum(now.get(ChronoField.ALIGNED_WEEK_OF_YEAR) - (userCurrWeekNum - 1)); + } else { + logger.getLogger().warning("User input week num is invalid!"); + throw new TimeTableInitialiseException(); + } + timetable.setSemEndWeekNum(timetable.getSemStartWeekNum() + 14); + timetable.setSemRecessWeekNum(timetable.getSemStartWeekNum() + 6); + // e.g. semStartWeekNum is 44, NUS week 1 + // Current week is NUS week 2 + // therefore, userCurrWeekNum = 44 + 2 - 1 = 45 + userCurrWeekNum = timetable.getSemStartWeekNum() + userCurrWeekNum - 1; + logger.getLogger().info(String.format("Current, Start, Recess, End: %d, %d, %d, %d", + now.get(ChronoField.ALIGNED_WEEK_OF_YEAR), timetable.getSemStartWeekNum(), + timetable.getSemRecessWeekNum(), timetable.getSemEndWeekNum())); + + logger.getLogger().info("Filling semesterMap with empty LessonManagers"); + for (int weekNum = userCurrWeekNum; weekNum < timetable.getSemEndWeekNum(); weekNum++) { + timetable.initWeek(weekNum); + } + logger.getLogger().info("Initialisation of timetable complete"); + isInitialised = true; + } + + /** + * Checks if timetable is initialised. + * + * @return + * Boolean of whether it is initialised + */ + public static boolean isInitialised() { + return isInitialised; + } + + /** + * Adds the lesson to semesterMap based on the repeat parameter. E.g. add to every week, every other week, etc. + * Does not add to recess week (week 7) or reading week (week 15). + * The repeat parameter where + * 0: Current week only. + * 1: Every week. + * 2: Every even week. + * 3: Every odd week. + * + * @param lesson The lesson object + * @param repeat The repeat parameter + * @throws LessonInvalidTimeException + * When the lesson to be added overlaps with an existing lesson + * @throws ModuleNotFoundException + * When the lesson to be added is not in the module list + * @throws LessonOverlapException + * When the lesson to be added overlaps with an existing lesson + */ + public static void addLesson(Lesson lesson, int repeat) throws + LessonInvalidTimeException, ModuleNotFoundException, LessonOverlapException { + // Check for errors and throw exceptions accordingly + logger.getLogger().info("Adding lesson: " + lesson.toString() + " with repeat: " + repeat); + if (!ModuleManager.doesContainMod(lesson.getModuleCode())) { + logger.getLogger().warning("Could not add lesson as module not in user module list!"); + throw new ModuleNotFoundException(); + } + Lesson overlapLesson = doesOverlap(lesson, repeat); + if (overlapLesson != null) { + logger.getLogger().warning("Lesson overlaps with other lesson! " + overlapLesson.toString()); + throw new LessonOverlapException(overlapLesson.toString()); + } + + // Get current week number and generate lesson's hidden ID + int currWeek = getCurrWeekNum(); + logger.getLogger().info("Current week num is: " + currWeek); + LessonManager lessonManager = timetable.getLessonManagerOfWeek(currWeek); + lesson.generateHiddenId(); // tag lesson with unique ID for identifying when removing + logger.getLogger().info("The lesson's hiddenId is: " + lesson.getHiddenId()); + + // If repeat is 0, add for current week only + if (repeat == 0) { + lessonManager.addLesson(lesson); + return; + } + + // Otherwise, use for loop to add to the right weeks + for (; currWeek < timetable.getSemEndWeekNum(); currWeek++) { // don't add for reading week + lessonManager = timetable.getLessonManagerOfWeek(currWeek); + if (currWeek == timetable.getSemRecessWeekNum()) { + // don't add for recess week + } else if (repeat == 1) { // if repeat every week + lessonManager.addLesson(lesson); + } else if (isEvenWeek(currWeek) && repeat == 2) { // if repeat every even week + lessonManager.addLesson(lesson); + } else if (isOddWeek(currWeek) && repeat == 3) { // if repeat every odd week + lessonManager.addLesson(lesson); + } + } + } + + /** + * Deletes lesson by identifying the unique lesson from the current week, dayOfWeek, and lessonIndex. + * Using the params, the lesson is found and the unique hiddenId is obtained. + * Uses the removeLessonById method of LessonManager to delete all lessons with this hiddenId. + * + * @param dayOfWeek + * The day of week. + * @param lessonIndex + * The lesson index. + * @return + * The deleted lesson. + * @throws IndexOutOfBoundsException + * When the lesson index is out of bounds. + */ + public static Lesson deleteLesson(DayOfWeek dayOfWeek, int lessonIndex) throws IndexOutOfBoundsException { + logger.getLogger().info("Deleting lesson with index " + lessonIndex + " on " + dayOfWeek + + " (failed if no successful deletion log below)"); + int currWeek = getCurrWeekNum(); + + // retrieve the unique ID, as index does not stay constant over different weeks + LessonManager lessonManager = timetable.getLessonManagerOfWeek(currWeek); + Lesson lesson = lessonManager.getDayLessonList(dayOfWeek).get(lessonIndex); + String id = lesson.getHiddenId(); + + // remove by ID + Lesson deletedLesson = timetable.getLessonManagerOfWeek(currWeek).getDayLessonList(dayOfWeek).get(lessonIndex); + timetable.deleteLessonById(dayOfWeek, id); + logger.getLogger().info("Successful deletion of lesson with hiddenId " + id); + return deletedLesson; + } + + /** + * Get an ArrayList of lessons happening on a certain day. + * + * @param dayOfWeek + * The specific day of week. + * @return + * The ArrayList of lessons. + */ + public static ArrayList getSpecificDayLessons(DayOfWeek dayOfWeek) { + int currWeek = getCurrWeekNum(); + LessonManager lessonManager = timetable.getLessonManagerOfWeek(currWeek); + return lessonManager.getDayLessonList(dayOfWeek); + } + + /** + * Checks if the given lesson overlaps with any lesson already in timetable with the given repeat. + * + * @param lesson + * The specified lesson + * @param repeat + * The repeat interval for the lesson. + * + * @return + * The lesson in timetable that the given lesson overlaps with, or null if no overlap + */ + public static Lesson doesOverlap(Lesson lesson, int repeat) { + LessonManager lessonManager; + for (int i = getCurrWeekNum(); i < timetable.getSemEndWeekNum(); i++) { + if (repeat == 2 && !isEvenWeek(i)) { // Handle even repeat + continue; + } else if (repeat == 3 && !isOddWeek(i)) { // Handle odd repeat + continue; + } + + lessonManager = timetable.getLessonManagerOfWeek(i); + for (Lesson eachLesson : lessonManager.getDayLessonList(lesson.getDay())) { + if (eachLesson.checkOverlap(lesson)) { + return eachLesson; + } + } + + if (repeat == 0) { // Handle no repeat + return null; + } + } + return null; + } + + /** + * Get an ArrayList of ArrayLists of lessons happening in the specified week. + * Outer ArrayList: Holds one ArrayList for each day of week, starting from Monday. + * Inner ArrayList: Holds lessons happening on that day of week. + * + * @param currWeek + * The current week. + * @return + * The ArrayList of ArrayList of lessons. + */ + public static ArrayList> getSpecifiedWeekLessons(int currWeek) { + ArrayList> outputList = new ArrayList<>(); + LessonManager lessonManager = timetable.getLessonManagerOfWeek(currWeek); + for (DayOfWeek eachDay : DayOfWeek.values()) { + outputList.add(lessonManager.getDayLessonList(eachDay)); + } + return outputList; + } + + /** + * Get the current week number (of the year). + * + * @return + * The current week number. + */ + public static int getCurrWeekNum() { + LocalDateTime now = LocalDateTime.now(); + return now.get(ChronoField.ALIGNED_WEEK_OF_YEAR); + } + + /** + * Get the current week number (of NUS calendar). + * + * @return + * The current week number. + */ + public static String getCurrNusWeekStr() { + if (getCurrWeekNum() == timetable.getSemRecessWeekNum()) { + return "Recess week"; + } else if (getCurrWeekNum() == timetable.getSemEndWeekNum()) { + return "Reading week"; + } else { + return Integer.toString(getCurrWeekNum() - timetable.getSemStartWeekNum() + 1); + } + } + + /** + * Checks whether the current NUS week is odd. + * + * @param week + * The week number to check. + * @return + * Whether current NUS week is odd. + */ + public static boolean isOddWeek(int week) { + int recessWeek = timetable.getSemRecessWeekNum(); + int startWeek = timetable.getSemStartWeekNum(); + if (week < recessWeek) { + return (week - startWeek + 1) % 2 == 1; // check if the NUS week is even + } else if (week == recessWeek) { + return false; + } else { + return (week - startWeek + 1) % 2 == 0; // check if the NUS week is even (accounting for recess week) + } + } + + /** + * Checks whether the current NUS week is even. + * + * @param week + * The week number to check. + * @return + * Whether current NUS week is even. + */ + public static boolean isEvenWeek(int week) { + int recessWeek = timetable.getSemRecessWeekNum(); + int startWeek = timetable.getSemStartWeekNum(); + if (week < recessWeek) { + return (week - startWeek + 1) % 2 == 0; // check if the NUS week is even + } else if (week == recessWeek) { + return false; + } else { + return (week - startWeek + 1) % 2 == 1; // check if the NUS week is even (accounting for recess week) + } + } + + /** + * Returns an ArrayList with lessons by filtering all lessons in lessonList through the given LessonFilter. + * + * @param lessonList + * The ArrayList of lessons to be filtered + * @param currentFilter + * The current LessonFilter in use + * @return + * The filtered ArrayList of lessons generated from lessonMap + */ + public static ArrayList filterLessonList(ArrayList lessonList, LessonFilter currentFilter) { + ArrayList outputList = new ArrayList<>(); + for (Lesson eachLesson : lessonList) { + if (currentFilter.filter(eachLesson)) { + outputList.add(eachLesson); + } + } + return outputList; + } + + public static ArrayList> filterWeekWithFilterList(ArrayList currentFilter) { + ArrayList> outputList = new ArrayList<>(); + for (DayOfWeek day : DayOfWeek.values()) { + ArrayList lessonList = timetable.getLessonManagerOfWeek(getCurrWeekNum()).getDayLessonList(day); + for (LessonFilter eachFilter : currentFilter) { + lessonList = filterLessonList(lessonList, eachFilter); + } + outputList.add(lessonList); + } + return outputList; + } + + /** + * Initialises the timetable to get the current nus week. + * + * @throws NoSuchElementException + * When the user input is ctrl-c. + */ + public static void initialiseTimetable() throws NoSuchElementException { + try { + TextUi.showTimeTableInitialisationMessage(); + int currWeekNum = TextUi.getCurrentWeekNum(); + TimeTableManager.initialise(currWeekNum); + } catch (TimeTableInitialiseException | NumberFormatException e) { + TextUi.outputToUser(TIMETABLE_NOT_INITIALISED); + } + } + + public static int getWeekLessonCount(int week) { + return timetable.countWeekLessons(week); + } + + public static int getTimetableLessonCount() { + return timetable.countTimetableLessons(); + } + + public static TimeTable getTimeTable() { + return timetable; + } + + public static void loadTimeTable(TimeTable loadedTimeTable) { + timetable = loadedTimeTable; + isInitialised = true; + } + + public static void clearTimeTable() { + timetable = new TimeTable(); + isInitialised = false; + } + + /* + public static int getSemEndWeekNum() { + return semEndWeekNum; + } + + public static int getSemStartWeekNum() { + return semStartWeekNum; + } + + public static int getSemRecessWeekNum() { + return semRecessWeekNum; + } + + public static boolean isSemRecessWeek(int week) { + return week == semRecessWeekNum; + } + */ +} diff --git a/src/main/java/seedu/ravi/data/storage/Decoder.java b/src/main/java/seedu/ravi/data/storage/Decoder.java new file mode 100644 index 0000000000..aafb48edc1 --- /dev/null +++ b/src/main/java/seedu/ravi/data/storage/Decoder.java @@ -0,0 +1,225 @@ +package seedu.ravi.data.storage; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONException; +import seedu.ravi.data.Module; +import seedu.ravi.data.Task; +import seedu.ravi.data.TimeTable; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; +import java.net.ConnectException; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import static seedu.ravi.data.storage.InputOutputManager.JAR_NUS_MODULE_FILE; + +/** + * Manages all outputs from files, and the conversion from String in file to Object in memory. + * Throws exceptions to InputOutputManager and handles none. + * + * @author Sim Jun You + * @author Wang Qin + */ + +public class Decoder { + public static TimeTable loadTimeTable(String dataFileName) throws IOException, JSONException { + String jsonStr; + jsonStr = loadJsonStringFromFile(dataFileName); + TimeTable timetable = JSON.parseObject(jsonStr, TimeTable.class); + return timetable; + } + + /** + * Loads a HashMap of Module objects from the specified file. Used for both user and NUS modules. + * + * @param dataFileName + * The file to load from + * @return + * The HashMap of Module objects + * @throws JSONException + * When the file to be parsed has caused some error + * @throws IOException + * When the file cannot be loaded or read + */ + public static HashMap loadModules(String dataFileName) throws IOException, JSONException { + String jsonStr; + jsonStr = loadJsonStringFromFile(dataFileName); + // FastJSON doesn't write the square brackets for some reason when we save, so we add it in here + // so that parseArray works as it should + if (jsonStr != null) { + jsonStr = "[" + jsonStr + "]"; + } + List moduleList = JSON.parseArray(jsonStr, Module.class); + HashMap modulesMap = new HashMap<>(); + if (moduleList != null) { + for (Module eachModule : moduleList) { + modulesMap.put(eachModule.getModuleCode(), eachModule); + } + } + return modulesMap; + } + + /** + * Parses the specified save file to return an ArrayList of Task objects. + * + * @param dataFileName + * The name of the file to read from + * @return + * The ArrayList tasksList + * @throws JSONException + * When the file to be parsed has caused some error + * @throws IOException + * When the file cannot be loaded or read + */ + public static ArrayList loadTasks(String dataFileName) throws IOException, JSONException { + String jsonStr; + jsonStr = loadJsonStringFromFile(dataFileName); + + if (jsonStr != null) { + String[] lines = jsonStr.split("\\r?\\n"); + ArrayList tasksList = new ArrayList(); + for (String eachTaskStr : lines) { + tasksList.add(JSON.parseObject(eachTaskStr, Task.class)); + } + return tasksList; + } else { + return new ArrayList(); + } + } + + /** + * Loads NUSMods list from the JAR file's resources folder. + * + * @return + * The HashMap of Module objects (from NUSMods) + * @throws IOException + * When the file cannot be read + * @throws JSONException + * When the file to be parsed has caused some error + * @throws NullPointerException + * When the file cannot be loaded + */ + public static HashMap loadNusModsFromJar() throws IOException, JSONException, NullPointerException { + BufferedReader br = new BufferedReader(new InputStreamReader( + Decoder.class.getResourceAsStream(JAR_NUS_MODULE_FILE))); + String jsonStr = ""; + while (br.ready()) { + jsonStr += br.readLine(); + } + if (jsonStr != null) { + jsonStr = "[" + jsonStr + "]"; + } + List modulesList = JSON.parseArray(jsonStr, Module.class); + HashMap retrievedNusModsList = new HashMap<>(); + for (Module eachModule : modulesList) { + retrievedNusModsList.put(eachModule.getModuleCode(), eachModule); + } + return retrievedNusModsList; + } + + /** + * Pulls JSON from the NUSMods API, parses it, and returns the HashMap of Module objects. + * + * @return + * The HashMap of Module objects (from NUSMods) + * @throws ConnectException + * When the connection to the NUSMods API fails + * @throws JSONException + * When the JSON data cannot be parsed + */ + public static HashMap generateNusModsList() throws ConnectException, JSONException { + HashMap retrievedNusModsList = new HashMap<>(); + String retrievedJson; + retrievedJson = requestNusModsJsonString("https://api.nusmods.com/v2/2020-2021/moduleList.json"); + // This JSON string comes with the square brackets, so no need to add + List modulesList = JSON.parseArray(retrievedJson, Module.class);// extractModules(jsonStr); + + for (Module eachModule : modulesList) { + retrievedNusModsList.put(eachModule.getModuleCode(), eachModule); + } + + return retrievedNusModsList; + } + + /** + * Reads a string from a file (doesn't necessarily have to be JSON). + * + * @param dataFileName + * The specified file + * @return + * The string read from file + * @throws IOException + * When the file cannot be loaded or read + */ + private static String loadJsonStringFromFile(String dataFileName) throws IOException { + File file = new File(dataFileName); + long fileLength = file.length(); + byte[] fileContent = new byte[(int) fileLength]; + + FileInputStream in = new FileInputStream(file); + in.read(fileContent); + in.close(); + + String encoding = "utf8"; + try { + return new String(fileContent, encoding); + } catch (UnsupportedEncodingException e) { + System.err.println("The OS does not support " + encoding); + e.printStackTrace(); + return null; + } + } + + /** + * Uses the NUSMods API to get a JSON string with the information of all available mods. + * + * @param filePath + * The endpoint for the NUSMods API. + * @return + * The JSON string with information of all currently available mods in NUS. + * @throws ConnectException + * When the connection to the NUSMods API fails + */ + private static String requestNusModsJsonString(String filePath) throws ConnectException { + int httpResult; // the status from the server response + String content = ""; + + try { + URL url = new URL(filePath); // create URL + URLConnection urlConn = url.openConnection(); // try to connect and get the status code + urlConn.connect(); + HttpURLConnection httpConn = (HttpURLConnection) urlConn; + httpResult = httpConn.getResponseCode(); + if (httpResult != HttpURLConnection.HTTP_OK) { + throw new ConnectException(); + } else { + int fileSize = urlConn.getContentLength(); // get the length of the data + InputStreamReader isReader = new InputStreamReader(urlConn.getInputStream(), StandardCharsets.UTF_8); + BufferedReader reader = new BufferedReader(isReader); + StringBuffer buffer = new StringBuffer(); + String line; // to save the content of every line + line = reader.readLine(); // read the first line + while (line != null) { // if line is empty, means finish reading + buffer.append(line); // append to the buffer + buffer.append(" "); // add new line + line = reader.readLine(); // read the next line + } + content = buffer.toString(); + } + } catch (Exception e) { + throw new ConnectException(); + } + + return content; + } +} diff --git a/src/main/java/seedu/ravi/data/storage/Encoder.java b/src/main/java/seedu/ravi/data/storage/Encoder.java new file mode 100644 index 0000000000..32da89154e --- /dev/null +++ b/src/main/java/seedu/ravi/data/storage/Encoder.java @@ -0,0 +1,130 @@ +package seedu.ravi.data.storage; + +import com.alibaba.fastjson.JSON; +import seedu.ravi.data.Module; +import seedu.ravi.data.ModuleManager; +import seedu.ravi.data.Task; +import seedu.ravi.data.TaskManager; +import seedu.ravi.data.TimeTableManager; +import seedu.ravi.exception.ModuleNotFoundException; +import seedu.ravi.exception.ModuleNotProvidedException; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + +/** + * Manages all inputs to files, and the conversion from Object in memory to String in file. + * Throws exceptions to InputOutputManager and handles none. + * + * @author Sim Jun You + */ +public class Encoder { + /** + * Saves timetable to file path/name specified. + * + * @param dataFileName + * The name of the file to save to + * @throws IOException + * When there is an error preparing the save file + */ + public static void saveTimetable(String dataFileName) throws IOException { + File mySaveFile = new File(dataFileName); + prepareSaveFile(mySaveFile); + writeToFile(mySaveFile, JSON.toJSONString(TimeTableManager.getTimeTable())); + } + + /** + * Saves all tasks to file path/name specified. + * + * @param dataFileName + * The name of the file to save to + * @throws IOException + * When there is an error preparing the save file + * @throws TaskManager.TaskNotFoundException + * If index out of range (should never happen) + */ + public static void saveTasks(String dataFileName) throws IOException, TaskManager.TaskNotFoundException { + int taskCount = TaskManager.getTaskCount(); + File mySaveFile = new File(dataFileName); + prepareSaveFile(mySaveFile); + Task currentTask; + for (int i = 0; i < taskCount; i++) { + currentTask = TaskManager.getTask(i); + writeToFile(mySaveFile, JSON.toJSONString(currentTask)); + } + } + + /** + * Saves all modules to file path/name specified. + * + * @param dataFileName + * The name of the file to save to + * @throws IOException + * When there is an error preparing the save file + * @throws ModuleNotFoundException + * If module not found (should never happen) + */ + public static void saveModules(String dataFileName) throws IOException, ModuleNotFoundException { + File mySaveFile = new File(dataFileName); + prepareSaveFile(mySaveFile); + + Module currentModule; + for (String eachModCode : ModuleManager.getModCodeList()) { + currentModule = ModuleManager.getModule(eachModCode); + writeToFile(mySaveFile, JSON.toJSONString(currentModule)); + } + } + + /** + * Saves all NUS modules to file path/name specified. + * + * @param dataFileName + * The name of the file to save to + * @throws IOException + * When there is an error preparing the save file + * @throws ModuleNotProvidedException + * If module not found (should never happen) + */ + public static void saveNusModules(String dataFileName) throws IOException, ModuleNotProvidedException { + File mySaveFile = new File(dataFileName); + prepareSaveFile(mySaveFile); + Module currentModule; + for (String eachModCode : ModuleManager.getNusModCodeList()) { + currentModule = ModuleManager.getNusModule(eachModCode); + writeToFile(mySaveFile, JSON.toJSONString(currentModule)); + } + } + + /** + * Prepares the specified save file (and dir) by creating it or deleting then creating it (if the file exists). + * + * @param saveFile + * The File object to prepare the actual file for + * + * @throws IOException + * If createNewFile does not work as expected + */ + private static void prepareSaveFile(File saveFile) throws IOException { + if (saveFile.exists()) { // overwrite by deleting first + saveFile.delete(); + } + saveFile.createNewFile(); + } + + /** + * Appends the specified string to the specified File object. + * + * @param saveFile + * The File object to write to + * @param textToAdd + * The string to write + * @throws IOException + * If FileWriter cannot write or close the file + */ + private static void writeToFile(File saveFile, String textToAdd) throws IOException { + FileWriter fw = new FileWriter(saveFile, true); // true to append data instead of overwrite + fw.write(textToAdd + "\n"); + fw.close(); + } +} diff --git a/src/main/java/seedu/ravi/data/storage/InputOutputManager.java b/src/main/java/seedu/ravi/data/storage/InputOutputManager.java new file mode 100644 index 0000000000..4d57f19b31 --- /dev/null +++ b/src/main/java/seedu/ravi/data/storage/InputOutputManager.java @@ -0,0 +1,260 @@ +package seedu.ravi.data.storage; + +import com.alibaba.fastjson.JSONException; +import seedu.ravi.RaviLogger; +import seedu.ravi.data.Module; +import seedu.ravi.data.ModuleManager; +import seedu.ravi.data.TimeTableManager; +import seedu.ravi.exception.ModuleNotFoundException; +import seedu.ravi.exception.ModuleNotProvidedException; +import seedu.ravi.exception.NusModsNotLoadedException; +import seedu.ravi.util.FileName; +import seedu.ravi.data.TaskManager; + +import java.io.IOException; +import java.net.ConnectException; +import java.nio.file.Files; + +import java.util.HashMap; +import java.util.logging.Level; + + +/** + * Manages all inputs and outputs (to and from files). + * Encoder and Decoder are only used by InputOutputManager. + * InputOutputManager also handles exceptions thrown by Encoder and Decoder. No exceptions are thrown from here. + * + * @author Sim Jun You + */ +public class InputOutputManager { + static final String ROOT = System.getProperty("user.dir"); + static final java.nio.file.Path DIR_PATH = java.nio.file.Paths.get(ROOT, "data"); + static final java.nio.file.Path RESOURCE_DIR_PATH = java.nio.file.Paths.get(ROOT, "src/main/resources"); + + static final String USER_MOD_F_NAME = FileName.MOD_SAVE_FILE_NAME + FileName.FILE_EXT; + static final String USER_TASK_F_NAME = FileName.TASK_SAVE_FILE_NAME + FileName.FILE_EXT; + static final String TTABLE_F_NAME = FileName.TIMETABLE_SAVE_FILE_NAME + FileName.FILE_EXT; + static final String NUS_MOD_F_NAME = FileName.NUSMOD_SAVE_FILE_NAME + FileName.FILE_EXT; + + static final String BACKUP = ".bak"; + + static final String MOD_BK_NAME = FileName.MOD_SAVE_FILE_NAME + FileName.FILE_EXT + BACKUP; + static final String TASK_BK_NAME = FileName.TASK_SAVE_FILE_NAME + FileName.FILE_EXT + BACKUP; + static final String TTABLE_BK_NAME = FileName.TIMETABLE_SAVE_FILE_NAME + FileName.FILE_EXT + BACKUP; + + static final java.nio.file.Path USER_MODULE_FILE = + java.nio.file.Paths.get(String.valueOf(DIR_PATH), USER_MOD_F_NAME); + static final java.nio.file.Path USER_TASK_FILE = + java.nio.file.Paths.get(String.valueOf(DIR_PATH), USER_TASK_F_NAME); + static final java.nio.file.Path TIMETABLE_FILE = + java.nio.file.Paths.get(String.valueOf(DIR_PATH), TTABLE_F_NAME); + static final java.nio.file.Path NUS_MODULE_FILE = + java.nio.file.Paths.get(String.valueOf(DIR_PATH), NUS_MOD_F_NAME); + static final String JAR_NUS_MODULE_FILE = "/" + NUS_MOD_F_NAME; + + private static final RaviLogger logger = new RaviLogger(InputOutputManager.class.getName()); + + /** + * Creates the save directory if it has not been created. + * Loads the user's module and task saves into memory. + * + * @return + * the integer containing the status of loading of the modules, task and timetable. + * @throws NusModsNotLoadedException + * When no NUSMods data could be loaded. Signals the main class to crash. + */ + public static int start() throws NusModsNotLoadedException { + int status = 0; // 'Skipped load' status for all 3 files by default + logger.getLogger().info("Starting InputOutputManager"); + java.io.File saveFolder = DIR_PATH.toFile(); + if (!saveFolder.exists()) { + logger.getLogger().info("Save folder does not exist, creating now"); + saveFolder.mkdir(); + status += tryLoadNusMods() * 1000; + } else { + // For documentation of this part, look at TextUi's showWelcomeMessage + status += tryLoadMods(); + status += tryLoadTasks() * 10; + status += tryLoadTimetable() * 100; + status += tryLoadNusMods() * 1000; + } + return status; + } + + public static int tryLoadMods() { + try { + if (Files.exists(USER_MODULE_FILE)) { + logger.getLogger().info("Loading user module saves from " + USER_MOD_F_NAME); + ModuleManager.loadMods(Decoder.loadModules(USER_MODULE_FILE.toString())); + logger.getLogger().info("Successfully loaded user module saves from " + USER_MOD_F_NAME); + return 1; // 'Success' status + } else { + logger.getLogger().info("Skipping user module save; file does not exist: " + USER_MOD_F_NAME); + return 0; // 'Skipped' status + } + } catch (JSONException e) { + logger.getLogger().severe("JSON string can't be parsed! Error: " + e.getMessage()); + handleCorruptedFile(USER_MODULE_FILE, MOD_BK_NAME); + return 2; // 'Corrupted' status + } catch (IOException e) { + // should not happen + logger.getLogger().severe("IOException in tryLoadMods - check me now!!"); + return 0; // 'Skipped' status + } + } + + public static int tryLoadTasks() { + try { + if (Files.exists(USER_TASK_FILE)) { + logger.getLogger().info("Loading user task saves from " + USER_TASK_F_NAME); + TaskManager.loadTasks(Decoder.loadTasks(USER_TASK_FILE.toString())); + return 1; // 'Success' status + } else { + logger.getLogger().info("Skipping user task save; file does not exist: " + USER_TASK_F_NAME); + return 0; // 'Skipped' status + } + } catch (JSONException e) { + logger.getLogger().severe("JSON string can't be parsed! Error: " + e.getMessage()); + handleCorruptedFile(USER_TASK_FILE, TASK_BK_NAME); + return 2; // 'Corrupted' status + } catch (IOException e) { + // should not happen + logger.getLogger().severe("IOException in tryLoadTasks - check me now!!"); + return 0; // 'Skipped' status + } + } + + public static int tryLoadTimetable() { + try { + if (Files.exists(TIMETABLE_FILE)) { + logger.getLogger().info("Loading timetable save from " + TTABLE_F_NAME); + TimeTableManager.loadTimeTable(Decoder.loadTimeTable(TIMETABLE_FILE.toString())); + return 1; // 'Success' status + } else { + logger.getLogger().info("Skipping timetable save; file does not exist: " + TTABLE_F_NAME); + return 0; // 'Skipped' status + } + } catch (JSONException e) { + logger.getLogger().severe("JSON string can't be parsed! Error: " + e.getMessage()); + handleCorruptedFile(TIMETABLE_FILE, TTABLE_BK_NAME); + return 2; // 'Corrupted' status + } catch (IOException e) { + // should not happen + logger.getLogger().severe("IOException in tryLoadTimetable - check me now!!"); + return 0; // 'Skipped' status + } + } + + /** + * Loads NUSMods from the saved file in the data directory. + * Failing that, it will try to load from the online NUSMods API. + * Failing even that, it will fall back to the packaged NUSMods list in the jar file. + * Finally, failing all these, it will throw the NusModsNotLoadedException as a signal to crash the program. + * + * @return + * The status code (refer to TextUi's showWelcomeMessage method) + * @throws NusModsNotLoadedException + * When no NUSMods data can be loaded + */ + public static int tryLoadNusMods() throws NusModsNotLoadedException { + HashMap loadedNusModsMap; + int status; + try { + logger.getLogger().info("Loading NUSMods data from data directory..."); + loadedNusModsMap = Decoder.loadModules(NUS_MODULE_FILE.toString()); + logger.getLogger().info("Successfully loaded NUSMods data from data directory!"); + status = 0; + } catch (IOException | JSONException e1) { + try { + logger.getLogger().warning("Could not load from data directory!"); + logger.getLogger().info("Loading NUSMods from NUSMods API..."); + loadedNusModsMap = Decoder.generateNusModsList(); + logger.getLogger().info("Successfully loaded NUSMods data from NUSMods API!"); + status = 1; + } catch (ConnectException | JSONException e2) { + try { + logger.getLogger().warning("Could not load from NUSMods API! (No Internet connection?)"); + logger.getLogger().info("Loading NUSMods data from JAR resource file..."); + loadedNusModsMap = Decoder.loadNusModsFromJar(); + logger.getLogger().info("Successfully loaded NUSMods data from JAR resource file!"); + status = 2; + } catch (IOException | JSONException | NullPointerException e3) { + logger.getLogger().severe("Could not load from JAR resource file! Crashing..."); + throw new NusModsNotLoadedException(); + } + } + } + ModuleManager.loadNusMods(loadedNusModsMap); + return status; + } + + /** + * Updates the user's save files. Does not save NUS Modules. + */ + public static void save() { + try { + if (ModuleManager.getModCodeList().length != 0) { + Encoder.saveModules(USER_MODULE_FILE.toString()); + logger.getLogger().info("Saved module data to " + USER_MOD_F_NAME); + } else { + logger.getLogger().warning("No module data to save!"); + } + if (TaskManager.getTaskCount() != 0) { + Encoder.saveTasks(USER_TASK_FILE.toString()); + logger.getLogger().info("Saved task data to " + USER_TASK_F_NAME); + } else { + logger.getLogger().warning("No task data to save!"); + } + if (TimeTableManager.isInitialised()) { + Encoder.saveTimetable(TIMETABLE_FILE.toString()); + logger.getLogger().info("Saved timetable data to " + TTABLE_F_NAME); + } else { + logger.getLogger().warning("No timetable data to save!"); + } + } catch (ModuleNotFoundException | TaskManager.TaskNotFoundException | IOException e) { + logger.getLogger().severe("Something went wrong while trying to save files!"); + logger.getLogger().log(Level.SEVERE, e.getLocalizedMessage(), e); + } + + } + + /** + * Updates the user's NUS Modules save file. Will not create file to save if there is nothing to save. + */ + public static void saveNusMods() { + try { + logger.getLogger().info("Saving NUS modules into " + NUS_MOD_F_NAME); + if (ModuleManager.getNusModCodeList().length != 0) { + Encoder.saveNusModules(NUS_MODULE_FILE.toString()); + } else { + logger.getLogger().warning("No NUSMods data to save!"); + } + } catch (ModuleNotProvidedException | IOException e) { + logger.getLogger().log(Level.WARNING, e.getLocalizedMessage(), e); + } + } + + /** + * Renames the corrupted files (if any) by adding a ".bak" behind the file name. + */ + public static void handleAllCorruptedFiles() { + String backup = ".bak"; + + String modBackup = FileName.MOD_SAVE_FILE_NAME + FileName.FILE_EXT + backup; + String taskBackup = FileName.TASK_SAVE_FILE_NAME + FileName.FILE_EXT + backup; + String timetableBackup = FileName.TIMETABLE_SAVE_FILE_NAME + FileName.FILE_EXT + backup; + + handleCorruptedFile(USER_MODULE_FILE, modBackup); + handleCorruptedFile(USER_TASK_FILE, taskBackup); + handleCorruptedFile(TIMETABLE_FILE, timetableBackup); + } + + public static void handleCorruptedFile(java.nio.file.Path currentFile, String newName) { + try { + Files.move(currentFile, currentFile.resolveSibling(newName)); + logger.getLogger().info("Renamed corrupted file to " + newName); + } catch (IOException e) { + logger.getLogger().severe("Could not rename corrupted file to " + newName); + } + } +} \ No newline at end of file diff --git a/src/main/java/seedu/ravi/directory/Directory.java b/src/main/java/seedu/ravi/directory/Directory.java new file mode 100644 index 0000000000..940862fb43 --- /dev/null +++ b/src/main/java/seedu/ravi/directory/Directory.java @@ -0,0 +1,38 @@ +package seedu.ravi.directory; + +public abstract class Directory { + protected Directory parent; + + /** + * Constructs the Directory without a parent. + */ + public Directory() { + this.parent = null; + } + + /** + * Constructs the Directory that has a parent. + * + * @param parent + * The parent of the class in the Directory + */ + public Directory(Directory parent) { + this.parent = parent; + } + + /** + * Returns the parent of the class in the Directory. + * + * @return + * The parent of the class in the Directory + */ + public abstract Directory getParent(); + + /** + * Returns the corresponding level of the Directory. + * + * @return + * The level of the Directory + */ + public abstract DirectoryLevel getLevel(); +} diff --git a/src/main/java/seedu/ravi/directory/DirectoryLevel.java b/src/main/java/seedu/ravi/directory/DirectoryLevel.java new file mode 100644 index 0000000000..30fd8d736e --- /dev/null +++ b/src/main/java/seedu/ravi/directory/DirectoryLevel.java @@ -0,0 +1,19 @@ +package seedu.ravi.directory; + +public enum DirectoryLevel { + NONE, + ROOT, + MODULE, + TASK, + + TAG { + @Override + public DirectoryLevel next() { + return NONE; + } + }; + + public DirectoryLevel next() { + return values()[ordinal() + 1]; + } +} diff --git a/src/main/java/seedu/ravi/directory/Root.java b/src/main/java/seedu/ravi/directory/Root.java new file mode 100644 index 0000000000..cb628e5fc1 --- /dev/null +++ b/src/main/java/seedu/ravi/directory/Root.java @@ -0,0 +1,17 @@ +package seedu.ravi.directory; + +public class Root extends Directory { + public Root() { + super(); + } + + @Override + public Directory getParent() { + return null; + } + + @Override + public DirectoryLevel getLevel() { + return DirectoryLevel.ROOT; + } +} diff --git a/src/main/java/seedu/ravi/exception/DataNotFoundException.java b/src/main/java/seedu/ravi/exception/DataNotFoundException.java new file mode 100644 index 0000000000..1712373cc4 --- /dev/null +++ b/src/main/java/seedu/ravi/exception/DataNotFoundException.java @@ -0,0 +1,4 @@ +package seedu.ravi.exception; + +public abstract class DataNotFoundException extends Exception { +} diff --git a/src/main/java/seedu/ravi/exception/DuplicateDataException.java b/src/main/java/seedu/ravi/exception/DuplicateDataException.java new file mode 100644 index 0000000000..27330811f5 --- /dev/null +++ b/src/main/java/seedu/ravi/exception/DuplicateDataException.java @@ -0,0 +1,4 @@ +package seedu.ravi.exception; + +public abstract class DuplicateDataException extends Exception { +} diff --git a/src/main/java/seedu/ravi/exception/DuplicateModuleException.java b/src/main/java/seedu/ravi/exception/DuplicateModuleException.java new file mode 100644 index 0000000000..b800fc5bd8 --- /dev/null +++ b/src/main/java/seedu/ravi/exception/DuplicateModuleException.java @@ -0,0 +1,4 @@ +package seedu.ravi.exception; + +public class DuplicateModuleException extends DuplicateDataException { +} diff --git a/src/main/java/seedu/ravi/exception/InvalidCapCalculatedException.java b/src/main/java/seedu/ravi/exception/InvalidCapCalculatedException.java new file mode 100644 index 0000000000..72ab588339 --- /dev/null +++ b/src/main/java/seedu/ravi/exception/InvalidCapCalculatedException.java @@ -0,0 +1,6 @@ +//@@author tobiasceg + +package seedu.ravi.exception; + +public class InvalidCapCalculatedException extends Exception { +} diff --git a/src/main/java/seedu/ravi/exception/InvalidCapException.java b/src/main/java/seedu/ravi/exception/InvalidCapException.java new file mode 100644 index 0000000000..de75ffaba3 --- /dev/null +++ b/src/main/java/seedu/ravi/exception/InvalidCapException.java @@ -0,0 +1,6 @@ +//@@author tobiasceg + +package seedu.ravi.exception; + +public class InvalidCapException extends Exception{ +} diff --git a/src/main/java/seedu/ravi/exception/InvalidCommandException.java b/src/main/java/seedu/ravi/exception/InvalidCommandException.java new file mode 100644 index 0000000000..c547e4bca4 --- /dev/null +++ b/src/main/java/seedu/ravi/exception/InvalidCommandException.java @@ -0,0 +1,4 @@ +package seedu.ravi.exception; + +public class InvalidCommandException extends Exception{ +} diff --git a/src/main/java/seedu/ravi/exception/InvalidGradeException.java b/src/main/java/seedu/ravi/exception/InvalidGradeException.java new file mode 100644 index 0000000000..4797ceb28e --- /dev/null +++ b/src/main/java/seedu/ravi/exception/InvalidGradeException.java @@ -0,0 +1,6 @@ +//@@author tobiasceg + +package seedu.ravi.exception; + +public class InvalidGradeException extends Exception { +} diff --git a/src/main/java/seedu/ravi/exception/InvalidMatchException.java b/src/main/java/seedu/ravi/exception/InvalidMatchException.java new file mode 100644 index 0000000000..05a3fa0ed5 --- /dev/null +++ b/src/main/java/seedu/ravi/exception/InvalidMatchException.java @@ -0,0 +1,15 @@ +//@@author tobiasceg + +package seedu.ravi.exception; + +import static seedu.ravi.util.Message.MESSAGE_CHECK_COMMAND_FORMAT; +import static seedu.ravi.util.Message.MESSAGE_INVALID_COMMAND_FORMAT; + +public class InvalidMatchException extends Exception { + + public InvalidMatchException(String parameters, String format, String helpPrompt) { + super(String.format("%s%s\n\n%s%s\n\n%s\n", + MESSAGE_INVALID_COMMAND_FORMAT, parameters, MESSAGE_CHECK_COMMAND_FORMAT, format, + helpPrompt)); + } +} diff --git a/src/main/java/seedu/ravi/exception/InvalidModuleCreditException.java b/src/main/java/seedu/ravi/exception/InvalidModuleCreditException.java new file mode 100644 index 0000000000..267ca218de --- /dev/null +++ b/src/main/java/seedu/ravi/exception/InvalidModuleCreditException.java @@ -0,0 +1,4 @@ +package seedu.ravi.exception; + +public class InvalidModuleCreditException extends Exception{ +} diff --git a/src/main/java/seedu/ravi/exception/LessonInvalidTimeException.java b/src/main/java/seedu/ravi/exception/LessonInvalidTimeException.java new file mode 100644 index 0000000000..8d3b71c2f6 --- /dev/null +++ b/src/main/java/seedu/ravi/exception/LessonInvalidTimeException.java @@ -0,0 +1,4 @@ +package seedu.ravi.exception; + +public class LessonInvalidTimeException extends Exception{ +} diff --git a/src/main/java/seedu/ravi/exception/LessonNotFoundException.java b/src/main/java/seedu/ravi/exception/LessonNotFoundException.java new file mode 100644 index 0000000000..79a2114005 --- /dev/null +++ b/src/main/java/seedu/ravi/exception/LessonNotFoundException.java @@ -0,0 +1,4 @@ +package seedu.ravi.exception; + +public class LessonNotFoundException extends Exception{ +} diff --git a/src/main/java/seedu/ravi/exception/LessonOverlapException.java b/src/main/java/seedu/ravi/exception/LessonOverlapException.java new file mode 100644 index 0000000000..d8d65d3801 --- /dev/null +++ b/src/main/java/seedu/ravi/exception/LessonOverlapException.java @@ -0,0 +1,9 @@ +package seedu.ravi.exception; + +public class LessonOverlapException extends Throwable { + public String overlapLessonStr; + + public LessonOverlapException(String overlapLessonStr) { + this.overlapLessonStr = overlapLessonStr; + } +} diff --git a/src/main/java/seedu/ravi/exception/ModuleNotFoundException.java b/src/main/java/seedu/ravi/exception/ModuleNotFoundException.java new file mode 100644 index 0000000000..bcec570793 --- /dev/null +++ b/src/main/java/seedu/ravi/exception/ModuleNotFoundException.java @@ -0,0 +1,4 @@ +package seedu.ravi.exception; + +public class ModuleNotFoundException extends DataNotFoundException { +} diff --git a/src/main/java/seedu/ravi/exception/ModuleNotProvidedException.java b/src/main/java/seedu/ravi/exception/ModuleNotProvidedException.java new file mode 100644 index 0000000000..63987807e5 --- /dev/null +++ b/src/main/java/seedu/ravi/exception/ModuleNotProvidedException.java @@ -0,0 +1,4 @@ +package seedu.ravi.exception; + +public class ModuleNotProvidedException extends Exception { +} diff --git a/src/main/java/seedu/ravi/exception/NusModsNotLoadedException.java b/src/main/java/seedu/ravi/exception/NusModsNotLoadedException.java new file mode 100644 index 0000000000..f9027df499 --- /dev/null +++ b/src/main/java/seedu/ravi/exception/NusModsNotLoadedException.java @@ -0,0 +1,4 @@ +package seedu.ravi.exception; + +public class NusModsNotLoadedException extends Exception { +} diff --git a/src/main/java/seedu/ravi/exception/RepeatFrequencyInvalidException.java b/src/main/java/seedu/ravi/exception/RepeatFrequencyInvalidException.java new file mode 100644 index 0000000000..6c1a08ae5c --- /dev/null +++ b/src/main/java/seedu/ravi/exception/RepeatFrequencyInvalidException.java @@ -0,0 +1,6 @@ +//@@author aseanseen + +package seedu.ravi.exception; + +public class RepeatFrequencyInvalidException extends Exception { +} diff --git a/src/main/java/seedu/ravi/exception/TaskNotFoundException.java b/src/main/java/seedu/ravi/exception/TaskNotFoundException.java new file mode 100644 index 0000000000..2005e8b3da --- /dev/null +++ b/src/main/java/seedu/ravi/exception/TaskNotFoundException.java @@ -0,0 +1,4 @@ +package seedu.ravi.exception; + +public class TaskNotFoundException extends Exception { +} diff --git a/src/main/java/seedu/ravi/exception/TimeTableInitialiseException.java b/src/main/java/seedu/ravi/exception/TimeTableInitialiseException.java new file mode 100644 index 0000000000..2188e7cdaa --- /dev/null +++ b/src/main/java/seedu/ravi/exception/TimeTableInitialiseException.java @@ -0,0 +1,6 @@ +//@@author aseanseen + +package seedu.ravi.exception; + +public class TimeTableInitialiseException extends Exception{ +} diff --git a/src/main/java/seedu/ravi/parser/AddCommandParser.java b/src/main/java/seedu/ravi/parser/AddCommandParser.java new file mode 100644 index 0000000000..731f3a0b62 --- /dev/null +++ b/src/main/java/seedu/ravi/parser/AddCommandParser.java @@ -0,0 +1,111 @@ +//@@author tobiasceg + +package seedu.ravi.parser; + +import seedu.ravi.command.Command; +import seedu.ravi.command.IncorrectCommand; +import seedu.ravi.command.add.AddCommand; +import seedu.ravi.command.add.AddModuleCommand; +import seedu.ravi.command.add.AddTaskCommand; +import seedu.ravi.exception.InvalidMatchException; + +import java.security.InvalidParameterException; +import java.time.format.DateTimeParseException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static seedu.ravi.util.ExceptionMessage.MESSAGE_ADD_TASK_DATE_TIME_UNKNOWN; +import static seedu.ravi.util.ExceptionMessage.MESSAGE_NO_ADD_MODULE; +import static seedu.ravi.util.ExceptionMessage.MESSAGE_NO_ADD_TASK; +import static seedu.ravi.util.Message.MESSAGE_CHECK_COMMAND_FORMAT; +import static seedu.ravi.util.Message.MESSAGE_INVALID_COMMAND_FORMAT; + +public class AddCommandParser { + public static final String MODULE_PREFIX = "-m"; + public static final String TASK_PREFIX = "-t"; + protected static final String COMMAND_FLAG_GROUP = "commandFlag"; + protected static final String DESC_GROUP = "desc"; + protected static final String DEADLINE_GROUP = "deadline"; + protected static final String BY_GROUP = "by"; + //@@author aseanseen + protected static final Pattern ADD_FORMAT = + Pattern.compile("(?-\\S+)" + "(?(?:(?!-by).)*)" + + "((?-by)?)" + "((?.*)?)"); + + //@@author tobiasceg + /** + * Takes the user's input and parses it into the respective arguments for AddCommand. + * + * @param parameters + * the user's input without the command word + * @return + * AddCommand with the relevant parameters + * @throws InvalidParameterException + * When an invalid parameter is given by the user + * @throws IllegalStateException + * When a method has been invoked at an illegal time + * @throws InvalidMatchException + * When the user input doesn't match the REGEX format for the AddCommand + */ + protected static Command prepareAddCommand(String parameters) + throws InvalidParameterException, IllegalStateException, InvalidMatchException { + Matcher matcher = ADD_FORMAT.matcher(parameters); + + Parser.matcherMatches(matcher, parameters, AddCommand.FORMAT, AddCommand.PROMPT_HELP); + + String commandFlag = Parser.isMatcherNull(matcher.group(COMMAND_FLAG_GROUP)) + ? null : matcher.group(COMMAND_FLAG_GROUP).toLowerCase().trim(); + + if (!(commandFlag.equals(MODULE_PREFIX) || commandFlag.equals(TASK_PREFIX))) { + return new IncorrectCommand(String.format("%s%s\n\n%s%s\n\n%s\n", + MESSAGE_INVALID_COMMAND_FORMAT, parameters, MESSAGE_CHECK_COMMAND_FORMAT, + AddCommand.FORMAT, AddCommand.PROMPT_HELP)); + } + + String addedTask = matcher.group(DESC_GROUP).trim(); + String taskDeadline = null; + // Checks for presence of -by + String dashBy = matcher.group(BY_GROUP); + if (dashBy != null) { + taskDeadline = matcher.group(DEADLINE_GROUP).trim(); + if (taskDeadline.isEmpty()) { // -by is present but empty deadline + return new IncorrectCommand(String.format("%s%s\n\n%s%s\n\n%s\n", + MESSAGE_INVALID_COMMAND_FORMAT, parameters, MESSAGE_CHECK_COMMAND_FORMAT, + AddTaskCommand.FORMAT, AddCommand.PROMPT_HELP)); + } + } + // no task input by user + if (Parser.isEmptyParse(addedTask)) { + return (commandFlag.equals(MODULE_PREFIX)) + ? new IncorrectCommand(MESSAGE_NO_ADD_MODULE) + : new IncorrectCommand(MESSAGE_NO_ADD_TASK); + } + try { + return getAddCommand(commandFlag, addedTask, taskDeadline); + } catch (DateTimeParseException e) { + return new IncorrectCommand(MESSAGE_ADD_TASK_DATE_TIME_UNKNOWN); + } + } + + /** + * Checks the prefix of the user's input and calls the respective Add command according to it. + * + * @param commandFlag + * The command flag which is either '-t' for task or '-m' for module + * @param addedTask + * Task or module to be added + * @param taskDeadline + * The deadline, if given , assigned to the task + * @return + * the respective Add command for either task or module + */ + private static AddCommand getAddCommand(String commandFlag, String addedTask, String taskDeadline) { + if (commandFlag.equals(MODULE_PREFIX)) { + return new AddModuleCommand(addedTask.toUpperCase()); + } else if (commandFlag.equals(TASK_PREFIX)) { + return new AddTaskCommand(addedTask, taskDeadline); + } else { + throw new InvalidParameterException(); + } + } +} diff --git a/src/main/java/seedu/ravi/parser/DeleteCommandParser.java b/src/main/java/seedu/ravi/parser/DeleteCommandParser.java new file mode 100644 index 0000000000..0017932dab --- /dev/null +++ b/src/main/java/seedu/ravi/parser/DeleteCommandParser.java @@ -0,0 +1,66 @@ +//@@author tobiasceg + +package seedu.ravi.parser; + +import seedu.ravi.command.Command; +import seedu.ravi.command.IncorrectCommand; +import seedu.ravi.command.delete.DeleteCommand; +import seedu.ravi.command.delete.DeleteModuleCommand; +import seedu.ravi.command.delete.DeleteTaskCommand; +import seedu.ravi.exception.InvalidMatchException; + +import java.security.InvalidParameterException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static seedu.ravi.util.Message.MESSAGE_CHECK_COMMAND_FORMAT; +import static seedu.ravi.util.Message.MESSAGE_INVALID_COMMAND_FORMAT; + +public class DeleteCommandParser { + public static final String MODULE_PREFIX = "-m"; + public static final String TASK_PREFIX = "-t"; + protected static final String TASK_MODULE_GROUP = "taskModule"; + protected static final String INVALID_GROUP = "invalid"; + protected static final Pattern DELETE_FORMAT = + Pattern.compile("((?.*-\\S+)?)" + + "(?\\s*\\S+)" + "((?.*)?)"); + + /** + * Takes the user's input and parses it into the respective arguments for Delete Command. + * + * @param parameters + * the user's input without the command word + * @return + * Delete command with relevant arguments + * @throws NumberFormatException + * When a string is parsed as an integer/double + * @throws InvalidMatchException + * When the user input doesn't match the REGEX format for the Delete Command + */ + protected static Command getDeleteCommand(String parameters) throws NumberFormatException, InvalidMatchException { + Matcher matcher = DELETE_FORMAT.matcher(parameters); + + Parser.matcherMatches(matcher, parameters, DeleteCommand.FORMAT, DeleteCommand.PROMPT_HELP); + + String commandFlag = Parser.isMatcherNull(matcher.group(Parser.COMMAND_FLAG_GROUP)) + ? null : matcher.group(Parser.COMMAND_FLAG_GROUP).toLowerCase().trim(); + + String stringTaskIndex = matcher.group(TASK_MODULE_GROUP).trim(); + + // Checks for any string after the module or index given + String invalid = matcher.group(INVALID_GROUP).trim(); + if (!invalid.isEmpty()) { + return new IncorrectCommand(String.format("%s%s\n\n%s%s\n\n%s\n", + MESSAGE_INVALID_COMMAND_FORMAT, invalid, MESSAGE_CHECK_COMMAND_FORMAT, + DeleteCommand.FORMAT, DeleteCommand.PROMPT_HELP)); + } + + if (commandFlag.equals(MODULE_PREFIX)) { + return new DeleteModuleCommand(stringTaskIndex); //parameter is module code + } else if (commandFlag.equals(TASK_PREFIX)) { + return new DeleteTaskCommand(Integer.parseInt(stringTaskIndex) - 1);//parameters is the index + } else { + throw new InvalidParameterException(); + } + } +} diff --git a/src/main/java/seedu/ravi/parser/DoneCommandParser.java b/src/main/java/seedu/ravi/parser/DoneCommandParser.java new file mode 100644 index 0000000000..1dd447ada1 --- /dev/null +++ b/src/main/java/seedu/ravi/parser/DoneCommandParser.java @@ -0,0 +1,49 @@ +//@@author tobiasceg + +package seedu.ravi.parser; + +import seedu.ravi.command.Command; +import seedu.ravi.command.done.DoneCommand; +import seedu.ravi.exception.InvalidMatchException; + +import java.security.InvalidParameterException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class DoneCommandParser { + protected static final String NUMBER_GROUP = "digit"; + protected static final Pattern DONE_FORMAT = Pattern.compile("(?\\S+)"); + + /** + * Takes the user's input and parses it into the respective arguments for Done Command. + * + * @param parameters + * the user's input without the command word + * @return + * Done Command with relevant arguments + * @throws NumberFormatException + * When a string is parsed as an integer/double + * @throws InvalidParameterException + * Parameters entered by the user is invalid + * @throws InvalidMatchException + * When the user input doesn't match the REGEX format for the Done Command + */ + protected static Command prepareDoneCommand(String parameters) + throws NumberFormatException, InvalidParameterException, InvalidMatchException { + Matcher matcher = DONE_FORMAT.matcher(parameters); + + Parser.matcherMatches(matcher, parameters, DoneCommand.FORMAT, DoneCommand.PROMPT_HELP); + + String digit = Parser.isMatcherNull(matcher.group(NUMBER_GROUP)) + ? null : matcher.group(NUMBER_GROUP).trim(); + + if (digit == null) { + throw new InvalidParameterException(); + } + + int intDigit = Integer.parseInt(digit) - 1; + + return new DoneCommand(intDigit); + } + +} diff --git a/src/main/java/seedu/ravi/parser/EditCommandParser.java b/src/main/java/seedu/ravi/parser/EditCommandParser.java new file mode 100644 index 0000000000..34a3e9a9d9 --- /dev/null +++ b/src/main/java/seedu/ravi/parser/EditCommandParser.java @@ -0,0 +1,134 @@ +//@@author tobiasceg + +package seedu.ravi.parser; + +import seedu.ravi.command.Command; +import seedu.ravi.command.IncorrectCommand; +import seedu.ravi.command.edit.EditCommand; +import seedu.ravi.command.edit.EditModuleCommand; +import seedu.ravi.command.edit.EditTaskCommand; +import seedu.ravi.exception.InvalidMatchException; + +import java.security.InvalidParameterException; +import java.time.format.DateTimeParseException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static seedu.ravi.util.ExceptionMessage.MESSAGE_ADD_TASK_DATE_TIME_UNKNOWN; +import static seedu.ravi.util.ExceptionMessage.MESSAGE_NO_EDIT_TASK; +import static seedu.ravi.util.ExceptionMessage.MESSAGE_NO_EDIT_MODULE; +import static seedu.ravi.util.Message.MESSAGE_CHECK_COMMAND_FORMAT; +import static seedu.ravi.util.Message.MESSAGE_INVALID_COMMAND_FORMAT; + +public class EditCommandParser { + public static final String MODULE_PREFIX = "-m"; + public static final String TASK_PREFIX = "-t"; + protected static final String COMMAND_FLAG_GROUP = "commandFlag"; + protected static final String ARGUMENT_IDENTIFIER_GROUP = "argument"; + protected static final String TASK_INDEX_IDENTIFIER_GROUP = "taskIndex"; + protected static final String TASK_DESC_IDENTIFIER_GROUP = "desc"; + protected static final String BY_FLAG_IDENTIFIER_GROUP = "by"; + protected static final String DEADLINE_IDENTIFIER_GROUP = "deadline"; + + protected static final Pattern EDIT_PREFIX_FORMAT = + Pattern.compile("(?-\\S+)" + "(?.*)"); + + protected static final Pattern EDIT_FORMAT = + Pattern.compile("(?\\S+)" + "(?(?:(?!-by).)*)" + "((?-by)?)" + "((?.*)?)"); + + /** + * Splits the user's input, based on the prefix and parse it into the respective prepare methods. + * + * @param parameters + * The parameters given by the user, but unknown if its module or task yet + * @return + * The command to prepare the respective module or task command for edit + */ + protected static Command getEditCommand(String parameters) throws InvalidMatchException { + Matcher matcher = EDIT_PREFIX_FORMAT.matcher(parameters); + + Parser.matcherMatches(matcher, parameters, EditModuleCommand.FORMAT + "\n" + EditTaskCommand.FORMAT, + EditCommand.PROMPT_HELP); + + String commandFlag = Parser.isMatcherNull(matcher.group(COMMAND_FLAG_GROUP)) + ? null : matcher.group(COMMAND_FLAG_GROUP).toLowerCase().trim(); + String argument = Parser.isMatcherNull(matcher.group(ARGUMENT_IDENTIFIER_GROUP)) + ? null : matcher.group(ARGUMENT_IDENTIFIER_GROUP).toLowerCase().trim(); + + if (commandFlag.equals(MODULE_PREFIX)) { + return prepareEditModuleCommand(argument.trim()); + } else if (commandFlag.equals(TASK_PREFIX)) { + return prepareEditTaskCommand(argument.trim()); + } else { + throw new InvalidParameterException(); + } + } + + /** + * Prepares the command to edit a module. + * + * @param parameters + * The parameters given by the user + * @return + * The command to edit a module + */ + protected static Command prepareEditModuleCommand(String parameters) + throws InvalidParameterException, InvalidMatchException { + Matcher matcher = EDIT_FORMAT.matcher(parameters); + + Parser.matcherMatches(matcher, parameters, EditModuleCommand.FORMAT, EditCommand.PROMPT_HELP); + + String oldModuleCode = matcher.group(TASK_INDEX_IDENTIFIER_GROUP).trim(); + String newModuleCode = matcher.group(TASK_DESC_IDENTIFIER_GROUP).trim(); + + if (Parser.isEmptyParse(oldModuleCode) || Parser.isEmptyParse(newModuleCode)) { + return new IncorrectCommand(MESSAGE_NO_EDIT_MODULE); + } else { + return new EditModuleCommand(oldModuleCode, newModuleCode); + } + } + + /** + * Prepares the command to edit a task. + * + * @param parameters + * The parameters given by user + * @return + * The command to edit a task + */ + protected static Command prepareEditTaskCommand(String parameters) + throws InvalidParameterException, NumberFormatException, InvalidMatchException { + Matcher matcher = EDIT_FORMAT.matcher(parameters); + + Parser.matcherMatches(matcher, parameters, EditTaskCommand.FORMAT, EditCommand.PROMPT_HELP); + + String stringTaskIndex = matcher.group(TASK_INDEX_IDENTIFIER_GROUP).trim(); + int taskIndex = Integer.parseInt(stringTaskIndex) - 1; + String newTaskDescription = matcher.group(TASK_DESC_IDENTIFIER_GROUP).trim(); + + // Checks for presence of -by + String taskDeadline = null; + String dashBy = matcher.group(BY_FLAG_IDENTIFIER_GROUP); + if (dashBy != null) { + taskDeadline = matcher.group(DEADLINE_IDENTIFIER_GROUP).trim(); + if (taskDeadline.isEmpty()) { // -by is present but empty deadline + return new IncorrectCommand(String.format("%s%s\n\n%s%s\n\n%s\n", + MESSAGE_INVALID_COMMAND_FORMAT, parameters, MESSAGE_CHECK_COMMAND_FORMAT, + EditTaskCommand.FORMAT, EditCommand.PROMPT_HELP)); + } + } + + if (Parser.isEmptyParse(newTaskDescription)) { + return new IncorrectCommand(MESSAGE_NO_EDIT_TASK); + } else if (dashBy == null) { + return new EditTaskCommand(taskIndex, newTaskDescription); + } + + try { + return new EditTaskCommand(taskIndex, newTaskDescription, taskDeadline); + } catch (DateTimeParseException e) { + return new IncorrectCommand(MESSAGE_ADD_TASK_DATE_TIME_UNKNOWN); + } + + } +} diff --git a/src/main/java/seedu/ravi/parser/GradeCommandParser.java b/src/main/java/seedu/ravi/parser/GradeCommandParser.java new file mode 100644 index 0000000000..2a3d522d66 --- /dev/null +++ b/src/main/java/seedu/ravi/parser/GradeCommandParser.java @@ -0,0 +1,58 @@ +//@@author tobiasceg + +package seedu.ravi.parser; + +import seedu.ravi.command.Command; +import seedu.ravi.command.grade.GradeCommand; +import seedu.ravi.exception.InvalidMatchException; +import seedu.ravi.exception.InvalidModuleCreditException; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class GradeCommandParser { + protected static final String MODULE_GROUP = "module"; + protected static final String GRADE_GROUP = "grade"; + protected static final String MC_GROUP = "mc"; + protected static final Pattern GRADE_FORMAT = + Pattern.compile("(?[a-zA-Z0-9]+)" + "(?\\s\\S+)" + "(?\\s\\S+)"); + + /** + * Takes the user's input and parses it into the respective arguments for Grade Command. + * + * @param parameters + * the user's input without the command word + * @return + * Grade Command with relevant arguments + * @throws NumberFormatException + * When a string is parsed as an integer/double + * @throws InvalidMatchException + * When the user input doesn't match the REGEX format for the Grade Command + */ + protected static Command prepareGradeCommand(String parameters) + throws NumberFormatException, InvalidMatchException, InvalidModuleCreditException { + Matcher matcher = GRADE_FORMAT.matcher(parameters); + + Parser.matcherMatches(matcher, parameters, GradeCommand.FORMAT, GradeCommand.PROMPT_HELP); + + String module = Parser.isMatcherNull(matcher.group(MODULE_GROUP)) + ? null : matcher.group(MODULE_GROUP).toLowerCase().trim(); + String mc = Parser.isMatcherNull(matcher.group(MC_GROUP)) + ? null : matcher.group(MC_GROUP).toLowerCase().trim(); + String grade = Parser.isMatcherNull(matcher.group(GRADE_GROUP)) + ? null : matcher.group(GRADE_GROUP).trim(); + + double intMc = Double.parseDouble(mc); + + isValidMc(intMc); + + return new GradeCommand(module, intMc, grade); + } + + private static void isValidMc(double intMc) throws InvalidModuleCreditException { + if (intMc < 0 || intMc > 20) { + throw new InvalidModuleCreditException(); + } + } + +} diff --git a/src/main/java/seedu/ravi/parser/HelpCommandParser.java b/src/main/java/seedu/ravi/parser/HelpCommandParser.java new file mode 100644 index 0000000000..ab68b58b7a --- /dev/null +++ b/src/main/java/seedu/ravi/parser/HelpCommandParser.java @@ -0,0 +1,41 @@ +//@@author tobiasceg + +package seedu.ravi.parser; + +import seedu.ravi.command.Command; +import seedu.ravi.command.help.HelpCommand; +import seedu.ravi.exception.InvalidMatchException; + +import java.security.InvalidParameterException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class HelpCommandParser { + protected static final String HCW_GROUP = "helpCommandWord"; + protected static final Pattern HELP_FORMAT = + Pattern.compile("((?\\S+)?)"); + + /** + * Takes the user's input and parses it into the respective arguments for Help Command. + * + * @param parameters + * the user's input without the command word + * @return + * Help Command with relevant arguments + * @throws InvalidParameterException + * When the user inputs parameters that arent accepted by the commands format + * @throws InvalidMatchException + * When the user input doesn't match the REGEX format for the Help Command + */ + protected static Command prepareHelpCommand(String parameters) + throws InvalidParameterException, InvalidMatchException { + Matcher matcher = HELP_FORMAT.matcher(parameters); + + Parser.matcherMatches(matcher, parameters, HelpCommand.FORMAT, HelpCommand.HELP); + + String helpCommandWord = Parser.isMatcherNull(matcher.group(HCW_GROUP)) + ? null : matcher.group(HCW_GROUP).trim(); + + return new HelpCommand(helpCommandWord); + } +} diff --git a/src/main/java/seedu/ravi/parser/LessonParser.java b/src/main/java/seedu/ravi/parser/LessonParser.java new file mode 100644 index 0000000000..5b5f82f3a3 --- /dev/null +++ b/src/main/java/seedu/ravi/parser/LessonParser.java @@ -0,0 +1,118 @@ +package seedu.ravi.parser; + +import seedu.ravi.data.Lesson; +import seedu.ravi.data.LessonFilter; +import seedu.ravi.data.LessonType; +import seedu.ravi.data.ModuleManager; +import seedu.ravi.exception.LessonInvalidTimeException; +import seedu.ravi.exception.ModuleNotFoundException; + +import java.time.DayOfWeek; +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.util.ArrayList; +import java.util.regex.Matcher; + +import static seedu.ravi.parser.TimeTableCommandParser.DAY_GROUP; +import static seedu.ravi.parser.TimeTableCommandParser.END_TIME_GROUP; +import static seedu.ravi.parser.TimeTableCommandParser.LESSON_TYPE_GROUP; +import static seedu.ravi.parser.TimeTableCommandParser.MODULE_GROUP; +import static seedu.ravi.parser.TimeTableCommandParser.START_TIME_GROUP; + +public class LessonParser { + public static final String SKIP_PARAMETER_CHAR = "-"; + + /** + * Parses the user input for the Lesson parameters, to create a Lesson. + * + * @param lessonMatcher Matcher for the parameters. + * @return Lesson created from the Lesson parameters. + * @throws ModuleNotFoundException When the module is not found in the module list. + * @throws LessonInvalidTimeException When the start is greater than or equal to end time of the Lesson. + * @throws DateTimeParseException When the time of either the start or end is in the wrong format. + * @throws IllegalArgumentException When the Lesson to be created has illegal arguments. + */ + public static Lesson parseLesson(Matcher lessonMatcher) throws + ModuleNotFoundException, LessonInvalidTimeException, DateTimeParseException { + String modString = lessonMatcher.group(MODULE_GROUP).toUpperCase().trim(); + String dayString = lessonMatcher.group(DAY_GROUP).toUpperCase().trim(); + String startTimeString = lessonMatcher.group(START_TIME_GROUP).trim(); + String endTimeString = lessonMatcher.group(END_TIME_GROUP).trim(); + String lessonTypeString = lessonMatcher.group(LESSON_TYPE_GROUP).toUpperCase().trim(); + // Check if modString is in module list + if (!ModuleManager.doesContainMod(modString)) { + throw new ModuleNotFoundException(); + } + // Convert dayString to DayOfWeek + DayOfWeek dayOfWeek = DayOfWeek.valueOf(dayString); + // Convert start, end strings to LocalTime + DateTimeFormatter time = DateTimeFormatter.ofPattern("Hmm"); + LocalTime startTime = LocalTime.parse(startTimeString, time); + LocalTime endTime = LocalTime.parse(endTimeString, time); + // Convert lessonTypeString to lessonType + LessonType lessonType = LessonType.valueOf(lessonTypeString); + // Create the Lesson object + Lesson newLesson = new Lesson(modString, lessonType, dayOfWeek, startTime, endTime); + return newLesson; + } + + + public static ArrayList parseFilterLesson(Matcher filterMatcher) throws + ModuleNotFoundException, DateTimeParseException, + IllegalArgumentException { + final String modString = filterMatcher.group(MODULE_GROUP).toUpperCase().trim(); + final String dayString = filterMatcher.group(DAY_GROUP).toUpperCase().trim(); + final String startTimeString = filterMatcher.group(START_TIME_GROUP).trim(); + final String endTimeString = filterMatcher.group(END_TIME_GROUP).trim(); + final String lessonTypeString = filterMatcher.group(LESSON_TYPE_GROUP).toUpperCase().trim(); + + ArrayList filterList = new ArrayList<>(); + + if (!modString.equals(SKIP_PARAMETER_CHAR)) { + // Check if modString is in module list + if (!ModuleManager.doesContainMod(modString)) { + throw new ModuleNotFoundException(); + } else { + LessonFilter modFilter = (l) -> l.getModuleCode().equals(modString); + filterList.add(modFilter); + } + } + + if (!dayString.equals(SKIP_PARAMETER_CHAR)) { + // Convert dayString to DayOfWeek + DayOfWeek dayOfWeek = DayOfWeek.valueOf(dayString); + LessonFilter dayFilter = (l) -> l.getDay().equals(dayOfWeek); + filterList.add(dayFilter); + } + + // Convert start, end strings to LocalTime + DateTimeFormatter time = DateTimeFormatter.ofPattern("Hmm"); + + // Filter for start time. i.e. Filter lessons that start after HH:MM + if (!startTimeString.equals(SKIP_PARAMETER_CHAR)) { + LocalTime startTime = LocalTime.parse(startTimeString, time); + LessonFilter startFilter = (l) -> + (l.getStartTime().isAfter(startTime) || l.getStartTime().equals(startTime)); + filterList.add(startFilter); + } + + // Filter for start time. i.e. Filter lessons that end before HH:MM + if (!endTimeString.equals(SKIP_PARAMETER_CHAR)) { + LocalTime endTime = LocalTime.parse(endTimeString, time); + LessonFilter endFilter = (l) -> + (l.getEndTime().isBefore(endTime) || l.getEndTime().equals(endTime)); + filterList.add(endFilter); + } + + if (!lessonTypeString.equals(SKIP_PARAMETER_CHAR)) { + // Convert lessonTypeString to lessonType + LessonType lessonType = LessonType.valueOf(lessonTypeString); + LessonFilter lessonTypeFilter = (l) -> l.getLessonType().equals(lessonType); + filterList.add(lessonTypeFilter); + } + + return filterList; + } + +} diff --git a/src/main/java/seedu/ravi/parser/ListCommandParser.java b/src/main/java/seedu/ravi/parser/ListCommandParser.java new file mode 100644 index 0000000000..4e1defc370 --- /dev/null +++ b/src/main/java/seedu/ravi/parser/ListCommandParser.java @@ -0,0 +1,45 @@ +//@@author tobiasceg + +package seedu.ravi.parser; + +import seedu.ravi.command.Command; +import seedu.ravi.command.list.ListCommand; +import seedu.ravi.exception.InvalidMatchException; + +import java.security.InvalidParameterException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class ListCommandParser { + public static final String MODULE_PREFIX = "-m"; + public static final String TASK_PREFIX = "-t"; + protected static final Pattern LIST_FORMAT = + Pattern.compile("(?.*-\\S+)"); + + /** + * Takes the user's input and parses it into the respective arguments for List Command. + * + * @param parameters + * the user's input without the command word + * @return + * List Command with relevant arguments + * @throws InvalidMatchException + * When the user input doesn't match the REGEX format for the List Command + */ + protected static Command getListCommand(String parameters) throws InvalidMatchException { + Matcher matcher = LIST_FORMAT.matcher(parameters); + + Parser.matcherMatches(matcher, parameters, ListCommand.FORMAT, ListCommand.PROMPT_HELP); + + String commandFlag = Parser.isMatcherNull(matcher.group(Parser.COMMAND_FLAG_GROUP)) + ? null : matcher.group(Parser.COMMAND_FLAG_GROUP).toLowerCase().trim(); + + if (commandFlag.equals(MODULE_PREFIX)) { + return new ListCommand(Parser.TypeOfEntries.MODULE); + } else if (commandFlag.equals(TASK_PREFIX)) { + return new ListCommand(Parser.TypeOfEntries.TASK); + } else { + throw new InvalidParameterException(); + } + } +} diff --git a/src/main/java/seedu/ravi/parser/Parser.java b/src/main/java/seedu/ravi/parser/Parser.java new file mode 100644 index 0000000000..e7c555f360 --- /dev/null +++ b/src/main/java/seedu/ravi/parser/Parser.java @@ -0,0 +1,170 @@ +//@@author tobiasceg + +package seedu.ravi.parser; + +import seedu.ravi.RaviLogger; +import seedu.ravi.command.Command; +import seedu.ravi.command.ExitCommand; +import seedu.ravi.command.IncorrectCommand; +import seedu.ravi.command.add.AddCommand; +import seedu.ravi.command.cap.CapCommand; +import seedu.ravi.command.delete.DeleteCommand; +import seedu.ravi.command.done.DoneCommand; +import seedu.ravi.command.edit.EditCommand; +import seedu.ravi.command.grade.GradeCommand; +import seedu.ravi.command.help.HelpCommand; +import seedu.ravi.command.list.ListCommand; +import seedu.ravi.command.misc.UndoCommand; +import seedu.ravi.command.summary.SummaryCommand; +import seedu.ravi.command.timetable.TimeTableCommand; +import seedu.ravi.exception.InvalidCommandException; +import seedu.ravi.exception.InvalidMatchException; +import seedu.ravi.exception.InvalidModuleCreditException; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static seedu.ravi.util.ExceptionMessage.MESSAGE_INVALID_COMMAND_WORD; +import static seedu.ravi.util.ExceptionMessage.MESSAGE_INVALID_MC; +import static seedu.ravi.util.ExceptionMessage.MESSAGE_INVALID_PARAMETERS; +import static seedu.ravi.util.ExceptionMessage.MESSAGE_STRING_IN_NUMBER; +import static seedu.ravi.util.Message.MESSAGE_EMPTY_INPUT; +import static seedu.ravi.util.Message.MESSAGE_INVALID_COMMAND_FORMAT; + +public class Parser { + private static final RaviLogger logger = new RaviLogger(Parser.class.getName()); + + public enum TypeOfEntries { + TASK, MODULE + } + + /** + * Used for initial separation of command word and args. + */ + + private static final String COMMAND_WORD_GROUP = "commandWord"; + protected static final String COMMAND_FLAG_GROUP = "commandFlag"; + private static final String PARAMETERS_GROUP = "parameters"; + + private static final Pattern BASIC_COMMAND_FORMAT = + Pattern.compile("(?\\S+)" + "((?.*)?)"); + + + /** + * Takes the user's full input and parses it, checking for the command word and assigning it to the relevant + * prepare command. + * + * @param input + * User's full input + * @return + * Relevant prepare command from the respective commands' parsers + */ + public Command parseCommand(String input) { + logger.getLogger().info("Received input: " + input); + if (input.isBlank()) { + return new IncorrectCommand(MESSAGE_EMPTY_INPUT); + } + + final Matcher matcher = BASIC_COMMAND_FORMAT.matcher(input.trim()); + if (!matcher.matches()) { + logger.getLogger().warning("Invalid command format"); + return new IncorrectCommand(MESSAGE_INVALID_COMMAND_FORMAT); + } + + String commandWord = ""; + String parameters = ""; + try { + // Checks if the matched groups are null + commandWord = isMatcherNull(matcher.group(COMMAND_WORD_GROUP)) + ? null : matcher.group(COMMAND_WORD_GROUP).toLowerCase().trim(); + parameters = isMatcherNull(matcher.group(PARAMETERS_GROUP)) + ? null : matcher.group(PARAMETERS_GROUP).trim(); + + switch (commandWord) { + case ExitCommand.COMMAND_WORD: + return new ExitCommand(); + case CapCommand.COMMAND_WORD: + return new CapCommand(); + case GradeCommand.COMMAND_WORD: + return GradeCommandParser.prepareGradeCommand(parameters); + case UndoCommand.COMMAND_WORD: + return new UndoCommand(); + case EditCommand.COMMAND_WORD: + return EditCommandParser.getEditCommand(parameters); + case AddCommand.COMMAND_WORD: + return AddCommandParser.prepareAddCommand(parameters); + case DeleteCommand.COMMAND_WORD: + return DeleteCommandParser.getDeleteCommand(parameters); + case DoneCommand.COMMAND_WORD: + return DoneCommandParser.prepareDoneCommand(parameters); + case ListCommand.COMMAND_WORD: + return ListCommandParser.getListCommand(parameters); //command flag is the -t or -m + case SummaryCommand.COMMAND_WORD: + return new SummaryCommand(); + case TimeTableCommand.COMMAND_WORD: + return TimeTableCommandParser.parseTimeTableCommand(parameters); + case HelpCommand.COMMAND_WORD: + logger.getLogger().info("Unrecognised or help command"); + return HelpCommandParser.prepareHelpCommand(parameters); + default: + throw new InvalidCommandException(); + } + } catch (NumberFormatException e) { + logger.getLogger().warning("Found a string where a number should be"); + return new IncorrectCommand(String.format(MESSAGE_STRING_IN_NUMBER, commandWord)); + } catch (IllegalStateException | IllegalArgumentException e) { + logger.getLogger().warning("Invalid parameters for the command"); + return new IncorrectCommand(String.format(MESSAGE_INVALID_PARAMETERS, commandWord)); + } catch (NullPointerException e) { + logger.getLogger().warning("Invalid command word"); + return new IncorrectCommand(MESSAGE_INVALID_COMMAND_WORD); + } catch (InvalidMatchException e) { + logger.getLogger().warning(e.getMessage()); + return new IncorrectCommand(e.getMessage()); + } catch (InvalidModuleCreditException e) { + logger.getLogger().warning("Invalid Module Credit input"); + return new IncorrectCommand(MESSAGE_INVALID_MC); + } catch (InvalidCommandException e) { + logger.getLogger().warning("Invalid Command Word input detected"); + return new IncorrectCommand(MESSAGE_INVALID_COMMAND_WORD); + } + } + + protected static boolean isMatcherNull(String matcherTest) { + return (matcherTest == null); + } + + /** + * Checks the input given by the user is empty. + * + * @param attributes + * The input from the user + * @return + * true if the input is empty, or false otherwise + */ + protected static boolean isEmptyParse(String... attributes) { + for (String attribute : attributes) { + if (!attribute.isEmpty()) { + return false; + } + } + return true; + } + + /** + * Checks if the user input matches the REGEX format of the parser. + * + * @param matcher + * the format to follow + * @param parameters + * the user input + * @param format + * the actual correct format if user input doesn't match + */ + protected static void matcherMatches(Matcher matcher, String parameters, String format, String helpPrompt) + throws InvalidMatchException { + if (!matcher.matches()) { + throw new InvalidMatchException(parameters, format, helpPrompt); + } + } +} diff --git a/src/main/java/seedu/ravi/parser/TimeTableCommandParser.java b/src/main/java/seedu/ravi/parser/TimeTableCommandParser.java new file mode 100644 index 0000000000..6c3d59c26d --- /dev/null +++ b/src/main/java/seedu/ravi/parser/TimeTableCommandParser.java @@ -0,0 +1,206 @@ +//@@author aseanseen + +package seedu.ravi.parser; + +import seedu.ravi.command.Command; +import seedu.ravi.command.IncorrectCommand; +import seedu.ravi.command.timetable.TimeTableAddCommand; +import seedu.ravi.command.timetable.TimeTableCommand; +import seedu.ravi.command.timetable.TimeTableDeleteCommand; +import seedu.ravi.command.timetable.TimeTableFilterCommand; +import seedu.ravi.command.timetable.TimeTableResetCommand; +import seedu.ravi.command.timetable.TimeTableViewCommand; +import seedu.ravi.data.Lesson; +import seedu.ravi.data.LessonFilter; +import seedu.ravi.exception.InvalidMatchException; +import seedu.ravi.exception.LessonInvalidTimeException; +import seedu.ravi.exception.ModuleNotFoundException; + +import java.time.DayOfWeek; +import java.time.format.DateTimeParseException; +import java.util.ArrayList; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static seedu.ravi.command.timetable.TimeTableCommand.TIMETABLE_LESSON_ADD_USER_FORMAT; +import static seedu.ravi.command.timetable.TimeTableCommand.TIMETABLE_LESSON_DELETE_USER_FORMAT; +import static seedu.ravi.command.timetable.TimeTableCommand.TIMETABLE_LESSON_FILTER_USER_FORMAT; +import static seedu.ravi.util.ExceptionMessage.MESSAGE_ADD_LESSON_DATE_TIME_UNKNOWN; +import static seedu.ravi.util.ExceptionMessage.MESSAGE_LESSON_INVALID_TIME; +import static seedu.ravi.util.ExceptionMessage.MESSAGE_MODULE_NOT_FOUND; +import static seedu.ravi.util.Message.MESSAGE_CHECK_COMMAND_FORMAT; +import static seedu.ravi.util.Message.MESSAGE_INVALID_COMMAND_FORMAT; + +public class TimeTableCommandParser { + public static final String REPEAT_GROUP = "repeat"; + public static final String TIMETABLE_GROUP = "timeTableParams"; + public static final String INDEX_GROUP = "index"; + public static final String MODULE_GROUP = "module"; + public static final String DAY_GROUP = "day"; + public static final String START_TIME_GROUP = "start"; + public static final String END_TIME_GROUP = "end"; + public static final String LESSON_TYPE_GROUP = "type"; + public static final String ADD_FORMAT = "-add"; + public static final String DELETE_FORMAT = "-del"; + public static final String FILTER_FORMAT = "-filter"; + public static final String VIEW_DAY_FORMAT = "-day"; + public static final String VIEW_WEEK_FORMAT = "-week"; + public static final String RESET_FORMAT = "-reset"; + private static final Pattern TIMETABLE_FORMAT = Pattern.compile("(?-[a-zA-Z]+)" + + "(?.*)"); + private static final Pattern TIMETABLE_LESSON_PARAMETER_FORMAT = + Pattern.compile("(?[a-zA-Z0-9]+\\s+)(?[a-zA-Z]+\\s+)(?[0-9]+\\s+)(?[0-9]+\\s+)" + + "(?[a-zA-Z]+\\s+)(?[0-9]+\\s*)"); + private static final Pattern TIMETABLE_LESSON_FILTER_PARAMETER_FORMAT = + Pattern.compile("(?[-a-zA-Z0-9]+\\s+)(?[-a-zA-Z]+\\s+)(?[-0-9]+\\s+)(?[-0-9]+\\s+)" + + "(?[-a-zA-Z]+\\s*)"); + private static final Pattern TIMETABLE_DELETE_PARAMETER_FORMAT = + Pattern.compile("(?[a-zA-Z]+\\s+)(?[0-9]+\\s*)"); + + /** + * Parses all timetable related commands into their respective parsers. + * Able to Add, Delete, View. + * + * @param parameters User input after determining it is a timetable related command. + * @return IncorrectCommand or any of the timetable commands. + * @throws NumberFormatException When the timetable view command is not given DAY, WEEK or a number. + * @throws InvalidMatchException When the command entered does not match the regex pattern. + */ + public static Command parseTimeTableCommand(String parameters) + throws NumberFormatException, InvalidMatchException { + Command command; + Matcher matcher = TIMETABLE_FORMAT.matcher(parameters); + + Parser.matcherMatches(matcher, parameters, TimeTableCommand.FORMAT, TimeTableCommand.PROMPT_HELP); + + try { + String commandFlag = matcher.group(Parser.COMMAND_FLAG_GROUP).toLowerCase().trim(); + String timeTableParams = matcher.group(TIMETABLE_GROUP).toLowerCase().trim(); + switch (commandFlag) { + case ADD_FORMAT: + command = parseTimeTableAddCommand(timeTableParams); + break; + case DELETE_FORMAT: + command = parseTimeTableDeleteCommand(timeTableParams); + break; + case FILTER_FORMAT: + command = parseTimeTableFilterCommand(timeTableParams); + break; + case RESET_FORMAT: + command = parseTimeTableResetCommand(timeTableParams); + break; + default: // Check if it is a view command + command = parseTimeTableViewCommand(commandFlag, timeTableParams); + break; + } + } catch (ModuleNotFoundException e) { + return new IncorrectCommand(MESSAGE_MODULE_NOT_FOUND); + } catch (LessonInvalidTimeException e) { + return new IncorrectCommand(MESSAGE_LESSON_INVALID_TIME); + } catch (DateTimeParseException e) { + return new IncorrectCommand(MESSAGE_ADD_LESSON_DATE_TIME_UNKNOWN); + } + return command; + } + + /** + * Parses the timetable view command. + * Accepted commands will be: + * timetable -day + * timetable -week + * + * @param commandFlag User input determining if it is day, week or custom view. + * @param timeTableParams Remaining user input. + * @return TimeTableViewCommand or IncorrectCommand. + */ + private static Command parseTimeTableViewCommand(String commandFlag, String timeTableParams) { + int daysToView; + if (!timeTableParams.isEmpty()) { + commandFlag = ""; + } + switch (commandFlag) { + case VIEW_DAY_FORMAT: + daysToView = 1; + break; + case VIEW_WEEK_FORMAT: + daysToView = 7; + break; + default: + return new IncorrectCommand(String.format("%s%s\n\n%s%s\n", MESSAGE_INVALID_COMMAND_FORMAT, commandFlag, + MESSAGE_CHECK_COMMAND_FORMAT, TimeTableCommand.FORMAT)); + } + return new TimeTableViewCommand(daysToView); + } + + /** + * Parses the timetable add command. For the adding of Lessons into the timetable. + * Accepted commands will be in the format: timetable -add module day start end type repeat + * e.g. timetable -add CS2101 FRIDAY 1400 1600 LECTURE 1 + * + * @return TimeTableAddCommand or IncorrectCommand + * @throws ModuleNotFoundException When the module is not found in the module list. + * @throws LessonInvalidTimeException When the start is greater than or equal to end time of the Lesson. + * @throws DateTimeParseException When the time of either the start or end is in the wrong format. + * @throws InvalidMatchException When the lessonParams do not match the TimeTableAddCommand regex. + */ + private static Command parseTimeTableAddCommand(String lessonParams) + throws ModuleNotFoundException, LessonInvalidTimeException, + DateTimeParseException, InvalidMatchException { + Matcher lessonMatcher = TIMETABLE_LESSON_PARAMETER_FORMAT.matcher(lessonParams); + + Parser.matcherMatches(lessonMatcher, lessonParams, TIMETABLE_LESSON_ADD_USER_FORMAT, + TimeTableCommand.PROMPT_HELP); + + Lesson newLesson = LessonParser.parseLesson(lessonMatcher); + // Convert repeatString to int + String repeatString = lessonMatcher.group(REPEAT_GROUP).toLowerCase().trim(); + int repeatFreq = Integer.parseInt(repeatString); + return new TimeTableAddCommand(newLesson, repeatFreq); + } + + /** + * Parses the timetable delete command. For the deleting of Lessons from the timetable. + * Accepted commands will be in the format: timetable -del day index + * e.g. timetable -del MONDAY 2 + * index can be found through timetable -week + * + * @return TimeTableDeleteCommand or IncorrectCommand + * @throws InvalidMatchException When the lessonParams do not match the TimeTableDeleteCommand regex. + */ + private static Command parseTimeTableDeleteCommand(String deleteParams) throws InvalidMatchException { + Matcher lessonMatcher = TIMETABLE_DELETE_PARAMETER_FORMAT.matcher(deleteParams); + Parser.matcherMatches(lessonMatcher, deleteParams, TIMETABLE_LESSON_DELETE_USER_FORMAT, + TimeTableCommand.PROMPT_HELP); + String dayString = lessonMatcher.group(DAY_GROUP).toUpperCase().trim(); + DayOfWeek dayOfWeek = DayOfWeek.valueOf(dayString); + // Must account for the user input vs the week of year number + int indexToBeDeleted = Integer.parseInt(lessonMatcher.group(INDEX_GROUP)) - 1; + return new TimeTableDeleteCommand(dayOfWeek, indexToBeDeleted); + } + + public static Command parseTimeTableFilterCommand(String filterParams) throws + InvalidMatchException, ModuleNotFoundException { + Matcher filterMatcher = TIMETABLE_LESSON_FILTER_PARAMETER_FORMAT.matcher(filterParams); + Parser.matcherMatches(filterMatcher, filterParams, TIMETABLE_LESSON_FILTER_USER_FORMAT, + TimeTableCommand.PROMPT_HELP); + ArrayList filterList = LessonParser.parseFilterLesson(filterMatcher); + + return new TimeTableFilterCommand(filterList); + } + + /** + * Parses the timetable reset command. + * Accepted command will be: + * timetable -reset + * + * @param resetParams Remaining user input. + * @return TimeTableResetCommand or IncorrectCommand. + */ + public static Command parseTimeTableResetCommand(String resetParams) { + if (!resetParams.isEmpty()) { + return new IncorrectCommand(String.format("%s%s\n\n%s%s\n", MESSAGE_INVALID_COMMAND_FORMAT, resetParams, + MESSAGE_CHECK_COMMAND_FORMAT, TimeTableCommand.FORMAT)); + } + return new TimeTableResetCommand(); + } +} diff --git a/src/main/java/seedu/ravi/system/SystemSetting.java b/src/main/java/seedu/ravi/system/SystemSetting.java new file mode 100644 index 0000000000..26e9c8ca52 --- /dev/null +++ b/src/main/java/seedu/ravi/system/SystemSetting.java @@ -0,0 +1,4 @@ +package seedu.ravi.system; + +public class SystemSetting { +} diff --git a/src/main/java/seedu/ravi/ui/TextHelper.java b/src/main/java/seedu/ravi/ui/TextHelper.java new file mode 100644 index 0000000000..cc1bb65e01 --- /dev/null +++ b/src/main/java/seedu/ravi/ui/TextHelper.java @@ -0,0 +1,137 @@ +package seedu.ravi.ui; + +import static seedu.ravi.util.Message.MESSAGE_LOADING_TEMPLATE; + +public class TextHelper { + public static final String DIV_LINE = + "════════════════════════════════════════════════════════════════════════════════"; + + public static final String MESSAGE_TIMETABLE_HEADER = + " ┌───────────┬────┬────────────────────┐\n" + + " │ Time │ ID │ Lesson │\n" + + " ├───────────┼────┼────────────────────┤\n"; + public static final String MESSAGE_TIMETABLE_MIDDLE = "\n ├───────────┼────┼────────────────────┤\n"; + public static final String MESSAGE_TIMETABLE_FOOTER = "\n └───────────┴────┴────────────────────┘\n"; + + public static final int MAX_WIDTH = DIV_LINE.length(); + + //Offset required to convert between 1-indexing and 0-indexing + public static final int DISPLAY_INDEX_OFFSET = 1; + + //%1$ catches the furthest left arg, %2$ catches the 2nd arg + private static final String MESSAGE_INDEX_LIST_FORMAT = "\n%1$d. %2$s"; + + /** + * Formats a string with its index in the list. + * + * @param listIndex task/module index + * @param listItem task/module name or description + * @return String containing the index list in the intended format + */ + public static String getIndexListFormat(int listIndex, String listItem) { + return String.format(MESSAGE_INDEX_LIST_FORMAT, listIndex, listItem); + } + + /** + * Returns a string of the loading status based on the status code. + * Status parameter is a 4 digit number. First 3 digits are Hundreds: Timetable, Tens: Tasks, Ones: Modules. + * 0 - Files do not exist, skipping + * 1 - Files exist, loading success + * 2 - Files exist, error parsing JSON + * Then for the Thousands: NUSMods. + * 0 - Loaded from data directory + * 1 - Loaded from NUSMods API (subsequently to be saved to data directory) + * 2 - No internet connection, loaded from backup in jar file + * + * @param status + * The status code parameter + * @return + * The loading status string + */ + public static String parseStatusCode(int status) { + String[] items = {"Modules", "Tasks", "Timetable"}; + int latestCode; + String eachItem; + String statusMsg; + String loadingOutcomes = ""; + for (int i = 0; i < 3; i++) { + eachItem = items[i]; + latestCode = status % 10; // find ones digit of status + status /= 10; // remove ones digit + switch (latestCode) { + case 0: + statusMsg = "@|bold,blue,BG_BLACK Skipped (file not found!)|@"; + break; + case 1: + statusMsg = "@|bold,green,BG_BLACK Success!|@"; + break; + case 2: + statusMsg = "@|bold,red,BG_BLACK Failed (corrupted file auto-renamed)|@"; + break; + default: + statusMsg = "You shouldn't be here"; + break; + } + loadingOutcomes += centerString(String.format(MESSAGE_LOADING_TEMPLATE, eachItem, statusMsg)) + "\n"; + } + + // Now find the NUSMods status, the remaining digit in the status code + String nusModsStatus; + switch (status) { + case 0: + nusModsStatus = "@|bold,green,BG_BLACK Loaded from data directory!|@"; + break; + case 1: + nusModsStatus = "@|bold,blue,BG_BLACK Downloaded latest version!|@"; + break; + case 2: + nusModsStatus = "@|bold,red,BG_BLACK No internet - using packaged backup|@"; + break; + default: + nusModsStatus = "You shouldn't be here"; + break; + } + loadingOutcomes += centerString(String.format(MESSAGE_LOADING_TEMPLATE, "NUSMods", nusModsStatus)) + "\n"; + return loadingOutcomes; + } + + /** + * Simple function that returns a string centered in 'width' number of characters. + * Empty characters (i.e. left/right padding) are spaces. + * DOES NOT ACCOUNT for the formatting required by JANSI! + * + * @param width + * The number of characters for width + * @param s + * The string to be centered + * @return + * The centered string + */ + public static String centerString(int width, String s) { + return String.format("%-" + width + "s", + String.format("%" + (s.length() + (width - s.length()) / 2) + "s", s)); + } + + /** + * Overloaded centerString that defaults width to MAX_WIDTH. + * Accounts for the formatting required by JANSI. + * + * @param s + * The string to be centered + * @return + * The centered string + */ + public static String centerString(String s) { + String temp = s; + if (s.contains("@|")) { + // If the string is "a@|...b|@c", + String[] splitFrontFormat = s.split("@\\S*\\s+", 0); // this is [a, b|@c] + String[] splitBackFormat = splitFrontFormat[1].split("\\|@", 0); // this is [b, c] + temp = splitFrontFormat[0] + splitBackFormat[0] + + (splitBackFormat.length == 2 ? splitBackFormat[1] : ""); // Get a + b + c (c might be null) + } + int numSpaces = (MAX_WIDTH - temp.length()) / 2; + String spaces = String.format("%" + numSpaces + "s", ""); + return spaces + s; + } +} diff --git a/src/main/java/seedu/ravi/ui/TextUi.java b/src/main/java/seedu/ravi/ui/TextUi.java new file mode 100644 index 0000000000..ec82928bd5 --- /dev/null +++ b/src/main/java/seedu/ravi/ui/TextUi.java @@ -0,0 +1,251 @@ +package seedu.ravi.ui; + +import seedu.ravi.command.CommandResult; +import seedu.ravi.data.Lesson; +import seedu.ravi.data.Module; +import seedu.ravi.data.Task; +import seedu.ravi.util.Message; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.NoSuchElementException; +import java.util.Scanner; + +import static org.fusesource.jansi.Ansi.ansi; +import static seedu.ravi.util.ExceptionMessage.EXCEPTION_HEADER; +import static seedu.ravi.util.ExceptionMessage.MESSAGE_LIST_EMPTY; +import static seedu.ravi.util.Message.MESSAGE_COMPLETED_TASKLIST; +import static seedu.ravi.util.Message.MESSAGE_GENERAL_HELP; +import static seedu.ravi.util.Message.MESSAGE_INCOMPLETE_DATED_TASKLIST; +import static seedu.ravi.util.Message.MESSAGE_INCOMPLETE_UNDATED_TASKLIST; +import static seedu.ravi.util.Message.MESSAGE_NO_LESSONS; +import static seedu.ravi.util.Message.MESSAGE_TIMETABLE_INIT; + +public class TextUi { + private static Scanner in; + + public static void initialiseTextUi(Scanner in) { + TextUi.in = in; + } + + /** + * Prints welcome message, and shows file loading status according to the status parameter. + * Enum not used because it's only used by InputOutputManager.start() and this function. + * + * @param status + * The status code as shown above + */ + public static void showWelcomeMessage(int status) { + outputToUser( + TextHelper.centerString(Message.MESSAGE_WELCOME), + "", + TextHelper.parseStatusCode(status)); + } + + public static void showTimeTableInitialisationMessage() { + outputToUser(MESSAGE_TIMETABLE_INIT); + } + + /** + * Shows the result of a command execution to the user. + * + * @param result + * The relevant message shown to user + */ + public static void showResultToUser(CommandResult result) { + if (!result.isError) { + outputToUser(result.feedbackToUser); + } else { + outputToUser(TextHelper.centerString(EXCEPTION_HEADER), result.feedbackToUser); + } + } + + /** + * Print the given Strings to the user, capped at top and bottom by the DIV_LINE. + * + * @param output + * The strings to be printed to the user + */ + public static void outputToUser(String... output) { + System.out.println(TextHelper.DIV_LINE); + for (String o : output) { + System.out.println(ansi().render(o)); + } + System.out.println(TextHelper.DIV_LINE); + } + + /** + * Formats the lists in summaryLists to string with their index. + * + * @param summaryLists the list of ArrayLists to be formatted + * @return message as a string, containing the summary list + */ + public static String getSummaryList(ArrayList> summaryLists) { + final StringBuilder message = new StringBuilder(); + + ArrayList incompleteDatedList = summaryLists.get(0); + message.append(MESSAGE_INCOMPLETE_DATED_TASKLIST); + if (incompleteDatedList.size() > 0) { + message.append(getIndexTaskList(incompleteDatedList)); + } else { + message.append(MESSAGE_LIST_EMPTY); + } + + ArrayList incompleteUndatedList = summaryLists.get(1); + message.append(MESSAGE_INCOMPLETE_UNDATED_TASKLIST); + if (incompleteUndatedList.size() > 0) { + message.append(getIndexTaskList(incompleteUndatedList)); + } else { + message.append(MESSAGE_LIST_EMPTY); + } + + ArrayList completeList = summaryLists.get(2); + message.append(MESSAGE_COMPLETED_TASKLIST); + if (completeList.size() > 0) { + message.append(getIndexTaskList(completeList)); + } else { + message.append(MESSAGE_LIST_EMPTY); + } + + return message.toString(); + } + + /** + * Prints day timetable. + * + * @param now the LocalDate object for the current day + * @param lessonList the lesson list for the day + * @return the String of the day's timetable + */ + public static String printDayTimetable(LocalDate now, ArrayList lessonList) { + StringBuilder output = new StringBuilder(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern(", dd-MM-yy"); + if (lessonList.size() > 0) { + output.append(System.lineSeparator()) + .append(now.getDayOfWeek() + now.format(formatter) + ":") + .append(System.lineSeparator()) + .append(TextHelper.MESSAGE_TIMETABLE_HEADER); + for (Lesson lesson : lessonList) { + int lessonNumber = lessonList.indexOf(lesson) + 1; + output.append(printLessonBlock(lesson, lessonNumber)); + if (lessonNumber == lessonList.size()) { + output.append(TextHelper.MESSAGE_TIMETABLE_FOOTER); + } else { + output.append(TextHelper.MESSAGE_TIMETABLE_MIDDLE); + } + } + } else { + output = new StringBuilder(MESSAGE_NO_LESSONS + now.getDayOfWeek() + now.format(formatter) + ".\n"); + } + return output.toString(); + } + + /** + * Prints a timetable block for a particular lesson. + * + * @param lesson the Lesson to be printed + * @param lessonIndex the index of the Lesson to be printed + * @return the timetable block containing lesson time, number and name + */ + public static String printLessonBlock(Lesson lesson, int lessonIndex) { + DateTimeFormatter time = DateTimeFormatter.ofPattern("HHmm"); + String startTime = lesson.getStartTime().format(time); + String endTime = lesson.getEndTime().format(time); + String lessonNumber = String.format("%02d", lessonIndex); + return String.format(" │%s│%s│%s│", + TextHelper.centerString(11, startTime + "-" + endTime), + TextHelper.centerString(4, lessonNumber), + TextHelper.centerString(20, lesson.getModuleCode() + " " + lesson.getLessonTypeString())); + } + + /** + * Formats an Arraylist of type Task with their Index. + * + * @param taskList the list to be formatted + * @return stringFormat as a string, containing the index task list + */ + public static String getIndexTaskList(ArrayList taskList) { + final StringBuilder stringFormat = new StringBuilder(); + int displayIndex = TextHelper.DISPLAY_INDEX_OFFSET; + for (Task t : taskList) { + stringFormat.append(TextHelper.getIndexListFormat(displayIndex, t.toString())); + displayIndex++; + } + stringFormat.append("\n"); + return stringFormat.toString(); + } + + /** + * Formats the HashMap to string with their index. + * + * @param modulesMap + * The HashMap to be formatted + * @return + * Formatted string containing the index module list + */ + public static String getIndexModuleList(HashMap modulesMap) { + final StringBuilder stringFormat = new StringBuilder(); + int displayIndex = TextHelper.DISPLAY_INDEX_OFFSET; + for (Module module : modulesMap.values()) { + stringFormat.append(TextHelper.getIndexListFormat(displayIndex, module.toString())); + displayIndex++; + } + return stringFormat.toString(); + } + + /** + * Gets the User's input command. + * + * @return + * The trimmed user input command. + * @throws NoSuchElementException + * When the user input is ctrl-c. + */ + public static String getUserCommand() throws NoSuchElementException { + System.out.println("\n\nCommand: "); + System.out.print("»\t"); + + String userInput = in.nextLine(); + return userInput; + } + + /** + * The current week of year. + * + * @return + * The current week of year. + * @throws NoSuchElementException + * When the user input is ctrl-c. + * @throws NumberFormatException + * When the user input is not an integer. + */ + public static int getCurrentWeekNum() throws NoSuchElementException, NumberFormatException { + String userInput = in.nextLine().trim(); + return Integer.parseInt(userInput); + } + + /** + * Gets command list. + * + * @return + * The list of available commands + */ + public static String getCommandList() { + return MESSAGE_GENERAL_HELP; + } + + /** + * Gets Help Message prompt. + * + * @param commandWord + * The command word entered by the user + * @return + * The list of available commands + */ + public static String getCommandHelpMessage(String commandWord) { + return String.format("For more information on %s, type `help %s`.", commandWord, commandWord); + } +} + diff --git a/src/main/java/seedu/ravi/util/DummyModule.java b/src/main/java/seedu/ravi/util/DummyModule.java new file mode 100644 index 0000000000..937f0c039c --- /dev/null +++ b/src/main/java/seedu/ravi/util/DummyModule.java @@ -0,0 +1,22 @@ +package seedu.ravi.util; + +public class DummyModule { + private String moduleCode; + private String title; + + public void setModuleCode(String moduleCode) { + this.moduleCode = moduleCode; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getModuleCode() { + return moduleCode; + } + + public String getTitle() { + return title; + } +} \ No newline at end of file diff --git a/src/main/java/seedu/ravi/util/ExceptionMessage.java b/src/main/java/seedu/ravi/util/ExceptionMessage.java new file mode 100644 index 0000000000..f0cb408e2b --- /dev/null +++ b/src/main/java/seedu/ravi/util/ExceptionMessage.java @@ -0,0 +1,156 @@ +package seedu.ravi.util; + +public class ExceptionMessage { + public static final String EXCEPTION_HEADER = "@|bold,white,BG_RED Error!|@"; + + public static final String MESSAGE_NUS_MODS_NOT_LOADED = + "@|bold,red,BG_BLACK,NEGATIVE_ON NUSMods data could not be loaded!|@\n" + + "ra.VI is meant to be able to work offline, and so is packaged with a \n" + + "copy of NUSMods data. If you're reading this, the ra.VI jar file you are \n" + + "using may be corrupted. Please try to download again when you have an \n" + + "Internet connection. Sorry for the inconvenience.\n"; + + public static final String MESSAGE_MODULE_NOT_FOUND = + "Sorry, the module is @|bold,red,BG_BLACK not in your module list|@.\n" + + "Try checking the spelling of your module code?\n"; + public static final String MESSAGE_MODULE_NOT_PROVIDED = + "Sorry, the module is @|bold,red,BG_BLACK not provided by NUS currently|@.\n" + + "Try checking the spelling of your module code?\n"; + public static final String MESSAGE_DUPLICATE_MODULE = + "Sorry, the module @|bold,red,BG_BLACK already exists in your list|@, so I can't add it again.\n" + + "Perhaps you meant a different module?\n"; + public static final String MESSAGE_TASK_NOT_FOUND = + "Sorry, that @|bold,red,BG_BLACK task index is not valid|@.\n" + + "Use @|bold,green,BG_BLACK 'list -t'|@ to look at your tasks, and their index.\n" + + "You can't use the task index from the summary command!\n"; + public static final String MESSAGE_NO_EDIT_MODULE = + "Sorry, @|bold,red,BG_BLACK please enter a proper module code|@ to edit.\n" + + "It should be a module code of an actual NUS mod. E.g. CS1010.\n"; + public static final String MESSAGE_NO_EDIT_TASK = + "Sorry, @|bold,red,BG_BLACK please enter a proper task index|@ to edit.\n" + + "Use @|bold,green,BG_BLACK 'list -t'|@ to look at your tasks, and their index.\n" + + "You can't use the task index from the summary command!\n"; + public static final String MESSAGE_NO_ADD_MODULE = + "Sorry, @|bold,red,BG_BLACK please enter a new module code|@ to add.\n" + + "It should be a module code of an actual NUS mod. E.g. CS1010.\n"; + public static final String MESSAGE_NO_ADD_TASK = + "Sorry, @|bold,red,BG_BLACK please enter a new task|@ to add.\n" + + "Use @|bold,green,BG_BLACK 'list -t'|@ to look at your tasks, and their index.\n" + + "You can't use the task index from the summary command!\n"; + public static final String MESSAGE_INVALID_PARAMETERS = + "Some @|bold,red,BG_BLACK invalid or missing parameters|@ were found!\n" + + "Use @|bold,green,BG_BLACK 'help'|@ to find out about the parameters required: " + + "@|bold,green,BG_BLACK 'help %s'|@\n"; + public static final String MESSAGE_LIST_EMPTY = + "\nYour list is empty.\n"; + public static final String MESSAGE_STRING_IN_NUMBER = + "The task index you have entered is @|bold,red,BG_BLACK either not an integer or is too long|@!\n" + + "Use @|bold,green,BG_BLACK 'list -t'|@ to look at your tasks, and their index.\n" + + "Please check your command! Use @|bold,green,BG_BLACK 'help %s'|@ for assistance.\n"; + public static final String MESSAGE_INVALID_COMMAND_WORD = + "ra.VI @|bold,red,BG_BLACK does not recognise|@ that command.\n" + + "Please use @|bold,green,BG_BLACK 'help'|@ to see our list of commands.\n"; + public static final String MESSAGE_INVALID_GRADE = + "Your grade input @|bold,red,BG_BLACK isn't part of the NUS grading scheme|@. \n" + + "For your reference: A+, A, A-, B+, B, B-, C+, C, C-, D+, F, CS, CU.\n"; + public static final String MESSAGE_LESSON_INVALID_TIME = + "Sorry, the lesson you have attempted to add has an @|bold,red,BG_BLACK invalid start/end time|@.\n" + + "Try using @|bold,green,BG_BLACK 'timetable -day'|@ or " + + "@|bold,green,BG_BLACK 'timetable -week'|@ to look at your\n" + + "current lessons first, or review your new lesson's start/end time.\n"; + public static final String MESSAGE_LESSON_NOT_FOUND = + "Sorry, the lesson you have attempted to delete @|bold,red,BG_BLACK does not exist|@.\n" + + "Use @|bold,green,BG_BLACK 'timetable (-week/-day)'|@ to look at your lessons and their index (ID).\n"; + public static final String MESSAGE_LESSON_OVERLAP = + "Sorry, the lesson you have attempted to add @|bold,red,BG_BLACK overlaps with other lessons|@.\n" + + "This is the lesson you're overlapping with: %s\n"; + public static final String MESSAGE_REPEAT_FREQUENCY_UNKNOWN = + "Sorry, the lesson you have attempted to add @|bold,red,BG_BLACK does " + + "not have the correct repeatability|@.\n" + + "For your reference:\n" + + "0 - This week only\n" + + "1 - Every week\n" + + "2 - Every even week\n" + + "3 - Every odd week\n"; + public static final String TIMETABLE_NOT_INITIALISED = + "Sorry, please enter a @|bold,red,BG_BLACK proper week number|@ as instructed.\n"; + public static final String MESSAGE_ADD_TASK_DATE_TIME_UNKNOWN = + "Sorry, please enter a @|bold,red,BG_BLACK valid date and time|@.\n" + + "\tRequired date time format: dd-MM-yyyy HHmm\n" + + "\tExample: 30-12-2020 1600"; + public static final String MESSAGE_ADD_LESSON_DATE_TIME_UNKNOWN = + "Sorry, please enter a @|bold,red,BG_BLACK valid start time and end time|@.\n" + + "\tRequired date time format: HHmm HHmm (start, end)\n" + + "\tExample: 1800 2000"; + public static final String MESSAGE_INVALID_CAP = + "The CAP you entered is @|bold,red,BG_BLACK invalid|@.\n"; + public static final String MESSAGE_INVALID_CAP_ATTAINED = + "The CAP calculated from your input is @|bold,red,BG_BLACK invalid|@.\n" + + "For more information, use @|bold,green,BG_BLACK 'help cap'|@.\n"; + public static final String MESSAGE_INVALID_MC = + "The number of MCs you entered is @|bold,red,BG_BLACK invalid|@.\n" + + "For more information, use @|bold,green,BG_BLACK 'help grade'|@.\n"; + public static final String MESSAGE_INVALID_HELP_COMMAND = + "The help command you have entered is @|bold,red,BG_BLACK invalid|@.\n" + + "For more information, use @|bold,green,BG_BLACK 'help'|@.\n"; + + /* + + public static final String MESSAGE_MISSING_DIRECTORY_NAME = + "Please include the name of the directory you want to move to.\n" + + "Alternatively, enter .. to move to the parent directory instead.\n"; + + public static final String MESSAGE_CATEGORY_NOT_FOUND = "Sorry, the category is not found.\n"; + public static final String MESSAGE_DUPLICATE_CATEGORY = "Sorry, the category already exists.\n"; + + public static final String MESSAGE_DUPLICATE_TASK = "Sorry, the task already exists.\n"; + + public static final String MESSAGE_TASK_FILE_NOT_FOUND = "Sorry, the file is not found.\n"; + public static final String MESSAGE_DUPLICATE_TASK_FILE = "Sorry, the file already exists.\n"; + public static final String MESSAGE_IMPLICIT_FILE_EXCEED_LIMIT = + "Sorry, the name of the file you are adding exceeds 30 characters.\n" + + "Please enter a new file name.\n"; + + public static final String MESSAGE_MISSING_PARAMETERS = "Sorry, some parameters seem to be missing.\n"; + + public static final String MESSAGE_INVALID_PRIORITY = "Alert! Priority should be a number between 0 and 20.\n"; + public static final String MESSAGE_INVALID_DATETIME_FORMAT = + "Sorry, the deadline you entered is not in a recognised datetime format.\n" + + "Please make sure to follow the datetime format as such:\n\t" + + DateTime.FORMAT + "\nExample: 06/06/2020 12:00am\n"; + public static final String MESSAGE_INVALID_DATE_FORMAT = + "Sorry, the date you entered is not in a recognised date format.\n" + + "Please make sure to follow the date format as such:\n\t" + + DateTime.DATE_FORMAT + "\nExample: 07/07/2020\n"; + + public static final String MESSAGE_LIST_NUMBER_NOT_FOUND = + "The List number is not found on the list! Deletion is aborted.\n"; + + public static final String MESSAGE_TRAVERSE_ERROR = + "There seems to be an error when traversing. Moving back to Root...\n"; + public static final String MESSAGE_FAILED_DIRECTORY_TRAVERSAL = "Unable to traverse further.\n"; + public static final String MESSAGE_DIRECTORY_NOT_FOUND = "Sorry, the next directory could not be found.\n"; + public static final String MESSAGE_INCORRECT_DIRECTORY_LEVEL = + "Sorry, unable to execute the command at the current directory level.\n" + + "Either move to the appropriate directory level, or enter the full directory path.\n"; + + + public static final String MESSAGE_DUPLICATE_PREFIX_FOUND = + "There seems to be duplicate prefix(es) in your input...\n"; + + public static final String MESSAGE_FILE_IO_EXCEPTION = "Oh no! There was an error in retrieving your file.\n"; + public static final String MESSAGE_FILE_SYSTEM_EXCEPTION = "Oh no! There was an error in retrieving your file. " + + "Please check that your file is not currently running.\n"; + public static final String MESSAGE_INVALID_FILE_PATH = "Sorry, the file path entered is invalid.\n"; + public static final String MESSAGE_ADD_FILE_NOT_FOUND = + "Sorry, the file does not exists. Please check the file path again.\n"; + public static final String MESSAGE_FILE_SECURITY_EXCEPTION = + "Oh no! File access was denied by device's security program.\n"; + public static final String MESSAGE_FILE_NOT_FOUND_OPEN = + "The following file(s) could not be opened as they cannot be found:\n"; + public static final String MESSAGE_FILE_NOT_FOUND_DELETE = + "Deletion completed.\n" + + "However, note that the following file(s) could not be deleted completely from Nuke as they " + + "could not be found:\n"; + */ +} diff --git a/src/main/java/seedu/ravi/util/FileName.java b/src/main/java/seedu/ravi/util/FileName.java new file mode 100644 index 0000000000..6d6f439197 --- /dev/null +++ b/src/main/java/seedu/ravi/util/FileName.java @@ -0,0 +1,10 @@ +package seedu.ravi.util; + +public class FileName { + public static final String FILE_EXT = ".json"; + + public static final String TASK_SAVE_FILE_NAME = "task_data"; + public static final String MOD_SAVE_FILE_NAME = "mod_data"; + public static final String NUSMOD_SAVE_FILE_NAME = "nus_mod_data"; + public static final String TIMETABLE_SAVE_FILE_NAME = "timetable_data"; +} diff --git a/src/main/java/seedu/ravi/util/Message.java b/src/main/java/seedu/ravi/util/Message.java new file mode 100644 index 0000000000..4070899aa8 --- /dev/null +++ b/src/main/java/seedu/ravi/util/Message.java @@ -0,0 +1,100 @@ +package seedu.ravi.util; + +public class Message { + public static final String MESSAGE_GOODBYE = "@|bold,magenta,BG_BLACK Goodbye, hope to see you soon!|@"; + public static final String MESSAGE_WELCOME = "@|bold,magenta,BG_BLACK Welcome to ra.VI v2.0|@"; + public static final String MESSAGE_SHUTDOWN = "@|bold,magenta,BG_BLACK Shutting down ra.VI...|@"; + + public static final String MESSAGE_LOADING_TEMPLATE = "Loading %s: %s"; + + public static final String MESSAGE_ADD_TASK_SUCCESS = + "Your task has been @|bold,green added successfully|@.\n" + + "Your new task:\n'%s'\n"; + public static final String MESSAGE_ADD_MODULE_SUCCESS = + "Your module has been @|bold,green added successfully|@.\n" + + "Your new module:\n'%s'\n"; + public static final String MESSAGE_ADD_LESSON_SUCCESS = + "Your lesson has been @|bold,green added successfully|@.\n" + + "Your new lesson:\n'%s'\n" + + "Added to: %s\n"; + + public static final String MESSAGE_DONE_TASK_SUCCESS = + "The task has been @|bold,green successfully|@ marked as complete.\n" + + "Your completed task - '%s'\n"; + + public static final String MESSAGE_DELETE_TASK_SUCCESS = + "Your task has been @|bold,green deleted successfully|@.\n" + + "Your deleted task - '%s'\n"; + public static final String MESSAGE_DELETE_MODULE_SUCCESS = + "Your module has been @|bold,green deleted successfully|@.\n" + + "Your deleted module - '%s'\n"; + public static final String MESSAGE_DELETE_LESSON_SUCCESS = + "Your lesson has been @|bold,green deleted successfully|@ from " + + "all weeks.\n" + + "Your deleted lesson - '%s'\n"; + + public static final String MESSAGE_EDIT_TASK_SUCCESS = + "Your task has been @|bold,green edited successfully|@.\n" + + "Your task before editing - '%s'\n" + + "Your task after editing - '%s'\n"; + public static final String MESSAGE_EDIT_MODULE_SUCCESS = + "Your module has been @|bold,green edited successfully|@.\n" + + "Your module before editing - '%s'\n" + + "Your module after editing - '%s'\n"; + + public static final String MESSAGE_EMPTY_INPUT = "Please enter a command for me.\n"; + public static final String MESSAGE_INVALID_COMMAND_FORMAT = + "The command entered contains some @|bold,blue,BG_BLACK unrecognised parameters|@ starting from here:\n"; + public static final String MESSAGE_CHECK_COMMAND_FORMAT = + "@|bold,red,BG_BLACK,NEGATIVE_ON Please check to make sure to follow the command format:|@\n"; + public static final String ICON_DONE = "\u221A"; + public static final String ICON_NOT_DONE = "\u0078"; + public static final String MESSAGE_LIST_PRINTED = "Here's your list:\n"; + public static final String MESSAGE_UNDO_SUCCESS = "Undo is @|bold,green successful|@.\n" + + "Command undone - '%s'\n"; + public static final String MESSAGE_UNDO_AT_BEGINNING = "There is nothing to undo."; + public static final String MESSAGE_GRADE_MODULE_SUCCESS = + "Your module has been @|bold,green graded successfully|@.\n" + + "The module - '%s'. \n"; + public static final String MESSAGE_CAP_DISPLAY = "Your current CAP is \n"; + + public static final String MESSAGE_SUMMARY_PRINTED = "Here's a summary of your latest tasks...\n"; + public static final String MESSAGE_COMPLETED_TASKLIST = + "\n@|bold,green,BG_BLACK,NEGATIVE_ON Completed tasks:|@"; + public static final String MESSAGE_INCOMPLETE_UNDATED_TASKLIST = + "\n@|bold,blue,BG_BLACK,NEGATIVE_ON Incomplete tasks with no deadline:|@"; + public static final String MESSAGE_INCOMPLETE_DATED_TASKLIST = + "\n@|bold,red,BG_BLACK,NEGATIVE_ON Incomplete tasks with deadlines:|@"; + + public static final String MESSAGE_GENERAL_HELP = + "Hello! I'm @|bold,magenta,BG_BLACK ra.VI|@, your personal NUS assistant.\n" + + "I'm here to help you manage your tasks, modules, and lessons.\n" + + "This help message appears when you type @|bold,green,BG_BLACK 'help'|@, or an unrecognised command.\n" + + "To find out more about any of my commands, type @|bold,green,BG_BLACK 'help '|@.\n" + + "Here's a list of my commands to help you out:\n\n" + + "@|bold,red,BG_BLACK,NEGATIVE_ON Action commands:|@\n" + + "\t» add - Add a task or module\n" + + "\t» del - Delete a task or module\n" + + "\t» edit - Edit a task or module\n" + + "\t» done - Mark a task as complete\n" + + "\t» grade - Grades and allocates MCs to a Module\n" + + "\t» cap - Calculates your CAP\n" + + "\t» undo - Undo the previous action (if you made changes)\n" + + "\t» timetable - Manage your timetable\n" + + "@|bold,blue,BG_BLACK,NEGATIVE_ON Viewing commands:|@\n" + + "\t» list - Lists all tasks or modules\n" + + "\t» summary - See a neat summary of your tasks\n" + + "\t» timetable - View your timetable, by day or by week\n" + + "@|bold,yellow,BG_BLACK,NEGATIVE_ON Utility commands:|@\n" + + "\t» help - Get detailed help for each command\n" + + "\t» bye - Exit ra.VI (saves all changes!)"; + public static final String MESSAGE_TIMETABLE_INIT = + "Please enter the @|bold,blue,BG_BLACK current week number|@ e.g. 1 - 14" + + " where 7 is recess week,\n" + "and NUS week 7 onwards is week 8 onwards. \n\n" + + "@|bold,red,BG_BLACK Before|@ recess week : please input the current NUS week number.\n" + + "@|bold,red,BG_BLACK During|@ recess week : please input 7.\n" + + "@|bold,red,BG_BLACK After|@ recess week : please input the current NUS week number + 1.\n\n" + + "E.g. if it's week 7, enter '8'.\n"; + public static final String MESSAGE_NO_LESSONS = "\nNo lessons on "; + public static final String MESSAGE_TIMETABLE_RESET = "Timetable reset successful."; +} diff --git a/src/main/resources/nus_mod_data.json b/src/main/resources/nus_mod_data.json new file mode 100644 index 0000000000..d1c2125e14 --- /dev/null +++ b/src/main/resources/nus_mod_data.json @@ -0,0 +1,5864 @@ +{"moduleCode":"CP3107","moduleCredit":0,"title":"Computing for Voluntary Welfare Organisations"} +{"moduleCode":"IE4230","moduleCredit":0,"title":"Quality Engineering II"} +{"moduleCode":"NUR5009","moduleCredit":0,"title":"Principles & Practice of Palliative Care"} +{"moduleCode":"CP3106","moduleCredit":0,"title":"Independent Project"} +{"moduleCode":"PS2238","moduleCredit":0,"title":"International Politics of Northeast Asia"} +{"moduleCode":"LL4094BV","moduleCredit":0,"title":"Law & Practice - The Law Clinic"} +{"moduleCode":"NUR5002","moduleCredit":0,"title":"Statistics for Health Research"} +{"moduleCode":"NUR5003","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"PS2237","moduleCredit":0,"title":"Introduction to International Relations"} +{"moduleCode":"DOS3714","moduleCredit":0,"title":"Sustainable Operations Management"} +{"moduleCode":"MS6770","moduleCredit":0,"title":"Graduate Research Seminar"} +{"moduleCode":"PS2240","moduleCredit":0,"title":"Introduction to Public Administration"} +{"moduleCode":"GEM1913","moduleCredit":0,"title":"Beasts, People and Wild Environments in South Asia"} +{"moduleCode":"ULS2202","moduleCredit":0,"title":"Evolution"} +{"moduleCode":"TCE2155","moduleCredit":0,"title":"Structural Mechanics and Materials"} +{"moduleCode":"ULS2201","moduleCredit":0,"title":"The Biomolecular Revolution"} +{"moduleCode":"ST2334","moduleCredit":0,"title":"Probability and Statistics"} +{"moduleCode":"AR1328","moduleCredit":0,"title":"The Tropical Envelope"} +{"moduleCode":"AR1327","moduleCredit":0,"title":"Structural Principles"} +{"moduleCode":"IE6881","moduleCredit":0,"title":"Topics in Data Science 1"} +{"moduleCode":"IE6880","moduleCredit":0,"title":"Topics in Operations Research 1"} +{"moduleCode":"LL4094AV","moduleCredit":0,"title":"Law & Practice - The Law Clinic"} +{"moduleCode":"EE5401","moduleCredit":0,"title":"Cellular Mobile Communications"} +{"moduleCode":"EE6733","moduleCredit":0,"title":"Advanced Topics on Vision and Machine Learning"} +{"moduleCode":"CM1501","moduleCredit":0,"title":"Organic Chemistry for Engineers"} +{"moduleCode":"SE3660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"ULS2206","moduleCredit":0,"title":"The Doors of Perception: Biology, Technology & Culture"} +{"moduleCode":"PS3551","moduleCredit":0,"title":"FASS Undergraduate Research Opportunity (UROP )"} +{"moduleCode":"DOS3701","moduleCredit":0,"title":"Supply Chain Management"} +{"moduleCode":"PS3550","moduleCredit":0,"title":"Political Science Internship"} +{"moduleCode":"DOS3702","moduleCredit":0,"title":"Purchasing and Materials Management"} +{"moduleCode":"IE4220","moduleCredit":0,"title":"Supply Chain Modelling"} +{"moduleCode":"DOS3703","moduleCredit":0,"title":"Service Operations Management"} +{"moduleCode":"ULS2208","moduleCredit":0,"title":"Biodiversity and Natural History in Singapore"} +{"moduleCode":"BMA5237A","moduleCredit":0,"title":"Topics in Managing Global Value Chains and Networks"} +{"moduleCode":"BSP1703","moduleCredit":0,"title":"Managerial Economics"} +{"moduleCode":"CP3110","moduleCredit":0,"title":"Computing for Voluntary Welfare Organisations II"} +{"moduleCode":"BSP1702","moduleCredit":0,"title":"Legal Environment of Business"} +{"moduleCode":"EE4104","moduleCredit":0,"title":"Microwave Circuits & Devices"} +{"moduleCode":"EE5434","moduleCredit":0,"title":"Microelectronic Processes and Integration"} +{"moduleCode":"BMK5201","moduleCredit":0,"title":"Customer Relationship Management"} +{"moduleCode":"EE5439","moduleCredit":0,"title":"Micro/Nano Electromechanical Systems"} +{"moduleCode":"BMK5200","moduleCredit":0,"title":"Pricing Analytics"} +{"moduleCode":"PS2256","moduleCredit":0,"title":"Politics on Screen"} +{"moduleCode":"PS2257","moduleCredit":0,"title":"Contemporary African Politics"} +{"moduleCode":"PS2258","moduleCredit":0,"title":"Introduction to Political Theory"} +{"moduleCode":"LLD5322V","moduleCredit":0,"title":"Trade Finance Law"} +{"moduleCode":"IE4211","moduleCredit":0,"title":"Modelling & Analytics"} +{"moduleCode":"IE4210","moduleCredit":0,"title":"Operations Research II"} +{"moduleCode":"PS2255","moduleCredit":0,"title":"Politics of the Middle East"} +{"moduleCode":"TCE2134","moduleCredit":0,"title":"Hydraulics"} +{"moduleCode":"EE5440","moduleCredit":0,"title":"Magnetic Data Storage for Big Data"} +{"moduleCode":"LL5202V","moduleCredit":0,"title":"ASEAN Economic Community Law and Policy"} +{"moduleCode":"EE4113","moduleCredit":0,"title":"Digital Communications & Coding"} +{"moduleCode":"EE4112","moduleCredit":0,"title":"Radio Frequency Design and Systems"} +{"moduleCode":"BPS5229","moduleCredit":0,"title":"Data Science for the Built Environment"} +{"moduleCode":"BPS5228","moduleCredit":0,"title":"Advanced Building Materials and Structures"} +{"moduleCode":"CP3108A","moduleCredit":0,"title":"Independent Work"} +{"moduleCode":"EE4214E","moduleCredit":0,"title":"Real-Time Embedded Systems"} +{"moduleCode":"LL4094CV","moduleCredit":0,"title":"Law & Practice - The Law Clinic"} +{"moduleCode":"PS2249","moduleCredit":0,"title":"Government and Politics of Singapore"} +{"moduleCode":"CP3108B","moduleCredit":0,"title":"Independent Work"} +{"moduleCode":"BPS5221","moduleCredit":0,"title":"Microclimate Design"} +{"moduleCode":"PS6603","moduleCredit":0,"title":"Topics in Research Methods"} +{"moduleCode":"BPS5223","moduleCredit":0,"title":"Building Energy Performance - Passive Systems"} +{"moduleCode":"BPS5222","moduleCredit":0,"title":"Indoor Environmental Quality"} +{"moduleCode":"PS2248","moduleCredit":0,"title":"Chinese Politics"} +{"moduleCode":"BMK6111O","moduleCredit":0,"title":"Marketing Strategy"} +{"moduleCode":"BPS5224","moduleCredit":0,"title":"Building Energy Performance - Active Systems"} +{"moduleCode":"BMK6111R","moduleCredit":0,"title":"Behavioral Aspects of Pricing"} +{"moduleCode":"BPS5226","moduleCredit":0,"title":"Smart Buildings and Facilities"} +{"moduleCode":"PS2244","moduleCredit":0,"title":"Public Administration in Singapore"} +{"moduleCode":"PS2250","moduleCredit":0,"title":"International Politics of Southeast Asia"} +{"moduleCode":"PS2251","moduleCredit":0,"title":"The Region in the Postcolonial World"} +{"moduleCode":"EE4101","moduleCredit":0,"title":"RF Communications"} +{"moduleCode":"EE5431","moduleCredit":0,"title":"Fundamentals of Nanoelectronics"} +{"moduleCode":"ESE3011","moduleCredit":0,"title":"Integrated Project for Environmental Sustainability"} +{"moduleCode":"SH5201","moduleCredit":0,"title":"Hazard Identification & Evaluation Techniques"} +{"moduleCode":"SH5203","moduleCredit":0,"title":"Emergency Planning"} +{"moduleCode":"FST1101","moduleCredit":0,"title":"Science and Technology of Foods"} +{"moduleCode":"LL4263V","moduleCredit":0,"title":"Intellectual Property Rights and Competition Policy"} +{"moduleCode":"SH5202","moduleCredit":0,"title":"Quantified Risk Analysis"} +{"moduleCode":"FST1103","moduleCredit":0,"title":"Fundamentals of Food Engineering"} +{"moduleCode":"SH5204","moduleCredit":0,"title":"Safety Engineering"} +{"moduleCode":"EG2701A","moduleCredit":0,"title":"Aspirational Project I"} +{"moduleCode":"SH5206","moduleCredit":0,"title":"Human Factors in Process Safety"} +{"moduleCode":"NM3234Y","moduleCredit":0,"title":"Leadership, Organisations and Communication"} +{"moduleCode":"EL5103R","moduleCredit":0,"title":"Language in Society"} +{"moduleCode":"BMA5506","moduleCredit":0,"title":"Product & Brand Management"} +{"moduleCode":"TCE2112","moduleCredit":0,"title":"Soil Mechanics"} +{"moduleCode":"BMA5505","moduleCredit":0,"title":"Services Marketing"} +{"moduleCode":"LAJ4205","moduleCredit":0,"title":"Expository Writing & Public Speaking"} +{"moduleCode":"AR3102A","moduleCredit":0,"title":"Design 6 (Landscape Architecture Emphasis)"} +{"moduleCode":"LAJ4203","moduleCredit":0,"title":"Newspaper Reading"} +{"moduleCode":"SC5209R","moduleCredit":0,"title":"Sociology of Everyday Life"} +{"moduleCode":"YIR3320G","moduleCredit":0,"title":"Independent Reading and Research"} +{"moduleCode":"EL6660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"SSS1207","moduleCredit":0,"title":"Natural Heritage of Singapore"} +{"moduleCode":"CS4277","moduleCredit":0,"title":"3D Computer Vision"} +{"moduleCode":"CS4278","moduleCredit":0,"title":"Intelligent Robots: Algorithms and Systems"} +{"moduleCode":"CS4276","moduleCredit":0,"title":"IoT Security"} +{"moduleCode":"BL5202A","moduleCredit":0,"title":"Biophysical Methods in Life Sciences"} +{"moduleCode":"LL5205V","moduleCredit":0,"title":"Maritime Conflict of Laws"} +{"moduleCode":"PC3311","moduleCredit":0,"title":"Undergraduate Professional Internship"} +{"moduleCode":"PC3310","moduleCredit":0,"title":"Undergraduate Professional Internship Programme"} +{"moduleCode":"LL5338V","moduleCredit":0,"title":"Advanced Practicum in International Arbitration"} +{"moduleCode":"PC3312","moduleCredit":0,"title":"Enhanced Undergraduate Professional Internship Programme"} +{"moduleCode":"SSY2223","moduleCredit":0,"title":"Western Music within a Singaporean Context"} +{"moduleCode":"SC4882B","moduleCredit":0,"title":"Citizenship, Nation and Globalization"} +{"moduleCode":"FIN2004","moduleCredit":0,"title":"Finance"} +{"moduleCode":"LL6405A","moduleCredit":0,"title":"Law of Intellectual Property (a)"} +{"moduleCode":"NM3232Y","moduleCredit":0,"title":"Strategic Communication"} +{"moduleCode":"CS4268","moduleCredit":0,"title":"Quantum Computing"} +{"moduleCode":"EL5101R","moduleCredit":0,"title":"Grammatical Analysis"} +{"moduleCode":"CS4269","moduleCredit":0,"title":"Fundamentals of Logic in Computer Science"} +{"moduleCode":"TTG2415","moduleCredit":0,"title":"Ethics In Engineering"} +{"moduleCode":"ACC1002","moduleCredit":0,"title":"Financial Accounting"} +{"moduleCode":"PS6660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"JS4231","moduleCredit":0,"title":"Technologies and Traditional Japanese Theatre"} +{"moduleCode":"ACC1006","moduleCredit":0,"title":"Accounting Information Systems"} +{"moduleCode":"JS4232","moduleCredit":0,"title":"FDI and Local Development: Japanese Firms in Asia"} +{"moduleCode":"CS4261","moduleCredit":0,"title":"Algorithmic Mechanism Design"} +{"moduleCode":"ENV3101","moduleCredit":0,"title":"Environmental Challenges: Asian Case Studies I"} +{"moduleCode":"JS4233","moduleCredit":0,"title":"Japan’s Immigration Politics in Global Perspective"} +{"moduleCode":"SPH5801","moduleCredit":0,"title":"Field Practice"} +{"moduleCode":"ME6101","moduleCredit":0,"title":"Research Topics in Applied Mechanics"} +{"moduleCode":"IE4240","moduleCredit":0,"title":"Project Management"} +{"moduleCode":"LL4260V","moduleCredit":0,"title":"Chinese Commercial Law"} +{"moduleCode":"CAS6101","moduleCredit":0,"title":"Asian Studies in Asia"} +{"moduleCode":"EE4210E","moduleCredit":0,"title":"Network Protocols and Applications"} +{"moduleCode":"PS5312","moduleCredit":0,"title":"Seminar in Comparative Politics"} +{"moduleCode":"SW5880R","moduleCredit":0,"title":"Special Topics in Social Work"} +{"moduleCode":"EL5102R","moduleCredit":0,"title":"Phonetics and Phonology"} +{"moduleCode":"IE4242","moduleCredit":0,"title":"Cost Analysis And Management"} +{"moduleCode":"IE4243","moduleCredit":0,"title":"Decision Modeling & Risk Analysis"} +{"moduleCode":"LAS3201","moduleCredit":0,"title":"Spanish 3"} +{"moduleCode":"LAS3202","moduleCredit":0,"title":"Spanish 4"} +{"moduleCode":"IE4230E","moduleCredit":0,"title":"Quality Engineering II"} +{"moduleCode":"AR3101A","moduleCredit":0,"title":"Design 5 (Landscape Architecture Emphasis)"} +{"moduleCode":"YLL1201","moduleCredit":0,"title":"Beginning Latin"} +{"moduleCode":"IS4010","moduleCredit":0,"title":"Industry Internship Programme"} +{"moduleCode":"GL4880B","moduleCredit":0,"title":"Globalisation and the Imagination of Work"} +{"moduleCode":"LAR1201","moduleCredit":0,"title":"Arabic 1"} +{"moduleCode":"CE5883A","moduleCredit":0,"title":"Topics in Hydraulic & Water Resources - Environmental Hydraulics"} +{"moduleCode":"SC4880B","moduleCredit":0,"title":"Advanced Sociological Analysis of Singapore Society"} +{"moduleCode":"MUA4271","moduleCredit":0,"title":"Advanced Live Sound Reinforcement 1"} +{"moduleCode":"MUA4272","moduleCredit":0,"title":"Advanced Live Sound Reinforcement 2"} +{"moduleCode":"LL4009V","moduleCredit":0,"title":"Chinese Legal Tradition And Legal Chinese"} +{"moduleCode":"CN4211E","moduleCredit":0,"title":"Petrochemicals & Processing Technology"} +{"moduleCode":"DMB1201DAO","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"PL5221R","moduleCredit":0,"title":"Analysis of Psychological Data using GLM"} +{"moduleCode":"IE6001","moduleCredit":0,"title":"Foundations of Optimization"} +{"moduleCode":"PC2020","moduleCredit":0,"title":"Electromagnetics for Electrical Engineers"} +{"moduleCode":"TBA3102","moduleCredit":0,"title":"Text Analytics"} +{"moduleCode":"SC6224","moduleCredit":0,"title":"Producing Ethnography"} +{"moduleCode":"BT4212","moduleCredit":0,"title":"Search Engine Optimization and Analytics"} +{"moduleCode":"CN4211R","moduleCredit":0,"title":"Petrochemicals and Processing Technology"} +{"moduleCode":"NM3237Y","moduleCredit":0,"title":"Health Communication"} +{"moduleCode":"BT4211","moduleCredit":0,"title":"Data-Driven Marketing"} +{"moduleCode":"PLC5010","moduleCredit":0,"title":"Research Project"} +{"moduleCode":"IE6004","moduleCredit":0,"title":"Stochastic Processes I"} +{"moduleCode":"IE6002","moduleCredit":0,"title":"Advanced Engineering Statistics"} +{"moduleCode":"IE2140E","moduleCredit":0,"title":"Engineering Economy"} +{"moduleCode":"LL5289V","moduleCredit":0,"title":"The Evolution of International Arbitration"} +{"moduleCode":"BMA5533","moduleCredit":0,"title":"Marketing in the Digital Age"} +{"moduleCode":"DMB1204MKT","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"ID5351","moduleCredit":0,"title":"Design Studies"} +{"moduleCode":"BMA5530","moduleCredit":0,"title":"Design Thinking & Product Innovations"} +{"moduleCode":"GL4882B","moduleCredit":0,"title":"Contested Globalisation: Resistance and Resilience"} +{"moduleCode":"CM3310","moduleCredit":0,"title":"Undergraduate Professional Internship Programme"} +{"moduleCode":"GL4882D","moduleCredit":0,"title":"Global Corporations and Power"} +{"moduleCode":"IE4100R","moduleCredit":0,"title":"B.Eng.Dissertation"} +{"moduleCode":"PLC5009","moduleCredit":0,"title":"Research Proposal"} +{"moduleCode":"GL4882C","moduleCredit":0,"title":"The Politics of Global Finance"} +{"moduleCode":"PLC5008","moduleCredit":0,"title":"Graduate Research Methods"} +{"moduleCode":"CM3312","moduleCredit":0,"title":"Enhanced Undergraduate Professional Internship Programme"} +{"moduleCode":"PLC5007","moduleCredit":0,"title":"Advanced Psychological Practice"} +{"moduleCode":"CM3311","moduleCredit":0,"title":"Undergraduate Professional Internship Programme"} +{"moduleCode":"PLC5006","moduleCredit":0,"title":"Ethics and Professional Issues"} +{"moduleCode":"GEM1050","moduleCredit":0,"title":"Framing Bollywood: Unpacking The Magic"} +{"moduleCode":"SC6213","moduleCredit":0,"title":"Families in Transition"} +{"moduleCode":"GEM1051","moduleCredit":0,"title":"Ethnicity and Nation-Building: Singapore and Malaysia"} +{"moduleCode":"SC6212","moduleCredit":0,"title":"Global Transformations"} +{"moduleCode":"GEM1052","moduleCredit":0,"title":"Understanding the Changing Global Economic Landscape"} +{"moduleCode":"LA5302","moduleCredit":0,"title":"Detail Design"} +{"moduleCode":"PLC5001","moduleCredit":0,"title":"Psychological Assessment"} +{"moduleCode":"FST4199","moduleCredit":0,"title":"Honours Project in Food Science & Tech"} +{"moduleCode":"LA5303","moduleCredit":0,"title":"Urban Greening: Technologies and Techniques"} +{"moduleCode":"ME5608","moduleCredit":0,"title":"Additive and Non-Conventional Manufacturing Processes"} +{"moduleCode":"PLC5005","moduleCredit":0,"title":"Child Psychopathology"} +{"moduleCode":"PLC5004","moduleCredit":0,"title":"Psychological Intervention and Therapy"} +{"moduleCode":"PLC5003","moduleCredit":0,"title":"Health across the lifespan"} +{"moduleCode":"PLC5002","moduleCredit":0,"title":"Adult Psychopathology"} +{"moduleCode":"IE2010E","moduleCredit":0,"title":"Introduction to Industrial System"} +{"moduleCode":"ME5612","moduleCredit":0,"title":"Computer Aided Product Development"} +{"moduleCode":"LL5024V","moduleCredit":0,"title":"Indonesian Law"} +{"moduleCode":"LSM4199","moduleCredit":0,"title":"Honours Project in Life Sciences"} +{"moduleCode":"ME5611","moduleCredit":0,"title":"Sustainable Product Design & Manufacturing"} +{"moduleCode":"IE4100E","moduleCredit":0,"title":"BTech Dissertation"} +{"moduleCode":"SC6216","moduleCredit":0,"title":"The Anthropological Perspective"} +{"moduleCode":"BI3003","moduleCredit":0,"title":"Work Experience Internship"} +{"moduleCode":"LAC1201","moduleCredit":0,"title":"Chinese 1"} +{"moduleCode":"BL5207A","moduleCredit":0,"title":"Topics In Developmental Biology"} +{"moduleCode":"ESE3001","moduleCredit":0,"title":"Water Quality Engineering"} +{"moduleCode":"CM3301","moduleCredit":0,"title":"Advanced Forensic Science"} +{"moduleCode":"LL6356V","moduleCredit":0,"title":"International Economic Law Clinic"} +{"moduleCode":"CH5660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"CM3302","moduleCredit":0,"title":"Overseas Exploratory Project (Europe)"} +{"moduleCode":"YID1201","moduleCredit":0,"title":"Introduction to Environmental Studies"} +{"moduleCode":"LL4006V","moduleCredit":0,"title":"Banking Law"} +{"moduleCode":"DSC1007","moduleCredit":0,"title":"Business Analytics - Models & Decisions"} +{"moduleCode":"MUA4240","moduleCredit":0,"title":"Collaborative Piano - Piano Ensemble"} +{"moduleCode":"MUA4241","moduleCredit":0,"title":"Collaborative Piano - Vocal Accompaniment"} +{"moduleCode":"ESE5666","moduleCredit":0,"title":"Industrial Attachment"} +{"moduleCode":"MUA4242","moduleCredit":0,"title":"Collaborative Piano - Instrumental Accompaniment"} +{"moduleCode":"MUA4243","moduleCredit":0,"title":"Collaborative Piano - Chamber Music"} +{"moduleCode":"ESE6999","moduleCredit":0,"title":"Doctoral Seminars"} +{"moduleCode":"CE5804","moduleCredit":0,"title":"Global Infrastructure Project Management"} +{"moduleCode":"CE5806","moduleCredit":0,"title":"Advanced Project Management with Lean Construction"} +{"moduleCode":"CN4210E","moduleCredit":0,"title":"Membrane Science And Engineering"} +{"moduleCode":"IE4101E","moduleCredit":0,"title":"B.Tech. Dissertation"} +{"moduleCode":"CE5805","moduleCredit":0,"title":"DfMA & Productivity Analytics in Construction"} +{"moduleCode":"CE5808","moduleCredit":0,"title":"Digital Design and Construction (BIM and VDC)"} +{"moduleCode":"TM3101","moduleCredit":0,"title":"Mechanical Systems Design"} +{"moduleCode":"EL1101E","moduleCredit":0,"title":"The Nature of Language"} +{"moduleCode":"BMA5511","moduleCredit":0,"title":"Strategic Pricing"} +{"moduleCode":"LL5158V","moduleCredit":0,"title":"Climate Change Law"} +{"moduleCode":"PL5222R","moduleCredit":0,"title":"Multivariate Statistics in Psychology"} +{"moduleCode":"GEM1031","moduleCredit":0,"title":"Names as Markers of Socio-cultural Identity"} +{"moduleCode":"GEM1033","moduleCredit":0,"title":"Religion and Film"} +{"moduleCode":"GEM1030","moduleCredit":0,"title":"Art and Identity"} +{"moduleCode":"DOS3751","moduleCredit":0,"title":"Independent Study in Ops & Supply Chain Management"} +{"moduleCode":"LL6357V","moduleCredit":0,"title":"Regulation & Political Economy"} +{"moduleCode":"CN2121E","moduleCredit":0,"title":"Chemical Engineering Thermodynamics"} +{"moduleCode":"DMB1204MNO","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"CN4215E","moduleCredit":0,"title":"Food Technology And Engineering"} +{"moduleCode":"MUH1101","moduleCredit":0,"title":"Foundations for Musical Discovery"} +{"moduleCode":"MUH1100","moduleCredit":0,"title":"Understanding and Describing Music"} +{"moduleCode":"PL6770","moduleCredit":0,"title":"Graduate Research Seminar"} +{"moduleCode":"BT4240","moduleCredit":0,"title":"Machine Learning for Predictive Data Analytics"} +{"moduleCode":"IE4239E","moduleCredit":0,"title":"Selected Topics in Quality Engineering"} +{"moduleCode":"GEM1036","moduleCredit":0,"title":"Globalisation and New Media"} +{"moduleCode":"PA1113","moduleCredit":0,"title":"Basic Pharmacology"} +{"moduleCode":"LL6358Z","moduleCredit":0,"title":"ICC Arbitration"} +{"moduleCode":"MUA1196","moduleCredit":0,"title":"Diction for Singers 1"} +{"moduleCode":"CLC1101","moduleCredit":0,"title":"Engaging and Building Communities"} +{"moduleCode":"MUA4226","moduleCredit":0,"title":"Collaboratory C"} +{"moduleCode":"MUA1192","moduleCredit":0,"title":"Chamber Singers 1"} +{"moduleCode":"MUA4227","moduleCredit":0,"title":"Collaboratory D"} +{"moduleCode":"MUA1193","moduleCredit":0,"title":"Chamber Singers 2"} +{"moduleCode":"MUA1190","moduleCredit":0,"title":"Applied Voice Major Study 1A"} +{"moduleCode":"MUA1191","moduleCredit":0,"title":"Applied Voice Major Studies 1B"} +{"moduleCode":"CN4215R","moduleCredit":0,"title":"Food Technology and Engineering"} +{"moduleCode":"LL6359Z","moduleCredit":0,"title":"SIAC and Institutional Arbitration"} +{"moduleCode":"MUA4215","moduleCredit":0,"title":"Vocal Pedagogy"} +{"moduleCode":"MKT4423","moduleCredit":0,"title":"Design Thinking & Business Innovations"} +{"moduleCode":"MKT4422","moduleCredit":0,"title":"The Business of Happiness"} +{"moduleCode":"GE3550A","moduleCredit":0,"title":"GIS Internship Module"} +{"moduleCode":"BT4222","moduleCredit":0,"title":"Mining Web Data for Business Insights"} +{"moduleCode":"GE3550B","moduleCredit":0,"title":"Geography Internship"} +{"moduleCode":"MKT4420","moduleCredit":0,"title":"Marketing Analytics"} +{"moduleCode":"BMS5311","moduleCredit":0,"title":"Corporate Finance"} +{"moduleCode":"BMS5312","moduleCredit":0,"title":"Fintech Management"} +{"moduleCode":"MUA4210","moduleCredit":0,"title":"Chamber Music in Mixed Ensemble 4"} +{"moduleCode":"UIS4932","moduleCredit":0,"title":"Independent Study Module"} +{"moduleCode":"BMS5310","moduleCredit":0,"title":"Financial Management of Family Business"} +{"moduleCode":"BBP6791","moduleCredit":0,"title":"Seminar in International Business"} +{"moduleCode":"ESE5608","moduleCredit":0,"title":"Heavy Metals in the Environment"} +{"moduleCode":"BT4221","moduleCredit":0,"title":"Big Data Techniques and Technologies"} +{"moduleCode":"MUA4209","moduleCredit":0,"title":"Chamber Music 4"} +{"moduleCode":"BMS5304","moduleCredit":0,"title":"Selected Topics in Finance: Private Equity"} +{"moduleCode":"MUA1172","moduleCredit":0,"title":"Critical Listening 1"} +{"moduleCode":"MUA4203","moduleCredit":0,"title":"Advanced Conducting I"} +{"moduleCode":"MUA1173","moduleCredit":0,"title":"Critical Listening 2"} +{"moduleCode":"MUA1170","moduleCredit":0,"title":"Fundamentals of Music Production and Recording 1"} +{"moduleCode":"MUA4205","moduleCredit":0,"title":"Advanced Conducting II"} +{"moduleCode":"NM3239Y","moduleCredit":0,"title":"Retrieving, Exploring and Analysing Data"} +{"moduleCode":"LL4002V","moduleCredit":0,"title":"Admiralty Law & Practice"} +{"moduleCode":"MUA1171","moduleCredit":0,"title":"Fundamentals of Music Production and Recording 2"} +{"moduleCode":"BMS5307","moduleCredit":0,"title":"Financial Markets and Institutions"} +{"moduleCode":"MUA4208","moduleCredit":0,"title":"Advanced Leadership in an Orchestral Context"} +{"moduleCode":"CN2122E","moduleCredit":0,"title":"Fluid Mechanics"} +{"moduleCode":"MKT4413","moduleCredit":0,"title":"Pricing Strategy"} +{"moduleCode":"PS2204","moduleCredit":0,"title":"Modern Western Political Thought"} +{"moduleCode":"MKT4419","moduleCredit":0,"title":"Advanced Independent Study in Marketing"} +{"moduleCode":"MKT4418","moduleCredit":0,"title":"Consumer Culture Theory"} +{"moduleCode":"MKT4417","moduleCredit":0,"title":"Consumer Decision Making"} +{"moduleCode":"LL5009GRSI","moduleCredit":0,"title":"Graduate Research Seminar I (Legal Scholarship)"} +{"moduleCode":"BBP6781","moduleCredit":0,"title":"Theory of Strategic Management"} +{"moduleCode":"ME6999","moduleCredit":0,"title":"Doctoral Seminars"} +{"moduleCode":"ME5666","moduleCredit":0,"title":"Industrial Attachment"} +{"moduleCode":"ME3000","moduleCredit":0,"title":"Independent Study 1"} +{"moduleCode":"ME4245E","moduleCredit":0,"title":"Robot Mechanics and Control"} +{"moduleCode":"GEM1003","moduleCredit":0,"title":"Introduction to Theatre and Performance"} +{"moduleCode":"GEM1004","moduleCredit":0,"title":"Reason and Persuasion"} +{"moduleCode":"ME3001","moduleCredit":0,"title":"Independent Study 2"} +{"moduleCode":"IE6099","moduleCredit":0,"title":"Ise Research Methodology"} +{"moduleCode":"MA4247","moduleCredit":0,"title":"Complex Analysis II"} +{"moduleCode":"GEK1505","moduleCredit":0,"title":"Living with Mathematics"} +{"moduleCode":"NUR2203C","moduleCredit":0,"title":"Clinical Experience II"} +{"moduleCode":"BN2001","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"GEK1508","moduleCredit":0,"title":"Einstein's Universe & Quantum Weirdness"} +{"moduleCode":"HY4225","moduleCredit":0,"title":"Ideological Origins of US Foreign Policy"} +{"moduleCode":"GEK1509","moduleCredit":0,"title":"The Emerging Nanoworld"} +{"moduleCode":"CN2125E","moduleCredit":0,"title":"Heat And Mass Transfer"} +{"moduleCode":"LL4088","moduleCredit":0,"title":"Chinese Contract Law"} +{"moduleCode":"CM3251","moduleCredit":0,"title":"Nanochemistry"} +{"moduleCode":"CM3253","moduleCredit":0,"title":"Materials Chemistry 1"} +{"moduleCode":"HY4228","moduleCredit":0,"title":"Material Culture in History: Theory and Practice"} +{"moduleCode":"CM3252","moduleCredit":0,"title":"Polymer Chemistry 1"} +{"moduleCode":"HY4227","moduleCredit":0,"title":"Sources of Singaporean History"} +{"moduleCode":"MUA4310","moduleCredit":0,"title":"Chamber Music in Mixed Ensemble 5"} +{"moduleCode":"SE2880A","moduleCredit":0,"title":"Southeast Asia's Cultural Mosaic"} +{"moduleCode":"HY6882","moduleCredit":0,"title":"Topics in Chinese History"} +{"moduleCode":"BN5999","moduleCredit":0,"title":"Graduate Seminars"} +{"moduleCode":"HY4222","moduleCredit":0,"title":"Asian Business History: Case Studies"} +{"moduleCode":"GL4889A","moduleCredit":0,"title":"International Law's Regulation of Violence"} +{"moduleCode":"GL4889B","moduleCredit":0,"title":"Debates on Human Rights"} +{"moduleCode":"MUA4309","moduleCredit":0,"title":"Chamber Music 5"} +{"moduleCode":"PR5150","moduleCredit":0,"title":"Ambulatory Care Clerkship"} +{"moduleCode":"PR5151","moduleCredit":0,"title":"Acute Care Medicine Clerkship"} +{"moduleCode":"KE5105","moduleCredit":0,"title":"Knowledge Engineering Project"} +{"moduleCode":"NUR5807","moduleCredit":0,"title":"Professional Development and Ethical Healthcare"} +{"moduleCode":"PR5152","moduleCredit":0,"title":"Adult General Medicine Clerkship"} +{"moduleCode":"KE5106","moduleCredit":0,"title":"Data Warehousing for Business Analytics"} +{"moduleCode":"ME4256E","moduleCredit":0,"title":"Functional Materials and Devices"} +{"moduleCode":"PR5153","moduleCredit":0,"title":"Critical Care Clerkship"} +{"moduleCode":"KE5107","moduleCredit":0,"title":"Data Mining Methodology and Methods"} +{"moduleCode":"PR5154","moduleCredit":0,"title":"Drug Information Clerkship"} +{"moduleCode":"KE5108","moduleCredit":0,"title":"Developing Intelligent Systems for Performing Business Analytics"} +{"moduleCode":"TEE3131","moduleCredit":0,"title":"Communication Systems"} +{"moduleCode":"LAM2201","moduleCredit":0,"title":"Malay 2"} +{"moduleCode":"MA4254","moduleCredit":0,"title":"Discrete Optimization"} +{"moduleCode":"PR5135","moduleCredit":0,"title":"Foundations in Advanced Pharmacy Practice"} +{"moduleCode":"LL4071","moduleCredit":0,"title":"International Patent Law, Policy and Practice"} +{"moduleCode":"MUA4301","moduleCredit":0,"title":"Advanced Preparation in International Competition"} +{"moduleCode":"PR5136","moduleCredit":0,"title":"Seminar and Teaching"} +{"moduleCode":"PR5137","moduleCredit":0,"title":"Advanced Pharmacotherapy in Geriatrics"} +{"moduleCode":"MA4255","moduleCredit":0,"title":"Numerical Methods in Differential Equations"} +{"moduleCode":"GEQ1917","moduleCredit":0,"title":"Understanding and Critiquing Sustainability"} +{"moduleCode":"MUA1270","moduleCredit":0,"title":"Interdisciplinary Electronic Arts Survey"} +{"moduleCode":"NUR2204C","moduleCredit":0,"title":"Women and Children Health"} +{"moduleCode":"SC3230","moduleCredit":0,"title":"Volunteer Workforce"} +{"moduleCode":"HY4237","moduleCredit":0,"title":"Global Histories of the Nuclear Age"} +{"moduleCode":"HY4236","moduleCredit":0,"title":"Topics in Singaporean History"} +{"moduleCode":"HY4234","moduleCredit":0,"title":"Grand Strategy in Peace and War"} +{"moduleCode":"TE3801","moduleCredit":0,"title":"Robust Design Of Electronic Circuits"} +{"moduleCode":"CM3242","moduleCredit":0,"title":"Instrumental Analysis II"} +{"moduleCode":"HY4239","moduleCredit":0,"title":"History of Gender in India"} +{"moduleCode":"CM3241","moduleCredit":0,"title":"Instrumental Analysis I"} +{"moduleCode":"HY4238","moduleCredit":0,"title":"Gender, Culture & History"} +{"moduleCode":"LL5293S","moduleCredit":0,"title":"Business Torts"} +{"moduleCode":"EG4301A","moduleCredit":0,"title":"Ideas to Start-up"} +{"moduleCode":"HY4230","moduleCredit":0,"title":"Historiography and Historical Method"} +{"moduleCode":"QF3312","moduleCredit":0,"title":"Enhanced Undergraduate Professional Internship Programme"} +{"moduleCode":"TCN1111","moduleCredit":0,"title":"Chemical Engineering Principles"} +{"moduleCode":"MA4252","moduleCredit":0,"title":"Advanced Ordinary Differential Equations"} +{"moduleCode":"QF3310","moduleCredit":0,"title":"Undergraduate Professional Internship Programme"} +{"moduleCode":"MA4251","moduleCredit":0,"title":"Stochastic Processes II"} +{"moduleCode":"QF3311","moduleCredit":0,"title":"Undergraduate Professional Internship"} +{"moduleCode":"SP2201","moduleCredit":0,"title":"Agri-Science in Japan and Singapore"} +{"moduleCode":"MA4264","moduleCredit":0,"title":"Game Theory"} +{"moduleCode":"HY4209","moduleCredit":0,"title":"Imperialism and Empires"} +{"moduleCode":"LL5396","moduleCredit":0,"title":"University Research Opportunities Programme"} +{"moduleCode":"MA4266","moduleCredit":0,"title":"Topology"} +{"moduleCode":"LL5397","moduleCredit":0,"title":"University Research Opportunities Programme"} +{"moduleCode":"MA4269","moduleCredit":0,"title":"Mathematical Finance II"} +{"moduleCode":"OT5001A","moduleCredit":0,"title":"Independent Study Module: Subsea Engineering"} +{"moduleCode":"SC3221","moduleCredit":0,"title":"Qualitative Inquiry"} +{"moduleCode":"LL5398","moduleCredit":0,"title":"University Research Opportunities Programme"} +{"moduleCode":"MA4268","moduleCredit":0,"title":"Mathematics for Visual Data Processing"} +{"moduleCode":"NUR2201C","moduleCredit":0,"title":"Pathophysiology, Pharmacology and Nursing Practice I"} +{"moduleCode":"OT5001B","moduleCredit":0,"title":"Independent Study Module: Petroleum Engineering"} +{"moduleCode":"SC3222","moduleCredit":0,"title":"Social Transformations in Modern China"} +{"moduleCode":"CE3121","moduleCredit":0,"title":"Transportation Engineering"} +{"moduleCode":"DE5109","moduleCredit":0,"title":"Dissertation"} +{"moduleCode":"DE5107","moduleCredit":0,"title":"Environmental Planning"} +{"moduleCode":"DE5108","moduleCredit":0,"title":"Study Report"} +{"moduleCode":"DE5106","moduleCredit":0,"title":"Environmental Management And Assessment"} +{"moduleCode":"HY4207","moduleCredit":0,"title":"Special Paper in Military History"} +{"moduleCode":"YLC2202","moduleCredit":0,"title":"Intermediate Chinese 2"} +{"moduleCode":"YLC2201","moduleCredit":0,"title":"Intermediate Chinese 1"} +{"moduleCode":"LL5294S","moduleCredit":0,"title":"Security and Insolvency Law"} +{"moduleCode":"IE1111R","moduleCredit":0,"title":"Industrial & Systems Engrg Principles & Practice I"} +{"moduleCode":"SC3225","moduleCredit":0,"title":"Social Capital"} +{"moduleCode":"SC3223","moduleCredit":0,"title":"Visual Culture: Seeing and Representing"} +{"moduleCode":"CE3115","moduleCredit":0,"title":"Geotechnical Engineering"} +{"moduleCode":"CN5251","moduleCredit":0,"title":"Membrane Science & Technology"} +{"moduleCode":"MA4261","moduleCredit":0,"title":"Coding and Cryptography"} +{"moduleCode":"SC3229","moduleCredit":0,"title":"Comparing Deviance: Perverts & Scandalous Improprieties"} +{"moduleCode":"CE3116","moduleCredit":0,"title":"Foundation Engineering"} +{"moduleCode":"CN5252","moduleCredit":0,"title":"Metabolic Engineering"} +{"moduleCode":"MA4260","moduleCredit":0,"title":"Stochastic Operations Research"} +{"moduleCode":"MA4263","moduleCredit":0,"title":"Introduction to Analytic Number Theory"} +{"moduleCode":"SC3227","moduleCredit":0,"title":"Modernity and Social Change"} +{"moduleCode":"MA4262","moduleCredit":0,"title":"Measure and Integration"} +{"moduleCode":"SC3228","moduleCredit":0,"title":"Senses and Society"} +{"moduleCode":"CM3267","moduleCredit":0,"title":"Computational Thinking and Programming in Chemistry"} +{"moduleCode":"TCN2411","moduleCredit":0,"title":"Mathematics for Chemical Engineers 2"} +{"moduleCode":"NUR2202C","moduleCredit":0,"title":"Pathophysiology, Pharmacology and Nursing Practice II"} +{"moduleCode":"SW2104","moduleCredit":0,"title":"Human Development over the Lifespan"} +{"moduleCode":"SC3211","moduleCredit":0,"title":"Science, Technology & Society"} +{"moduleCode":"SW2101","moduleCredit":0,"title":"Working with Individuals and Families"} +{"moduleCode":"GL3202","moduleCredit":0,"title":"Global Refugee Management"} +{"moduleCode":"HY4214","moduleCredit":0,"title":"Approaches to Chinese History"} +{"moduleCode":"SW2106","moduleCredit":0,"title":"Social Group Work Practice"} +{"moduleCode":"DSC4211G","moduleCredit":0,"title":"SIOSCM: Service Design"} +{"moduleCode":"GL3201","moduleCredit":0,"title":"Global Studies and Humanities Research"} +{"moduleCode":"HY4212","moduleCredit":0,"title":"Special Paper in Modern European History"} +{"moduleCode":"SW2105","moduleCredit":0,"title":"Values & Skills for Helping Relationships"} +{"moduleCode":"CM3261","moduleCredit":0,"title":"Environmental Chemistry"} +{"moduleCode":"HY4218","moduleCredit":0,"title":"Approaches to Modern Japanese History"} +{"moduleCode":"HY4217","moduleCredit":0,"title":"Approaches to Study of SE Asian History"} +{"moduleCode":"DSC4211C","moduleCredit":0,"title":"SIOSCM: Operations Strategy"} +{"moduleCode":"HY4216","moduleCredit":0,"title":"Culture and Literature in S.E.A. History"} +{"moduleCode":"LL4317V","moduleCredit":0,"title":"International Arbitration in Asian Centres"} +{"moduleCode":"ACC4761H","moduleCredit":0,"title":"Sem. in Acctg: Accounting & Business Analysis for Banks"} +{"moduleCode":"DL5101","moduleCredit":0,"title":"Digital Organisation Models"} +{"moduleCode":"HY4210","moduleCredit":0,"title":"Issues and Events in Malaysian History"} +{"moduleCode":"DL5103","moduleCredit":0,"title":"Innovation By Design"} +{"moduleCode":"SC3214","moduleCredit":0,"title":"Sociology of Life Course and Ageing"} +{"moduleCode":"CE3101","moduleCredit":0,"title":"Integrated Infrastructure Project"} +{"moduleCode":"SC3215","moduleCredit":0,"title":"Law and Society"} +{"moduleCode":"CE3102","moduleCredit":0,"title":"Socio-economically sustainable developments"} +{"moduleCode":"MA4270","moduleCredit":0,"title":"Data Modelling and Computation"} +{"moduleCode":"SC3212","moduleCredit":0,"title":"Southeast Asia in a Globalizing World"} +{"moduleCode":"ACC4761A","moduleCredit":0,"title":"Seminars in Accounting: Internal Audit"} +{"moduleCode":"SC3213","moduleCredit":0,"title":"Visual Ethnography: Theory and Practice"} +{"moduleCode":"MA4271","moduleCredit":0,"title":"Differential Geometry of Curves and Surfaces"} +{"moduleCode":"SC3216","moduleCredit":0,"title":"Self and Society"} +{"moduleCode":"LL5371","moduleCredit":0,"title":"Charity Law Today"} +{"moduleCode":"LL5372","moduleCredit":0,"title":"International Intellectual Property Law"} +{"moduleCode":"LL5373","moduleCredit":0,"title":"Advanced Copyright"} +{"moduleCode":"CM3212","moduleCredit":0,"title":"Transition Metal Chemistry"} +{"moduleCode":"LL5374","moduleCredit":0,"title":"Water Rights & Resources: Issues in Law & Development"} +{"moduleCode":"LL5375","moduleCredit":0,"title":"Traditional Chinese Legal Thought"} +{"moduleCode":"LL5376","moduleCredit":0,"title":"Regulation & Private Law in Banking & Financial Service"} +{"moduleCode":"BN6402","moduleCredit":0,"title":"Advanced Electrophysiology"} +{"moduleCode":"EN4401","moduleCredit":0,"title":"Honours Thesis"} +{"moduleCode":"FST4299","moduleCredit":0,"title":"Applied Project in FST"} +{"moduleCode":"LL4043","moduleCredit":0,"title":"Law Of Marine Insurance"} +{"moduleCode":"MUT1201","moduleCredit":0,"title":"Introduction to Classical Music Composition"} +{"moduleCode":"BN6401","moduleCredit":0,"title":"Advanced Quantitative Fluorescence Microscopy"} +{"moduleCode":"LL5370","moduleCredit":0,"title":"The Law of Cybersecurity, Privacy and Data Compliance"} +{"moduleCode":"CN1101A","moduleCredit":0,"title":"Chemical Engineering Principles and Practice I"} +{"moduleCode":"TME3261","moduleCredit":0,"title":"Computer-Aided Design and Manufacturing"} +{"moduleCode":"PL5225R","moduleCredit":0,"title":"Structural Equation Modeling"} +{"moduleCode":"LL5030V","moduleCredit":0,"title":"International Commercial Litigation"} +{"moduleCode":"LL5368","moduleCredit":0,"title":"Comparative Constitutionalism"} +{"moduleCode":"SP2251","moduleCredit":0,"title":"Science at the Nanoscale"} +{"moduleCode":"LL5369","moduleCredit":0,"title":"Constitutionalism in Asia"} +{"moduleCode":"LL6360Z","moduleCredit":0,"title":"Current Challenges to Investment Arbitration"} +{"moduleCode":"DSA1361","moduleCredit":0,"title":"Introductory Data Science with Python and Tableau"} +{"moduleCode":"TME3263","moduleCredit":0,"title":"Design for Manufacturing and Assembly"} +{"moduleCode":"PR5198","moduleCredit":0,"title":"Graduate Seminar Module in Pharmacy"} +{"moduleCode":"MLE5999","moduleCredit":0,"title":"Graduate Seminars"} +{"moduleCode":"ME4251E","moduleCredit":0,"title":"Thermal Engineering Of Materials"} +{"moduleCode":"CM3201","moduleCredit":0,"title":"Principles of Chemical Processes"} +{"moduleCode":"CE3132","moduleCredit":0,"title":"Water Resources Engineering"} +{"moduleCode":"LL4032","moduleCredit":0,"title":"International Investment Law"} +{"moduleCode":"NM5218","moduleCredit":0,"title":"Cultural Policy"} +{"moduleCode":"NM5216","moduleCredit":0,"title":"Advanced Health Communication"} +{"moduleCode":"LL5031V","moduleCredit":0,"title":"International Environmental Law & Policy"} +{"moduleCode":"LL5164V","moduleCredit":0,"title":"International Projects Law & Practice"} +{"moduleCode":"LL6361Z","moduleCredit":0,"title":"Complex Arbitrations: Multiparty – Multicontract"} +{"moduleCode":"PC4199R","moduleCredit":0,"title":"Integrated B.ENG./B.SC. (Hons) Dissertation"} +{"moduleCode":"HY1101E","moduleCredit":0,"title":"Asia and the Modern World"} +{"moduleCode":"MA4292","moduleCredit":0,"title":"Undergraduate Topics in Mathematics II"} +{"moduleCode":"GL4886A","moduleCredit":0,"title":"Citizenship and the Politics of Belonging"} +{"moduleCode":"LLD5140V","moduleCredit":0,"title":"Law of the Sea: Theory and Practice"} +{"moduleCode":"USR4002A","moduleCredit":0,"title":"Critical Reflection"} +{"moduleCode":"CE3165","moduleCredit":0,"title":"Structural Concrete Design"} +{"moduleCode":"MUA1223","moduleCredit":0,"title":"Desktop Mixing Production"} +{"moduleCode":"CM3231","moduleCredit":0,"title":"Quantum Chem & Molecular Thermodynamics"} +{"moduleCode":"NM5205","moduleCredit":0,"title":"Cognition and Media"} +{"moduleCode":"CN5215","moduleCredit":0,"title":"Atomistic Modelling of Molecules and Materials"} +{"moduleCode":"CE3155","moduleCredit":0,"title":"Structural Analysis"} +{"moduleCode":"EG5911","moduleCredit":0,"title":"Research Methodology & Ethics"} +{"moduleCode":"TME3241","moduleCredit":0,"title":"Microprocessor Applications"} +{"moduleCode":"TME3242","moduleCredit":0,"title":"Automation"} +{"moduleCode":"CM3222","moduleCredit":0,"title":"Organic Reaction Mechanisms"} +{"moduleCode":"CM3221","moduleCredit":0,"title":"Organic Synthesis: The Disconnection Approach"} +{"moduleCode":"LL6364V","moduleCredit":0,"title":"Principles of Civil Law: Law of Obligations & Property"} +{"moduleCode":"CM3225","moduleCredit":0,"title":"Biomolecules"} +{"moduleCode":"BN5102","moduleCredit":0,"title":"Clinical Instrumentation"} +{"moduleCode":"BN5101","moduleCredit":0,"title":"Biomedical Engineering Systems"} +{"moduleCode":"BN5104","moduleCredit":0,"title":"Quantitative Physiology Principles in Bioengineering"} +{"moduleCode":"LL5033V","moduleCredit":0,"title":"International Legal Process"} +{"moduleCode":"NM2219Y","moduleCredit":0,"title":"Principles of Communication Management"} +{"moduleCode":"NM5201","moduleCredit":0,"title":"State and Civil Society in the Information Age"} +{"moduleCode":"ES1601","moduleCredit":0,"title":"Professional and Academic Communication"} +{"moduleCode":"TME3251","moduleCredit":0,"title":"Materials For Engineers"} +{"moduleCode":"LL4004","moduleCredit":0,"title":"Aviation Law & Policy"} +{"moduleCode":"LSM2301","moduleCredit":0,"title":"Life Sciences Industry Seminar"} +{"moduleCode":"LL5339","moduleCredit":0,"title":"Comparative Evidence in International Arbitration"} +{"moduleCode":"TCN4205","moduleCredit":0,"title":"Pinch Analysis and Process Integration"} +{"moduleCode":"DSA3101","moduleCredit":0,"title":"Data Science in Practice"} +{"moduleCode":"TCN4208","moduleCredit":0,"title":"Biochemical Engineering"} +{"moduleCode":"DSA3102","moduleCredit":0,"title":"Essential Data Analytics Tools: Convex Optimisation"} +{"moduleCode":"CDM5101","moduleCredit":0,"title":"Fundamentals of Cancer Biology"} +{"moduleCode":"CDM5102","moduleCredit":0,"title":"Translational Cancer Research"} +{"moduleCode":"LL4001","moduleCredit":0,"title":"Administration Of Criminal Justice"} +{"moduleCode":"CDM5103","moduleCredit":0,"title":"Advanced Topics in RNA Biology and Human Diseases"} +{"moduleCode":"CDM5104","moduleCredit":0,"title":"Introduction to Bioinformatics for Metagenomics"} +{"moduleCode":"CS4248","moduleCredit":0,"title":"Natural Language Processing"} +{"moduleCode":"CS4249","moduleCredit":0,"title":"Phenomena and Theories of Human-Computer Interaction"} +{"moduleCode":"MUA1201","moduleCredit":0,"title":"Rudiments of Musicianship"} +{"moduleCode":"CS4246","moduleCredit":0,"title":"AI Planning and Decision Making"} +{"moduleCode":"CS4247","moduleCredit":0,"title":"Graphics Rendering Techniques"} +{"moduleCode":"CS4244","moduleCredit":0,"title":"Knowledge Representation and Reasoning"} +{"moduleCode":"LAG1201","moduleCredit":0,"title":"German 1"} +{"moduleCode":"CS4242","moduleCredit":0,"title":"Social Media Computing"} +{"moduleCode":"CS4243","moduleCredit":0,"title":"Computer Vision and Pattern Recognition"} +{"moduleCode":"CS4240","moduleCredit":0,"title":"Interaction Design for Virtual and Augmented Reality"} +{"moduleCode":"MT5766","moduleCredit":0,"title":"Technology Management Internship"} +{"moduleCode":"SE4101","moduleCredit":0,"title":"Southeast Asia Studies: Theory and Practice"} +{"moduleCode":"JS4213","moduleCredit":0,"title":"Approaches to Modern Japanese History"} +{"moduleCode":"JS4214","moduleCredit":0,"title":"Ideas, Values and Identity in Japan"} +{"moduleCode":"JS4216","moduleCredit":0,"title":"Tales and Performance in Premodern Japan"} +{"moduleCode":"LL5328","moduleCredit":0,"title":"Sports Law"} +{"moduleCode":"JS4217","moduleCredit":0,"title":"Selected Topics in Japanese Studies"} +{"moduleCode":"LL5208V","moduleCredit":0,"title":"Advanced Criminal Legal Process"} +{"moduleCode":"TCN4211","moduleCredit":0,"title":"Petrochemicals & Processing Technology"} +{"moduleCode":"TCN4210","moduleCredit":0,"title":"Membrane Science And Engineering"} +{"moduleCode":"JS4209","moduleCredit":0,"title":"Selected Topics in Japanese Linguistics"} +{"moduleCode":"PHS3311","moduleCredit":0,"title":"Undergraduate Professional Internship"} +{"moduleCode":"TCN4215","moduleCredit":0,"title":"Food Technology and Engineering"} +{"moduleCode":"PHS3310","moduleCredit":0,"title":"Undergraduate Professional Internship Programme"} +{"moduleCode":"PHS3312","moduleCredit":0,"title":"Enhanced Undergraduate Professional Internship Programme"} +{"moduleCode":"CS4239","moduleCredit":0,"title":"Software Security"} +{"moduleCode":"SE6770","moduleCredit":0,"title":"Graduate Research Seminar"} +{"moduleCode":"CS4238","moduleCredit":0,"title":"Computer Security Practice"} +{"moduleCode":"CS4236","moduleCredit":0,"title":"Cryptography Theory and Practice"} +{"moduleCode":"CS4234","moduleCredit":0,"title":"Optimisation Algorithms"} +{"moduleCode":"CS4231","moduleCredit":0,"title":"Parallel and Distributed Algorithms"} +{"moduleCode":"CS4232","moduleCredit":0,"title":"Theory of Computation"} +{"moduleCode":"CE3166","moduleCredit":0,"title":"Structural Steel Design and System"} +{"moduleCode":"LL5209V","moduleCredit":0,"title":"Legal Argument & Narrative"} +{"moduleCode":"JS4207","moduleCredit":0,"title":"Readings in Modern Japanese"} +{"moduleCode":"OT5205","moduleCredit":0,"title":"Offshore Pipelines"} +{"moduleCode":"OT5204","moduleCredit":0,"title":"Moorings & Risers"} +{"moduleCode":"UIS4911EL","moduleCredit":0,"title":"Independent Study Module"} +{"moduleCode":"OT5203","moduleCredit":0,"title":"Analysis & Design of Floating Offshore Structures"} +{"moduleCode":"OT5202","moduleCredit":0,"title":"Analysis & Design of Fixed Offshore Structures"} +{"moduleCode":"UIS4911EN","moduleCredit":0,"title":"Independent Study Module"} +{"moduleCode":"BIS3001A","moduleCredit":0,"title":"Independent Study Module in Business"} +{"moduleCode":"CS4226","moduleCredit":0,"title":"Internet Architecture"} +{"moduleCode":"SW5208","moduleCredit":0,"title":"Using Play Therapy with Children and Families"} +{"moduleCode":"CS4224","moduleCredit":0,"title":"Distributed Databases"} +{"moduleCode":"OT5207","moduleCredit":0,"title":"Arctic Offshore Engineering"} +{"moduleCode":"PF4501","moduleCredit":0,"title":"Total Building Performance"} +{"moduleCode":"CS4225","moduleCredit":0,"title":"Big Data Systems for Data Science"} +{"moduleCode":"OT5206","moduleCredit":0,"title":"Offshore Foundations"} +{"moduleCode":"SW5209","moduleCredit":0,"title":"Theory and Practice of Social Work Supervision"} +{"moduleCode":"CS4222","moduleCredit":0,"title":"Wireless Networking"} +{"moduleCode":"CS4223","moduleCredit":0,"title":"Multi-core Architectures"} +{"moduleCode":"CE5806A","moduleCredit":0,"title":"Advanced Project Management"} +{"moduleCode":"CS4220","moduleCredit":0,"title":"Knowledge Discovery Methods in Bioinformatics"} +{"moduleCode":"DMC1401IS","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"CE5806B","moduleCredit":0,"title":"Lean Construction Management"} +{"moduleCode":"CS4221","moduleCredit":0,"title":"Database Applications Design and Tuning"} +{"moduleCode":"TEE4407","moduleCredit":0,"title":"Analog Electronics"} +{"moduleCode":"MUL1105","moduleCredit":0,"title":"Italian for Musicians 1"} +{"moduleCode":"SN4401","moduleCredit":0,"title":"Honours Thesis"} +{"moduleCode":"MUL1107","moduleCredit":0,"title":"French for Musicians 1"} +{"moduleCode":"MUL1106","moduleCredit":0,"title":"Italian for Musicians 2"} +{"moduleCode":"MUL1109","moduleCredit":0,"title":"German for Musicians 1"} +{"moduleCode":"AY1130","moduleCredit":0,"title":"Human Anatomy and Physiology I"} +{"moduleCode":"LL5307","moduleCredit":0,"title":"EU Maritime Law"} +{"moduleCode":"MUL1108","moduleCredit":0,"title":"French for Musicians 2"} +{"moduleCode":"YSS4101","moduleCredit":0,"title":"Global Affairs Capstone Project"} +{"moduleCode":"PC5198","moduleCredit":0,"title":"Graduate Seminar Module in Physics"} +{"moduleCode":"SW5217","moduleCredit":0,"title":"Continuum of Care and Healthy Ageing"} +{"moduleCode":"MNO3761A","moduleCredit":0,"title":"TILHCM: Employee and Organizational Misbehaviours"} +{"moduleCode":"SW5216","moduleCredit":0,"title":"Family and Interpersonal Violence"} +{"moduleCode":"ESP3903","moduleCredit":0,"title":"Major Design Project 2"} +{"moduleCode":"SW5211","moduleCredit":0,"title":"Risk Assessment & Management: Mental Health"} +{"moduleCode":"ESP3902","moduleCredit":0,"title":"Major Design Project I"} +{"moduleCode":"UTS2500","moduleCredit":0,"title":"College 3 Capstone Experience"} +{"moduleCode":"MKT2711","moduleCredit":0,"title":"Marketing Venture Challenge"} +{"moduleCode":"YSS4106","moduleCredit":0,"title":"Politics, Philosophy and Economics Capstone Project"} +{"moduleCode":"CS4218","moduleCredit":0,"title":"Software Testing"} +{"moduleCode":"YSS4107","moduleCredit":0,"title":"Capstone Project"} +{"moduleCode":"CS4215","moduleCredit":0,"title":"Programming Language Implementation"} +{"moduleCode":"YSS4104","moduleCredit":0,"title":"Economics Capstone Project"} +{"moduleCode":"YSS4105","moduleCredit":0,"title":"Urban Studies Capstone Project"} +{"moduleCode":"YSS4102","moduleCredit":0,"title":"Psychology Capstone Project"} +{"moduleCode":"YSS4103","moduleCredit":0,"title":"Anthropology Capstone Project"} +{"moduleCode":"CS4211","moduleCredit":0,"title":"Formal Methods for Software Engineering"} +{"moduleCode":"CS4212","moduleCredit":0,"title":"Compiler Design"} +{"moduleCode":"UTC1112A","moduleCredit":0,"title":"Jr Sem Special Topics: Humanising Technology"} +{"moduleCode":"MUL1110","moduleCredit":0,"title":"German for Musicians 2"} +{"moduleCode":"CE4257B","moduleCredit":0,"title":"Finite Element Analysis for Civil Engineering"} +{"moduleCode":"IGL3550","moduleCredit":0,"title":"Extended Global Studies Internship"} +{"moduleCode":"LL4097V","moduleCredit":0,"title":"Islamic Law"} +{"moduleCode":"MA4203","moduleCredit":0,"title":"Galois Theory"} +{"moduleCode":"PH5420","moduleCredit":0,"title":"Advanced Political Philosophy"} +{"moduleCode":"ESE6001","moduleCredit":0,"title":"Environmental Fate of Organic Contaminant"} +{"moduleCode":"CM3291","moduleCredit":0,"title":"Advanced Experiments In Organic & Inorganic Chemistry"} +{"moduleCode":"MA4207","moduleCredit":0,"title":"Mathematical Logic"} +{"moduleCode":"CE4257A","moduleCredit":0,"title":"Finite Element Concepts & Applications"} +{"moduleCode":"CM3292","moduleCredit":0,"title":"Advanced Experiments In Analytical & Physical Chemistry"} +{"moduleCode":"CM3295","moduleCredit":0,"title":"Selected Experiments in Analytical Chemistry"} +{"moduleCode":"CM3296","moduleCredit":0,"title":"Molecular Modelling: Theory & Practice"} +{"moduleCode":"CE5808A","moduleCredit":0,"title":"Digital Design Using BIM Technologies"} +{"moduleCode":"BMF5391C","moduleCredit":0,"title":"Experiential Learning: Applied Faculty Project"} +{"moduleCode":"CE5808B","moduleCredit":0,"title":"Virtual Design & Construction: Moving Beyond BIM"} +{"moduleCode":"BMF5391B","moduleCredit":0,"title":"Experiential Learning: Applied Team Project"} +{"moduleCode":"SC3209","moduleCredit":0,"title":"Data Analysis in Social Research"} +{"moduleCode":"BMF5391A","moduleCredit":0,"title":"Experiential Learning: Individual Internship"} +{"moduleCode":"AR5601","moduleCredit":0,"title":"Urban Design Theory and Praxis"} +{"moduleCode":"DMC1401CS","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"UTC2101","moduleCredit":0,"title":"Time and Life"} +{"moduleCode":"UTC2102","moduleCredit":0,"title":"Climate Change"} +{"moduleCode":"GE4660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"SC3203","moduleCredit":0,"title":"Race and Ethnic Relations"} +{"moduleCode":"SC3204","moduleCredit":0,"title":"Sociology of Education"} +{"moduleCode":"UTC2107","moduleCredit":0,"title":"Senior Seminar: Negotiating in a Complex World"} +{"moduleCode":"SC3202","moduleCredit":0,"title":"From Modernization to Globalization"} +{"moduleCode":"UTC2108","moduleCredit":0,"title":"Senior Seminar: Technology and the Fate of Knowledge"} +{"moduleCode":"SC3207","moduleCredit":0,"title":"Cultures of Kinship"} +{"moduleCode":"UTC2109","moduleCredit":0,"title":"Asia Now! The Archaeology of the Future City"} +{"moduleCode":"SC3208","moduleCredit":0,"title":"Religion in Society & Culture"} +{"moduleCode":"SC3206","moduleCredit":0,"title":"Urban Sociology"} +{"moduleCode":"CM3288","moduleCredit":0,"title":"Advanced UROPS in Chemistry I"} +{"moduleCode":"EL3551","moduleCredit":0,"title":"FASS Undergraduate Research Opportunity (UROP)"} +{"moduleCode":"PH6760","moduleCredit":0,"title":"Philosophical Topics"} +{"moduleCode":"CM3289","moduleCredit":0,"title":"Advanced UROPS in Chemistry II"} +{"moduleCode":"MA4211","moduleCredit":0,"title":"Functional Analysis"} +{"moduleCode":"MS4208","moduleCredit":0,"title":"Syariah Law in Southeast Asia"} +{"moduleCode":"PP5507","moduleCredit":0,"title":"Policy Innovation Lab"} +{"moduleCode":"MS4204","moduleCredit":0,"title":"The Malay Middle Class"} +{"moduleCode":"PP5504","moduleCredit":0,"title":"Public Finance and Budgeting"} +{"moduleCode":"PP5509","moduleCredit":0,"title":"Pensions and Retirement Policies"} +{"moduleCode":"NM2104","moduleCredit":0,"title":"Qualitative Communication Research Methods"} +{"moduleCode":"BN3301","moduleCredit":0,"title":"Introduction To Biomaterials"} +{"moduleCode":"NM2103","moduleCredit":0,"title":"Quantitative Research Methods"} +{"moduleCode":"UTC2111","moduleCredit":0,"title":"Picturing and Seeing Development"} +{"moduleCode":"UTC2113","moduleCredit":0,"title":"Gaming Life"} +{"moduleCode":"TEE4415","moduleCredit":0,"title":"Integrated Digital Design"} +{"moduleCode":"LL6050V","moduleCredit":0,"title":"Public International Law"} +{"moduleCode":"ID2323","moduleCredit":0,"title":"Technology for Design"} +{"moduleCode":"PP5510","moduleCredit":0,"title":"Governing Cities of Tomorrow"} +{"moduleCode":"MA4221","moduleCredit":0,"title":"Partial Differential Equations"} +{"moduleCode":"PP5514","moduleCredit":0,"title":"ASEAN and Regionalism in Southeast Asia"} +{"moduleCode":"PH6770","moduleCredit":0,"title":"Graduate Research Seminar"} +{"moduleCode":"PP5513","moduleCredit":0,"title":"Governing Nation-State and Global-City Singapore"} +{"moduleCode":"TCN4227","moduleCredit":0,"title":"Advanced Process Control"} +{"moduleCode":"PP5512","moduleCredit":0,"title":"US-China Relations and Great Power Policy Making"} +{"moduleCode":"PP5511","moduleCredit":0,"title":"Systemic and Integrated Policy Design and Analysis"} +{"moduleCode":"PP5518","moduleCredit":0,"title":"Pragmatism and Public Morality in Singapore"} +{"moduleCode":"PP5517","moduleCredit":0,"title":"Gender and Public Policy: The life course approach"} +{"moduleCode":"SPH3109","moduleCredit":0,"title":"Designing Public Health Programmes"} +{"moduleCode":"PP5516","moduleCredit":0,"title":"Practical Political Risk Analysis"} +{"moduleCode":"PP5515","moduleCredit":0,"title":"Gender and Development"} +{"moduleCode":"MA4229","moduleCredit":0,"title":"Approximation Theory"} +{"moduleCode":"LCD5204BV","moduleCredit":0,"title":"Charterparties"} +{"moduleCode":"NM2101","moduleCredit":0,"title":"Theories of Communications and New Media"} +{"moduleCode":"ACC3702","moduleCredit":0,"title":"Corporate and Securities Law"} +{"moduleCode":"ACC3701","moduleCredit":0,"title":"Assurance and Attestation"} +{"moduleCode":"ACC3704","moduleCredit":0,"title":"Advanced Corporate Accounting and Reporting"} +{"moduleCode":"ACC3703","moduleCredit":0,"title":"Taxation"} +{"moduleCode":"SPH3105","moduleCredit":0,"title":"Prevention and Control of Non-Communicable Diseases"} +{"moduleCode":"ACC3706","moduleCredit":0,"title":"Corporate Governance and Risk Management"} +{"moduleCode":"PS3880G","moduleCredit":0,"title":"Topics in PS: Research Design and Methods"} +{"moduleCode":"SPH3104","moduleCredit":0,"title":"Infectious disease epidemiology and public health"} +{"moduleCode":"ACC3705","moduleCredit":0,"title":"Valuation"} +{"moduleCode":"PR5130","moduleCredit":0,"title":"Advanced Pharmacotherapy I"} +{"moduleCode":"SPH3103","moduleCredit":0,"title":"Public Health Economics"} +{"moduleCode":"PP5521","moduleCredit":0,"title":"The Economic Analysis of Law"} +{"moduleCode":"PR5131","moduleCredit":0,"title":"Advanced Pharmacotherapy II"} +{"moduleCode":"SPH3102","moduleCredit":0,"title":"Introduction to Public Health Communication"} +{"moduleCode":"ACC3707","moduleCredit":0,"title":"Integrated Perspectives in Accounting and Business"} +{"moduleCode":"PP5520","moduleCredit":0,"title":"The Political Economy of Reform in China"} +{"moduleCode":"PR5132","moduleCredit":0,"title":"Advanced Pharmacotherapy III"} +{"moduleCode":"SPH3101","moduleCredit":0,"title":"Biostatistics for Public Health"} +{"moduleCode":"PR5133","moduleCredit":0,"title":"Advanced Pharmacotherapy in Special Populations"} +{"moduleCode":"TCN4233","moduleCredit":0,"title":"Good Manufacturing Practices in Pharmaceutical Industry"} +{"moduleCode":"BSP3513","moduleCredit":0,"title":"Family Business"} +{"moduleCode":"PR5134","moduleCredit":0,"title":"Advanced Skills in Pharmacy Practice"} +{"moduleCode":"PF3201","moduleCredit":0,"title":"Measurement (Specialist Works)"} +{"moduleCode":"PR5113","moduleCredit":0,"title":"Clinical Pharmacokinetics & Therapeutic Drug Monitoring"} +{"moduleCode":"LL4094V","moduleCredit":0,"title":"Law & Practice - The Law Clinic"} +{"moduleCode":"MA4235","moduleCredit":0,"title":"Topics in Graph Theory"} +{"moduleCode":"PF3209","moduleCredit":0,"title":"Building Information Modelling"} +{"moduleCode":"FST4202","moduleCredit":0,"title":"Nutritional Biochemistry"} +{"moduleCode":"PF3207","moduleCredit":0,"title":"Project Management Law"} +{"moduleCode":"PF3208","moduleCredit":0,"title":"Project Leadership"} +{"moduleCode":"LCD5204AV","moduleCredit":0,"title":"Carriage of Goods By Sea"} +{"moduleCode":"PF3205","moduleCredit":0,"title":"Advanced Measurement"} +{"moduleCode":"PF3206","moduleCredit":0,"title":"Project Scheduling and Control"} +{"moduleCode":"SG5015","moduleCredit":0,"title":"Enterprise Architecture"} +{"moduleCode":"SG5013","moduleCredit":0,"title":"Software Entrepreneurship"} +{"moduleCode":"TCE2184","moduleCredit":0,"title":"Infrastructure & the Environment"} +{"moduleCode":"MLE5104","moduleCredit":0,"title":"Physical Properties of Materials"} +{"moduleCode":"TCE2183","moduleCredit":0,"title":"Construction Project Management"} +{"moduleCode":"SG5018","moduleCredit":0,"title":"Advanced Topics in Software Process Improvement"} +{"moduleCode":"SG5017","moduleCredit":0,"title":"Software Product Line Engineering"} +{"moduleCode":"SG5016","moduleCredit":0,"title":"Business Transformation Through Technology Innovation"} +{"moduleCode":"TCN4242","moduleCredit":0,"title":"Optimization of Chemical Processes"} +{"moduleCode":"TEE4435","moduleCredit":0,"title":"Modern Transistors and Memory Devices"} +{"moduleCode":"TEE4436","moduleCredit":0,"title":"Fabrication Process Technology"} +{"moduleCode":"TCN4240","moduleCredit":0,"title":"Unit Operations and Processes for Effluent Treatment"} +{"moduleCode":"TCN4246","moduleCredit":0,"title":"Chemical And Bio-Catalysis"} +{"moduleCode":"MA4230","moduleCredit":0,"title":"Matrix Computation"} +{"moduleCode":"EE4205","moduleCredit":0,"title":"Quantum Communication and Cryptography"} +{"moduleCode":"EE4204","moduleCredit":0,"title":"Computer Networks"} +{"moduleCode":"SE5247R","moduleCredit":0,"title":"Country Studies: Vietnam"} +{"moduleCode":"CHC5326","moduleCredit":0,"title":"Comparative Grammar between Chinese and English"} +{"moduleCode":"ST1131","moduleCredit":0,"title":"Introduction to Statistics"} +{"moduleCode":"CS3233R","moduleCredit":0,"title":"Competitive Programming"} +{"moduleCode":"LL4146V","moduleCredit":0,"title":"Law & Society"} +{"moduleCode":"AR5803","moduleCredit":0,"title":"Architectural & Technology Design 1"} +{"moduleCode":"IE5908B","moduleCredit":0,"title":"Research Project in Operations Research II"} +{"moduleCode":"AR5802","moduleCredit":0,"title":"Options Design Research Studio 2"} +{"moduleCode":"AR5801","moduleCredit":0,"title":"Options Design Research Studio 1"} +{"moduleCode":"IE5908A","moduleCredit":0,"title":"Research Project in Operations Research I"} +{"moduleCode":"EE3331E","moduleCredit":0,"title":"Feedback Control Systems"} +{"moduleCode":"EE3331C","moduleCredit":0,"title":"Feedback Control Systems"} +{"moduleCode":"ME4261","moduleCredit":0,"title":"Tool Engineering"} +{"moduleCode":"ME4263","moduleCredit":0,"title":"Fundamentals of Product Development"} +{"moduleCode":"AR5808","moduleCredit":0,"title":"Final Design Project"} +{"moduleCode":"ME4262","moduleCredit":0,"title":"Automation In Manufacturing"} +{"moduleCode":"AR5807","moduleCredit":0,"title":"Architectural Design Thesis"} +{"moduleCode":"EE4212","moduleCredit":0,"title":"Computer Vision"} +{"moduleCode":"LAR4201","moduleCredit":0,"title":"Arabic 5"} +{"moduleCode":"AR5806","moduleCredit":0,"title":"Architectural Design Research Report"} +{"moduleCode":"BMO6006Z","moduleCredit":0,"title":"Independent Study: Special Topics in Mindfulness"} +{"moduleCode":"EE4211","moduleCredit":0,"title":"Data Science for the Internet of Things"} +{"moduleCode":"LAR4202","moduleCredit":0,"title":"Arabic 6"} +{"moduleCode":"AR5805","moduleCredit":0,"title":"Advanced Architecture Studio"} +{"moduleCode":"BMO6006Y","moduleCredit":0,"title":"Independent Study: Special Topics in Workplace Secrecy"} +{"moduleCode":"EE4210","moduleCredit":0,"title":"Network Protocols and Applications"} +{"moduleCode":"AR5804","moduleCredit":0,"title":"Architectural & Technology Design 2"} +{"moduleCode":"LL4012V","moduleCredit":0,"title":"Comparative Constitutional Law"} +{"moduleCode":"SE5246R","moduleCredit":0,"title":"Country Studies: Myanmar"} +{"moduleCode":"CHC5317","moduleCredit":0,"title":"New Approaches to Modern Chinese Culture"} +{"moduleCode":"CHC5316","moduleCredit":0,"title":"Print Culture and Chinese Literature: From Ming to Modern"} +{"moduleCode":"CHC5315","moduleCredit":0,"title":"Neo‐Taoism"} +{"moduleCode":"BI3001C","moduleCredit":0,"title":"Business Internship I"} +{"moduleCode":"FDP2022","moduleCredit":0,"title":"Special Physics Class 3"} +{"moduleCode":"BI3001D","moduleCredit":0,"title":"Business Internship I"} +{"moduleCode":"BI3001A","moduleCredit":0,"title":"Business Internship I"} +{"moduleCode":"BI3001B","moduleCredit":0,"title":"Business Internship I"} +{"moduleCode":"GEH1025T","moduleCredit":0,"title":"Global Environmental Issues"} +{"moduleCode":"FDP2021","moduleCredit":0,"title":"Special Physics Class 1, 2"} +{"moduleCode":"SN3262","moduleCredit":0,"title":"The Struggle for India, 1920-1964"} +{"moduleCode":"TEE3801","moduleCredit":0,"title":"Robust Design Of Electronic Circuits"} +{"moduleCode":"GEQ1000","moduleCredit":0,"title":"Asking Questions"} +{"moduleCode":"CHC5322","moduleCredit":0,"title":"Pragmatics and Politeness"} +{"moduleCode":"MA2202S","moduleCredit":0,"title":"Algebra I (S)"} +{"moduleCode":"DMB1201BSP","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"CHC5309","moduleCredit":0,"title":"Economic & Management Thought in Pre-Modern China"} +{"moduleCode":"CHC5306","moduleCredit":0,"title":"Chinese Intellectual History, 10th – 19th Century"} +{"moduleCode":"CHC5305","moduleCredit":0,"title":"Prominent Nanyang Chinese in Modern China"} +{"moduleCode":"CHC5304","moduleCredit":0,"title":"Society and Culture of the Ming Dynasty"} +{"moduleCode":"LL4011V","moduleCredit":0,"title":"Civil Justice & Process"} +{"moduleCode":"IE6999","moduleCredit":0,"title":"Doctoral Seminars"} +{"moduleCode":"IE5666","moduleCredit":0,"title":"Industrial Attachment"} +{"moduleCode":"LL6109V","moduleCredit":0,"title":"International Law & Asia"} +{"moduleCode":"FDP2011","moduleCredit":0,"title":"Special Mathematics Class 1, 2"} +{"moduleCode":"FDP2012","moduleCredit":0,"title":"Special Mathematics Class 3"} +{"moduleCode":"TR2201","moduleCredit":0,"title":"Entrepreneurial Marketing"} +{"moduleCode":"SG5103","moduleCredit":0,"title":"Software Quality Management"} +{"moduleCode":"IE5906A","moduleCredit":0,"title":"Research Project in Systems Engineering I"} +{"moduleCode":"IS4103","moduleCredit":0,"title":"Information Systems Capstone Project"} +{"moduleCode":"SG5102","moduleCredit":0,"title":"Software Project Management"} +{"moduleCode":"SG5101","moduleCredit":0,"title":"Software Analysis & Design"} +{"moduleCode":"SN3274","moduleCredit":0,"title":"South Asian Cinema"} +{"moduleCode":"IE5906B","moduleCredit":0,"title":"Research Project in Systems Engineering II"} +{"moduleCode":"CHC5314","moduleCredit":0,"title":"Chinese Religion"} +{"moduleCode":"CHC5313","moduleCredit":0,"title":"Thematics in Chinese Literature"} +{"moduleCode":"CHC5312","moduleCredit":0,"title":"Tang-Song Poetry and Poetics"} +{"moduleCode":"ME4241","moduleCredit":0,"title":"Aircraft Performance, Stability and Control"} +{"moduleCode":"CM1417","moduleCredit":0,"title":"Fundamentals of Chemistry"} +{"moduleCode":"CHC5310","moduleCredit":0,"title":"Chinese Rhapsody"} +{"moduleCode":"IS4100","moduleCredit":0,"title":"IT Project Management"} +{"moduleCode":"SN3275","moduleCredit":0,"title":"Tamil Culture and Society"} +{"moduleCode":"ME4245","moduleCredit":0,"title":"Robot Mechanics and Control"} +{"moduleCode":"PC1421","moduleCredit":0,"title":"Physics for Life Sciences"} +{"moduleCode":"LAC4201","moduleCredit":0,"title":"Chinese 5"} +{"moduleCode":"LAC4202","moduleCredit":0,"title":"Chinese 6"} +{"moduleCode":"CM1401","moduleCredit":0,"title":"Chemistry for Life Sciences"} +{"moduleCode":"EE4218","moduleCredit":0,"title":"Embedded Hardware System Design"} +{"moduleCode":"SE5244R","moduleCredit":0,"title":"Country Studies: The Philippines"} +{"moduleCode":"CM1402","moduleCredit":0,"title":"General Chemistry"} +{"moduleCode":"BL5312","moduleCredit":0,"title":"Natural History Collections and Conservation"} +{"moduleCode":"ZB4171","moduleCredit":0,"title":"Advanced Topics in Bioinformatics"} +{"moduleCode":"BMA5118A","moduleCredit":0,"title":"Special Topics in Strategy and Policy: Sustainability Strategy"} +{"moduleCode":"SN3281","moduleCredit":0,"title":"The Story of Indian Business"} +{"moduleCode":"CHC5303","moduleCredit":0,"title":"Traditional Chinese Culture in Singapore and Malaysia"} +{"moduleCode":"CHC5302","moduleCredit":0,"title":"Chinese Buddhist Proselytic Literature"} +{"moduleCode":"CHC5301","moduleCredit":0,"title":"History and Civilizations of the Tang Empire"} +{"moduleCode":"TS6660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"PC1433","moduleCredit":0,"title":"Mechanics and Waves"} +{"moduleCode":"ME4253","moduleCredit":0,"title":"Biomaterials Engineering"} +{"moduleCode":"PC1431","moduleCredit":0,"title":"Physics IE"} +{"moduleCode":"ME4255","moduleCredit":0,"title":"Materials Failure"} +{"moduleCode":"PC1432","moduleCredit":0,"title":"Physics IIE"} +{"moduleCode":"CH4203","moduleCredit":0,"title":"Chinese Dialectology"} +{"moduleCode":"CH4201","moduleCredit":0,"title":"Chinese Classical Phonology"} +{"moduleCode":"EL6770","moduleCredit":0,"title":"Graduate Research Seminar"} +{"moduleCode":"ESP1111","moduleCredit":0,"title":"Engineering Principles In-Action"} +{"moduleCode":"CE5509B","moduleCredit":0,"title":"Design of Composite Steel and Concrete Structures to EC4"} +{"moduleCode":"CE5509A","moduleCredit":0,"title":"Advanced Structural Steel Design to EC3"} +{"moduleCode":"MUA4190","moduleCredit":0,"title":"Applied Voice Major Study 4A"} +{"moduleCode":"MUA4191","moduleCredit":0,"title":"Senior Recital in Voice"} +{"moduleCode":"IS5451","moduleCredit":0,"title":"Pervasive Technology Solutions and Development"} +{"moduleCode":"ID6770","moduleCredit":0,"title":"Doctoral Seminar Module in Industrial Design"} +{"moduleCode":"PP5110A","moduleCredit":0,"title":"Policy Analysis Exercise"} +{"moduleCode":"LL5349V","moduleCredit":0,"title":"Energy Arbitration"} +{"moduleCode":"LC2008B","moduleCredit":0,"title":"Company Law (B)"} +{"moduleCode":"LC2008A","moduleCredit":0,"title":"Company Law (A)"} +{"moduleCode":"LC2008D","moduleCredit":0,"title":"Company Law (D)"} +{"moduleCode":"FIN3120B","moduleCredit":0,"title":"TIF: Transaction Banking"} +{"moduleCode":"LC2008C","moduleCredit":0,"title":"Company Law (C)"} +{"moduleCode":"MA1100","moduleCredit":0,"title":"Basic Discrete Mathematics"} +{"moduleCode":"RE2801","moduleCredit":0,"title":"Research Methodology in Real Estate"} +{"moduleCode":"LC2008F","moduleCredit":0,"title":"Company Law (F)"} +{"moduleCode":"LC2008E","moduleCredit":0,"title":"Company Law (E)"} +{"moduleCode":"CS3230R","moduleCredit":0,"title":"Design and Analysis of Algorithms"} +{"moduleCode":"PL3551","moduleCredit":0,"title":"FASS Undergraduate Research Opportunity (UROP)"} +{"moduleCode":"BMK6105J","moduleCredit":0,"title":"ISM: Technology and implications on Judgement and Decision-Making"} +{"moduleCode":"IE4220E","moduleCredit":0,"title":"Supply Chain Modelling"} +{"moduleCode":"ID4105","moduleCredit":0,"title":"Design Platforms 4"} +{"moduleCode":"ID4106","moduleCredit":0,"title":"Design Thesis Project"} +{"moduleCode":"MUA4180","moduleCredit":0,"title":"Internship in Audio Arts and Science 2"} +{"moduleCode":"MUA4181","moduleCredit":0,"title":"Professional Concepts in Orchestral Repertoire"} +{"moduleCode":"PP5242J","moduleCredit":0,"title":"Effective Implementation: Learning from Effective Implementers"} +{"moduleCode":"PR3202","moduleCredit":0,"title":"Community Health & Preventative Care"} +{"moduleCode":"LL4140V","moduleCredit":0,"title":"Law of the Sea: Theory and Practice"} +{"moduleCode":"MUA4179","moduleCredit":0,"title":"Final Project"} +{"moduleCode":"EE5518","moduleCredit":0,"title":"Vlsi Digital Circuit Design"} +{"moduleCode":"EE5517","moduleCredit":0,"title":"Optical Engineering"} +{"moduleCode":"MUA4172","moduleCredit":0,"title":"Internship in Audio Arts and Sciences 1"} +{"moduleCode":"MUA4173","moduleCredit":0,"title":"Audio for Media 1"} +{"moduleCode":"MUA4174","moduleCredit":0,"title":"Audio for Media 2"} +{"moduleCode":"ZB4199","moduleCredit":0,"title":"Honours Project in Computational Biology"} +{"moduleCode":"MUA4175","moduleCredit":0,"title":"AAS Final Project"} +{"moduleCode":"YID3202H","moduleCredit":0,"title":"Special Topics: Asia's Edible Ocean"} +{"moduleCode":"DOS3811","moduleCredit":0,"title":"Technology and Business Innovation"} +{"moduleCode":"MUA4176","moduleCredit":0,"title":"Music Production and Marketing"} +{"moduleCode":"YID3202G","moduleCredit":0,"title":"Special Topics: Planetary Health"} +{"moduleCode":"LLD5205V","moduleCredit":0,"title":"Maritime Conflict of Laws"} +{"moduleCode":"MUA4177","moduleCredit":0,"title":"Music Production and Marketing II"} +{"moduleCode":"YID3202F","moduleCredit":0,"title":"Topic: Entangled Environments: Ocean & Society in S.E.A"} +{"moduleCode":"CS5478","moduleCredit":0,"title":"Intelligent Robots: Algorithms and Systems"} +{"moduleCode":"MUA4178","moduleCredit":0,"title":"MS / MCP Capstone Project"} +{"moduleCode":"PS5201","moduleCredit":0,"title":"Seminar in Political Theory"} +{"moduleCode":"CS5477","moduleCredit":0,"title":"3D Computer Vision"} +{"moduleCode":"CS5476","moduleCredit":0,"title":"IoT Security"} +{"moduleCode":"ESE5880A","moduleCredit":0,"title":"Topics in Environmental Engineering: Chem. & Lab Safety"} +{"moduleCode":"CP3880","moduleCredit":0,"title":"Advanced Technology Attachment Programme"} +{"moduleCode":"EE5502","moduleCredit":0,"title":"Mos Devices"} +{"moduleCode":"EE5507","moduleCredit":0,"title":"Analog Integrated Circuits Design"} +{"moduleCode":"EE6831","moduleCredit":0,"title":"Advanced Electromagnetic Theory and Applications"} +{"moduleCode":"EE6832","moduleCredit":0,"title":"Advanced Multi-Antenna Communications"} +{"moduleCode":"EE6833","moduleCredit":0,"title":"Selected Topics in Microwave and Antenna Engineering"} +{"moduleCode":"ME4291","moduleCredit":0,"title":"Finite Element Analysis"} +{"moduleCode":"MUA4161","moduleCredit":0,"title":"Advanced Studies on Principal Instrument"} +{"moduleCode":"BPS5300","moduleCredit":0,"title":"Topics in Building Performance and Sustainability"} +{"moduleCode":"MUA4162","moduleCredit":0,"title":"Senior Recital - Instrumental Performance Capstone"} +{"moduleCode":"EE5508","moduleCredit":0,"title":"Semiconductor Fundamentals"} +{"moduleCode":"CS5469","moduleCredit":0,"title":"Fundamentals of Logic in Computer Science"} +{"moduleCode":"CS5461","moduleCredit":0,"title":"Algorithmic Mechanism Design"} +{"moduleCode":"GS6001","moduleCredit":0,"title":"Research Ethics and Scientific Integrity"} +{"moduleCode":"CH4243","moduleCredit":0,"title":"Selected Periods of Chinese History II"} +{"moduleCode":"ACC4612A","moduleCredit":0,"title":"SIA: Internal Auditing"} +{"moduleCode":"CH4247","moduleCredit":0,"title":"Print Culture in Modern China"} +{"moduleCode":"MNO3751","moduleCredit":0,"title":"Independent Study in Leadership & Human Capital Mgmt"} +{"moduleCode":"ST4241","moduleCredit":0,"title":"Design & Analysis of Clinical Trials"} +{"moduleCode":"ST4242","moduleCredit":0,"title":"Analysis of Longitudinal Data"} +{"moduleCode":"MUA4153","moduleCredit":0,"title":"Noon Recital Series 4A"} +{"moduleCode":"EE3207E","moduleCredit":0,"title":"Computer Architecture"} +{"moduleCode":"MUA4154","moduleCredit":0,"title":"Noon Recital Series 4B"} +{"moduleCode":"BN6202","moduleCredit":0,"title":"Advanced Human Motion Biomechanics"} +{"moduleCode":"TR3002N","moduleCredit":0,"title":"New Venture Creation"} +{"moduleCode":"ME5513","moduleCredit":0,"title":"Fracture And Fatigue Of Materials"} +{"moduleCode":"LL5034V","moduleCredit":0,"title":"International Regulation of Shipping"} +{"moduleCode":"BN6209","moduleCredit":0,"title":"Neurotechnology"} +{"moduleCode":"ENV3202","moduleCredit":0,"title":"Environmental Studies Internship Programme"} +{"moduleCode":"ME5516","moduleCredit":0,"title":"Emerging Energy Conversion and Storage Technologies"} +{"moduleCode":"TME2134","moduleCredit":0,"title":"Fluid Mechanics I"} +{"moduleCode":"TME2135","moduleCredit":0,"title":"Fluid Mechanics II"} +{"moduleCode":"CN2125","moduleCredit":0,"title":"Heat & Mass Transfer"} +{"moduleCode":"ST4234","moduleCredit":0,"title":"Bayesian Statistics"} +{"moduleCode":"CN2122","moduleCredit":0,"title":"Fluid Mechanics"} +{"moduleCode":"CN2121","moduleCredit":0,"title":"Chemical Engineering Thermodynamics"} +{"moduleCode":"ST4238","moduleCredit":0,"title":"Stochastic Processes II"} +{"moduleCode":"BMS5403","moduleCredit":0,"title":"Global Management Practice"} +{"moduleCode":"LL6233V","moduleCredit":0,"title":"European Company Law"} +{"moduleCode":"ESE3101","moduleCredit":0,"title":"Solid And Hazardous Waste Management"} +{"moduleCode":"BMS5407","moduleCredit":0,"title":"Workplace and Corporate Deviance"} +{"moduleCode":"LAK1201","moduleCredit":0,"title":"Korean 1"} +{"moduleCode":"BMS5408","moduleCredit":0,"title":"Special Topics in Organizational Behavior"} +{"moduleCode":"CN4223R","moduleCredit":0,"title":"Microelectronic Thin Films"} +{"moduleCode":"CG2271","moduleCredit":0,"title":"Real-Time Operating Systems"} +{"moduleCode":"PC3239","moduleCredit":0,"title":"Special Problems in Undergrad Physics II"} +{"moduleCode":"CN2116","moduleCredit":0,"title":"Chemical Kinetics & Reactor Design"} +{"moduleCode":"PC3233","moduleCredit":0,"title":"Atomic & Molecular Physics I"} +{"moduleCode":"ST4248","moduleCredit":0,"title":"Statistical Learning II"} +{"moduleCode":"BMS5409","moduleCredit":0,"title":"Principles of Multinational Management"} +{"moduleCode":"PC3232","moduleCredit":0,"title":"Nuclear & Particle Physics"} +{"moduleCode":"ST4245","moduleCredit":0,"title":"Statistical Methods for Finance"} +{"moduleCode":"PC3231","moduleCredit":0,"title":"Electricity & Magnetism II"} +{"moduleCode":"PC3238","moduleCredit":0,"title":"Fluid Dynamics"} +{"moduleCode":"SWE5007","moduleCredit":0,"title":"Capstone Project in Software Engineering"} +{"moduleCode":"TME2142","moduleCredit":0,"title":"Feedback Control Systems"} +{"moduleCode":"PC3236","moduleCredit":0,"title":"Computational Methods in Physics"} +{"moduleCode":"SWE5005","moduleCredit":0,"title":"Securing Ubiquitous Systems"} +{"moduleCode":"TME2143","moduleCredit":0,"title":"Sensors and Actuators"} +{"moduleCode":"EE4407E","moduleCredit":0,"title":"Analog Electronics"} +{"moduleCode":"PC3235","moduleCredit":0,"title":"Solid State Physics I"} +{"moduleCode":"SWE5004","moduleCredit":0,"title":"Architecting Smart Systems"} +{"moduleCode":"CH4222","moduleCredit":0,"title":"Chinese Classical Novels"} +{"moduleCode":"RE5004","moduleCredit":0,"title":"Real Estate Economics"} +{"moduleCode":"SWE5003","moduleCredit":0,"title":"Engineering Big Data"} +{"moduleCode":"RE5005","moduleCredit":0,"title":"Real Estate Finance"} +{"moduleCode":"SWE5002","moduleCredit":0,"title":"Designing and Managing Products and Platforms"} +{"moduleCode":"SWE5001","moduleCredit":0,"title":"Architecting Scalable Systems"} +{"moduleCode":"RE5003","moduleCredit":0,"title":"Real Estate Investment"} +{"moduleCode":"RE5009","moduleCredit":0,"title":"Commercial Real Estate Appraisal"} +{"moduleCode":"RE5006","moduleCredit":0,"title":"Portfolio and Asset Management"} +{"moduleCode":"LL4322V","moduleCredit":0,"title":"Trade Finance Law"} +{"moduleCode":"TIE3101","moduleCredit":0,"title":"Statistics for Engineering Applications"} +{"moduleCode":"LL4019V","moduleCredit":0,"title":"Credit & Security"} +{"moduleCode":"TIE3100","moduleCredit":0,"title":"Systems Design Project"} +{"moduleCode":"TME2114","moduleCredit":0,"title":"Mechanics of Materials II"} +{"moduleCode":"UWC2101AA","moduleCredit":0,"title":"Writing & Critical Thinking: Religion in Public Life"} +{"moduleCode":"DAO1704X","moduleCredit":0,"title":"Decision Analytics using Spreadsheets"} +{"moduleCode":"RE5000","moduleCredit":0,"title":"Dissertation"} +{"moduleCode":"RE5001","moduleCredit":0,"title":"Real Estate Development"} +{"moduleCode":"LL6102V","moduleCredit":0,"title":"Advanced Torts"} +{"moduleCode":"RE5015","moduleCredit":0,"title":"Spatial Information Systems (SIS) for Urban Planning"} +{"moduleCode":"BN4101R","moduleCredit":0,"title":"B.Eng. Dissertation"} +{"moduleCode":"RE5016","moduleCredit":0,"title":"Real Estate Securitisation"} +{"moduleCode":"LC2006B","moduleCredit":0,"title":"Equity & Trusts (B)"} +{"moduleCode":"LL6235V","moduleCredit":0,"title":"International Contract Law: Principles and Practice"} +{"moduleCode":"RE5013","moduleCredit":0,"title":"Urban Policy & Real Estate Markets"} +{"moduleCode":"LC2006A","moduleCredit":0,"title":"Equity & Trusts (A)"} +{"moduleCode":"RE5014","moduleCredit":0,"title":"Real Estate Investment Trusts & Property Funds"} +{"moduleCode":"LL6008AV","moduleCredit":0,"title":"Carriage of Goods By Sea"} +{"moduleCode":"ST4232","moduleCredit":0,"title":"Nonparametric Statistics"} +{"moduleCode":"CN4221R","moduleCredit":0,"title":"Control of Industrial Processes"} +{"moduleCode":"ST4233","moduleCredit":0,"title":"Linear Models"} +{"moduleCode":"ST4231","moduleCredit":0,"title":"Computer Intensive Statistical Methods"} +{"moduleCode":"ME3233E","moduleCredit":0,"title":"Unsteady Flow in Fluid Systems"} +{"moduleCode":"LC2006D","moduleCredit":0,"title":"Equity & Trusts (D)"} +{"moduleCode":"TIE3110","moduleCredit":0,"title":"Simulation"} +{"moduleCode":"LC2006C","moduleCredit":0,"title":"Equity & Trusts (C)"} +{"moduleCode":"LC2006F","moduleCredit":0,"title":"Equity & Trusts (F)"} +{"moduleCode":"LC2006E","moduleCredit":0,"title":"Equity & Trusts (E)"} +{"moduleCode":"LL5340V","moduleCredit":0,"title":"International Refugee Law"} +{"moduleCode":"AR2723","moduleCredit":0,"title":"Strategies for Sustainable Architecture"} +{"moduleCode":"IE2130E","moduleCredit":0,"title":"Quality Engineering I"} +{"moduleCode":"ME5506","moduleCredit":0,"title":"Corrosion of Materials"} +{"moduleCode":"YSC4200G","moduleCredit":0,"title":"Special Project in Science"} +{"moduleCode":"RE5011","moduleCredit":0,"title":"International Field Study"} +{"moduleCode":"TME2121","moduleCredit":0,"title":"Engineering Thermodynamics"} +{"moduleCode":"ACC4612K","moduleCredit":0,"title":"Sem. in Acctg: Accounting & Business Analysis for Banks"} +{"moduleCode":"ID4121","moduleCredit":0,"title":"Project Research"} +{"moduleCode":"MUA4113","moduleCredit":0,"title":"Piano Pedagogy"} +{"moduleCode":"SE5243R","moduleCredit":0,"title":"Country Studies: Indonesia"} +{"moduleCode":"LL6008BV","moduleCredit":0,"title":"Charterparties"} +{"moduleCode":"CS1010X","moduleCredit":0,"title":"Programming Methodology"} +{"moduleCode":"CS1010R","moduleCredit":0,"title":"Programming Methodology"} +{"moduleCode":"CS1010S","moduleCredit":0,"title":"Programming Methodology"} +{"moduleCode":"BMC5010A","moduleCredit":0,"title":"Corporate Finance"} +{"moduleCode":"MUA4110","moduleCredit":0,"title":"Chamber Music in Mixed Ensemble"} +{"moduleCode":"ME4225","moduleCredit":0,"title":"Applied Heat Transfer"} +{"moduleCode":"ME4227","moduleCredit":0,"title":"Internal Combustion Engines"} +{"moduleCode":"BMC5010B","moduleCredit":0,"title":"Corporate Governance"} +{"moduleCode":"ME4226","moduleCredit":0,"title":"Energy and Thermal Systems"} +{"moduleCode":"CN4227E","moduleCredit":0,"title":"Advanced Process Control"} +{"moduleCode":"PC3267","moduleCredit":0,"title":"Biophysics II"} +{"moduleCode":"MNO3716","moduleCredit":0,"title":"Principles of Global Management"} +{"moduleCode":"MNO3715","moduleCredit":0,"title":"Leading Groups and Teams"} +{"moduleCode":"ME4223","moduleCredit":0,"title":"Thermal Environmental Engineering"} +{"moduleCode":"MNO3714","moduleCredit":0,"title":"Business with a Social Conscience"} +{"moduleCode":"MNO3713","moduleCredit":0,"title":"Management of Employee Relations"} +{"moduleCode":"MUA4102","moduleCredit":0,"title":"Composition Major Study 4B"} +{"moduleCode":"SE5242R","moduleCredit":0,"title":"Country Studies: Thailand"} +{"moduleCode":"TR3008A","moduleCredit":0,"title":"Technological Innovation"} +{"moduleCode":"IT3011","moduleCredit":0,"title":"Introduction to Machine Learning and Applications"} +{"moduleCode":"TR3008B","moduleCredit":0,"title":"Technological Innovation"} +{"moduleCode":"PC3274","moduleCredit":0,"title":"Mathematical Methods in Physics II"} +{"moduleCode":"MUA4107","moduleCredit":0,"title":"Large Ensembles 4A"} +{"moduleCode":"ST4299","moduleCredit":0,"title":"Applied Project in Statistics"} +{"moduleCode":"MUA4108","moduleCredit":0,"title":"Leadership Skills in an Orchestral Context"} +{"moduleCode":"MUA4109","moduleCredit":0,"title":"Chamber Music"} +{"moduleCode":"MUT4201","moduleCredit":0,"title":"Graduate Theory Preparation"} +{"moduleCode":"CN4227R","moduleCredit":0,"title":"Advanced Process Control"} +{"moduleCode":"LL6237V","moduleCredit":0,"title":"Law, Institutions, and Business in Greater China"} +{"moduleCode":"IT3010","moduleCredit":0,"title":"Data Management for Business Analytics"} +{"moduleCode":"MUA4101","moduleCredit":0,"title":"Composition Major Study 4A"} +{"moduleCode":"CS1010J","moduleCredit":0,"title":"Programming Methodology"} +{"moduleCode":"CG4001","moduleCredit":0,"title":"B. Eng. Dissertation"} +{"moduleCode":"CG4003","moduleCredit":0,"title":"Advanced Project and Internship"} +{"moduleCode":"LL5342V","moduleCredit":0,"title":"Taxation of Cross-Border Commercial Transactions"} +{"moduleCode":"CG4002","moduleCredit":0,"title":"Computer Engineering Capstone Project"} +{"moduleCode":"DL5201","moduleCredit":0,"title":"Strategic Thinking & Digital Foresight"} +{"moduleCode":"TME2101","moduleCredit":0,"title":"Fundamentals of Mechanical Design"} +{"moduleCode":"LAV3201","moduleCredit":0,"title":"Vietnamese 3"} +{"moduleCode":"LAV3202","moduleCredit":0,"title":"Vietnamese 4"} +{"moduleCode":"PL6660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"CS1010E","moduleCredit":0,"title":"Programming Methodology"} +{"moduleCode":"ME4231","moduleCredit":0,"title":"Aerodynamics"} +{"moduleCode":"CH4281","moduleCredit":0,"title":"Translation Studies"} +{"moduleCode":"ME4233","moduleCredit":0,"title":"Computational Methods In Fluid Mechanics"} +{"moduleCode":"BMU5001","moduleCredit":0,"title":"Leadership & Managerial Skills"} +{"moduleCode":"SA4104","moduleCredit":0,"title":"Digital Product Management"} +{"moduleCode":"SA4101","moduleCredit":0,"title":"Software Analysis and Design"} +{"moduleCode":"SA4102","moduleCredit":0,"title":"Enterprise Solutions Design and Development"} +{"moduleCode":"BT4103","moduleCredit":0,"title":"Business Analytics Capstone Project"} +{"moduleCode":"CN2108","moduleCredit":0,"title":"Chemical Engineering Process Laboratory I"} +{"moduleCode":"BT4101","moduleCredit":0,"title":"B.Sc. (Business Analytics) Dissertation"} +{"moduleCode":"ESE4405","moduleCredit":0,"title":"Urban Water Engineering & Management"} +{"moduleCode":"BI3002A","moduleCredit":0,"title":"Business Internship II"} +{"moduleCode":"ESE4406","moduleCredit":0,"title":"Energy and the Environment"} +{"moduleCode":"BMU5008","moduleCredit":0,"title":"Corporate Governance, Business Law & Ethics"} +{"moduleCode":"BMU5007","moduleCredit":0,"title":"Corporate Finance"} +{"moduleCode":"LL5190","moduleCredit":0,"title":"Freedom of Speech: Critical & Comparative Perspectives"} +{"moduleCode":"BI3002D","moduleCredit":0,"title":"Business Internship II"} +{"moduleCode":"BMU5006","moduleCredit":0,"title":"Marketing Strategy"} +{"moduleCode":"LL5191","moduleCredit":0,"title":"Wealth Management Law"} +{"moduleCode":"BMC5012B","moduleCredit":0,"title":"Special topics"} +{"moduleCode":"PC2130B","moduleCredit":0,"title":"Applied Quantum Physics"} +{"moduleCode":"BI3002B","moduleCredit":0,"title":"Business Internship II"} +{"moduleCode":"BMC5012A","moduleCredit":0,"title":"Economic analysis for managers"} +{"moduleCode":"BMU5004","moduleCredit":0,"title":"Macroeconomics and International Finance"} +{"moduleCode":"ESE4403","moduleCredit":0,"title":"Membrane Tech In Env Applns"} +{"moduleCode":"BMU5003","moduleCredit":0,"title":"Economic Analysis For Managers"} +{"moduleCode":"LA5222","moduleCredit":0,"title":"Urban Ecology and Design"} +{"moduleCode":"LAB2201","moduleCredit":0,"title":"Bahasa Indonesia 2"} +{"moduleCode":"LL5343V","moduleCredit":0,"title":"International Regulation of the Global Commons"} +{"moduleCode":"PL5304","moduleCredit":0,"title":"Advanced Developmental Psychology"} +{"moduleCode":"PL5303","moduleCredit":0,"title":"Advanced Cognitive Psychology"} +{"moduleCode":"PC3243","moduleCredit":0,"title":"Photonics"} +{"moduleCode":"CN2102","moduleCredit":0,"title":"Chemical Engineering Principles and Practice II"} +{"moduleCode":"PC3242","moduleCredit":0,"title":"Nanofabrication and Nanocharacterization"} +{"moduleCode":"CN2101","moduleCredit":0,"title":"Material and Energy Balances"} +{"moduleCode":"SA4107","moduleCredit":0,"title":"Industrial Attachment Project"} +{"moduleCode":"SA4108","moduleCredit":0,"title":"Mobile Application Development"} +{"moduleCode":"PC3247","moduleCredit":0,"title":"Modern Optics"} +{"moduleCode":"SA4105","moduleCredit":0,"title":"Web Application Development"} +{"moduleCode":"PC3246","moduleCredit":0,"title":"Astrophysics I"} +{"moduleCode":"SA4106","moduleCredit":0,"title":"AD Project"} +{"moduleCode":"UQR2215","moduleCredit":0,"title":"Developing Meaningful Indicators"} +{"moduleCode":"YLS1202","moduleCredit":0,"title":"Beginning Spanish 2"} +{"moduleCode":"YLS1201","moduleCredit":0,"title":"Beginning Spanish 1"} +{"moduleCode":"GMS1000","moduleCredit":0,"title":"The Duke-NUS Premed Course"} +{"moduleCode":"PC3251","moduleCredit":0,"title":"Nanophysics"} +{"moduleCode":"BI3003A","moduleCredit":0,"title":"Work Experience Internship"} +{"moduleCode":"BI3003B","moduleCredit":0,"title":"Work Experience Internship"} +{"moduleCode":"CS3236R","moduleCredit":0,"title":"Introduction to Information Theory"} +{"moduleCode":"LL4014V","moduleCredit":0,"title":"Construction Law"} +{"moduleCode":"BMU5018","moduleCredit":0,"title":"Entrepreneurship and New Venture Creation"} +{"moduleCode":"BMC5011B","moduleCredit":0,"title":"Contemporary Issues in Business 2"} +{"moduleCode":"BMU5017","moduleCredit":0,"title":"Management Practicum"} +{"moduleCode":"BMC5011A","moduleCredit":0,"title":"Contemporary Issues in Business 1"} +{"moduleCode":"BI3003C","moduleCredit":0,"title":"Work Experience Internship"} +{"moduleCode":"BMU5015","moduleCredit":0,"title":"Competitive Strategy & Business Policy"} +{"moduleCode":"BI3003D","moduleCredit":0,"title":"Work Experience Internship"} +{"moduleCode":"BMU5014","moduleCredit":0,"title":"Contemporary Issues in Business"} +{"moduleCode":"EE1111A","moduleCredit":0,"title":"Electrical Engineering Principles and Practice I"} +{"moduleCode":"MNO3701","moduleCredit":0,"title":"Human Capital Management"} +{"moduleCode":"CN3421","moduleCredit":0,"title":"Process Modeling And Numerical Simulation"} +{"moduleCode":"FAS3550","moduleCredit":0,"title":"FASS Industry Seminar"} +{"moduleCode":"ME4212","moduleCredit":0,"title":"Aircraft Structures"} +{"moduleCode":"MNO3703","moduleCredit":0,"title":"Leading in the 21st Century"} +{"moduleCode":"MNO3702","moduleCredit":0,"title":"Negotiation and Conflict Management"} +{"moduleCode":"MUA1163","moduleCredit":0,"title":"The Profession of Music 1"} +{"moduleCode":"MUA1161","moduleCredit":0,"title":"Foundational Studies on Principal Instrument"} +{"moduleCode":"MUA1162","moduleCredit":0,"title":"Juried Performance Presentation"} +{"moduleCode":"LAF2201","moduleCredit":0,"title":"French 2"} +{"moduleCode":"LL5299","moduleCredit":0,"title":"Advanced Issues in the Law & Practice of Int’l Arbitration"} +{"moduleCode":"EE3506C","moduleCredit":0,"title":"Intro to Elect Energy Systems"} +{"moduleCode":"YHU3276","moduleCredit":0,"title":"The Historian’s Craft"} +{"moduleCode":"YSS2214","moduleCredit":0,"title":"Intermediate Macroeconomics"} +{"moduleCode":"YSS2216","moduleCredit":0,"title":"Statistics and Research Methods for Psychology"} +{"moduleCode":"MUA1167","moduleCredit":0,"title":"The Profession of Music 2"} +{"moduleCode":"YSS2211","moduleCredit":0,"title":"Econometrics"} +{"moduleCode":"MUA1165","moduleCredit":0,"title":"Music and Machines"} +{"moduleCode":"YHU3275","moduleCredit":0,"title":"Descartes and the Perfection of Human Knowledge"} +{"moduleCode":"MUA1166","moduleCredit":0,"title":"Introduction to Computing Media in Max"} +{"moduleCode":"YHU3274","moduleCredit":0,"title":"Painting the Orient"} +{"moduleCode":"CS1010","moduleCredit":0,"title":"Programming Methodology"} +{"moduleCode":"YSS2208","moduleCredit":0,"title":"Ancient Greek Political Philosophy"} +{"moduleCode":"YHU3210E","moduleCredit":0,"title":"Proseminar in Literary Studies"} +{"moduleCode":"CN5111","moduleCredit":0,"title":"Optimization of Chemical Processes"} +{"moduleCode":"SE1101E","moduleCredit":0,"title":"Southeast Asia: A Changing Region"} +{"moduleCode":"MUA1153","moduleCredit":0,"title":"Noon Recital Series 1A"} +{"moduleCode":"YSS2220","moduleCredit":0,"title":"Adelaide to Zhuhai: Cities in Comparative Perspective"} +{"moduleCode":"EN4880A","moduleCredit":0,"title":"Usurpation and Authority, 1558-1674"} +{"moduleCode":"PH2241","moduleCredit":0,"title":"Philosophy of Mind"} +{"moduleCode":"PR5131A","moduleCredit":0,"title":"Advanced Pharmacotherapy IIA"} +{"moduleCode":"BMC5009B","moduleCredit":0,"title":"Supply Chain Management"} +{"moduleCode":"BT1101","moduleCredit":0,"title":"Introduction to Business Analytics"} +{"moduleCode":"BMC5009A","moduleCredit":0,"title":"Systems & Operations Management"} +{"moduleCode":"PH2243","moduleCredit":0,"title":"Epistemology"} +{"moduleCode":"PH2242","moduleCredit":0,"title":"Philosophy of Language"} +{"moduleCode":"YHU3266","moduleCredit":0,"title":"Democratic Theory"} +{"moduleCode":"YHU3265","moduleCredit":0,"title":"Philosophy of Religion"} +{"moduleCode":"TIC1001","moduleCredit":0,"title":"Introduction to Computing and Programming I"} +{"moduleCode":"TIC1002","moduleCredit":0,"title":"Introduction to Computing and Programming II"} +{"moduleCode":"YSS2227","moduleCredit":0,"title":"Introduction to Anthropology"} +{"moduleCode":"MUA1157","moduleCredit":0,"title":"Solfege 1"} +{"moduleCode":"YHU3261","moduleCredit":0,"title":"Analogical Reasoning and Metaphor"} +{"moduleCode":"MUA1154","moduleCredit":0,"title":"Noon Recital Series 1B"} +{"moduleCode":"YSS2223","moduleCredit":0,"title":"Religion, Ritual and Magic"} +{"moduleCode":"DMB1204DAO","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"LAG4201","moduleCredit":0,"title":"German 5"} +{"moduleCode":"YSS2218","moduleCredit":0,"title":"International Political Economy"} +{"moduleCode":"LAG4203","moduleCredit":0,"title":"German Studies 1"} +{"moduleCode":"HY6770","moduleCredit":0,"title":"Graduate Research Seminar"} +{"moduleCode":"LAG4202","moduleCredit":0,"title":"German 6"} +{"moduleCode":"SPH2105A","moduleCredit":0,"title":"Introduction to Global Health"} +{"moduleCode":"TEE3031","moduleCredit":0,"title":"Innovation & Enterprise I"} +{"moduleCode":"LL5276","moduleCredit":0,"title":"Advanced Contract Law"} +{"moduleCode":"YID4202","moduleCredit":0,"title":"Applied Environmental Research"} +{"moduleCode":"YHU3299","moduleCredit":0,"title":"Weimar Berlin: Urbanity and Sexology Before the Nazis"} +{"moduleCode":"YHU3294","moduleCredit":0,"title":"Socrates on Trial"} +{"moduleCode":"LL5173V","moduleCredit":0,"title":"Comparative Corporate Law"} +{"moduleCode":"PR4197A","moduleCredit":0,"title":"Pharmacy Internship I"} +{"moduleCode":"PC3289","moduleCredit":0,"title":"Advanced UROPS in Physics II"} +{"moduleCode":"PC3288","moduleCredit":0,"title":"Advanced UROPS in Physics I"} +{"moduleCode":"KE5205","moduleCredit":0,"title":"Text Mining"} +{"moduleCode":"KE5206","moduleCredit":0,"title":"Computational Intelligence I"} +{"moduleCode":"KE5207","moduleCredit":0,"title":"Computational Intelligence II"} +{"moduleCode":"PP6770","moduleCredit":0,"title":"Public Policy Graduate Seminar"} +{"moduleCode":"CN1111E","moduleCredit":0,"title":"Chemical Engineering Principles"} +{"moduleCode":"KE5208","moduleCredit":0,"title":"Sense Making and Insight Discovery"} +{"moduleCode":"JS1101E","moduleCredit":0,"title":"Introduction to Japan"} +{"moduleCode":"ST4199","moduleCredit":0,"title":"Honours Project in Statistics"} +{"moduleCode":"PC3294","moduleCredit":0,"title":"Radiation Laboratory"} +{"moduleCode":"SC4660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"LC2010A","moduleCredit":0,"title":"Legal Systems of Asia (A)"} +{"moduleCode":"YHU3288","moduleCredit":0,"title":"Installation Art"} +{"moduleCode":"YSS2203","moduleCredit":0,"title":"Intermediate Microeconomics"} +{"moduleCode":"LC2010C","moduleCredit":0,"title":"Legal Systems of Asia (C)"} +{"moduleCode":"DMB1202FIN","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"LC2010B","moduleCredit":0,"title":"Legal Systems of Asia (B)"} +{"moduleCode":"YHU3289","moduleCredit":0,"title":"Beyond China: Sinophone Literature, Film, and Culture"} +{"moduleCode":"YHU3283","moduleCredit":0,"title":"Fundamental Reality"} +{"moduleCode":"YHU3286","moduleCredit":0,"title":"Living & Dying as Japanese in WWII Anime and Drama"} +{"moduleCode":"YSS2202","moduleCredit":0,"title":"International Relations"} +{"moduleCode":"YSS2201","moduleCredit":0,"title":"Understanding Behavior and Cognition"} +{"moduleCode":"PR4198A","moduleCredit":0,"title":"Pharmacy Internship II"} +{"moduleCode":"YHU3291","moduleCredit":0,"title":"Sacrifice, Sex, and Power in Medieval Kashmir"} +{"moduleCode":"YHU3293","moduleCredit":0,"title":"Japanese Woodblock Prints"} +{"moduleCode":"YHU3292","moduleCredit":0,"title":"Life Drawing"} +{"moduleCode":"LC2010E","moduleCredit":0,"title":"Legal Systems of Asia (E)"} +{"moduleCode":"LC2010D","moduleCredit":0,"title":"Legal Systems of Asia (D)"} +{"moduleCode":"LC2010F","moduleCredit":0,"title":"Legal Systems of Asia (F)"} +{"moduleCode":"SC5103","moduleCredit":0,"title":"Qualitative Data Analysis"} +{"moduleCode":"YHU3239","moduleCredit":0,"title":"Kazimir Malevich and the Black Square"} +{"moduleCode":"CS2309","moduleCredit":0,"title":"CS Research Methodology"} +{"moduleCode":"BMC5006B","moduleCredit":0,"title":"Contemporary Issues in Marketing"} +{"moduleCode":"BMC5006A","moduleCredit":0,"title":"Marketing Management"} +{"moduleCode":"EE3501E","moduleCredit":0,"title":"Power Electronics"} +{"moduleCode":"CP6010","moduleCredit":0,"title":"Doctoral Seminar"} +{"moduleCode":"TIC2301","moduleCredit":0,"title":"Introduction to Information Security"} +{"moduleCode":"EM1201","moduleCredit":0,"title":"English for Academic Purposes (Music) 1"} +{"moduleCode":"EM1202","moduleCredit":0,"title":"English for Academic Purposes (Music) 2"} +{"moduleCode":"FIN2704","moduleCredit":0,"title":"Finance"} +{"moduleCode":"NUR1122C","moduleCredit":0,"title":"Health Assessment"} +{"moduleCode":"EC3396","moduleCredit":0,"title":"Economic Analysis of Law I"} +{"moduleCode":"EC3394","moduleCredit":0,"title":"Economics and Psychology"} +{"moduleCode":"YHU3225","moduleCredit":0,"title":"Pompeii: Art, Urban Life & Culture in the Roman Empire"} +{"moduleCode":"MUA1116","moduleCredit":0,"title":"Foundations of Instrumental Accompaniment"} +{"moduleCode":"PH2201","moduleCredit":0,"title":"Introduction to Philosophy Of Science"} +{"moduleCode":"BMC5005B","moduleCredit":0,"title":"International Business Law"} +{"moduleCode":"HY5402","moduleCredit":0,"title":"Reconsidering the Cold War"} +{"moduleCode":"YHU3221","moduleCredit":0,"title":"Nietzsche: An Untimely Thinker and His Times"} +{"moduleCode":"BMC5005A","moduleCredit":0,"title":"International Business"} +{"moduleCode":"MUA1115","moduleCredit":0,"title":"Foundations of Vocal Accompaniment / Sight-Reading"} +{"moduleCode":"LL4327V","moduleCredit":0,"title":"Mergers and Acquisitions: A Practitioner’s Perspective"} +{"moduleCode":"MUA1112","moduleCredit":0,"title":"Piano Ensemble 1B"} +{"moduleCode":"AR3151","moduleCredit":0,"title":"Design - ISM"} +{"moduleCode":"PH2207","moduleCredit":0,"title":"Hume and Kant"} +{"moduleCode":"MUA1111","moduleCredit":0,"title":"Piano Ensemble 1A"} +{"moduleCode":"PH2206","moduleCredit":0,"title":"Founders of Modern Philosophy"} +{"moduleCode":"EG2201A","moduleCredit":0,"title":"Introduction to Design Thinking"} +{"moduleCode":"SSA1201","moduleCredit":0,"title":"Singapore Society"} +{"moduleCode":"MUA1109","moduleCredit":0,"title":"Foundations for String Chamber Music"} +{"moduleCode":"MUA1107","moduleCredit":0,"title":"Large Ensembles 1A"} +{"moduleCode":"SSA1202","moduleCredit":0,"title":"Southeast Asia: A Changing Region"} +{"moduleCode":"MUA1108","moduleCredit":0,"title":"Large Ensembles 1B"} +{"moduleCode":"SSA1208","moduleCredit":0,"title":"Everyday Life of Chinese Singaporeans: Past & Present (taught in English)"} +{"moduleCode":"EC5104","moduleCredit":0,"title":"Mathematical Economics"} +{"moduleCode":"CE5666","moduleCredit":0,"title":"Industrial Attachment"} +{"moduleCode":"EC5103","moduleCredit":0,"title":"Econometric Modelling and Applications I"} +{"moduleCode":"SSA1206","moduleCredit":0,"title":"Representing Singapore"} +{"moduleCode":"EC5102","moduleCredit":0,"title":"Macroeconomic Theory"} +{"moduleCode":"SSA1207","moduleCredit":0,"title":"Singapore Literature in English: Selected Texts"} +{"moduleCode":"EC5101","moduleCredit":0,"title":"Microeconomic Theory"} +{"moduleCode":"CE6999","moduleCredit":0,"title":"Doctoral Seminars"} +{"moduleCode":"ME4262E","moduleCredit":0,"title":"Automation in Manufacturing"} +{"moduleCode":"YSS2231","moduleCredit":0,"title":"The Anthropology of Politics and Law: An Introduction"} +{"moduleCode":"YSS2230","moduleCredit":0,"title":"Ethnic Diversity in Japan"} +{"moduleCode":"BMC5008B","moduleCredit":0,"title":"Contemporary Issues in Human Resouce Managment and Organuzational Behavior"} +{"moduleCode":"BMC5008A","moduleCredit":0,"title":"Organizational Behavior and Human Resource Management"} +{"moduleCode":"LL6242V","moduleCredit":0,"title":"Financial Regulation and Central Banking"} +{"moduleCode":"TS5232R","moduleCredit":0,"title":"Performance, History and Cultural Memory"} +{"moduleCode":"YSS2237","moduleCredit":0,"title":"Nuclear Politics"} +{"moduleCode":"NM6660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"PH2211","moduleCredit":0,"title":"Philosophy of Religion"} +{"moduleCode":"YSS2236","moduleCredit":0,"title":"Middle East Societies and Politics"} +{"moduleCode":"YSS2238","moduleCredit":0,"title":"Game Theory and International Relations"} +{"moduleCode":"MUA1101","moduleCredit":0,"title":"Composition Major Study 1A"} +{"moduleCode":"YSS2233","moduleCredit":0,"title":"Investment Analysis and Economics"} +{"moduleCode":"MUA1102","moduleCredit":0,"title":"Composition Major Study 1B"} +{"moduleCode":"YSS2232","moduleCredit":0,"title":"Medicine, Culture and Modernity"} +{"moduleCode":"YSS2235","moduleCredit":0,"title":"Sociology of Law"} +{"moduleCode":"MUT1101","moduleCredit":0,"title":"Introduction to Musical Concepts and Materials"} +{"moduleCode":"YSS2234","moduleCredit":0,"title":"The Good Company"} +{"moduleCode":"LL5044V","moduleCredit":0,"title":"Mediation"} +{"moduleCode":"SPH5002","moduleCredit":0,"title":"Public Health Research Methods"} +{"moduleCode":"PH2208","moduleCredit":0,"title":"Applied Ethics"} +{"moduleCode":"SPH5003","moduleCredit":0,"title":"Health Behaviour and Communication"} +{"moduleCode":"SPH5004","moduleCredit":0,"title":"Introduction to Health Systems and Policies"} +{"moduleCode":"TS1101E","moduleCredit":0,"title":"Introduction to Theatre and Performance"} +{"moduleCode":"SPH5005","moduleCredit":0,"title":"Practicum"} +{"moduleCode":"SPH5006","moduleCredit":0,"title":"STATA Primer for Public Health"} +{"moduleCode":"MT5866","moduleCredit":0,"title":"Industrial Project and Attachment"} +{"moduleCode":"SPH5001","moduleCredit":0,"title":"Foundations of Public Health"} +{"moduleCode":"MA4199","moduleCredit":0,"title":"Honours Project in Mathematics"} +{"moduleCode":"LL6243V","moduleCredit":0,"title":"Law, Economics, Development, and Geography"} +{"moduleCode":"BMC5007A","moduleCredit":0,"title":"Accounting"} +{"moduleCode":"ME4261E","moduleCredit":0,"title":"Tool Engineering"} +{"moduleCode":"PH2222","moduleCredit":0,"title":"Greek Philosophy (Socrates and Plato)"} +{"moduleCode":"BMC5007B","moduleCredit":0,"title":"Financial Management"} +{"moduleCode":"PH2224","moduleCredit":0,"title":"Philosophy and Film"} +{"moduleCode":"LL5045V","moduleCredit":0,"title":"Negotiation"} +{"moduleCode":"LL5178V","moduleCredit":0,"title":"Law and Practice of Investment Treaties"} +{"moduleCode":"ME1102","moduleCredit":0,"title":"Engineering Principles and Practice I"} +{"moduleCode":"MLE3202","moduleCredit":0,"title":"Materials for Biointerfaces"} +{"moduleCode":"MA1301X","moduleCredit":0,"title":"Introductory Mathematics"} +{"moduleCode":"LL5214","moduleCredit":0,"title":"International and Comparative Oil and Gas Law"} +{"moduleCode":"MLE3203","moduleCredit":0,"title":"Engineering Materials"} +{"moduleCode":"LL5219","moduleCredit":0,"title":"The Trial of Jesus in Western Legal Thought"} +{"moduleCode":"OT5304","moduleCredit":0,"title":"Subsea Construction & Operational Support"} +{"moduleCode":"UTC1102S","moduleCredit":0,"title":"Living and Dying in the Internet Age"} +{"moduleCode":"UTC1102R","moduleCredit":0,"title":"Junior Seminar: Green Capitalism: A Critical Engagement"} +{"moduleCode":"LL4150V","moduleCredit":0,"title":"International Investment Law and Arbitration"} +{"moduleCode":"LL4283V","moduleCredit":0,"title":"Artificial Intelligence, Information Science & Law"} +{"moduleCode":"OT5301","moduleCredit":0,"title":"Subsea Systems Engineering"} +{"moduleCode":"EN3231","moduleCredit":0,"title":"American Literature I"} +{"moduleCode":"SE4220","moduleCredit":0,"title":"Special Studies on Southeast Asia"} +{"moduleCode":"ECA5305","moduleCredit":0,"title":"Programming for Economists"} +{"moduleCode":"ECA5304","moduleCredit":0,"title":"Machine Learning and Economic Forecasting"} +{"moduleCode":"UTC1102G","moduleCredit":0,"title":"Junior Seminar: Proof: What’s Truth got to do with it?"} +{"moduleCode":"ACC3601","moduleCredit":0,"title":"Corporate Accounting and Reporting"} +{"moduleCode":"LSM2231","moduleCredit":0,"title":"General Physiology"} +{"moduleCode":"JS5660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"LSM2232","moduleCredit":0,"title":"Genes, Genomes and Biomedical Implications"} +{"moduleCode":"SE4225","moduleCredit":0,"title":"The Cold War in Southeast Asia"} +{"moduleCode":"ACC3603","moduleCredit":0,"title":"Assurance and Attestation"} +{"moduleCode":"AR3101","moduleCredit":0,"title":"Design 5"} +{"moduleCode":"LSM2233","moduleCredit":0,"title":"Cell Biology"} +{"moduleCode":"AR3102","moduleCredit":0,"title":"Design 6"} +{"moduleCode":"LSM2234","moduleCredit":0,"title":"Introduction to Quantitative Biology"} +{"moduleCode":"ACC3605","moduleCredit":0,"title":"Taxation"} +{"moduleCode":"LL5203","moduleCredit":0,"title":"International Moots and Other Competitions"} +{"moduleCode":"ACC3604","moduleCredit":0,"title":"Corporate and Securities Law"} +{"moduleCode":"CN5193","moduleCredit":0,"title":"Instrumental Methods of Analysis"} +{"moduleCode":"TS5101R","moduleCredit":0,"title":"Text and Performance"} +{"moduleCode":"EG1611","moduleCredit":0,"title":"Engineering Co-Op Immersion Programme I"} +{"moduleCode":"ACC3606","moduleCredit":0,"title":"Advanced Corporate Accounting and Reporting"} +{"moduleCode":"EC3351","moduleCredit":0,"title":"Public Finance"} +{"moduleCode":"EN5883","moduleCredit":0,"title":"Screen Culture in Southeast Asia"} +{"moduleCode":"CN5191","moduleCredit":0,"title":"Project Engineering"} +{"moduleCode":"UTS2400","moduleCredit":0,"title":"Identities in Asia"} +{"moduleCode":"UTS2403","moduleCredit":0,"title":"Citizenship in a Changing World"} +{"moduleCode":"EN3222","moduleCredit":0,"title":"The Eighteenth Century"} +{"moduleCode":"UTS2402","moduleCredit":0,"title":"Environment and Civil Society in Singapore"} +{"moduleCode":"ECA5315","moduleCredit":0,"title":"Financial Econometrics"} +{"moduleCode":"UTS2405","moduleCredit":0,"title":"Work and Inequality"} +{"moduleCode":"AR5770","moduleCredit":0,"title":"Graduate Seminar"} +{"moduleCode":"EN3224","moduleCredit":0,"title":"The Twentieth Century"} +{"moduleCode":"UTS2404","moduleCredit":0,"title":"Cities and nature"} +{"moduleCode":"ECA5313","moduleCredit":0,"title":"Topics in Econometrics"} +{"moduleCode":"UTS2407","moduleCredit":0,"title":"Understanding Communities: Theory & Practice"} +{"moduleCode":"CS5446","moduleCredit":0,"title":"AI Planning and Decision Making"} +{"moduleCode":"EN3229","moduleCredit":0,"title":"Shakespeare in His Time and Ours"} +{"moduleCode":"UTS2409","moduleCredit":0,"title":"Mental wellness: Local and global approaches"} +{"moduleCode":"UTS2408","moduleCredit":0,"title":"Unequal Parenthoods in Asia"} +{"moduleCode":"UTC1102C","moduleCredit":0,"title":"Junior Seminar: Fakes"} +{"moduleCode":"FIN4761A","moduleCredit":0,"title":"SIF: Private Equity"} +{"moduleCode":"UTC1102B","moduleCredit":0,"title":"Junior Seminar: The Darwinian Revolution"} +{"moduleCode":"FIN4761D","moduleCredit":0,"title":"SIF: Family Business & Wealth Management"} +{"moduleCode":"LSM2241","moduleCredit":0,"title":"Introductory Bioinformatics"} +{"moduleCode":"BSN3701B","moduleCredit":0,"title":"Technological Innovation"} +{"moduleCode":"ACC3614","moduleCredit":0,"title":"Valuation"} +{"moduleCode":"EG1603","moduleCredit":0,"title":"InnoVenture - Leadership & Innovation Challenge"} +{"moduleCode":"ACC3616","moduleCredit":0,"title":"Corporate Governance and Risk Management"} +{"moduleCode":"IS4151","moduleCredit":0,"title":"Pervasive Technology Solutions and Development"} +{"moduleCode":"ACC3619","moduleCredit":0,"title":"Integrated Perspective in Accounting and Business"} +{"moduleCode":"EC3361","moduleCredit":0,"title":"Labour Economics I"} +{"moduleCode":"DMB1203ACC","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"EN3252","moduleCredit":0,"title":"The Genealogy of Affect Theory"} +{"moduleCode":"YHU3216","moduleCredit":0,"title":"Photojournalism"} +{"moduleCode":"YHU3211","moduleCredit":0,"title":"Chinese Tales of the Strange"} +{"moduleCode":"CS5439","moduleCredit":0,"title":"Software Security"} +{"moduleCode":"ECA5325","moduleCredit":0,"title":"Project & Policy Evaluation"} +{"moduleCode":"YHU3212","moduleCredit":0,"title":"Kant"} +{"moduleCode":"CS2040S","moduleCredit":0,"title":"Data Structures and Algorithms"} +{"moduleCode":"UD5622","moduleCredit":0,"title":"Methods Of Urban Design & Urban Analysis"} +{"moduleCode":"UD5628","moduleCredit":0,"title":"Sustainable Urban Design and Development"} +{"moduleCode":"LSM2211","moduleCredit":0,"title":"Metabolism and Regulation"} +{"moduleCode":"LL6060B","moduleCredit":0,"title":"World Trade Law"} +{"moduleCode":"LSM2212","moduleCredit":0,"title":"Human Anatomy"} +{"moduleCode":"SW6660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"EC3373","moduleCredit":0,"title":"Asean Economies"} +{"moduleCode":"CS2040C","moduleCredit":0,"title":"Data Structures and Algorithms"} +{"moduleCode":"CE6101","moduleCredit":0,"title":"Geotechnical Constitutive Modeling"} +{"moduleCode":"CE6102","moduleCredit":0,"title":"Geotechnical Analysis"} +{"moduleCode":"MNO1706X","moduleCredit":0,"title":"Organisational Behavior"} +{"moduleCode":"EN3242","moduleCredit":0,"title":"History of Film"} +{"moduleCode":"YHU3205","moduleCredit":0,"title":"Ming Imperial Voyages"} +{"moduleCode":"ECA5337","moduleCredit":0,"title":"Applied Financial Economics"} +{"moduleCode":"ECA5335","moduleCredit":0,"title":"Derivative Securities"} +{"moduleCode":"MNO3313J","moduleCredit":0,"title":"TILHCM: Employee and Organizational Misbehaviours"} +{"moduleCode":"CS5425","moduleCredit":0,"title":"Big Data Systems for Data Science"} +{"moduleCode":"ECA5334","moduleCredit":0,"title":"Corporate Finance"} +{"moduleCode":"CS5424","moduleCredit":0,"title":"Distributed Databases"} +{"moduleCode":"ECA5333","moduleCredit":0,"title":"Financial Markets & Portfolio Management"} +{"moduleCode":"CS5422","moduleCredit":0,"title":"Wireless Networking"} +{"moduleCode":"MNO1706E","moduleCredit":0,"title":"Organisational Behavior"} +{"moduleCode":"CS5421","moduleCredit":0,"title":"Database Applications Design and Tuning"} +{"moduleCode":"EC3381","moduleCredit":0,"title":"Urban Economics"} +{"moduleCode":"MNO1706D","moduleCredit":0,"title":"Organisational Behavior"} +{"moduleCode":"MNO1706C","moduleCredit":0,"title":"Organisational Behavior"} +{"moduleCode":"MNO1706B","moduleCredit":0,"title":"Organisational Behavior"} +{"moduleCode":"NUR4104B","moduleCredit":0,"title":"Honours Project in Nursing"} +{"moduleCode":"EC3386","moduleCredit":0,"title":"Port Economics"} +{"moduleCode":"FST2102B","moduleCredit":0,"title":"Chemistry of Food Components"} +{"moduleCode":"MNO1706A","moduleCredit":0,"title":"Organisational Behavior"} +{"moduleCode":"EE6004","moduleCredit":0,"title":"Selected Advanced Topics In EM Modelling"} +{"moduleCode":"PP6703","moduleCredit":0,"title":"Foundations of Public Administration"} +{"moduleCode":"PP6704","moduleCredit":0,"title":"The Economics of Public Policy"} +{"moduleCode":"BSN3811","moduleCredit":0,"title":"People Strategy"} +{"moduleCode":"PP6705","moduleCredit":0,"title":"The Politics of Public Policy"} +{"moduleCode":"EN3271","moduleCredit":0,"title":"Advanced Playwriting"} +{"moduleCode":"PP6706","moduleCredit":0,"title":"Quantitative Methods for Public Policy Research"} +{"moduleCode":"EC3304","moduleCredit":0,"title":"Econometrics II"} +{"moduleCode":"EC3305","moduleCredit":0,"title":"Programming Tools for Economics"} +{"moduleCode":"EC3303","moduleCredit":0,"title":"Econometrics I"} +{"moduleCode":"PP6702","moduleCredit":0,"title":"Foundations of Public Policy: Theories and Methods"} +{"moduleCode":"GL4401","moduleCredit":0,"title":"Honours Thesis"} +{"moduleCode":"IE3105","moduleCredit":0,"title":"Fundamentals of Systems Engineering and Architecture"} +{"moduleCode":"PP6707","moduleCredit":0,"title":"Qualitative Methods for Public Policy Research"} +{"moduleCode":"BN4501","moduleCredit":0,"title":"Engineering Biology"} +{"moduleCode":"GE3204","moduleCredit":0,"title":"Cities and Regions: Planning for Change"} +{"moduleCode":"IE3101","moduleCredit":0,"title":"Statistics For Engineering Applications"} +{"moduleCode":"PP6708","moduleCredit":0,"title":"Research Design in Public Policy"} +{"moduleCode":"GE3206","moduleCredit":0,"title":"Gender, Space & Place"} +{"moduleCode":"GE3210","moduleCredit":0,"title":"Natural Resources: Policy and Practice"} +{"moduleCode":"UD5602","moduleCredit":0,"title":"Urban Studio Design 2"} +{"moduleCode":"ECA5351","moduleCredit":0,"title":"Public Finance"} +{"moduleCode":"UD5601","moduleCredit":0,"title":"Urban Design Studio 1"} +{"moduleCode":"IE5904B","moduleCredit":0,"title":"Research Project in Project Management II"} +{"moduleCode":"TEE4305","moduleCredit":0,"title":"Introduction To Fuzzy/Neural Systems"} +{"moduleCode":"IE5904A","moduleCredit":0,"title":"Research Project in Project Management I"} +{"moduleCode":"TEE4303","moduleCredit":0,"title":"Industrial Control Systems"} +{"moduleCode":"EC3312","moduleCredit":0,"title":"Game Theory & Applications to Economics"} +{"moduleCode":"NUR4103B","moduleCredit":0,"title":"Applied Research Methods"} +{"moduleCode":"SPH3201","moduleCredit":0,"title":"Public Health Practice"} +{"moduleCode":"ID1121","moduleCredit":0,"title":"Human-Centred Design"} +{"moduleCode":"EN3263","moduleCredit":0,"title":"Singapore Literature in Context"} +{"moduleCode":"LLD5214","moduleCredit":0,"title":"International and Comparative Oil and Gas Law"} +{"moduleCode":"ID1106","moduleCredit":0,"title":"Design Fundamentals 2"} +{"moduleCode":"LL6063V","moduleCredit":0,"title":"Business & Finance For Lawyers"} +{"moduleCode":"EC3314","moduleCredit":0,"title":"Mathematical Economics"} +{"moduleCode":"ID1105","moduleCredit":0,"title":"Design Fundamentals 1"} +{"moduleCode":"GE3219","moduleCredit":0,"title":"Globalisation and the Asian Cities"} +{"moduleCode":"EN3268","moduleCredit":0,"title":"Tragedy"} +{"moduleCode":"GE3216","moduleCredit":0,"title":"Applications of GIS & Remote Sensing"} +{"moduleCode":"LSM2291","moduleCredit":0,"title":"Fundamental Techniques in Microbiology"} +{"moduleCode":"PF3105","moduleCredit":0,"title":"Research Methods"} +{"moduleCode":"SG5118","moduleCredit":0,"title":"Individual Software Practicum"} +{"moduleCode":"EU4401","moduleCredit":0,"title":"Honours Thesis"} +{"moduleCode":"SG5117","moduleCredit":0,"title":"Software Engineering Overseas Practicum"} +{"moduleCode":"LSM2288","moduleCredit":0,"title":"Basic UROPS in Life Sciences I"} +{"moduleCode":"NUR4102B","moduleCredit":0,"title":"Consolidated Clinical Practice"} +{"moduleCode":"SG5116","moduleCredit":0,"title":"Software Engineering Project"} +{"moduleCode":"LSM2289","moduleCredit":0,"title":"Basic UROPS in Life Sciences II"} +{"moduleCode":"EC3322","moduleCredit":0,"title":"Industrial Organisation I"} +{"moduleCode":"ID1113","moduleCredit":0,"title":"Modelling and Sketching for Design"} +{"moduleCode":"PR3289","moduleCredit":0,"title":"Advanced UROPS in Pharmacy II"} +{"moduleCode":"PR3288","moduleCredit":0,"title":"Advanced UROPS in Pharmacy I"} +{"moduleCode":"SN3223","moduleCredit":0,"title":"International Relations of South Asia"} +{"moduleCode":"PR5134A","moduleCredit":0,"title":"Physical Assessment and Diagnostic Tests for Advanced Pharmacy Practice"} +{"moduleCode":"LL6064V","moduleCredit":0,"title":"Competition Law and Policy"} +{"moduleCode":"NM2219","moduleCredit":0,"title":"Principles of Communication Management"} +{"moduleCode":"BSN3701A","moduleCredit":0,"title":"Technological Innovation"} +{"moduleCode":"GE3226","moduleCredit":0,"title":"Tourism Development"} +{"moduleCode":"GE3227","moduleCredit":0,"title":"Urban Climates"} +{"moduleCode":"MS5660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"NM2213","moduleCredit":0,"title":"Introduction to Human-Computer Interaction Design"} +{"moduleCode":"ECA5375","moduleCredit":0,"title":"Economic Growth in East Asia"} +{"moduleCode":"NM2222","moduleCredit":0,"title":"Ethics in Communication and New Media"} +{"moduleCode":"ECA5373","moduleCredit":0,"title":"The Singapore Economy"} +{"moduleCode":"LSM2251","moduleCredit":0,"title":"Ecology and Environment"} +{"moduleCode":"NM3551","moduleCredit":0,"title":"FASS Undergraduate Research Opportunity (UROP)"} +{"moduleCode":"ECA5372","moduleCredit":0,"title":"Big Data Analytics and Technologies"} +{"moduleCode":"LSM2252","moduleCredit":0,"title":"Biodiversity"} +{"moduleCode":"NM2220","moduleCredit":0,"title":"Introduction to Media Writing"} +{"moduleCode":"ECA5371","moduleCredit":0,"title":"Economic Growth And Development"} +{"moduleCode":"LSM2253","moduleCredit":0,"title":"Applied Data Analysis in Ecology and Evolution"} +{"moduleCode":"LSM2254","moduleCredit":0,"title":"Fundamentals of Plant Biology"} +{"moduleCode":"GE3231","moduleCredit":0,"title":"Natural Hazards"} +{"moduleCode":"NUR4101B","moduleCredit":0,"title":"Evidence-based Health Care Practice"} +{"moduleCode":"EC3333","moduleCredit":0,"title":"Financial Economics I"} +{"moduleCode":"CN5172","moduleCredit":0,"title":"Biochemical Engineering"} +{"moduleCode":"CN5173","moduleCredit":0,"title":"Downstream Processing of Biochemical & Pharmaceutical Products"} +{"moduleCode":"EC3332","moduleCredit":0,"title":"Money and Banking I"} +{"moduleCode":"EC4660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"SN3232","moduleCredit":0,"title":"South Asia : Development, Issues, Debates"} +{"moduleCode":"AH2101","moduleCredit":0,"title":"Introduction to Art History"} +{"moduleCode":"PH6660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"PP5403","moduleCredit":0,"title":"Economic Foundations for Public Policy"} +{"moduleCode":"PP5401","moduleCredit":0,"title":"Policy Challenges"} +{"moduleCode":"PP5408","moduleCredit":0,"title":"Qualitative Research Methods for Public Policy"} +{"moduleCode":"PP5407","moduleCredit":0,"title":"Quantitative Research Methods for Public Policy 2"} +{"moduleCode":"NM2209","moduleCredit":0,"title":"Social Psychology of New Media"} +{"moduleCode":"PP5406","moduleCredit":0,"title":"Quantitative Research Methods for Public Policy 1"} +{"moduleCode":"NM2207","moduleCredit":0,"title":"Computational Media Literacy"} +{"moduleCode":"SE4210","moduleCredit":0,"title":"Ancient Kingdoms of Southeast Asia"} +{"moduleCode":"PP5409","moduleCredit":0,"title":"Foundations of Public Policy"} +{"moduleCode":"GE3236","moduleCredit":0,"title":"Transport and Communications"} +{"moduleCode":"NM2201","moduleCredit":0,"title":"Intercultural Communication"} +{"moduleCode":"BN3202","moduleCredit":0,"title":"Musculoskeletal Biomechanics"} +{"moduleCode":"ECA5376","moduleCredit":0,"title":"Auctions and Market Design"} +{"moduleCode":"SE4217","moduleCredit":0,"title":"Southeast Asia in the Global Economy"} +{"moduleCode":"GE3246","moduleCredit":0,"title":"Environmental Pollution"} +{"moduleCode":"PLB1201","moduleCredit":0,"title":"Psychology in Everyday Life"} +{"moduleCode":"ECA5381","moduleCredit":0,"title":"Urban Economics"} +{"moduleCode":"GE3240","moduleCredit":0,"title":"Geographical Research: Developing Ideas"} +{"moduleCode":"AR4421","moduleCredit":0,"title":"Architecture Internship Programme"} +{"moduleCode":"GE3241","moduleCredit":0,"title":"Geographies of Social Life"} +{"moduleCode":"CN5161","moduleCredit":0,"title":"Polymer Processing Engineering"} +{"moduleCode":"EC3342","moduleCredit":0,"title":"International Trade I"} +{"moduleCode":"LL6056BV","moduleCredit":0,"title":"Tax Planning And Policy"} +{"moduleCode":"CN5162","moduleCredit":0,"title":"Advanced Polymeric Materials"} +{"moduleCode":"EC3343","moduleCredit":0,"title":"International Finance I"} +{"moduleCode":"LCC5366","moduleCredit":0,"title":"Law of Evidence & Sentencing Law"} +{"moduleCode":"PP5410","moduleCredit":0,"title":"Working with Stakeholders in International Development"} +{"moduleCode":"LCC5365","moduleCredit":0,"title":"Foundations of Common Law and Criminal Law & Procedure"} +{"moduleCode":"LAC3201","moduleCredit":0,"title":"Chinese 3"} +{"moduleCode":"LAC3202","moduleCredit":0,"title":"Chinese 4"} +{"moduleCode":"ME3291","moduleCredit":0,"title":"Numerical Methods In Engineering"} +{"moduleCode":"LL4243V","moduleCredit":0,"title":"Law, Economics, Development, and Geography"} +{"moduleCode":"MS5201","moduleCredit":0,"title":"Critiques in Malay Studies"} +{"moduleCode":"PL2132","moduleCredit":0,"title":"Research and Statistical Methods II"} +{"moduleCode":"RE2708","moduleCredit":0,"title":"Computational Thinking and Programming for Real Estate"} +{"moduleCode":"IE4299E","moduleCredit":0,"title":"Selected Topics in Industrial Engineering"} +{"moduleCode":"PS4660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"TIC2901","moduleCredit":0,"title":"Communications for Computing Professionals"} +{"moduleCode":"PL2131","moduleCredit":0,"title":"Research and Statistical Methods I"} +{"moduleCode":"IS4204","moduleCredit":0,"title":"IT Governance"} +{"moduleCode":"SG5209","moduleCredit":0,"title":"Enterprise Java"} +{"moduleCode":"SG5208","moduleCredit":0,"title":"Object Oriented Design Patterns"} +{"moduleCode":"TS5660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"LAC3204","moduleCredit":0,"title":"Chinese for Business & Social Sciences"} +{"moduleCode":"LL5006V","moduleCredit":0,"title":"Banking Law"} +{"moduleCode":"EN4271","moduleCredit":0,"title":"Research Workshop"} +{"moduleCode":"ESE5003","moduleCredit":0,"title":"Environmental Chemical Principles"} +{"moduleCode":"ESE5002","moduleCredit":0,"title":"Physical and Process Principles"} +{"moduleCode":"ESE5004","moduleCredit":0,"title":"Research Project"} +{"moduleCode":"LL4242V","moduleCredit":0,"title":"Financial Regulation and Central Banking"} +{"moduleCode":"ESE5001","moduleCredit":0,"title":"Environmental Engineering Principles"} +{"moduleCode":"MA1421","moduleCredit":0,"title":"Basic Applied Mathematics for Sciences"} +{"moduleCode":"LL6338V","moduleCredit":0,"title":"Advanced Practicum in International Arbitration"} +{"moduleCode":"LL6205V","moduleCredit":0,"title":"Maritime Conflict of Laws"} +{"moduleCode":"LAB1201","moduleCredit":0,"title":"Bahasa Indonesia 1"} +{"moduleCode":"BMA5128A","moduleCredit":0,"title":"Special Topics in Venture Capital"} +{"moduleCode":"DSA4262","moduleCredit":0,"title":"Sense-making Case Analysis: Health and Medicine"} +{"moduleCode":"NM5216R","moduleCredit":0,"title":"Advanced Health Communication"} +{"moduleCode":"DSA4261","moduleCredit":0,"title":"Sense-making Case Analysis: Logistics and Transport"} +{"moduleCode":"SW5111A","moduleCredit":0,"title":"Practicum"} +{"moduleCode":"ME5001","moduleCredit":0,"title":"Mechanical Engineering Project"} +{"moduleCode":"SW5111B","moduleCredit":0,"title":"Practicum"} +{"moduleCode":"AS2237","moduleCredit":0,"title":"The U.S.: From Settlement to Superpower"} +{"moduleCode":"BMS5115","moduleCredit":0,"title":"Strategic Negotiations"} +{"moduleCode":"BMS5116","moduleCredit":0,"title":"People Strategy"} +{"moduleCode":"UTC1119","moduleCredit":0,"title":"Junior Seminar: Crime and Punishment"} +{"moduleCode":"UTC1117","moduleCredit":0,"title":"Junior Seminar: Radiation and Society"} +{"moduleCode":"UTW2001P","moduleCredit":0,"title":"Science Fiction and Empire"} +{"moduleCode":"UTW2001Q","moduleCredit":0,"title":"'What's in a word?' Meaning across cultures"} +{"moduleCode":"UTW2001R","moduleCredit":0,"title":"Discourse, Citizenship, and Society"} +{"moduleCode":"UTC1114","moduleCredit":0,"title":"Junior Seminar From the Fire to the Frying Pan: Cooking and Eating in Human Culture(s)"} +{"moduleCode":"BMS5110","moduleCredit":0,"title":"Managerial Economics"} +{"moduleCode":"UTW2001M","moduleCredit":0,"title":"Sport and Socialization"} +{"moduleCode":"BMS5113","moduleCredit":0,"title":"Venture Capital"} +{"moduleCode":"SG5220","moduleCredit":0,"title":"Independent Work 1"} +{"moduleCode":"BMS5114","moduleCredit":0,"title":"Asian Business Environment"} +{"moduleCode":"TC1005","moduleCredit":0,"title":"MATLAB Programming for Chemical Engineers"} +{"moduleCode":"UTW2001H","moduleCredit":0,"title":"RISK and Popular Culture"} +{"moduleCode":"BMS5111","moduleCredit":0,"title":"Legal Issues in Business"} +{"moduleCode":"IE3120","moduleCredit":0,"title":"Manufacturing Logistics"} +{"moduleCode":"BMS5112","moduleCredit":0,"title":"Global Strategic Management"} +{"moduleCode":"UTW2001J","moduleCredit":0,"title":"Blood, Death and Desire, Interpreting the Vampire"} +{"moduleCode":"BRP6551","moduleCredit":0,"title":"Graduate Research Seminar 1"} +{"moduleCode":"ME6303","moduleCredit":0,"title":"Advanced Fluid Dynamics"} +{"moduleCode":"YSC4101","moduleCredit":0,"title":"Physical Sciences Capstone Project"} +{"moduleCode":"SG5221","moduleCredit":0,"title":"Independent Work 2"} +{"moduleCode":"SG5228","moduleCredit":0,"title":"Digital Innovation and Design"} +{"moduleCode":"BRP6552","moduleCredit":0,"title":"Graduate Research Seminar 2"} +{"moduleCode":"IS4228","moduleCredit":0,"title":"Information Technologies in Financial Services"} +{"moduleCode":"CS6240","moduleCredit":0,"title":"Multimedia Analysis"} +{"moduleCode":"SG5225","moduleCredit":0,"title":"Architecting Software Solutions"} +{"moduleCode":"EE6531","moduleCredit":0,"title":"Selected Topics in Smart Grid Technologies"} +{"moduleCode":"YSC4103","moduleCredit":0,"title":"Maths, Computational & Statistical Sci Capstone Project"} +{"moduleCode":"YSC4102","moduleCredit":0,"title":"Life Sciences Capstone Project"} +{"moduleCode":"GMS6266B","moduleCredit":0,"title":"Gastroenterology/Hepatology"} +{"moduleCode":"BMS5107","moduleCredit":0,"title":"Ethical Leadership and Corporate Strategy"} +{"moduleCode":"NM5218R","moduleCredit":0,"title":"Cultural Policy"} +{"moduleCode":"PF4211","moduleCredit":0,"title":"Addictive Manufacturing for Construction"} +{"moduleCode":"BMS5105","moduleCredit":0,"title":"Big Data and Business Strategy"} +{"moduleCode":"PF4212","moduleCredit":0,"title":"Advanced Building Information Modelling"} +{"moduleCode":"BMS5108","moduleCredit":0,"title":"Macroeconomics and Finance: Perspectives from Asia"} +{"moduleCode":"RE2701","moduleCredit":0,"title":"Urban Planning"} +{"moduleCode":"RE2702","moduleCredit":0,"title":"Land Law"} +{"moduleCode":"DOS4811","moduleCredit":0,"title":"Data Visualisation"} +{"moduleCode":"RE2705","moduleCredit":0,"title":"Urban Economics"} +{"moduleCode":"RE2704","moduleCredit":0,"title":"Introduction to Real Estate Valuation"} +{"moduleCode":"RE2707","moduleCredit":0,"title":"Asset and Property Management"} +{"moduleCode":"IE3110","moduleCredit":0,"title":"Simulation"} +{"moduleCode":"RE2706","moduleCredit":0,"title":"Real Estate and Infrastructure Finance"} +{"moduleCode":"TSC3223","moduleCredit":0,"title":"Supply Chain Financial Analysis and Management"} +{"moduleCode":"AR5955","moduleCredit":0,"title":"Topics in Research by Design"} +{"moduleCode":"SG5211","moduleCredit":0,"title":"Business Process Management"} +{"moduleCode":"AR5954","moduleCredit":0,"title":"Topics in Landscape Architecture"} +{"moduleCode":"CS6231","moduleCredit":0,"title":"Advanced Topics in Security and Privacy"} +{"moduleCode":"AR5951","moduleCredit":0,"title":"Topics in History & Theory of Architecture"} +{"moduleCode":"CS6230","moduleCredit":0,"title":"Topics in Information Security"} +{"moduleCode":"TSC3222","moduleCredit":0,"title":"Global Sourcing & Supply Management"} +{"moduleCode":"SG5214","moduleCredit":0,"title":"Software Requirements Engineering"} +{"moduleCode":"LL5009V","moduleCredit":0,"title":"Chinese Legal Tradition And Legal Chinese"} +{"moduleCode":"ME3281","moduleCredit":0,"title":"Microsystems Design And Applications"} +{"moduleCode":"ST1232","moduleCredit":0,"title":"Statistics for Life Sciences"} +{"moduleCode":"SN5103","moduleCredit":0,"title":"Contemporary India: Contexts & Narratives"} +{"moduleCode":"LAR3201","moduleCredit":0,"title":"Arabic 3"} +{"moduleCode":"AR5959","moduleCredit":0,"title":"Topics in Design Technology"} +{"moduleCode":"LAR3202","moduleCredit":0,"title":"Arabic 4"} +{"moduleCode":"CH3231","moduleCredit":0,"title":"Chinese Fiction"} +{"moduleCode":"NUR5207","moduleCredit":0,"title":"Ethics in Healthcare"} +{"moduleCode":"DMA1401CLS","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"NUR5203","moduleCredit":0,"title":"Evidence-based Healthcare"} +{"moduleCode":"IND5005","moduleCredit":0,"title":"Industry Consulting and Application Project"} +{"moduleCode":"LL6208V","moduleCredit":0,"title":"Advanced Criminal Legal Process"} +{"moduleCode":"OT5906","moduleCredit":0,"title":"Offshore Field Architecture and Subsea System"} +{"moduleCode":"IND5004","moduleCredit":0,"title":"Digital Infrastructure and Transformation"} +{"moduleCode":"OT5905","moduleCredit":0,"title":"Petroleum Fluid Valorisation"} +{"moduleCode":"IND5003","moduleCredit":0,"title":"Data Analytics for Sense-making"} +{"moduleCode":"OT5904","moduleCredit":0,"title":"Petroleum Process"} +{"moduleCode":"IND5002","moduleCredit":0,"title":"Digital-Physical Integration in Industry 4.0"} +{"moduleCode":"OT5903","moduleCredit":0,"title":"From Reservoir to Wellhead"} +{"moduleCode":"IND5001","moduleCredit":0,"title":"Introduction to Industry 4.0 and Applications"} +{"moduleCode":"OT5902","moduleCredit":0,"title":"Petroleum Geoscience & Drilling"} +{"moduleCode":"OT5901","moduleCredit":0,"title":"Reservoir Fluid Characterization"} +{"moduleCode":"OT5909","moduleCredit":0,"title":"From Construction to Decommissioning"} +{"moduleCode":"OT5908","moduleCredit":0,"title":"Subsea Umbilicals, Risers and Flowlines Design"} +{"moduleCode":"OT5907","moduleCredit":0,"title":"Design of Offshore Structures"} +{"moduleCode":"IS4243","moduleCredit":0,"title":"Information Systems Consulting"} +{"moduleCode":"IS4242","moduleCredit":0,"title":"Intelligent Systems and Techniques"} +{"moduleCode":"IS4241","moduleCredit":0,"title":"Social Media Network Analysis"} +{"moduleCode":"CH3225","moduleCredit":0,"title":"Keywords in S'pore and M'sian Chinese Literary Studies"} +{"moduleCode":"FST2201","moduleCredit":0,"title":"Introduction to Human Nutrition"} +{"moduleCode":"IE3010E","moduleCredit":0,"title":"Systems Thinking and Design"} +{"moduleCode":"LL6209V","moduleCredit":0,"title":"Legal Argument & Narrative"} +{"moduleCode":"CS6217","moduleCredit":0,"title":"Topics in Prog. Languages & Software Engineering"} +{"moduleCode":"OT5912","moduleCredit":0,"title":"Development of Offshore Upstream Projects"} +{"moduleCode":"CS6216","moduleCredit":0,"title":"Advanced Topics in Machine Learning"} +{"moduleCode":"OT5911","moduleCredit":0,"title":"Offshore Materials, Welding and Corrosion"} +{"moduleCode":"CS6215","moduleCredit":0,"title":"Advanced Topics in Program Analysis"} +{"moduleCode":"OT5910","moduleCredit":0,"title":"Special Topics on Energy"} +{"moduleCode":"IS4234","moduleCredit":0,"title":"Compliance and Regulation Technology"} +{"moduleCode":"CS6210","moduleCredit":0,"title":"The Art of Computer Science Research"} +{"moduleCode":"IS4231","moduleCredit":0,"title":"Information Security Management"} +{"moduleCode":"LL5314S","moduleCredit":0,"title":"Private Equity and Venture Capital: Law and Practice"} +{"moduleCode":"EL5103","moduleCredit":0,"title":"Language in Society"} +{"moduleCode":"EL5101","moduleCredit":0,"title":"Grammatical Analysis"} +{"moduleCode":"EL5102","moduleCredit":0,"title":"Phonetics and Phonology"} +{"moduleCode":"DSA4299","moduleCredit":0,"title":"Applied Project in Data Science and Analytics"} +{"moduleCode":"SW5117A","moduleCredit":0,"title":"Practice Research Capstone Seminar I"} +{"moduleCode":"IND5024","moduleCredit":0,"title":"Strategic Procurement in a Digital World"} +{"moduleCode":"CS6207","moduleCredit":0,"title":"Advanced Natural Language Processing"} +{"moduleCode":"IND5022","moduleCredit":0,"title":"Data Analytics for Smart Manufacturing"} +{"moduleCode":"IND5021","moduleCredit":0,"title":"Managing the Digital Supply Chain"} +{"moduleCode":"CS6203","moduleCredit":0,"title":"Advanced Topics in Database Systems"} +{"moduleCode":"PS5506R","moduleCredit":0,"title":"Globalization and Public Governance"} +{"moduleCode":"DBA4811","moduleCredit":0,"title":"Analytical Tools for Consulting"} +{"moduleCode":"UTC2400","moduleCredit":0,"title":"Community Leadership"} +{"moduleCode":"IS4261","moduleCredit":0,"title":"Designing IT-enabled Business Innovations"} +{"moduleCode":"UTC2402","moduleCredit":0,"title":"Environment and Civil Society in Singapore"} +{"moduleCode":"UTC2403","moduleCredit":0,"title":"Citizenship in a Changing World"} +{"moduleCode":"UTC2405","moduleCredit":0,"title":"Emerging Asia: Successes and Challenges"} +{"moduleCode":"UTC2406","moduleCredit":0,"title":"Cities and nature"} +{"moduleCode":"LL5315S","moduleCredit":0,"title":"China's Tax Law and International Tax Policy"} +{"moduleCode":"UTC2407","moduleCredit":0,"title":"Work and Inequality"} +{"moduleCode":"UTC2409","moduleCredit":0,"title":"Understanding Communities: Theory & Practice"} +{"moduleCode":"TBA4212","moduleCredit":0,"title":"Search Engine Optimisation and Analytics"} +{"moduleCode":"DMX1104","moduleCredit":0,"title":"DYOM via edX MOOC"} +{"moduleCode":"DMX1103","moduleCredit":0,"title":"DYOM via edX MOOC"} +{"moduleCode":"DMX1102","moduleCredit":0,"title":"DYOM via edX MOOC"} +{"moduleCode":"DMX1101","moduleCredit":0,"title":"DYOM via edX MOOC"} +{"moduleCode":"DMX1108","moduleCredit":0,"title":"DYOM via edX MOOC"} +{"moduleCode":"DMX1107","moduleCredit":0,"title":"DYOM via edX MOOC"} +{"moduleCode":"DMX1106","moduleCredit":0,"title":"DYOM via edX MOOC"} +{"moduleCode":"DMX1105","moduleCredit":0,"title":"DYOM via edX MOOC"} +{"moduleCode":"UTC2411","moduleCredit":0,"title":"Unequal Parenthoods in Asia"} +{"moduleCode":"UTC2412","moduleCredit":0,"title":"Mental wellness: Local and global approaches"} +{"moduleCode":"IS4250","moduleCredit":0,"title":"IT-enabled Healthcare Solutioning"} +{"moduleCode":"DMB1202MKT","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"FMS1205P","moduleCredit":0,"title":"FS: Nanoworld and Synchrotron Radiation"} +{"moduleCode":"SH5401","moduleCredit":0,"title":"Safety, Health, Environment & Quality Management System"} +{"moduleCode":"SH5403","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"SH5402","moduleCredit":0,"title":"Advanced Safety, Health & Environment Management"} +{"moduleCode":"SH5404","moduleCredit":0,"title":"Safety Health and Environmental Project"} +{"moduleCode":"BMA5309","moduleCredit":0,"title":"Fund Management"} +{"moduleCode":"LL5397V","moduleCredit":0,"title":"International Arbitration & Dispute Resolution Research"} +{"moduleCode":"BMA5302","moduleCredit":0,"title":"Investment Analysis and Management"} +{"moduleCode":"FMS1204S","moduleCredit":0,"title":"FS: Fraud, Deception and Data"} +{"moduleCode":"PP5267","moduleCredit":0,"title":"Urban Transport Policy: A Global View"} +{"moduleCode":"ME3211","moduleCredit":0,"title":"Mechanics Of Solids"} +{"moduleCode":"PP5266","moduleCredit":0,"title":"Global Health Policy and Issues"} +{"moduleCode":"PP5269","moduleCredit":0,"title":"Environmental Economics and Public Policy"} +{"moduleCode":"LL6009GRSI","moduleCredit":0,"title":"Graduate Research Seminar I (Legal Scholarship)"} +{"moduleCode":"FMS1203S","moduleCredit":0,"title":"FS: Randomness in Scientific Thinking"} +{"moduleCode":"ME3221","moduleCredit":0,"title":"Sustainable EnergyConversion"} +{"moduleCode":"NUR2113","moduleCredit":0,"title":"Mental Health Nursing"} +{"moduleCode":"QT5201T","moduleCredit":0,"title":"Bell nonlocality"} +{"moduleCode":"CE5510B","moduleCredit":0,"title":"Advanced Structural Concrete Design to EC2"} +{"moduleCode":"CE5510A","moduleCredit":0,"title":"Structural Concrete Design to EC2"} +{"moduleCode":"QT5201R","moduleCredit":0,"title":"Density Functionals for Many-Particle Systems"} +{"moduleCode":"LA4212","moduleCredit":0,"title":"Topics in Tropical Forest Ecology"} +{"moduleCode":"DEP5110","moduleCredit":0,"title":"Urban Design and Planning"} +{"moduleCode":"DEP5111","moduleCredit":0,"title":"Planning Technologies"} +{"moduleCode":"PL5222","moduleCredit":0,"title":"Multivariate Statistics in Psychology"} +{"moduleCode":"CN4233E","moduleCredit":0,"title":"Good Manufacturing Practices in Pharmaceutical Industry"} +{"moduleCode":"PL5221","moduleCredit":0,"title":"Analysis of Psychological Data Using Glm"} +{"moduleCode":"DMB1202MNO","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"PL5225","moduleCredit":0,"title":"Structural Equation Modeling"} +{"moduleCode":"CAS6770","moduleCredit":0,"title":"Graduate Research Seminar"} +{"moduleCode":"CP5103","moduleCredit":0,"title":"Master of Computing Project"} +{"moduleCode":"CP5104","moduleCredit":0,"title":"Graduate Project in Computing"} +{"moduleCode":"CH3261","moduleCredit":0,"title":"Prescribed Text: The Four Books"} +{"moduleCode":"NUR2118","moduleCredit":0,"title":"Pathophysiology and Pharmacology for Nurses II"} +{"moduleCode":"CP5101","moduleCredit":0,"title":"MComp Dissertation"} +{"moduleCode":"CP5102","moduleCredit":0,"title":"MComp Information Security Project"} +{"moduleCode":"GMS6850","moduleCredit":0,"title":"Core Concepts in Bioinformatics"} +{"moduleCode":"NUR2124","moduleCredit":0,"title":"Healthy Community Living"} +{"moduleCode":"FMS1206P","moduleCredit":0,"title":"Energy Storage Devices - State of the Art"} +{"moduleCode":"BT3103","moduleCredit":0,"title":"Application Systems Development for Business Analytics"} +{"moduleCode":"DMB1204BSP","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"NUR2120","moduleCredit":0,"title":"Professional Nursing Practice, Ethics and Law"} +{"moduleCode":"BT3102","moduleCredit":0,"title":"Computational Methods for Business Analytics"} +{"moduleCode":"BT3101","moduleCredit":0,"title":"Business Analytics Capstone Project"} +{"moduleCode":"CH3245","moduleCredit":0,"title":"Overseas Chinese Society"} +{"moduleCode":"NUR2122","moduleCredit":0,"title":"Psychology for Nurses"} +{"moduleCode":"DEP5103","moduleCredit":0,"title":"Urban and Regional Planning"} +{"moduleCode":"DEP5104","moduleCredit":0,"title":"Urban and Regional Economics"} +{"moduleCode":"DEP5101","moduleCredit":0,"title":"Urban Analysis Workshop"} +{"moduleCode":"DEP5102","moduleCredit":0,"title":"Urban Planning History & Theory"} +{"moduleCode":"NM6211","moduleCredit":0,"title":"Political Communication"} +{"moduleCode":"ME3112E","moduleCredit":0,"title":"Mechanics of Machines"} +{"moduleCode":"DEP5109","moduleCredit":0,"title":"Integrated Planning Project"} +{"moduleCode":"DEP5107","moduleCredit":0,"title":"Dissertation"} +{"moduleCode":"DEP5108","moduleCredit":0,"title":"MUP Internship Module"} +{"moduleCode":"DEP5105","moduleCredit":0,"title":"Urban Infrastructure and Mobility Systems"} +{"moduleCode":"DEP5106","moduleCredit":0,"title":"Integrated Urban Planning Studio"} +{"moduleCode":"IS1103","moduleCredit":0,"title":"IS Innovations in Organisations and Society"} +{"moduleCode":"MA6293","moduleCredit":0,"title":"Topics in Mathematics Iii"} +{"moduleCode":"PP5297","moduleCredit":0,"title":"Public Policy for Sustainability"} +{"moduleCode":"MA6291","moduleCredit":0,"title":"Topics in Mathematics I"} +{"moduleCode":"MA6292","moduleCredit":0,"title":"Topics in Mathematics Ii"} +{"moduleCode":"TCN1411","moduleCredit":0,"title":"Mathematics for Chemical Engineers 1"} +{"moduleCode":"CLC2201","moduleCredit":0,"title":"Community Development Practicum I"} +{"moduleCode":"SW1101E","moduleCredit":0,"title":"Social Work: A Heart-Head-Hand Connection"} +{"moduleCode":"YID3214","moduleCredit":0,"title":"Urban Ecological Systems"} +{"moduleCode":"CLC2202","moduleCredit":0,"title":"Research Methods for Community Development"} +{"moduleCode":"PC5239B","moduleCredit":0,"title":"Variational Principles"} +{"moduleCode":"YLS2201","moduleCredit":0,"title":"Intermediate Spanish 1"} +{"moduleCode":"YLS2202","moduleCredit":0,"title":"Intermediate Spanish 2"} +{"moduleCode":"FMS1209M","moduleCredit":0,"title":"Philosophy of Mathematics"} +{"moduleCode":"YID3216","moduleCredit":0,"title":"Environment, Development and Mobilisation in Asia"} +{"moduleCode":"CN4238R","moduleCredit":0,"title":"Chemical & Biochemical Process Modeling"} +{"moduleCode":"ESE4501","moduleCredit":0,"title":"Design Project"} +{"moduleCode":"LL5002V","moduleCredit":0,"title":"Admiralty Law & Practice"} +{"moduleCode":"ENV1101","moduleCredit":0,"title":"Environmental Studies: An Interdisciplinary Overview"} +{"moduleCode":"ME3251","moduleCredit":0,"title":"Materials For Engineers"} +{"moduleCode":"TCN1422","moduleCredit":0,"title":"Materials for Chemical Engineers"} +{"moduleCode":"YID3201","moduleCredit":0,"title":"Conservation Biology"} +{"moduleCode":"MA1102R","moduleCredit":0,"title":"Calculus"} +{"moduleCode":"TE3201","moduleCredit":0,"title":"Software Engineering"} +{"moduleCode":"LL4379V","moduleCredit":0,"title":"Future of Int'l Commercial Arbitration in APAC Region"} +{"moduleCode":"TIE3010","moduleCredit":0,"title":"Systems Thinking and Design"} +{"moduleCode":"YLC3204","moduleCredit":0,"title":"Advanced Chinese 2"} +{"moduleCode":"YLC3203","moduleCredit":0,"title":"Advanced Chinese 1"} +{"moduleCode":"LAL2201","moduleCredit":0,"title":"Tamil 2"} +{"moduleCode":"EE3431E","moduleCredit":0,"title":"Microelectronics Materials and Devices"} +{"moduleCode":"YLC3206","moduleCredit":0,"title":"Advanced Chinese: Readings in Modern Chinese Literature"} +{"moduleCode":"EE3431C","moduleCredit":0,"title":"Microelectronics Materials and Devices"} +{"moduleCode":"BMA5333","moduleCredit":0,"title":"Inclusive FinTech"} +{"moduleCode":"MUH2203","moduleCredit":0,"title":"Music of the Church and State"} +{"moduleCode":"CS6291","moduleCredit":0,"title":"Lecture Series in Computer Science II"} +{"moduleCode":"ME3261","moduleCredit":0,"title":"Computer-Aided Design And Manufacturing"} +{"moduleCode":"MUH2202","moduleCredit":0,"title":"What Was, and Is, Popular Music?"} +{"moduleCode":"PR1301","moduleCredit":0,"title":"Complementary Medicine and Health"} +{"moduleCode":"CS6290","moduleCredit":0,"title":"Lecture Series in Computer Science I"} +{"moduleCode":"ME3263","moduleCredit":0,"title":"Design For Manufacturing And Assembly"} +{"moduleCode":"CH3298","moduleCredit":0,"title":"Chinese in Southeast Asia (in English)"} +{"moduleCode":"LL6202V","moduleCredit":0,"title":"ASEAN Economic Community Law and Policy"} +{"moduleCode":"EE4704","moduleCredit":0,"title":"Image Processing and Analysis"} +{"moduleCode":"GMS6821","moduleCredit":0,"title":"R-Programming"} +{"moduleCode":"MUA2271","moduleCredit":0,"title":"Virtual Instrument Sound Design"} +{"moduleCode":"MUA2270","moduleCredit":0,"title":"Synthesis and Signal Processing"} +{"moduleCode":"GMS6820","moduleCredit":0,"title":"Core Concepts in Biostatistics"} +{"moduleCode":"LL4245V","moduleCredit":0,"title":"Regulatory Foundations of Public Law"} +{"moduleCode":"MA1101R","moduleCredit":0,"title":"Linear Algebra I"} +{"moduleCode":"TIC2002","moduleCredit":0,"title":"Introduction to Software Engineering"} +{"moduleCode":"ME3242E","moduleCredit":0,"title":"Automation"} +{"moduleCode":"CG3002","moduleCredit":0,"title":"Embedded Systems Design Project"} +{"moduleCode":"CS6284","moduleCredit":0,"title":"Topics in Computer Science: Big Data Meets New Hardware"} +{"moduleCode":"HY6660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"BMA5323","moduleCredit":0,"title":"Applied Portfolio Management"} +{"moduleCode":"MNO3811","moduleCredit":0,"title":"Social Entrepreneurship"} +{"moduleCode":"CS6281","moduleCredit":0,"title":"Topics in Computer Science: Property Testing"} +{"moduleCode":"CE2102","moduleCredit":0,"title":"Principles & Practice in Infrastructure and Environment"} +{"moduleCode":"ACC1002X","moduleCredit":0,"title":"Financial Accounting"} +{"moduleCode":"EG4301","moduleCredit":0,"title":"DCP Dissertation"} +{"moduleCode":"ES5000","moduleCredit":0,"title":"Graduate English Course (Basic Level)"} +{"moduleCode":"ES5002","moduleCredit":0,"title":"Graduate English Course (Advanced Level)"} +{"moduleCode":"ESE3201","moduleCredit":0,"title":"Air Quality Management"} +{"moduleCode":"GMS6810","moduleCredit":0,"title":"Clinical and Translational Research Journal Club"} +{"moduleCode":"GMS6811","moduleCredit":0,"title":"Principles of Clinical Research"} +{"moduleCode":"PC3130","moduleCredit":0,"title":"Quantum Mechanics II"} +{"moduleCode":"LL4244V","moduleCredit":0,"title":"Criminal Practice"} +{"moduleCode":"LC5186","moduleCredit":0,"title":"International & Commercial Trusts Law"} +{"moduleCode":"LL4377V","moduleCredit":0,"title":"Law in Action: Legal Policymaking Externship"} +{"moduleCode":"NUR5811A","moduleCredit":0,"title":"Clinical Practicum I"} +{"moduleCode":"LAM4201","moduleCredit":0,"title":"Malay 5"} +{"moduleCode":"BSP1702X","moduleCredit":0,"title":"Legal Environment of Business"} +{"moduleCode":"ME3241E","moduleCredit":0,"title":"Microprocessor Applications"} +{"moduleCode":"BMA5314","moduleCredit":0,"title":"Entrepreneurial Finance"} +{"moduleCode":"GMS6812","moduleCredit":0,"title":"Foundations of Precision Medicine"} +{"moduleCode":"BMA5313","moduleCredit":0,"title":"Private Equity"} +{"moduleCode":"GMS6813","moduleCredit":0,"title":"Biostatistics for Clinical Research"} +{"moduleCode":"ME3242","moduleCredit":0,"title":"Automation"} +{"moduleCode":"ME3241","moduleCredit":0,"title":"Microprocessor Applications"} +{"moduleCode":"ME3243","moduleCredit":0,"title":"Robotic System Design"} +{"moduleCode":"GMS6800","moduleCredit":0,"title":"Integrated Biostatistics and Bioinformatics Journal Club"} +{"moduleCode":"LL6030V","moduleCredit":0,"title":"International Commercial Litigation"} +{"moduleCode":"PS5201R","moduleCredit":0,"title":"Seminar in Political Theory"} +{"moduleCode":"PF2504","moduleCredit":0,"title":"Materials Technology"} +{"moduleCode":"PH2113","moduleCredit":0,"title":"Computation and Philosophy"} +{"moduleCode":"PH2112","moduleCredit":0,"title":"Non-Classical Logic"} +{"moduleCode":"UIS3902","moduleCredit":0,"title":"Independent Study Module"} +{"moduleCode":"PF2505","moduleCredit":0,"title":"M&E Systems"} +{"moduleCode":"UIS3901","moduleCredit":0,"title":"Independent Study Module"} +{"moduleCode":"PF2502","moduleCredit":0,"title":"Development Technology and Management"} +{"moduleCode":"AH2202","moduleCredit":0,"title":"Modern Art: A Critical Introduction"} +{"moduleCode":"AH2201","moduleCredit":0,"title":"Chinese Painting: Styles and Masters"} +{"moduleCode":"CL3201","moduleCredit":0,"title":"Communicating through Chinese Rhetoric and Metaphors"} +{"moduleCode":"AH2203","moduleCredit":0,"title":"Empire and Art: India, Singapore, Malaya"} +{"moduleCode":"GMS6803","moduleCredit":0,"title":"Design and Analysis of Modern Clinical Studies"} +{"moduleCode":"LAV4201","moduleCredit":0,"title":"Vietnamese 5"} +{"moduleCode":"GMS6804","moduleCredit":0,"title":"Biomedical Research Internship"} +{"moduleCode":"LAV4202","moduleCredit":0,"title":"Vietnamese 6"} +{"moduleCode":"EC6104","moduleCredit":0,"title":"Advanced Mathematical Economics"} +{"moduleCode":"GMS6801","moduleCredit":0,"title":"Study Designs in Clinical and Population Health Research"} +{"moduleCode":"EC6103","moduleCredit":0,"title":"Econometric Modelling and Applications Ii"} +{"moduleCode":"GMS6802","moduleCredit":0,"title":"Analysis of Complex Biomedical Data"} +{"moduleCode":"EC6102","moduleCredit":0,"title":"Advanced Macroeconomic Theory"} +{"moduleCode":"EC6101","moduleCredit":0,"title":"Advanced Microeconomic Theory"} +{"moduleCode":"CE5999","moduleCredit":0,"title":"Graduate Seminars"} +{"moduleCode":"PC3193","moduleCredit":0,"title":"Experimental Physics II"} +{"moduleCode":"LL6164V","moduleCredit":0,"title":"International Projects Law & Practice"} +{"moduleCode":"LL6031V","moduleCredit":0,"title":"International Environmental Law & Policy"} +{"moduleCode":"TIC3301","moduleCredit":0,"title":"Information Security Management"} +{"moduleCode":"AR5011","moduleCredit":0,"title":"Research Methodology"} +{"moduleCode":"NM3237","moduleCredit":0,"title":"Health Communication"} +{"moduleCode":"CL3213","moduleCredit":0,"title":"Chinese Semantics"} +{"moduleCode":"NM3241","moduleCredit":0,"title":"Cultural Studies: Theory and Practice"} +{"moduleCode":"TIC3302","moduleCredit":0,"title":"Computer Systems Security"} +{"moduleCode":"ME3251E","moduleCredit":0,"title":"Materials For Engineers"} +{"moduleCode":"CH6261","moduleCredit":0,"title":"Chinese Studies in the West"} +{"moduleCode":"CH6262","moduleCredit":0,"title":"Independent Study in Chinese Studies"} +{"moduleCode":"CH6263","moduleCredit":0,"title":"Translation: Formal, Cultural, Political"} +{"moduleCode":"YIR4301","moduleCredit":0,"title":"Special Project in Science"} +{"moduleCode":"YIR4302","moduleCredit":0,"title":"Special Project in Science"} +{"moduleCode":"CL3210","moduleCredit":0,"title":"The Grammars and Lexicons of the Chinese Dialects"} +{"moduleCode":"YIR4303","moduleCredit":0,"title":"Special Project in Science"} +{"moduleCode":"YIR4304","moduleCredit":0,"title":"Special Project in Science"} +{"moduleCode":"EC4880A","moduleCredit":0,"title":"Topics in Economics: Economics of Careers"} +{"moduleCode":"TEE2033","moduleCredit":0,"title":"Integrated System Lab"} +{"moduleCode":"PL4880Q","moduleCredit":0,"title":"Psychology of Bilingualism"} +{"moduleCode":"CH6248","moduleCredit":0,"title":"Studies in Sino-S.e. Asian Interactions"} +{"moduleCode":"PL4880P","moduleCredit":0,"title":"Psychology of Religion"} +{"moduleCode":"CH6249","moduleCredit":0,"title":"Essential\u00A0Outsiders?\u00A0 The\u00A0 Chinese\u00A0 in\u00A0 Southeast\u00A0Asia"} +{"moduleCode":"CM5212","moduleCredit":0,"title":"Crystal Engineering"} +{"moduleCode":"LL6001","moduleCredit":0,"title":"Administration Of Criminal Justice"} +{"moduleCode":"PL4880R","moduleCredit":0,"title":"Issues in Adolescent Developmt"} +{"moduleCode":"RE3101","moduleCredit":0,"title":"Advanced Real Estate Valuation"} +{"moduleCode":"PL4880U","moduleCredit":0,"title":"Historical Controversies in Psychology"} +{"moduleCode":"PL4880T","moduleCredit":0,"title":"Applying Psychology In Education"} +{"moduleCode":"LL6004","moduleCredit":0,"title":"Aviation Law & Policy"} +{"moduleCode":"PL4880H","moduleCredit":0,"title":"Sport Psychology"} +{"moduleCode":"PL4880K","moduleCredit":0,"title":"Parenting and Child Development"} +{"moduleCode":"CM5211","moduleCredit":0,"title":"Contemporary Organometallic Chemistry"} +{"moduleCode":"PL4880L","moduleCredit":0,"title":"Applying Cognitive Psychology to Learning & Instruction"} +{"moduleCode":"NM3224","moduleCredit":0,"title":"Culture Industries"} +{"moduleCode":"MLE3111","moduleCredit":0,"title":"Materials Properties & Processing Laboratory"} +{"moduleCode":"NM3234","moduleCredit":0,"title":"Leadership, Organisations and New Media"} +{"moduleCode":"HY2260","moduleCredit":0,"title":"History and Popular Culture"} +{"moduleCode":"NM3232","moduleCredit":0,"title":"Strategic Communication"} +{"moduleCode":"HY2263","moduleCredit":0,"title":"The Ancient World: Ancient Greece"} +{"moduleCode":"NM3230","moduleCredit":0,"title":"Digital Storytelling"} +{"moduleCode":"LAG3202","moduleCredit":0,"title":"German 4"} +{"moduleCode":"PL4880G","moduleCredit":0,"title":"Positive Psychology"} +{"moduleCode":"LAG3201","moduleCredit":0,"title":"German 3"} +{"moduleCode":"PL4880F","moduleCredit":0,"title":"Addictive Behaviours"} +{"moduleCode":"DY5310","moduleCredit":0,"title":"Endodontics"} +{"moduleCode":"QF3101","moduleCredit":0,"title":"Investment Instruments: Theory and Computation"} +{"moduleCode":"LC3001A","moduleCredit":0,"title":"Evidence (A)"} +{"moduleCode":"BMS5902","moduleCredit":0,"title":"Entrepreneurship Practicum"} +{"moduleCode":"LL6033V","moduleCredit":0,"title":"International Legal Process"} +{"moduleCode":"BMS5901","moduleCredit":0,"title":"Business Project"} +{"moduleCode":"BMS5900","moduleCredit":0,"title":"Block Seminar (with emphasis on Asian context)"} +{"moduleCode":"HY5304","moduleCredit":0,"title":"Imperialism & Empires: Historical Approaches"} +{"moduleCode":"HY5303","moduleCredit":0,"title":"Problems in Cultural History"} +{"moduleCode":"LL4299","moduleCredit":0,"title":"Advanced Issues in the Law & Practice of Int’l Arbitration"} +{"moduleCode":"NM3219","moduleCredit":0,"title":"Writing for Communication Management"} +{"moduleCode":"NM3217","moduleCredit":0,"title":"Principles of Communication Design"} +{"moduleCode":"NM3216","moduleCredit":0,"title":"Game Design"} +{"moduleCode":"NM3215","moduleCredit":0,"title":"Advertising Strategies"} +{"moduleCode":"NM3222","moduleCredit":0,"title":"Interactive Storytelling"} +{"moduleCode":"NM3221","moduleCredit":0,"title":"Mobile Interaction Design"} +{"moduleCode":"SPH6401","moduleCredit":0,"title":"Advanced approaches in physical activity research"} +{"moduleCode":"BMA5239","moduleCredit":0,"title":"Digitization for Business Model Innovation"} +{"moduleCode":"DY5320","moduleCredit":0,"title":"Oral & Maxillofacial Surgery"} +{"moduleCode":"BMA5237","moduleCredit":0,"title":"Managing Global Value Chains and Networks"} +{"moduleCode":"BMA5236","moduleCredit":0,"title":"Global Operations Strategy In The Digital Economy"} +{"moduleCode":"RE5770","moduleCredit":0,"title":"Graduate Seminar"} +{"moduleCode":"CM2121","moduleCredit":0,"title":"Organic Chemistry 2"} +{"moduleCode":"GEH1053","moduleCredit":0,"title":"Film Art and Human Concerns"} +{"moduleCode":"GEH1050","moduleCredit":0,"title":"Plants and Society"} +{"moduleCode":"LL6034V","moduleCredit":0,"title":"International Regulation of Shipping"} +{"moduleCode":"MA6222","moduleCredit":0,"title":"Topics in Logic I"} +{"moduleCode":"GEH1051","moduleCredit":0,"title":"Narrative"} +{"moduleCode":"SC5223","moduleCredit":0,"title":"Social Networks"} +{"moduleCode":"BSS4003A","moduleCredit":0,"title":"SSIB: Innovation and Productivity"} +{"moduleCode":"HY2245","moduleCredit":0,"title":"Empires, Colonies and Imperialism"} +{"moduleCode":"BSS4003B","moduleCredit":0,"title":"Innovation and Productivity (with Econometrics)"} +{"moduleCode":"GEH1058","moduleCredit":0,"title":"The Theatre Experience"} +{"moduleCode":"GEH1059","moduleCredit":0,"title":"Living in the Nuclear World"} +{"moduleCode":"GEH1056","moduleCredit":0,"title":"Cultural Diversity in the Contemporary World"} +{"moduleCode":"GEH1054","moduleCredit":0,"title":"Names as Markers of Socio-cultural Identity"} +{"moduleCode":"GEH1055","moduleCredit":0,"title":"Religion and Film"} +{"moduleCode":"SPH5101","moduleCredit":0,"title":"Advanced Quantitative Methods I"} +{"moduleCode":"SPH5102","moduleCredit":0,"title":"Design, Conduct and Analysis of Clinical Trials"} +{"moduleCode":"SPH5103","moduleCredit":0,"title":"Collection, Management & Analysis of Quantitative Data"} +{"moduleCode":"SPH5104","moduleCredit":0,"title":"Healthcare Analytics"} +{"moduleCode":"EE3731C","moduleCredit":0,"title":"Signal Analytics"} +{"moduleCode":"DY5330","moduleCredit":0,"title":"Orthodontics"} +{"moduleCode":"EG2620","moduleCredit":0,"title":"Engineering Co-Op Immersion Programme II"} +{"moduleCode":"EC4362","moduleCredit":0,"title":"Immigration Economics"} +{"moduleCode":"CM2111","moduleCredit":0,"title":"Inorganic Chemistry 2"} +{"moduleCode":"MT5006A","moduleCredit":0,"title":"New Product Development Process"} +{"moduleCode":"MT5006B","moduleCredit":0,"title":"New Product Development and Corporate Strategy"} +{"moduleCode":"GEH1040","moduleCredit":0,"title":"Exploration in Musical Production"} +{"moduleCode":"DY5340","moduleCredit":0,"title":"Periodontology"} +{"moduleCode":"GEH1049","moduleCredit":0,"title":"Public Health in Action"} +{"moduleCode":"GEH1047","moduleCredit":0,"title":"Social and Cultural Studies through Music"} +{"moduleCode":"LL4276","moduleCredit":0,"title":"Advanced Contract Law"} +{"moduleCode":"GEH1045","moduleCredit":0,"title":"World Religions"} +{"moduleCode":"GEH1043","moduleCredit":0,"title":"Microbes which Changed Human History"} +{"moduleCode":"GEH1044","moduleCredit":0,"title":"Understanding Globalisation"} +{"moduleCode":"HY2259","moduleCredit":0,"title":"The Craft of History"} +{"moduleCode":"ECA5881","moduleCredit":0,"title":"Topics in Economic Policy"} +{"moduleCode":"EC4371","moduleCredit":0,"title":"Development Economics"} +{"moduleCode":"MLE3101","moduleCredit":0,"title":"Materials Characterization Laboratory"} +{"moduleCode":"MLE3102","moduleCredit":0,"title":"Degradation and Failure of Materials"} +{"moduleCode":"MLE3103","moduleCredit":0,"title":"Materials Design and Selection"} +{"moduleCode":"HY2252","moduleCredit":0,"title":"Introduction to Business History"} +{"moduleCode":"HY2253","moduleCredit":0,"title":"Christianity in World History"} +{"moduleCode":"LL5140V","moduleCredit":0,"title":"Law of the Sea: Theory and Practice"} +{"moduleCode":"ES2007D","moduleCredit":0,"title":"Professional Communication"} +{"moduleCode":"HY2250","moduleCredit":0,"title":"Introduction to Southeast Asian History"} +{"moduleCode":"GE6211","moduleCredit":0,"title":"Spatial Data Handling"} +{"moduleCode":"EC4377","moduleCredit":0,"title":"Global Economic History"} +{"moduleCode":"EG2610","moduleCredit":0,"title":"Engineering Work Experience Internship"} +{"moduleCode":"MLE3104","moduleCredit":0,"title":"Polymeric and Composite Materials"} +{"moduleCode":"MLE3105","moduleCredit":0,"title":"Dielectric and Magnetic Materials"} +{"moduleCode":"EC4372","moduleCredit":0,"title":"Technology and Innovation"} +{"moduleCode":"SC5218","moduleCredit":0,"title":"Population Studies"} +{"moduleCode":"GEH1074","moduleCredit":0,"title":"Luck"} +{"moduleCode":"MT5007A","moduleCredit":0,"title":"Types and Patterns of Technological Innovation"} +{"moduleCode":"GEH1075","moduleCredit":0,"title":"Life, Disrupted: The Sharing Revolution"} +{"moduleCode":"MT5007B","moduleCredit":0,"title":"Technological Innovation Strategies"} +{"moduleCode":"GEH1072","moduleCredit":0,"title":"Culture in Action"} +{"moduleCode":"GEH1073","moduleCredit":0,"title":"The Art of Chinese Poetry: Past and Present"} +{"moduleCode":"GEH1070","moduleCredit":0,"title":"Traditional Chinese Knowledge of Health and Well-being"} +{"moduleCode":"GEH1071","moduleCredit":0,"title":"Religion in Malay-Indonesian Literary Worlds"} +{"moduleCode":"CE5101","moduleCredit":0,"title":"Seepage & Consolidation of Soils"} +{"moduleCode":"DY5350","moduleCredit":0,"title":"Prosthodontics"} +{"moduleCode":"OT5001","moduleCredit":0,"title":"Independent Study Module"} +{"moduleCode":"DSA1101","moduleCredit":0,"title":"Introduction to Data Science"} +{"moduleCode":"LC5230","moduleCredit":0,"title":"Elements of Company Law"} +{"moduleCode":"DSC2006","moduleCredit":0,"title":"Operations Management"} +{"moduleCode":"UTS2710","moduleCredit":0,"title":"Society and Economy in Singapore: A Systems View"} +{"moduleCode":"LC5232","moduleCredit":0,"title":"Principles of Competition Law"} +{"moduleCode":"DSC2008","moduleCredit":0,"title":"Business Analytics - Data & Decisions"} +{"moduleCode":"GEH1078","moduleCredit":0,"title":"Heroes of China"} +{"moduleCode":"ECA5884","moduleCredit":0,"title":"Applied Behavioural Economics"} +{"moduleCode":"FMS1215B","moduleCredit":0,"title":"Plant Pathogens that cause plants to end up in a bucket"} +{"moduleCode":"GEH1077","moduleCredit":0,"title":"Metropolis: The City in World History"} +{"moduleCode":"CN4122","moduleCredit":0,"title":"Process Synthesis and Simulation"} +{"moduleCode":"GE6225","moduleCredit":0,"title":"GIS Research Thesis"} +{"moduleCode":"UTS2708","moduleCredit":0,"title":"Navigation in Singapore Waters-Bridges and Barriers"} +{"moduleCode":"CN4123","moduleCredit":0,"title":"Design Project"} +{"moduleCode":"EC4382","moduleCredit":0,"title":"Transport Economics"} +{"moduleCode":"GE6224","moduleCredit":0,"title":"Political Geography"} +{"moduleCode":"NUR3117A","moduleCredit":0,"title":"Public and Community Health"} +{"moduleCode":"GE6226","moduleCredit":0,"title":"GIS Research Project"} +{"moduleCode":"TME2151","moduleCredit":0,"title":"Principles of Mechanical Engineering Materials"} +{"moduleCode":"UTS2709","moduleCredit":0,"title":"Energy and Singapore: Dynamics, Dilemmas and Decisions"} +{"moduleCode":"HY3551","moduleCredit":0,"title":"FASS Undergraduate Research Opportunity"} +{"moduleCode":"EG1311","moduleCredit":0,"title":"Design and Make"} +{"moduleCode":"SC5205","moduleCredit":0,"title":"Social Policy Analysis"} +{"moduleCode":"EC4387","moduleCredit":0,"title":"Housing Economics"} +{"moduleCode":"SC5209","moduleCredit":0,"title":"Sociology of Everyday Life"} +{"moduleCode":"EC4383","moduleCredit":0,"title":"Environmental Economics and Policy"} +{"moduleCode":"FMS1214P","moduleCredit":0,"title":"Silk: Fibers that make a difference in our world"} +{"moduleCode":"BMA5271","moduleCredit":0,"title":"Operations Leadership: Supply Chain and Service Management"} +{"moduleCode":"GEH1063","moduleCredit":0,"title":"Understanding Body, Mind and Culture through Sport"} +{"moduleCode":"MT5008B","moduleCredit":0,"title":"Collaborative Corporate Entrepreneurship"} +{"moduleCode":"GEH1061","moduleCredit":0,"title":"Representation and Media"} +{"moduleCode":"GEH1062","moduleCredit":0,"title":"Ghosts and Spirits in Society and Culture"} +{"moduleCode":"DY5360","moduleCredit":0,"title":"Paediatric Dentistry"} +{"moduleCode":"GEH1060","moduleCredit":0,"title":"Social History of the Piano"} +{"moduleCode":"LL6340V","moduleCredit":0,"title":"International Refugee Law"} +{"moduleCode":"HY2234","moduleCredit":0,"title":"Buddhism in Southeast Asian History"} +{"moduleCode":"LA4301","moduleCredit":0,"title":"Material and Design"} +{"moduleCode":"GEH1069","moduleCredit":0,"title":"Art in Asia: Through Media, Style, Space and Time"} +{"moduleCode":"UTS2702","moduleCredit":0,"title":"Singapore - A Smart Nation in Context : IoT & Big Data"} +{"moduleCode":"UTS2701","moduleCredit":0,"title":"Understanding Health and Social Care in Singapore"} +{"moduleCode":"FMS1214B","moduleCredit":0,"title":"Mysteries of Water, Protein Aggregation and Diseases"} +{"moduleCode":"GEH1067","moduleCredit":0,"title":"Superhero Entertainments"} +{"moduleCode":"UTS2704","moduleCredit":0,"title":"Hard to secure easy to waste - Singapore’s food story"} +{"moduleCode":"GEH1068","moduleCredit":0,"title":"The Life Aquatic: Machines and the Making of the Ocean"} +{"moduleCode":"GEH1065","moduleCredit":0,"title":"Art in Society"} +{"moduleCode":"LC5225","moduleCredit":0,"title":"Carriage of Goods by Sea"} +{"moduleCode":"UTS2706","moduleCredit":0,"title":"A social critique of markets in Singapore"} +{"moduleCode":"HY2237","moduleCredit":0,"title":"The U.S.: From Settlement to Superpower"} +{"moduleCode":"MT5008A","moduleCredit":0,"title":"Corporate Venture Creation"} +{"moduleCode":"UTS2705","moduleCredit":0,"title":"Modelling Singlehood, Marriage & Fertility in Singapore"} +{"moduleCode":"NUR3116A","moduleCredit":0,"title":"Transition to Professional Practice Experience"} +{"moduleCode":"CN4118","moduleCredit":0,"title":"B.Eng. Dissertation"} +{"moduleCode":"EC4398","moduleCredit":0,"title":"Economics of Inequality"} +{"moduleCode":"EC4399","moduleCredit":0,"title":"Behavioural Public Policy"} +{"moduleCode":"EC4394","moduleCredit":0,"title":"Behavioural Economics"} +{"moduleCode":"YHU3318","moduleCredit":0,"title":"Sexuality in Modern Europe and Its Empires"} +{"moduleCode":"YHU3317","moduleCredit":0,"title":"The Words and World of Lu Xun"} +{"moduleCode":"HY2207","moduleCredit":0,"title":"Struggle for Modern China, 1800-1949"} +{"moduleCode":"HY2208","moduleCredit":0,"title":"Pre-Modern Japan: History and Culture"} +{"moduleCode":"YHU3319","moduleCredit":0,"title":"Disability and the Arts"} +{"moduleCode":"MS2215","moduleCredit":0,"title":"The Malays in History"} +{"moduleCode":"YHU3314","moduleCredit":0,"title":"1989: The End of the Cold War"} +{"moduleCode":"MS2216","moduleCredit":0,"title":"Fieldwork in Studies of Malay Society"} +{"moduleCode":"YHU3313","moduleCredit":0,"title":"The Amarna Letters: Diplomacy in the Late Bronze Age"} +{"moduleCode":"MS2213","moduleCredit":0,"title":"Malay Families and Households"} +{"moduleCode":"YHU3316","moduleCredit":0,"title":"Singapore under Japanese Occupation"} +{"moduleCode":"YHU3315","moduleCredit":0,"title":"Gospels as Literature"} +{"moduleCode":"LL5029AV","moduleCredit":0,"title":"International Commercial Arbitration"} +{"moduleCode":"MS2212","moduleCredit":0,"title":"Law and Malay Society"} +{"moduleCode":"YHU3312","moduleCredit":0,"title":"Hollywood in the 1930s"} +{"moduleCode":"GEH1015","moduleCredit":0,"title":"Cultural Borrowing: Japan and China"} +{"moduleCode":"MS2210","moduleCredit":0,"title":"Malay Culture & Society"} +{"moduleCode":"YHU3311","moduleCredit":0,"title":"Ancient Tragedy: Gender, Politics, and Poetry"} +{"moduleCode":"GEH1013","moduleCredit":0,"title":"Pirates, Oceans and the Maritime World"} +{"moduleCode":"GEH1010","moduleCredit":0,"title":"Beasts, People and Wild Environments in South Asia"} +{"moduleCode":"HM5102","moduleCredit":0,"title":"Psychosis"} +{"moduleCode":"PS5111","moduleCredit":0,"title":"Research Design in Political Science"} +{"moduleCode":"HM5105","moduleCredit":0,"title":"Child & Adolescent Mental Health including Learning Disabilities"} +{"moduleCode":"HM5106","moduleCredit":0,"title":"Psychogeriatrics"} +{"moduleCode":"GEH1018","moduleCredit":0,"title":"A Brief History of Science"} +{"moduleCode":"HM5103","moduleCredit":0,"title":"Mood, Anxiety, & Grief"} +{"moduleCode":"AR3223","moduleCredit":0,"title":"Introduction to Urbanism"} +{"moduleCode":"GEH1019","moduleCredit":0,"title":"Food & Health"} +{"moduleCode":"HM5104","moduleCredit":0,"title":"Addiction/ Personality Disorders"} +{"moduleCode":"CE5113","moduleCredit":0,"title":"Geotechnical Investigation & Monitoring"} +{"moduleCode":"EC4324","moduleCredit":0,"title":"Economics of Competition Policy"} +{"moduleCode":"PR3117","moduleCredit":0,"title":"Formulation & Technology II"} +{"moduleCode":"PR3116","moduleCredit":0,"title":"Concepts in Pharmacokinetics and Biopharmaceutics"} +{"moduleCode":"EC4322","moduleCredit":0,"title":"Industrial Organisation II"} +{"moduleCode":"TCN3124","moduleCredit":0,"title":"Particle Technology"} +{"moduleCode":"CL3285","moduleCredit":0,"title":"Computer-Assisted Translation Tools"} +{"moduleCode":"LL5317V","moduleCredit":0,"title":"International Arbitration in Asian Centres"} +{"moduleCode":"CL3284","moduleCredit":0,"title":"Literary Translation"} +{"moduleCode":"TCN3121","moduleCredit":0,"title":"Process Dynamics & Control"} +{"moduleCode":"SW4103","moduleCredit":0,"title":"Advanced Research and Evaluation"} +{"moduleCode":"MKT1003D","moduleCredit":0,"title":"Principles of Marketing"} +{"moduleCode":"YHU3306","moduleCredit":0,"title":"Philippine Literature: American Period"} +{"moduleCode":"CM5268","moduleCredit":0,"title":"Advanced Organic Materials"} +{"moduleCode":"MKT1003A","moduleCredit":0,"title":"Principles of Marketing"} +{"moduleCode":"CE5112","moduleCredit":0,"title":"Structural Support Systems for Excavation"} +{"moduleCode":"LL4076V","moduleCredit":0,"title":"IT Law I"} +{"moduleCode":"ME5513A","moduleCredit":0,"title":"Fatigue Analysis for Additive Manufacturing"} +{"moduleCode":"MKT1003C","moduleCredit":0,"title":"Principles of Marketing"} +{"moduleCode":"SW4101","moduleCredit":0,"title":"Advanced Family-Centred Swk Practice"} +{"moduleCode":"CE5111","moduleCredit":0,"title":"Underground Construction Design Project"} +{"moduleCode":"MKT1003B","moduleCredit":0,"title":"Principles of Marketing"} +{"moduleCode":"SW4102","moduleCredit":0,"title":"Social Policy and Planning"} +{"moduleCode":"CM5262","moduleCredit":0,"title":"Contemporary Materials Chemistry"} +{"moduleCode":"GEH1006","moduleCredit":0,"title":"Chinese Music, Language and Literature (in English)"} +{"moduleCode":"GEH1004","moduleCredit":0,"title":"Chinese Heritage: Hist & Lit"} +{"moduleCode":"YHU3300","moduleCredit":0,"title":"1917: War and Revolution"} +{"moduleCode":"GEH1001","moduleCredit":0,"title":"Globalisation and New Media"} +{"moduleCode":"GEH1002","moduleCredit":0,"title":"Economic Issues in Dev World"} +{"moduleCode":"MS3550","moduleCredit":0,"title":"Malay Studies Internship"} +{"moduleCode":"GEH1009","moduleCredit":0,"title":"Framing Bollywood: Unpacking The Magic"} +{"moduleCode":"GEH1008","moduleCredit":0,"title":"Nations & Nat'lisms in S Asia"} +{"moduleCode":"EC4334","moduleCredit":0,"title":"Financial Market Microstructure"} +{"moduleCode":"CE5105","moduleCredit":0,"title":"Analytical & Numerical Methods In Foundation Engineering"} +{"moduleCode":"EC4332","moduleCredit":0,"title":"Money and Banking II"} +{"moduleCode":"CE5104","moduleCredit":0,"title":"Underground Space"} +{"moduleCode":"EC4333","moduleCredit":0,"title":"Financial Economics II"} +{"moduleCode":"CE5107","moduleCredit":0,"title":"Pile Foundations"} +{"moduleCode":"TCN3135","moduleCredit":0,"title":"Process Safety, Health and Environment"} +{"moduleCode":"CE5106","moduleCredit":0,"title":"Ground Improvement"} +{"moduleCode":"PR3124","moduleCredit":0,"title":"Pharmacotherapeutics III"} +{"moduleCode":"CE5108","moduleCredit":0,"title":"Earth Retaining Structures"} +{"moduleCode":"TCN3132","moduleCredit":0,"title":"Separation Processes"} +{"moduleCode":"GEH1030","moduleCredit":0,"title":"Science of Music"} +{"moduleCode":"EN6880","moduleCredit":0,"title":"Topics in the New Literatures"} +{"moduleCode":"GEH1031","moduleCredit":0,"title":"Understanding the Universe"} +{"moduleCode":"EN4222","moduleCredit":0,"title":"Topics in the Eighteenth Century"} +{"moduleCode":"EN6881","moduleCredit":0,"title":"Topics in Literary History"} +{"moduleCode":"EN6882","moduleCredit":0,"title":"Advanced Topics in Cultural Studies"} +{"moduleCode":"YHU3331","moduleCredit":0,"title":"Refining Vocal Technique and Performance"} +{"moduleCode":"GEH1036","moduleCredit":0,"title":"Living with Mathematics"} +{"moduleCode":"GEH1034","moduleCredit":0,"title":"Clean Energy and Storage"} +{"moduleCode":"GEH1035","moduleCredit":0,"title":"Phy'cal Qns from Everyday Life"} +{"moduleCode":"GEH1032","moduleCredit":0,"title":"Modern Technology in Medicine and Health"} +{"moduleCode":"GEH1033","moduleCredit":0,"title":"How the Ocean Works"} +{"moduleCode":"MKT3812","moduleCredit":0,"title":"Game Theory and Strategic Analysis"} +{"moduleCode":"LL4219","moduleCredit":0,"title":"The Trial of Jesus in Western Legal Thought"} +{"moduleCode":"GE4401","moduleCredit":0,"title":"Honours Thesis"} +{"moduleCode":"EG2604","moduleCredit":0,"title":"Innovation Programme"} +{"moduleCode":"IS6004","moduleCredit":0,"title":"Econometrics for IS Research"} +{"moduleCode":"EG2605","moduleCredit":0,"title":"Undergraduate Research Opportunities Programme"} +{"moduleCode":"LL4214","moduleCredit":0,"title":"International and Comparative Oil and Gas Law"} +{"moduleCode":"EG2603","moduleCredit":0,"title":"TIP - Product & Business Plan Development"} +{"moduleCode":"IS6000","moduleCredit":0,"title":"Qualifying Examination in IS"} +{"moduleCode":"JS3101","moduleCredit":0,"title":"Approaches to Japanese Studies II"} +{"moduleCode":"IS6001","moduleCredit":0,"title":"Qualitative Methods for IS Research"} +{"moduleCode":"EC4343","moduleCredit":0,"title":"International Finance II"} +{"moduleCode":"IS6002","moduleCredit":0,"title":"Quantitative Methods for IS Research"} +{"moduleCode":"IS6003","moduleCredit":0,"title":"Contemporary Theories for IS Research"} +{"moduleCode":"PR3137","moduleCredit":0,"title":"Pharmacy Professional Skills Development III"} +{"moduleCode":"PR3136","moduleCredit":0,"title":"Pharmacotherapeutics IV"} +{"moduleCode":"EC4342","moduleCredit":0,"title":"International Trade II"} +{"moduleCode":"LL4074V","moduleCredit":0,"title":"Mergers & Acquisitions"} +{"moduleCode":"YHU3329","moduleCredit":0,"title":"Advanced Latin: Ovid’s Metamorphoses"} +{"moduleCode":"YHU3328","moduleCredit":0,"title":"Contemporary Korean Cinema and the Colonial Past"} +{"moduleCode":"STR1000","moduleCredit":0,"title":"Career Creation Starter Workshops"} +{"moduleCode":"YHU3327","moduleCredit":0,"title":"Social Practice Art"} +{"moduleCode":"GEH1027","moduleCredit":0,"title":"Einstein's Universe & Quantum Weirdness"} +{"moduleCode":"YHU3321","moduleCredit":0,"title":"British Comic Fiction: The 20th Century"} +{"moduleCode":"GEH1028","moduleCredit":0,"title":"The Emerging Nanoworld"} +{"moduleCode":"YHU3320","moduleCredit":0,"title":"Vasubandhu"} +{"moduleCode":"GEH1025","moduleCredit":0,"title":"Global Environmental Issues"} +{"moduleCode":"YHU3323","moduleCredit":0,"title":"Model Operas and the Chinese Cultural Revolution"} +{"moduleCode":"GEH1026","moduleCredit":0,"title":"Drugs and Society"} +{"moduleCode":"LLD5034V","moduleCredit":0,"title":"International Regulation of Shipping"} +{"moduleCode":"YHU3322","moduleCredit":0,"title":"Crazy Rich Europeans: Wealth & Power in Modern History"} +{"moduleCode":"GEH1023","moduleCredit":0,"title":"Exploring Chinese Cinema: Shanghai‐Hong Kong‐Singapore"} +{"moduleCode":"TR5302","moduleCredit":0,"title":"Experiential Entrepreneurship Internship"} +{"moduleCode":"TR5301","moduleCredit":0,"title":"Summer Program in Entrepreneurship"} +{"moduleCode":"GEH1022","moduleCredit":0,"title":"Geopolitics:Geographies of War & Peace"} +{"moduleCode":"LL4203","moduleCredit":0,"title":"International Moots and Other Competitions"} +{"moduleCode":"BSP3701","moduleCredit":0,"title":"Strategic Management"} +{"moduleCode":"EC4354","moduleCredit":0,"title":"Economics of Education"} +{"moduleCode":"EC4352","moduleCredit":0,"title":"Singapore Economy: Practice and Policy"} +{"moduleCode":"EC4353","moduleCredit":0,"title":"Health Economics"} +{"moduleCode":"PR3146","moduleCredit":0,"title":"Pharmacy Law in Singapore"} +{"moduleCode":"PR3145","moduleCredit":0,"title":"Compliance & Good Practices in Pharmacy"} +{"moduleCode":"EC4351","moduleCredit":0,"title":"Public Economics"} +{"moduleCode":"PR3144","moduleCredit":0,"title":"Principles of Research Methods"} +{"moduleCode":"MA3110","moduleCredit":0,"title":"Mathematical Analysis II"} +{"moduleCode":"TS4401","moduleCredit":0,"title":"Honours Thesis"} +{"moduleCode":"MA3111","moduleCredit":0,"title":"Complex Analysis I"} +{"moduleCode":"EN4242","moduleCredit":0,"title":"Modern Critical Theory"} +{"moduleCode":"EN4241","moduleCredit":0,"title":"Utopias and Dystopias"} +{"moduleCode":"DI5100","moduleCredit":0,"title":"Dental Implantology"} +{"moduleCode":"FST5303","moduleCredit":0,"title":"Modern Human Nutrition"} +{"moduleCode":"FST5302","moduleCredit":0,"title":"Food, Nutrition and Health"} +{"moduleCode":"FST5301","moduleCredit":0,"title":"Evidence Based Functional Foods"} +{"moduleCode":"BN2202","moduleCredit":0,"title":"Introduction to Biotransport"} +{"moduleCode":"NM3205","moduleCredit":0,"title":"Digital Media Cultures"} +{"moduleCode":"BN2201","moduleCredit":0,"title":"Quantitative Physiology for Bioengineers"} +{"moduleCode":"NM3211","moduleCredit":0,"title":"News Reporting and Editing"} +{"moduleCode":"BN2204","moduleCredit":0,"title":"Fundamentals of Biomechanics"} +{"moduleCode":"MB5101","moduleCredit":0,"title":"The Cell as a Machine"} +{"moduleCode":"NM3210","moduleCredit":0,"title":"Cybercrime and Copyright"} +{"moduleCode":"SN4660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"MB5102","moduleCredit":0,"title":"Topics in Mechanobiology"} +{"moduleCode":"MB5103","moduleCredit":0,"title":"Research Seminars in Mechanobiology"} +{"moduleCode":"MB5104","moduleCredit":0,"title":"Integrative Approach To Understand Cell Functions"} +{"moduleCode":"MB5105","moduleCredit":0,"title":"Microfabrication for Biologists"} +{"moduleCode":"TEE2003","moduleCredit":0,"title":"Advanced Mathematics for Engineers"} +{"moduleCode":"TEE2002","moduleCredit":0,"title":"Engineering Mathematics II"} +{"moduleCode":"TEE3331","moduleCredit":0,"title":"Feedback Control Systems"} +{"moduleCode":"CM5225","moduleCredit":0,"title":"Asymmetric Catalysis"} +{"moduleCode":"DSC5102","moduleCredit":0,"title":"Business Analytics Capstone Project"} +{"moduleCode":"CM5223","moduleCredit":0,"title":"Topics in Supramolecular Chemistry"} +{"moduleCode":"CM5224","moduleCredit":0,"title":"Emerging Concepts in Drug Discovery"} +{"moduleCode":"DSC5101","moduleCredit":0,"title":"Analytics in Managerial Economics"} +{"moduleCode":"DSC5106","moduleCredit":0,"title":"Foundation in Data Analytics I"} +{"moduleCode":"DSC5107","moduleCredit":0,"title":"Data Analytics in Banking"} +{"moduleCode":"FST2289","moduleCredit":0,"title":"Basic UROPS in Food Science & Technology II"} +{"moduleCode":"DSC5104","moduleCredit":0,"title":"Introduction to Network Science & Analytics"} +{"moduleCode":"DSC5105","moduleCredit":0,"title":"Fintech, Enabling Technologies and Analytics"} +{"moduleCode":"EN4232","moduleCredit":0,"title":"Topics in American Literature"} +{"moduleCode":"CM2191","moduleCredit":0,"title":"Experiments in Chemistry 2"} +{"moduleCode":"EN4234","moduleCredit":0,"title":"Pynchon and the Poetics of Information"} +{"moduleCode":"FST2288","moduleCredit":0,"title":"Basic UROPS in Food Science & Technology I"} +{"moduleCode":"CM2192","moduleCredit":0,"title":"Experiments in Chemistry 3"} +{"moduleCode":"LL5094V","moduleCredit":0,"title":"Law & Practice - The Law Clinic"} +{"moduleCode":"CM5221","moduleCredit":0,"title":"Advanced Organic Synthesis"} +{"moduleCode":"CS3103","moduleCredit":0,"title":"Computer Networks Practice"} +{"moduleCode":"SG5235","moduleCredit":0,"title":"Scaling Agile"} +{"moduleCode":"SG5234","moduleCredit":0,"title":"Digital User Experience Design"} +{"moduleCode":"SG5233","moduleCredit":0,"title":"Internet of Things Technology"} +{"moduleCode":"XFC4101","moduleCredit":0,"title":"Integrated Honours Thesis"} +{"moduleCode":"SG5238","moduleCredit":0,"title":"Architecting IOT Solutions"} +{"moduleCode":"SG5237","moduleCredit":0,"title":"Secure Software Life Cycle"} +{"moduleCode":"SP4262","moduleCredit":0,"title":"Forensic Human Identification"} +{"moduleCode":"SG5236","moduleCredit":0,"title":"Machine Learning for Software Engineers"} +{"moduleCode":"SP4261","moduleCredit":0,"title":"Articulating Probability and Statistics in Court"} +{"moduleCode":"SC2101","moduleCredit":0,"title":"Methods of Social Research"} +{"moduleCode":"SP4263","moduleCredit":0,"title":"Forensic Toxicology and Poisons"} +{"moduleCode":"JS4401","moduleCredit":0,"title":"Honours Thesis"} +{"moduleCode":"PF4301","moduleCredit":0,"title":"Strategic Facilities Management"} +{"moduleCode":"PS4881H","moduleCredit":0,"title":"Topics in CP: Chinese Politics"} +{"moduleCode":"DSA4211","moduleCredit":0,"title":"High-Dimensional Statistical Analysis"} +{"moduleCode":"EN4266","moduleCredit":0,"title":"South Asian Literatures in English"} +{"moduleCode":"DSA4212","moduleCredit":0,"title":"Optimisation for Large-Scale Data-Driven Inference"} +{"moduleCode":"MLE4101R","moduleCredit":0,"title":"Integrated B.ENG./B.SC. (Hons) Dissertation"} +{"moduleCode":"PS4881B","moduleCredit":0,"title":"Topics in CP: Malaysian Politics"} +{"moduleCode":"PF4307","moduleCredit":0,"title":"Event Management"} +{"moduleCode":"PF4308","moduleCredit":0,"title":"Event Management Case Studies"} +{"moduleCode":"PF4305","moduleCredit":0,"title":"Green Development"} +{"moduleCode":"PS4881G","moduleCredit":0,"title":"Topics in CP: Politics of the Korean Peninsula"} +{"moduleCode":"MKT1003X","moduleCredit":0,"title":"Principles of Marketing"} +{"moduleCode":"PF4306","moduleCredit":0,"title":"REITs Facilities Management"} +{"moduleCode":"TEE2028","moduleCredit":0,"title":"Microcontroller Programming and Interfacing"} +{"moduleCode":"EC4301","moduleCredit":0,"title":"Microeconomic Analysis III"} +{"moduleCode":"EC4302","moduleCredit":0,"title":"Macroeconomic Analysis III"} +{"moduleCode":"ID1223","moduleCredit":0,"title":"History & Theory Of Industrial Design"} +{"moduleCode":"TEE2027","moduleCredit":0,"title":"Electronic Circuits"} +{"moduleCode":"TEE2026","moduleCredit":0,"title":"Digital Design"} +{"moduleCode":"UHB2204","moduleCredit":0,"title":"Virtue And Leadership"} +{"moduleCode":"LL4070V","moduleCredit":0,"title":"Foundations Of Intellectual Property Law"} +{"moduleCode":"TEE2023","moduleCredit":0,"title":"Signals and Systems"} +{"moduleCode":"UHB2207","moduleCredit":0,"title":"Language, Cognition, and Culture"} +{"moduleCode":"PH6540","moduleCredit":0,"title":"Topics in Analytic Philosophy"} +{"moduleCode":"TS3103","moduleCredit":0,"title":"Theatre Lab"} +{"moduleCode":"FIN2004X","moduleCredit":0,"title":"Finance"} +{"moduleCode":"CM5245","moduleCredit":0,"title":"Bioanalyticalchemistry"} +{"moduleCode":"EC4307","moduleCredit":0,"title":"Issues in Macroeconomics"} +{"moduleCode":"EN4251","moduleCredit":0,"title":"Jonathan Swift"} +{"moduleCode":"PS4882I","moduleCredit":0,"title":"Topics in IR: International Society"} +{"moduleCode":"EC4305","moduleCredit":0,"title":"Applied Econometrics"} +{"moduleCode":"EC4306","moduleCredit":0,"title":"Applied Microeconomic Analysis"} +{"moduleCode":"LAF1201","moduleCredit":0,"title":"French 1"} +{"moduleCode":"EC4303","moduleCredit":0,"title":"Econometrics III"} +{"moduleCode":"EL4660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"EC4304","moduleCredit":0,"title":"Economic and Financial Forecasting"} +{"moduleCode":"PS4882D","moduleCredit":0,"title":"Topics in IR: Politics of Global Migration"} +{"moduleCode":"SE5660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"PS4882A","moduleCredit":0,"title":"Topics in IR: Globalisation, Security and the State"} +{"moduleCode":"PS4882H","moduleCredit":0,"title":"Topics in IR: Food Politics"} +{"moduleCode":"CM5244","moduleCredit":0,"title":"Topics in Environmental Chemistry"} +{"moduleCode":"CM5241","moduleCredit":0,"title":"Modern Analytical Techniques"} +{"moduleCode":"PS4882E","moduleCredit":0,"title":"Topics in IR: Arms Control"} +{"moduleCode":"EL5251R","moduleCredit":0,"title":"Approaches to Discourse"} +{"moduleCode":"PS4883A","moduleCredit":0,"title":"Topics in PT: Orientalism and Femininity"} +{"moduleCode":"TMA2101","moduleCredit":0,"title":"Calculus for Computing"} +{"moduleCode":"TMA2102","moduleCredit":0,"title":"Linear Algebra"} +{"moduleCode":"LL5097V","moduleCredit":0,"title":"Islamic Law"} +{"moduleCode":"TMA2103","moduleCredit":0,"title":"Probability and Statistics"} +{"moduleCode":"UHB2212","moduleCredit":0,"title":"Singaporean Nostalgia"} +{"moduleCode":"EC4313","moduleCredit":0,"title":"Search Theory and Applications"} +{"moduleCode":"UHB2214","moduleCredit":0,"title":"Effective Decision Making"} +{"moduleCode":"TEE2011","moduleCredit":0,"title":"Engineering Electromagnetics"} +{"moduleCode":"BMK5102","moduleCredit":0,"title":"Big Data in Marketing"} +{"moduleCode":"EN6102","moduleCredit":0,"title":"Advanced Critical Reading"} +{"moduleCode":"BMK5103","moduleCredit":0,"title":"Consumer Insights"} +{"moduleCode":"CH4401","moduleCredit":0,"title":"Honours Thesis"} +{"moduleCode":"BMK5100","moduleCredit":0,"title":"Marketing Research"} +{"moduleCode":"UQF2101K","moduleCredit":0,"title":"Quantitative Reasoning Foundation: In Search of Soulmate"} +{"moduleCode":"BMK5101","moduleCredit":0,"title":"Digital Marketing"} +{"moduleCode":"UQF2101J","moduleCredit":0,"title":"Quantitative Reasoning Foundation: Pursuit of Happiness"} +{"moduleCode":"ES2002","moduleCredit":0,"title":"Business Communication for Leaders (BBA)"} +{"moduleCode":"DSC1007X","moduleCredit":0,"title":"Business Analytics - Models & Decisions"} +{"moduleCode":"LL6349V","moduleCredit":0,"title":"Energy Arbitration"} +{"moduleCode":"LSM4261","moduleCredit":0,"title":"Marine Biology"} +{"moduleCode":"LSM4260","moduleCredit":0,"title":"Plankton Ecology"} +{"moduleCode":"LSM4252","moduleCredit":0,"title":"Reproductive Biology"} +{"moduleCode":"LSM4251","moduleCredit":0,"title":"Plant Growth and Development"} +{"moduleCode":"LL4029AV","moduleCredit":0,"title":"International Commercial Arbitration"} +{"moduleCode":"ME6204","moduleCredit":0,"title":"Convective Heat Transfer"} +{"moduleCode":"LSM4256","moduleCredit":0,"title":"Evolution of Development"} +{"moduleCode":"LSM4255","moduleCredit":0,"title":"Methods in Mathematical Biology"} +{"moduleCode":"LSM4257","moduleCredit":0,"title":"Aquatic Vertebrate Diversity"} +{"moduleCode":"LSM4259","moduleCredit":0,"title":"Evolutionary Genetics of Reproduction"} +{"moduleCode":"YCC1114","moduleCredit":0,"title":"Philosophy and Political Thought 2"} +{"moduleCode":"YCC1112","moduleCredit":0,"title":"Literature and Humanities 2"} +{"moduleCode":"YCC1113","moduleCredit":0,"title":"Philosophy and Political Thought 1"} +{"moduleCode":"GEK2036","moduleCredit":0,"title":"Greek Philosophy (Socrates and Plato)"} +{"moduleCode":"YCC1111","moduleCredit":0,"title":"Literature and Humanities 1"} +{"moduleCode":"TS4217","moduleCredit":0,"title":"Cultural Performance in Asia"} +{"moduleCode":"EE4204E","moduleCredit":0,"title":"Computer Networks"} +{"moduleCode":"TS4216","moduleCredit":0,"title":"Theatre and Gender"} +{"moduleCode":"TS4219","moduleCredit":0,"title":"Media and Popular Performance"} +{"moduleCode":"TS4218","moduleCredit":0,"title":"Theatre and Postmodernism"} +{"moduleCode":"LC5050V","moduleCredit":0,"title":"Public International Law"} +{"moduleCode":"SE5222R","moduleCredit":0,"title":"The Arts in Contemporary Southeast Asia"} +{"moduleCode":"LL4254V","moduleCredit":0,"title":"Developing States in a Changing World Order"} +{"moduleCode":"MA1301","moduleCredit":0,"title":"Introductory Mathematics"} +{"moduleCode":"MS6660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"LSM4262","moduleCredit":0,"title":"Tropical Conservation Biology"} +{"moduleCode":"LSM4265","moduleCredit":0,"title":"Urban Ecology"} +{"moduleCode":"LSM4264","moduleCredit":0,"title":"Freshwater Biology"} +{"moduleCode":"FSP4003","moduleCredit":0,"title":"Field Service Project"} +{"moduleCode":"LL5322V","moduleCredit":0,"title":"Trade Finance Law"} +{"moduleCode":"LSM4267","moduleCredit":0,"title":"Light & Vision in Animal Communication"} +{"moduleCode":"LSM4266","moduleCredit":0,"title":"Aquatic Invertebrate Diversity"} +{"moduleCode":"GEK2040","moduleCredit":0,"title":"Philosophy and Film"} +{"moduleCode":"LSM4268","moduleCredit":0,"title":"Environmental Bioacoustics"} +{"moduleCode":"LL5019V","moduleCredit":0,"title":"Credit & Security"} +{"moduleCode":"UQF2101I","moduleCredit":0,"title":"Quantitative Reasoning Foundation: Quantifying Environmental Quality"} +{"moduleCode":"GEK2041","moduleCredit":0,"title":"Science Fiction and Philosophy"} +{"moduleCode":"TS4220","moduleCredit":0,"title":"Shakespeare and Film"} +{"moduleCode":"UQF2101G","moduleCredit":0,"title":"Quantitative Reasoning Foundation: Quantifying Nuclear Risks"} +{"moduleCode":"TS4222","moduleCredit":0,"title":"Performance as Research in Applied Theatre"} +{"moduleCode":"UQF2101E","moduleCredit":0,"title":"Quantitative Reasoning Foundation: Quantifying Our Eco-Footprint"} +{"moduleCode":"TS4221","moduleCredit":0,"title":"Performance Research"} +{"moduleCode":"GEK2048","moduleCredit":0,"title":"Effective Reasoning"} +{"moduleCode":"EE2111A","moduleCredit":0,"title":"Electrical Engineering Principles and Practice II"} +{"moduleCode":"SE5221R","moduleCredit":0,"title":"Landscapes of Southeast Asia"} +{"moduleCode":"PF4101","moduleCredit":0,"title":"Dissertation"} +{"moduleCode":"PF4102","moduleCredit":0,"title":"Contract and Procurement Management"} +{"moduleCode":"CP3209","moduleCredit":0,"title":"Undergraduate Research Project in Computing"} +{"moduleCode":"EL2151","moduleCredit":0,"title":"Social Variation in English"} +{"moduleCode":"CP3208","moduleCredit":0,"title":"Undergraduate Research in Computing I"} +{"moduleCode":"MA1312","moduleCredit":0,"title":"Calculus with Applications"} +{"moduleCode":"RE3902","moduleCredit":0,"title":"Housing Markets and Policies"} +{"moduleCode":"RE3901","moduleCredit":0,"title":"Advanced Urban Planning"} +{"moduleCode":"RE3903","moduleCredit":0,"title":"GIS for Real Estate"} +{"moduleCode":"BMA5313A","moduleCredit":0,"title":"Valuation and Mergers & Acquisitions"} +{"moduleCode":"YCC1131","moduleCredit":0,"title":"Scientific Inquiry 1"} +{"moduleCode":"LSM4232","moduleCredit":0,"title":"Advanced Cell Biology"} +{"moduleCode":"LSM4231","moduleCredit":0,"title":"Structural Biology"} +{"moduleCode":"BMA5313E","moduleCredit":0,"title":"Topics in Private Equity"} +{"moduleCode":"LSM4234","moduleCredit":0,"title":"Mechanobiology"} +{"moduleCode":"SE4401","moduleCredit":0,"title":"Honours Thesis"} +{"moduleCode":"BMA5313C","moduleCredit":0,"title":"Topics in Valuation and Mergers & Acquisitions"} +{"moduleCode":"NM5205R","moduleCredit":0,"title":"Cognition and Media"} +{"moduleCode":"CP3202","moduleCredit":0,"title":"Internship II"} +{"moduleCode":"CP3201","moduleCredit":0,"title":"Industry Seminar"} +{"moduleCode":"CP3200","moduleCredit":0,"title":"Internship"} +{"moduleCode":"YCC1133","moduleCredit":0,"title":"Week 7: Experiential Learning Field Trip"} +{"moduleCode":"GEK2028","moduleCredit":0,"title":"Founders of Modern Philosophy"} +{"moduleCode":"BS6770","moduleCredit":0,"title":"Phd Seminar"} +{"moduleCode":"EE5303","moduleCredit":0,"title":"Microwave Electronics"} +{"moduleCode":"GEK2029","moduleCredit":0,"title":"Applied Ethics"} +{"moduleCode":"EE5308","moduleCredit":0,"title":"Antenna Engineering"} +{"moduleCode":"LAK3202","moduleCredit":0,"title":"Korean 4"} +{"moduleCode":"LAK3201","moduleCredit":0,"title":"Korean 3"} +{"moduleCode":"NM4880G","moduleCredit":0,"title":"Election Reporting"} +{"moduleCode":"LSM4241","moduleCredit":0,"title":"Functional Genomics"} +{"moduleCode":"LSM4243","moduleCredit":0,"title":"Tumour Biology"} +{"moduleCode":"LSM4242","moduleCredit":0,"title":"Protein Engineering"} +{"moduleCode":"PL4660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"AR3411","moduleCredit":0,"title":"Architecture Internship Programme"} +{"moduleCode":"LSM4245","moduleCredit":0,"title":"Advanced Epigenetics and Chromatin Biology"} +{"moduleCode":"AR3412","moduleCredit":0,"title":"Work Experience Internship"} +{"moduleCode":"GEK2020","moduleCredit":0,"title":"Film Art and Human Concerns"} +{"moduleCode":"ME3162","moduleCredit":0,"title":"Manufacturing Processes"} +{"moduleCode":"EE5310","moduleCredit":0,"title":"Communication Networking Fundamentals"} +{"moduleCode":"YCC1121","moduleCredit":0,"title":"Comparative Social Inquiry"} +{"moduleCode":"GEK2025","moduleCredit":0,"title":"Politics of the Middle East"} +{"moduleCode":"YCC1122","moduleCredit":0,"title":"Quantitative Reasoning"} +{"moduleCode":"EL5202","moduleCredit":0,"title":"The Grammar of Modern English"} +{"moduleCode":"EL5203","moduleCredit":0,"title":"Sociophonetics"} +{"moduleCode":"LL4251V","moduleCredit":0,"title":"International Humanitarian Law"} +{"moduleCode":"MNO2007A","moduleCredit":0,"title":"Leadership and Ethics"} +{"moduleCode":"MNO2007B","moduleCredit":0,"title":"Leadership and Ethics"} +{"moduleCode":"PS3249","moduleCredit":0,"title":"Singapore's Foreign Policy"} +{"moduleCode":"CM5199","moduleCredit":0,"title":"M.Sc. R&D project"} +{"moduleCode":"IE5003","moduleCredit":0,"title":"Cost Analysis and Engineering Economy"} +{"moduleCode":"IE5004","moduleCredit":0,"title":"Engineering Probability And Simulation"} +{"moduleCode":"PS3242","moduleCredit":0,"title":"US Foreign Policy"} +{"moduleCode":"EL5204","moduleCredit":0,"title":"Linguistic Typology"} +{"moduleCode":"IE5001","moduleCredit":0,"title":"Operations Planning and Control I"} +{"moduleCode":"CM5198","moduleCredit":0,"title":"Graduate Seminar Module in Chemistry"} +{"moduleCode":"IE5002","moduleCredit":0,"title":"Applied Engineering Statistics"} +{"moduleCode":"CS6101","moduleCredit":0,"title":"Exploration of Computer Science Research"} +{"moduleCode":"LSM4299","moduleCredit":0,"title":"Applied Project in Life Sciences"} +{"moduleCode":"MNO2007C","moduleCredit":0,"title":"Leadership and Ethics"} +{"moduleCode":"MNO2007D","moduleCredit":0,"title":"Leadership and Ethics"} +{"moduleCode":"UTC2501","moduleCredit":0,"title":"Community Internship"} +{"moduleCode":"DSA4199","moduleCredit":0,"title":"Honours Project in Data Science and Analytics"} +{"moduleCode":"PS3239","moduleCredit":0,"title":"International Conflict Analysis"} +{"moduleCode":"PS3236","moduleCredit":0,"title":"Ethnicity and Religion in Asian Politics"} +{"moduleCode":"PS3238","moduleCredit":0,"title":"International Political Economy"} +{"moduleCode":"PS3237","moduleCredit":0,"title":"Women and Politics"} +{"moduleCode":"EL5216","moduleCredit":0,"title":"Corpus Linguistics"} +{"moduleCode":"GEK2001","moduleCredit":0,"title":"Changing Landscapes of Singapore"} +{"moduleCode":"GEK2003","moduleCredit":0,"title":"Government and Politics of Singapore"} +{"moduleCode":"IT5004","moduleCredit":0,"title":"Enterprise Systems Architecture Fundamentals"} +{"moduleCode":"XFB4002","moduleCredit":0,"title":"Integrated Honours Dissertation"} +{"moduleCode":"CN4240R","moduleCredit":0,"title":"Unit Operations and Processes for Effluent Treatment"} +{"moduleCode":"IT5002","moduleCredit":0,"title":"Computer Systems and Applications"} +{"moduleCode":"NUR5303","moduleCredit":0,"title":"Integrated Primary and Community Care (Adult Health)"} +{"moduleCode":"IT5003","moduleCredit":0,"title":"Data Structures and Algorithms"} +{"moduleCode":"XFB4001","moduleCredit":0,"title":"Integrated Honours Thesis"} +{"moduleCode":"EC1301","moduleCredit":0,"title":"Principles of Economics"} +{"moduleCode":"NUR5302","moduleCredit":0,"title":"Advanced Gerontological Nursing (Adult Health)"} +{"moduleCode":"ESP4401","moduleCredit":0,"title":"Optimization of Energy Systems"} +{"moduleCode":"PS3265","moduleCredit":0,"title":"Civil-Military Relations"} +{"moduleCode":"IT5001","moduleCredit":0,"title":"Software Development Fundamentals"} +{"moduleCode":"PS3267","moduleCredit":0,"title":"German Political Thought"} +{"moduleCode":"CN4240E","moduleCredit":0,"title":"Unit Operations and Processes for Effluent Treatment"} +{"moduleCode":"PS3272","moduleCredit":0,"title":"The International Relations of Sub-Saharan Africa"} +{"moduleCode":"PS3274","moduleCredit":0,"title":"Environmental Politics"} +{"moduleCode":"SE2660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"NM5201R","moduleCredit":0,"title":"State and Civil Society in the Information Age"} +{"moduleCode":"PC1221","moduleCredit":0,"title":"Fundamentals of Physics I"} +{"moduleCode":"PC1222","moduleCredit":0,"title":"Fundamentals of Physics II"} +{"moduleCode":"LL5327V","moduleCredit":0,"title":"Mergers and Acquisitions: A Practitioner’s Perspective"} +{"moduleCode":"NUR5312","moduleCredit":0,"title":"Clinical Practicum II (AH, AC & MH)"} +{"moduleCode":"NUR5311","moduleCredit":0,"title":"Clinical Practicum I (AH, AC & MH)"} +{"moduleCode":"PS3257","moduleCredit":0,"title":"Political Inquiry"} +{"moduleCode":"CG1111","moduleCredit":0,"title":"Engineering Principles and Practice I"} +{"moduleCode":"CG1112","moduleCredit":0,"title":"Engineering Principles and Practice II"} +{"moduleCode":"CN4242E","moduleCredit":0,"title":"Optimization of Chemical Processes"} +{"moduleCode":"PS3262","moduleCredit":0,"title":"Managing Non-Profit Organisations"} +{"moduleCode":"LAV1201","moduleCredit":0,"title":"Vietnamese 1"} +{"moduleCode":"ME2101E","moduleCredit":0,"title":"Fundamentals of Mechanical Design"} +{"moduleCode":"YIL2201S","moduleCredit":0,"title":"Directed Language Study: Intermediate Sanskrit"} +{"moduleCode":"YSC2229","moduleCredit":0,"title":"Introductory Data Structures and Algorithms"} +{"moduleCode":"ESE2001","moduleCredit":0,"title":"Environmental Challenges in the Anthropocene"} +{"moduleCode":"ESE2000","moduleCredit":0,"title":"Environmental Engineering Fundamentals"} +{"moduleCode":"CN4246R","moduleCredit":0,"title":"Chemical and Bio Catalysis"} +{"moduleCode":"ESE5999","moduleCredit":0,"title":"Graduate Seminars"} +{"moduleCode":"LAB4202","moduleCredit":0,"title":"Bahasa Indonesia 6"} +{"moduleCode":"LAB4201","moduleCredit":0,"title":"Bahasa Indonesia 5"} +{"moduleCode":"BMA5428","moduleCredit":0,"title":"Strategic Foresight"} +{"moduleCode":"YSC2225","moduleCredit":0,"title":"Physical Chemistry"} +{"moduleCode":"PP5142","moduleCredit":0,"title":"Liveable & Sustainable Cities - Lessons from Singapore & Other Cities"} +{"moduleCode":"YSC2227","moduleCredit":0,"title":"C: A Language for Science and Engineering"} +{"moduleCode":"COS2000","moduleCredit":0,"title":"Computational Thinking for Scientists"} +{"moduleCode":"TCE1109","moduleCredit":0,"title":"Statics And Mechanics of Materials"} +{"moduleCode":"YSC2221","moduleCredit":0,"title":"Introduction to Python"} +{"moduleCode":"YSC2222","moduleCredit":0,"title":"Organic Chemistry Laboratory"} +{"moduleCode":"YSC2224","moduleCredit":0,"title":"Accelerated Organic Chemistry"} +{"moduleCode":"LL6342V","moduleCredit":0,"title":"Taxation of Cross-Border Commercial Transactions"} +{"moduleCode":"GMS6991","moduleCredit":0,"title":"Thesis"} +{"moduleCode":"ES5101","moduleCredit":0,"title":"Technical Communication for Engineers"} +{"moduleCode":"FIN4751","moduleCredit":0,"title":"Advanced Independent Study in Finance"} +{"moduleCode":"GMS6992","moduleCredit":0,"title":"Thesis (HSSR)"} +{"moduleCode":"EL5251","moduleCredit":0,"title":"Approaches to Discourse"} +{"moduleCode":"CN4247R","moduleCredit":0,"title":"Enzyme Technology"} +{"moduleCode":"NUR5805G","moduleCredit":0,"title":"Chronic Wound Management in the Community"} +{"moduleCode":"LC6378","moduleCredit":0,"title":"Doctoral Workshop"} +{"moduleCode":"LL5011V","moduleCredit":0,"title":"Civil Justice & Process"} +{"moduleCode":"ME3103","moduleCredit":0,"title":"Mechanical Systems Design"} +{"moduleCode":"CP5010","moduleCredit":0,"title":"Graduate Research Paper"} +{"moduleCode":"PP5150","moduleCredit":0,"title":"Social Welfare in East Asia"} +{"moduleCode":"BHD4001","moduleCredit":0,"title":"Honours Dissertation"} +{"moduleCode":"YSC2216","moduleCredit":0,"title":"Evolutionary Biology"} +{"moduleCode":"PP5158","moduleCredit":0,"title":"International Relations of Asia after WWII"} +{"moduleCode":"YSC2213","moduleCredit":0,"title":"Discrete Mathematics"} +{"moduleCode":"LL6343V","moduleCredit":0,"title":"International Regulation of the Global Commons"} +{"moduleCode":"MUA2196","moduleCredit":0,"title":"Diction for Singers 2"} +{"moduleCode":"CM2101","moduleCredit":0,"title":"Physical Chemistry 2"} +{"moduleCode":"ST3131","moduleCredit":0,"title":"Regression Analysis"} +{"moduleCode":"MUA2193","moduleCredit":0,"title":"Chambers Singers 4"} +{"moduleCode":"MUA2192","moduleCredit":0,"title":"Chambers Singers 3"} +{"moduleCode":"YSC2209","moduleCredit":0,"title":"Proof"} +{"moduleCode":"MUA2191","moduleCredit":0,"title":"Applied Voice Major Study 2B"} +{"moduleCode":"NUR5804G","moduleCredit":0,"title":"Chronic Disease Management in the Community"} +{"moduleCode":"LC5035","moduleCredit":0,"title":"Taxation Issues in Cross-Border Transactions"} +{"moduleCode":"LL5012V","moduleCredit":0,"title":"Comparative Constitutional Law"} +{"moduleCode":"ID3041","moduleCredit":0,"title":"Special Studies"} +{"moduleCode":"BMA5404","moduleCredit":0,"title":"Entrepreneurship & Innovation"} +{"moduleCode":"BMA5406","moduleCredit":0,"title":"Negotiations and Conflict Management"} +{"moduleCode":"MUA2190","moduleCredit":0,"title":"Applied Voice Major Study 2A"} +{"moduleCode":"YSC2203","moduleCredit":0,"title":"Classical Mechanics"} +{"moduleCode":"ESE5901B","moduleCredit":0,"title":"Technologies in Environmental Engineering"} +{"moduleCode":"PP5168","moduleCredit":0,"title":"Public Service Leadership"} +{"moduleCode":"ESE5901A","moduleCredit":0,"title":"Introduction to Environmental Engineering"} +{"moduleCode":"YSC2202","moduleCredit":0,"title":"Biology Laboratory"} +{"moduleCode":"LC5029","moduleCredit":0,"title":"International Commercial Arbitration"} +{"moduleCode":"MUA2186","moduleCredit":0,"title":"Orchestral Repertoire for Harp 2A"} +{"moduleCode":"MUA2184","moduleCredit":0,"title":"Orchestral Repertoire for Double Bass 2A"} +{"moduleCode":"NM3550Y","moduleCredit":0,"title":"Communications & New Media Internship"} +{"moduleCode":"FMS1218B","moduleCredit":0,"title":"FS: How come aspirin can relieve my headache?"} +{"moduleCode":"TIE4203","moduleCredit":0,"title":"Decision Analysis in Industrial & Operations Management"} +{"moduleCode":"CN4246E","moduleCredit":0,"title":"Chemical And Bio-Catalysis"} +{"moduleCode":"LC5405A","moduleCredit":0,"title":"Law of Intellectual Property (a)"} +{"moduleCode":"EBA5003","moduleCredit":0,"title":"Customer Analytics"} +{"moduleCode":"PP5176","moduleCredit":0,"title":"China and the Global Economy"} +{"moduleCode":"EBA5004","moduleCredit":0,"title":"Practical Language Processing"} +{"moduleCode":"EBA5001","moduleCredit":0,"title":"Management of Business Analytics Project"} +{"moduleCode":"EBA5002","moduleCredit":0,"title":"Business Analytics Practice"} +{"moduleCode":"GET1016T","moduleCredit":0,"title":"Understanding The Changing Global Economic Landscape"} +{"moduleCode":"EBA5007","moduleCredit":0,"title":"Capstone Project in Data Analytics"} +{"moduleCode":"EBA5005","moduleCredit":0,"title":"Specialized Predictive Modelling and Forecasting"} +{"moduleCode":"EBA5006","moduleCredit":0,"title":"Big Data Engineering and Web Analytics"} +{"moduleCode":"MUA2176","moduleCredit":0,"title":"AAS Project 2"} +{"moduleCode":"GEK1544","moduleCredit":0,"title":"The Mathematics of Games"} +{"moduleCode":"MUA2175","moduleCredit":0,"title":"AAS Project 1"} +{"moduleCode":"CH6227","moduleCredit":0,"title":"Culture and Society Through Literature"} +{"moduleCode":"FIN4721","moduleCredit":0,"title":"AI, Blockchain and Quantum Computing"} +{"moduleCode":"GEK1547","moduleCredit":0,"title":"The Art of Science, the Science of Art"} +{"moduleCode":"MUA2172","moduleCredit":0,"title":"Room Acoustics"} +{"moduleCode":"GEK1548","moduleCredit":0,"title":"How the Ocean Works"} +{"moduleCode":"MUA2171","moduleCredit":0,"title":"Multitrack Recording 2"} +{"moduleCode":"NM4881C","moduleCredit":0,"title":"Critical Theory and Cultural Studies in New Media"} +{"moduleCode":"GEK1549","moduleCredit":0,"title":"Critical Thinking And Writing"} +{"moduleCode":"MUA2170","moduleCredit":0,"title":"Multitrack Recording 1"} +{"moduleCode":"NM4881A","moduleCredit":0,"title":"Topics in Media Studies: Social Media"} +{"moduleCode":"TE2003","moduleCredit":0,"title":"Advanced Mathematics for Engineers"} +{"moduleCode":"YSS1203","moduleCredit":0,"title":"Principles of Economics"} +{"moduleCode":"LL4259V","moduleCredit":0,"title":"Alternative Investments"} +{"moduleCode":"YSS1205","moduleCredit":0,"title":"Introduction to Game Theory"} +{"moduleCode":"TE2002","moduleCredit":0,"title":"Engineering Mathematics II"} +{"moduleCode":"TP5001","moduleCredit":0,"title":"Research Project"} +{"moduleCode":"UIS3941","moduleCredit":0,"title":"Independent Study Module"} +{"moduleCode":"LL5014V","moduleCredit":0,"title":"Construction Law"} +{"moduleCode":"LC5093","moduleCredit":0,"title":"Chinese Intellectual Property Law"} +{"moduleCode":"PP5180","moduleCredit":0,"title":"Trade Policy and Global Value Chains"} +{"moduleCode":"CN4118E","moduleCredit":0,"title":"B.Tech. Dissertation"} +{"moduleCode":"PP5184","moduleCredit":0,"title":"Communications for Public Leadership"} +{"moduleCode":"GEK1540","moduleCredit":0,"title":"Modern Technology in Medicine and Health"} +{"moduleCode":"PP5188","moduleCredit":0,"title":"Social Entrepreneurship"} +{"moduleCode":"BMS5205","moduleCredit":0,"title":"Business Analytics"} +{"moduleCode":"BMS5206","moduleCredit":0,"title":"Business Analytics with R"} +{"moduleCode":"GMS6950","moduleCredit":0,"title":"Health Services and Systems Research"} +{"moduleCode":"BMS5203","moduleCredit":0,"title":"The Knowledge & Innovation Economy 4.0"} +{"moduleCode":"MUA2163","moduleCredit":0,"title":"Leading and Guiding Through Music"} +{"moduleCode":"BMS5204","moduleCredit":0,"title":"Cross-Border Business Management in the Digital Age"} +{"moduleCode":"MUA2162","moduleCredit":0,"title":"Continuing Studies on Principal Instrument"} +{"moduleCode":"MUA2161","moduleCredit":0,"title":"Advanced Juried Performance Presentation"} +{"moduleCode":"GMS6951","moduleCredit":0,"title":"Dynamic Modelling of Healthcare Services and Systems"} +{"moduleCode":"NUR5801G","moduleCredit":0,"title":"Integrated Clinical Decision Making and Management I"} +{"moduleCode":"UIS3932","moduleCredit":0,"title":"Independent Study Module"} +{"moduleCode":"LC5089","moduleCredit":0,"title":"Chinese Corporate & Securities Law"} +{"moduleCode":"CN4118R","moduleCredit":0,"title":"B.Eng. Dissertation"} +{"moduleCode":"ESE3301","moduleCredit":0,"title":"Environmental Microbiological Principles"} +{"moduleCode":"ME3122E","moduleCredit":0,"title":"Heat Transfer"} +{"moduleCode":"BMS5202","moduleCredit":0,"title":"Global Supply Chain Management"} +{"moduleCode":"TIE4220","moduleCredit":0,"title":"Supply Chain Modelling"} +{"moduleCode":"UIS3931","moduleCredit":0,"title":"Independent Study Module"} +{"moduleCode":"WR1401","moduleCredit":0,"title":"Workplace Readiness"} +{"moduleCode":"YSC2250","moduleCredit":0,"title":"Research Tutorial: DNA and Urban Wildlife"} +{"moduleCode":"PP5193","moduleCredit":0,"title":"Asian International and Strategic Thought"} +{"moduleCode":"YSS1206","moduleCredit":0,"title":"Introduction to Comparative Politics"} +{"moduleCode":"PP5191","moduleCredit":0,"title":"Public Administration, Technology and Innovation"} +{"moduleCode":"YSS1208","moduleCredit":0,"title":"Deviance and Conformity: An Introduction to Sociology"} +{"moduleCode":"FIN4714","moduleCredit":0,"title":"Valuation and Mergers & Acquisition"} +{"moduleCode":"PP5198","moduleCredit":0,"title":"Chinese Political Leadership and Economic Development"} +{"moduleCode":"FIN4713","moduleCredit":0,"title":"Advanced Portfolio Management: Securities Analysis & Valuation"} +{"moduleCode":"LAJ1201","moduleCredit":0,"title":"Japanese 1"} +{"moduleCode":"CN4119E","moduleCredit":0,"title":"B.Tech. Dissertation"} +{"moduleCode":"FIN4716","moduleCredit":0,"title":"Equity Research Seminar"} +{"moduleCode":"PP5196","moduleCredit":0,"title":"Education Economics and Policy"} +{"moduleCode":"FIN4715","moduleCredit":0,"title":"Measuring Success in Philanthropy and Impact Investing"} +{"moduleCode":"LAT2201","moduleCredit":0,"title":"Thai 2"} +{"moduleCode":"FIN4718","moduleCredit":0,"title":"FinTech Management"} +{"moduleCode":"TCE2407","moduleCredit":0,"title":"Engineering & Uncertainty Analyses"} +{"moduleCode":"FIN4717","moduleCredit":0,"title":"Entrepreneurial Finance"} +{"moduleCode":"FIN4719","moduleCredit":0,"title":"FinTech and Financial Data Analytics"} +{"moduleCode":"CH6203","moduleCredit":0,"title":"Grammaticalization and Chinese Grammar"} +{"moduleCode":"CL1101E","moduleCredit":0,"title":"Chinese Language: Its Past and Present"} +{"moduleCode":"CM4199A","moduleCredit":0,"title":"Honours Project in Chemistry"} +{"moduleCode":"MUA2154","moduleCredit":0,"title":"Noon Recital Series 2B"} +{"moduleCode":"GEK1522","moduleCredit":0,"title":"Global Environmental Issues"} +{"moduleCode":"MUA2153","moduleCredit":0,"title":"Noon Recital Series 2A"} +{"moduleCode":"CH6201","moduleCredit":0,"title":"Topics in Chinese Linguistics"} +{"moduleCode":"GEK1529","moduleCredit":0,"title":"Food & Health"} +{"moduleCode":"ENV1202","moduleCredit":0,"title":"Communications for Environmental Studies"} +{"moduleCode":"NM4883F","moduleCredit":0,"title":"Financial Journalism"} +{"moduleCode":"TIE4230","moduleCredit":0,"title":"Quality Engineering II"} +{"moduleCode":"LC5204BV","moduleCredit":0,"title":"Charterparties"} +{"moduleCode":"TC2411","moduleCredit":0,"title":"Mathematics for Chemical Engineers 2"} +{"moduleCode":"IS4302","moduleCredit":0,"title":"Blockchain and Distributed Ledger Technologies"} +{"moduleCode":"MST5001","moduleCredit":0,"title":"Structures And Properties Of Materials"} +{"moduleCode":"IS4301","moduleCredit":0,"title":"Agile IT with DevOps"} +{"moduleCode":"MST5002","moduleCredit":0,"title":"Materials Characterisation"} +{"moduleCode":"YSC2242","moduleCredit":0,"title":"More is Different: Emergence in Physical Systems"} +{"moduleCode":"IFS2200","moduleCredit":0,"title":"Information Security Immersion Programme"} +{"moduleCode":"TIE4239","moduleCredit":0,"title":"Selected Topics in Quality Engineering"} +{"moduleCode":"HY5210","moduleCredit":0,"title":"Approaches to Modern Se Asian History"} +{"moduleCode":"LC5074","moduleCredit":0,"title":"Mergers & Acquisitions"} +{"moduleCode":"IS4303","moduleCredit":0,"title":"IT-mediated financial solutions and platforms"} +{"moduleCode":"YSC2247","moduleCredit":0,"title":"Ecology and Ecosystems"} +{"moduleCode":"YSC2249","moduleCredit":0,"title":"Writing about Science, Nature and the Environment"} +{"moduleCode":"YSC2243","moduleCredit":0,"title":"Probability"} +{"moduleCode":"BMC5012","moduleCredit":0,"title":"Advanced Study Project"} +{"moduleCode":"YSC2244","moduleCredit":0,"title":"Programming for Data Science"} +{"moduleCode":"YSC2246","moduleCredit":0,"title":"Experimental Methods in Physical Sciences"} +{"moduleCode":"UTC1702B","moduleCredit":0,"title":"Thinking in Systems: Diseases and Healthcare"} +{"moduleCode":"GEK1539","moduleCredit":0,"title":"A Brief History of Science"} +{"moduleCode":"UTC1702C","moduleCredit":0,"title":"Thinking in Systems: Sustainability and Us"} +{"moduleCode":"UTC1702D","moduleCredit":0,"title":"Thinking in Systems: Population Dynamics"} +{"moduleCode":"UTC1702E","moduleCredit":0,"title":"Thinking in Systems: Energy Systems"} +{"moduleCode":"UTC1702F","moduleCredit":0,"title":"Thinking in Systems: Disaster Resilience"} +{"moduleCode":"LL4099","moduleCredit":0,"title":"Maritime Law"} +{"moduleCode":"TIE4240","moduleCredit":0,"title":"Project Management"} +{"moduleCode":"TIE4242","moduleCredit":0,"title":"Cost Analysis And Management"} +{"moduleCode":"LC5204AV","moduleCredit":0,"title":"Carriage of Goods By Sea"} +{"moduleCode":"BMC5028","moduleCredit":0,"title":"Managing human capital"} +{"moduleCode":"SSA3203","moduleCredit":0,"title":"The Malays of Singapore"} +{"moduleCode":"BMC5027","moduleCredit":0,"title":"Accounting and information management"} +{"moduleCode":"DMB1202DAO","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"BMC5029","moduleCredit":0,"title":"Value chains, logistics and operations"} +{"moduleCode":"YSC2231","moduleCredit":0,"title":"Foundations of Neuroscience"} +{"moduleCode":"SSA3205","moduleCredit":0,"title":"Singapore's Foreign Policy"} +{"moduleCode":"IE2110E","moduleCredit":0,"title":"Operations Research I"} +{"moduleCode":"YSC2236","moduleCredit":0,"title":"Microbiomes"} +{"moduleCode":"DAO2703","moduleCredit":0,"title":"Operations and Technology Management"} +{"moduleCode":"YSC2237","moduleCredit":0,"title":"Computational Methods in Physical Sciences"} +{"moduleCode":"BMK5104","moduleCredit":0,"title":"Market Analytics Visualisation and Communications"} +{"moduleCode":"DAO2702","moduleCredit":0,"title":"Programming for Business Analytics"} +{"moduleCode":"BMC5021","moduleCredit":0,"title":"Leadership: exploration, assessment & development"} +{"moduleCode":"YSC2239","moduleCredit":0,"title":"Introduction to Data Science"} +{"moduleCode":"BMC5024","moduleCredit":0,"title":"Asia and global economy"} +{"moduleCode":"YSC2232","moduleCredit":0,"title":"Linear Algebra"} +{"moduleCode":"BMC5023","moduleCredit":0,"title":"Business analytics and decision making"} +{"moduleCode":"YSC2233","moduleCredit":0,"title":"Genetics"} +{"moduleCode":"BMC5026","moduleCredit":0,"title":"Marketing strategy"} +{"moduleCode":"YSC2234","moduleCredit":0,"title":"Human Biology"} +{"moduleCode":"GEK1531","moduleCredit":0,"title":"Cyber Security"} +{"moduleCode":"ME3122","moduleCredit":0,"title":"Heat Transfer"} +{"moduleCode":"YSC2235","moduleCredit":0,"title":"Field Research"} +{"moduleCode":"RE3000","moduleCredit":0,"title":"Work Experience Internship"} +{"moduleCode":"DMB1201ACC","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"MUA2251","moduleCredit":0,"title":"Live Interactivity"} +{"moduleCode":"GMS6920","moduleCredit":0,"title":"Metabolic Basis of Disease"} +{"moduleCode":"GMS6921","moduleCredit":0,"title":"Cardiovascular Molecular Biology"} +{"moduleCode":"EN5883R","moduleCredit":0,"title":"Screen Culture in Southeast Asia"} +{"moduleCode":"CE5881","moduleCredit":0,"title":"Topics in Geotechnical Engineering: Soil Dynamics"} +{"moduleCode":"PHS2191","moduleCredit":0,"title":"Laboratory Techniques in Pharmaceutical Science I"} +{"moduleCode":"TIC2101","moduleCredit":0,"title":"Information Systems and Organisations"} +{"moduleCode":"TIE4252","moduleCredit":0,"title":"Introduction to Systems Engineering"} +{"moduleCode":"AR5121","moduleCredit":0,"title":"Special Topics in Technology"} +{"moduleCode":"MUA2256","moduleCredit":0,"title":"Applied Secondary B"} +{"moduleCode":"MUA2255","moduleCredit":0,"title":"Applied Secondary A"} +{"moduleCode":"LL4308V","moduleCredit":0,"title":"Behavioural Economics, Law & Regulation"} +{"moduleCode":"TIE4259","moduleCredit":0,"title":"Selected Topics in Systems Engineering"} +{"moduleCode":"ASP1201EC","moduleCredit":0,"title":"H3 Humanities & Soc Sci Research Prog"} +{"moduleCode":"MUA2242","moduleCredit":0,"title":"Collaborative Piano - Instrumental Accompaniment"} +{"moduleCode":"ASP1201EN","moduleCredit":0,"title":"H3 Humanities & Soc Sci Research Prog"} +{"moduleCode":"BME5056B","moduleCredit":0,"title":"Special Topic 1B"} +{"moduleCode":"MUA2241","moduleCredit":0,"title":"Collaborative Piano - Vocal Accompaniment"} +{"moduleCode":"LL4191","moduleCredit":0,"title":"Wealth Management Law"} +{"moduleCode":"MUA2240","moduleCredit":0,"title":"Collaborative Piano - Piano Ensemble"} +{"moduleCode":"LL4190","moduleCredit":0,"title":"Freedom of Speech: Critical & Comparative Perspectives"} +{"moduleCode":"GMS6910","moduleCredit":0,"title":"Evolutionary Genetics"} +{"moduleCode":"BME5056A","moduleCredit":0,"title":"Special Topic 1A"} +{"moduleCode":"PH4660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"GEK1522T","moduleCredit":0,"title":"Global Environmental Issues"} +{"moduleCode":"GL1101E","moduleCredit":0,"title":"Global Issues"} +{"moduleCode":"TTG2901","moduleCredit":0,"title":"Communications for Engineering Professionals"} +{"moduleCode":"MUA2243","moduleCredit":0,"title":"Collaborative Piano - Chamber Music"} +{"moduleCode":"ME3263E","moduleCredit":0,"title":"Design for Manufacturing and Assembly"} +{"moduleCode":"IE2100E","moduleCredit":0,"title":"Probability Models with Applications"} +{"moduleCode":"EC5326R","moduleCredit":0,"title":"Policy Impact Evaluation Methods"} +{"moduleCode":"SP1230","moduleCredit":0,"title":"NUS H3 Science Research Programme"} +{"moduleCode":"BSP3001C","moduleCredit":0,"title":"Strategic Management"} +{"moduleCode":"BSP3001B","moduleCredit":0,"title":"Strategic Management"} +{"moduleCode":"BSP3001A","moduleCredit":0,"title":"Strategic Management"} +{"moduleCode":"LL6044V","moduleCredit":0,"title":"Mediation"} +{"moduleCode":"SPH5201","moduleCredit":0,"title":"Control of Communicable Diseases"} +{"moduleCode":"CS1231","moduleCredit":0,"title":"Discrete Structures"} +{"moduleCode":"SPH5202","moduleCredit":0,"title":"Control of Non-Communicable Diseases"} +{"moduleCode":"SPH5203","moduleCredit":0,"title":"Advanced Epidemiology I"} +{"moduleCode":"SPH5204","moduleCredit":0,"title":"Nutrition and Health - Fundamentals and Applications"} +{"moduleCode":"SPH5205","moduleCredit":0,"title":"Urban Outbreak Management"} +{"moduleCode":"SPH5206","moduleCredit":0,"title":"Urban Field Epidemiology"} +{"moduleCode":"GMS6902","moduleCredit":0,"title":"Laboratory Rotation 1"} +{"moduleCode":"GMS6903","moduleCredit":0,"title":"Laboratory Rotation 2"} +{"moduleCode":"GMS6900","moduleCredit":0,"title":"Student Research Seminars"} +{"moduleCode":"GMS6901","moduleCredit":0,"title":"Molecules to Medicines"} +{"moduleCode":"GMS6906","moduleCredit":0,"title":"Laboratory Rotation 3"} +{"moduleCode":"GMS6904","moduleCredit":0,"title":"Principles of Infectious Diseases"} +{"moduleCode":"LLD5099","moduleCredit":0,"title":"Maritime Law"} +{"moduleCode":"LL6045V","moduleCredit":0,"title":"Negotiation"} +{"moduleCode":"LL6178V","moduleCredit":0,"title":"Law and Practice of Investment Treaties"} +{"moduleCode":"PP5203","moduleCredit":0,"title":"Behavioral Economics and Public Policy"} +{"moduleCode":"LL4177","moduleCredit":0,"title":"Entertainment Law: Pop Iconography & Celebrity"} +{"moduleCode":"ASP1201CH","moduleCredit":0,"title":"H3 Humanities & Soc Sci Research Prog"} +{"moduleCode":"LL4172","moduleCredit":0,"title":"Japanese Corporate Law & Governance"} +{"moduleCode":"LL5283V","moduleCredit":0,"title":"Artificial Intelligence, Information Science & Law"} +{"moduleCode":"MLE5666","moduleCredit":0,"title":"Industrial Attachment Module"} +{"moduleCode":"BSP1707B","moduleCredit":0,"title":"Managerial Economics: Exposure"} +{"moduleCode":"LL5150V","moduleCredit":0,"title":"International Investment Law and Arbitration"} +{"moduleCode":"BSP1707A","moduleCredit":0,"title":"Managerial Economics: Exposure"} +{"moduleCode":"ME3261E","moduleCredit":0,"title":"Computer-Aided Design and Manufacturing"} +{"moduleCode":"BSP1005","moduleCredit":0,"title":"Managerial Economics"} +{"moduleCode":"BSP1004","moduleCredit":0,"title":"Legal Environment Of Business"} +{"moduleCode":"MNO4316","moduleCredit":0,"title":"Experiencing Work: Effects on Behavior and Well-Being"} +{"moduleCode":"MNO4314","moduleCredit":0,"title":"Consulting to Management"} +{"moduleCode":"MLE6999","moduleCredit":0,"title":"Doctoral Seminars"} +{"moduleCode":"PP5212","moduleCredit":0,"title":"Financial Issues, Trade and Investment in Asia"} +{"moduleCode":"MNO4319","moduleCredit":0,"title":"Adv Independent Study in Leadership & Human Capital Mgt"} +{"moduleCode":"MLE1001A","moduleCredit":0,"title":"Materials Science & Engineering Principles & Practice I"} +{"moduleCode":"PP5216","moduleCredit":0,"title":"Economic Growth in Developing Asia"} +{"moduleCode":"PP5215","moduleCredit":0,"title":"Changes in Singapore Political Economy"} +{"moduleCode":"LSM1106","moduleCredit":0,"title":"Molecular Cell Biology"} +{"moduleCode":"LSM1105","moduleCredit":0,"title":"Evolutionary Biology"} +{"moduleCode":"OT5102","moduleCredit":0,"title":"Oil & Gas Technology"} +{"moduleCode":"MKT3751","moduleCredit":0,"title":"Independent Study in Marketing"} +{"moduleCode":"LSM1102","moduleCredit":0,"title":"Molecular Genetics"} +{"moduleCode":"FMS1225B","moduleCredit":0,"title":"Infectious Diseases and Host-Pathogen Interactions"} +{"moduleCode":"MUA2210","moduleCredit":0,"title":"Rhythmical Devices in Performance 2"} +{"moduleCode":"TIE4299","moduleCredit":0,"title":"Selected Topics in Industrial Engineering"} +{"moduleCode":"GET1029","moduleCredit":0,"title":"Life, the Universe, and Everything"} +{"moduleCode":"GET1028","moduleCredit":0,"title":"Logic"} +{"moduleCode":"GET1027","moduleCredit":0,"title":"Reason and Persuasion"} +{"moduleCode":"MUA2209","moduleCredit":0,"title":"Advanced Contemporary Music Performance"} +{"moduleCode":"GET1026","moduleCredit":0,"title":"Effective Reasoning"} +{"moduleCode":"MUA2208","moduleCredit":0,"title":"Advanced Contemporary Music Performance"} +{"moduleCode":"GET1025","moduleCredit":0,"title":"Science Fiction and Philosophy"} +{"moduleCode":"GET1024","moduleCredit":0,"title":"Radiation-Scientific Understanding and Public Perception"} +{"moduleCode":"PP5220","moduleCredit":0,"title":"Innovation and Technology Policy"} +{"moduleCode":"GET1023","moduleCredit":0,"title":"Thinking Like An Economist"} +{"moduleCode":"GET1022","moduleCredit":0,"title":"Understanding Your Brain"} +{"moduleCode":"GET1021","moduleCredit":0,"title":"Critical Thinking And Writing"} +{"moduleCode":"GET1020","moduleCredit":0,"title":"Darwin and Evolution"} +{"moduleCode":"PP5224","moduleCredit":0,"title":"Value- Focused Negotiations"} +{"moduleCode":"PP5223","moduleCredit":0,"title":"Population Ageing, Public Policy, and Family"} +{"moduleCode":"PP5228","moduleCredit":0,"title":"Evidence-Informed Policy Development"} +{"moduleCode":"PP5227","moduleCredit":0,"title":"Environmental and Natural Resource Policy"} +{"moduleCode":"SC6660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"PP5226","moduleCredit":0,"title":"Social Policy Design"} +{"moduleCode":"DSC3203","moduleCredit":0,"title":"Service Operations Management"} +{"moduleCode":"LL6350V","moduleCredit":0,"title":"Privacy & Data Protection Law"} +{"moduleCode":"DSC3201","moduleCredit":0,"title":"Supply Chain Management"} +{"moduleCode":"DSC3202","moduleCredit":0,"title":"Purchasing And Materials Management"} +{"moduleCode":"MUA2206","moduleCredit":0,"title":"Harmonic Hearing for Performers"} +{"moduleCode":"BN5201","moduleCredit":0,"title":"Advanced Biomaterials"} +{"moduleCode":"LA4202","moduleCredit":0,"title":"Planting Design"} +{"moduleCode":"MKT2414","moduleCredit":0,"title":"Marketing Venture Challenge"} +{"moduleCode":"MUA2205","moduleCredit":0,"title":"Rhythmic Devices in Performance 1"} +{"moduleCode":"LA4203","moduleCredit":0,"title":"History and Theory of Landscape Architecture"} +{"moduleCode":"MUA2202","moduleCredit":0,"title":"Keyboard Literature II"} +{"moduleCode":"BN5205","moduleCredit":0,"title":"Computational Biomechanics"} +{"moduleCode":"MUA2201","moduleCredit":0,"title":"Keyboard Literature I"} +{"moduleCode":"BN5203","moduleCredit":0,"title":"Advanced Tissue Engineering"} +{"moduleCode":"IE5907","moduleCredit":0,"title":"Independent Study in Operations Research"} +{"moduleCode":"LL5285V","moduleCredit":0,"title":"International Dispute Settlement"} +{"moduleCode":"BN5209","moduleCredit":0,"title":"Neurosensors and Signal Processing"} +{"moduleCode":"BN5208","moduleCredit":0,"title":"Biomedical Quality and Regulatory Systems"} +{"moduleCode":"IE5905","moduleCredit":0,"title":"Independent Study In Systems Engineering"} +{"moduleCode":"BN5207","moduleCredit":0,"title":"Medical Imaging Systems"} +{"moduleCode":"IE5903","moduleCredit":0,"title":"Independent Study in PM"} +{"moduleCode":"GET1038","moduleCredit":0,"title":"Communication in Small Groups"} +{"moduleCode":"GET1037","moduleCredit":0,"title":"Big Picture History"} +{"moduleCode":"GET1036","moduleCredit":0,"title":"The Logic of Language"} +{"moduleCode":"GET1035","moduleCredit":0,"title":"Critical Perspectives in Advertising"} +{"moduleCode":"GET1034","moduleCredit":0,"title":"Communication and Critical Thinking for Community Leadership"} +{"moduleCode":"GET1032","moduleCredit":0,"title":"Building Relationship : Theories and Practice"} +{"moduleCode":"GET1031","moduleCredit":0,"title":"Computational Thinking"} +{"moduleCode":"GET1030","moduleCredit":0,"title":"Computers and the Humanities"} +{"moduleCode":"LC5118","moduleCredit":0,"title":"Foreign Direct Investment Law in Asia"} +{"moduleCode":"DSC3214","moduleCredit":0,"title":"Introduction To Optimisation"} +{"moduleCode":"LAF4204","moduleCredit":0,"title":"French Studies 2"} +{"moduleCode":"DSC3215","moduleCredit":0,"title":"Stochastic Models In Management"} +{"moduleCode":"LAF4203","moduleCredit":0,"title":"French Studies 1"} +{"moduleCode":"LAF4202","moduleCredit":0,"title":"French 6"} +{"moduleCode":"LAF4201","moduleCredit":0,"title":"French 5"} +{"moduleCode":"DSC3216","moduleCredit":0,"title":"Predictive Analytics in Business"} +{"moduleCode":"ALS1010","moduleCredit":0,"title":"Learning to Learn Better"} +{"moduleCode":"BN5210","moduleCredit":0,"title":"Biosensors and Biochips"} +{"moduleCode":"DMR1201WRB","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"DMR1201WRA","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"LC5115","moduleCredit":0,"title":"International Law"} +{"moduleCode":"PF2402","moduleCredit":0,"title":"Work Experience Internship"} +{"moduleCode":"GET1009","moduleCredit":0,"title":"Gandhi's Life, Thought And Legacy"} +{"moduleCode":"GET1008","moduleCredit":0,"title":"Public Speaking and Critical Reasoning"} +{"moduleCode":"NUR3105A","moduleCredit":0,"title":"Nursing Practice Experience 3.1"} +{"moduleCode":"GET1004","moduleCredit":0,"title":"Cyber Security"} +{"moduleCode":"GET1003","moduleCredit":0,"title":"Home"} +{"moduleCode":"LL5286V","moduleCredit":0,"title":"Transnational Terrorism and International Law"} +{"moduleCode":"GET1002","moduleCredit":0,"title":"Bridging East and West: Exploring Chinese Communication"} +{"moduleCode":"GET1001","moduleCredit":0,"title":"Seeing the World Through Maps"} +{"moduleCode":"DSC3226","moduleCredit":0,"title":"Sustainable Operations Management"} +{"moduleCode":"DSC3224","moduleCredit":0,"title":"Dynamic Pricing & Revenue Management"} +{"moduleCode":"ALS1020","moduleCredit":0,"title":"Learning to Choose Better"} +{"moduleCode":"DSC3229","moduleCredit":0,"title":"Independent Study in Ops & Supply Chain Mgt"} +{"moduleCode":"ESE5901","moduleCredit":0,"title":"Environmental Technology"} +{"moduleCode":"MKT3722","moduleCredit":0,"title":"Research for Marketing Insights"} +{"moduleCode":"DSC3227","moduleCredit":0,"title":"Technology and Business Innovation"} +{"moduleCode":"MUT2202","moduleCredit":0,"title":"Counterpoint Through the Ages"} +{"moduleCode":"MUT2203","moduleCredit":0,"title":"Texture and Timbre"} +{"moduleCode":"MUT2201","moduleCredit":0,"title":"Harmonic Practices"} +{"moduleCode":"MKT3718","moduleCredit":0,"title":"Advertising & Promotion Management"} +{"moduleCode":"MUT2204","moduleCredit":0,"title":"Formal Practices"} +{"moduleCode":"GET1018","moduleCredit":0,"title":"The Mathematics of Games"} +{"moduleCode":"MKT3717","moduleCredit":0,"title":"Product & Brand Management"} +{"moduleCode":"MUT2205","moduleCredit":0,"title":"Text and Music"} +{"moduleCode":"GET1016","moduleCredit":0,"title":"Understanding the Changing Global Economic Landscape"} +{"moduleCode":"LL5287V","moduleCredit":0,"title":"ASEAN Law and Policy"} +{"moduleCode":"GET1014","moduleCredit":0,"title":"The Art of Science, the Science of Art"} +{"moduleCode":"LL5021V","moduleCredit":0,"title":"Environmental Law"} +{"moduleCode":"GET1013","moduleCredit":0,"title":"Physics in the Life Sciences"} +{"moduleCode":"GET1011","moduleCredit":0,"title":"Towards an Understanding of the Complex World"} +{"moduleCode":"PP5257","moduleCredit":0,"title":"Urban Water Governance"} +{"moduleCode":"LLD5043","moduleCredit":0,"title":"Law of Marine Insurance"} +{"moduleCode":"SW4214","moduleCredit":0,"title":"Comparative Social Service Systems in SEA"} +{"moduleCode":"UTC2410A","moduleCredit":0,"title":"Reconstructing Communities: Insights from the Balkans"} +{"moduleCode":"YSS4230","moduleCredit":0,"title":"Psychology of Mindfulness"} +{"moduleCode":"SW4216","moduleCredit":0,"title":"Advanced Studies in Community Work"} +{"moduleCode":"LL4089V","moduleCredit":0,"title":"Chinese Corporate & Securities Law"} +{"moduleCode":"SW4210","moduleCredit":0,"title":"Social Work & Technology of the Future"} +{"moduleCode":"CE5001","moduleCredit":0,"title":"Research Project"} +{"moduleCode":"SPH3404","moduleCredit":0,"title":"Physical Activity For Better Population Health"} +{"moduleCode":"AUD5115","moduleCredit":0,"title":"Experimental Design & Statistics"} +{"moduleCode":"CM5151","moduleCredit":0,"title":"Energy Storage and Conversion Chemistry"} +{"moduleCode":"CM5152","moduleCredit":0,"title":"Water Chemistry and Environment"} +{"moduleCode":"MKT3711","moduleCredit":0,"title":"Services Marketing"} +{"moduleCode":"MKT3716","moduleCredit":0,"title":"Customer Relationship Management"} +{"moduleCode":"PS6314","moduleCredit":0,"title":"Advanced Studies in Asian Politics"} +{"moduleCode":"YSS4237","moduleCredit":0,"title":"Conquest, Territorial Expansion and International Law"} +{"moduleCode":"MKT3714","moduleCredit":0,"title":"Marketing in a Digital Age"} +{"moduleCode":"SW4219","moduleCredit":0,"title":"Crisis and Disaster Recovery Management"} +{"moduleCode":"YSS4234","moduleCredit":0,"title":"Urban Heritage: Place, Memory, Identity"} +{"moduleCode":"AUD5110","moduleCredit":0,"title":"Vestibular Assessment and Management A"} +{"moduleCode":"AUD5111","moduleCredit":0,"title":"Hearing Devices & Rehabilitation A - Part 2"} +{"moduleCode":"IS6103","moduleCredit":0,"title":"Design Science Research in Information Systems"} +{"moduleCode":"AUD5112","moduleCredit":0,"title":"Clinical Audiology A - Part 2"} +{"moduleCode":"AUD5113","moduleCredit":0,"title":"Paediatric Audiology A - Part 2"} +{"moduleCode":"ID1322","moduleCredit":0,"title":"Materials and Manufacturing for Industrial Design"} +{"moduleCode":"PLS8003","moduleCredit":0,"title":"Cultivating Resilience"} +{"moduleCode":"PLS8004","moduleCredit":0,"title":"Optimizing Performance"} +{"moduleCode":"PLS8001","moduleCredit":0,"title":"Cultivating Collaboration"} +{"moduleCode":"PLS8002","moduleCredit":0,"title":"Cultivating the Self"} +{"moduleCode":"YSS4241","moduleCredit":0,"title":"Multispecies Ethnography"} +{"moduleCode":"SW4221","moduleCredit":0,"title":"Social Work and Rehabilitation of Offenders"} +{"moduleCode":"SW4222","moduleCredit":0,"title":"Social Work Practice in the Field of Disability"} +{"moduleCode":"SW4223","moduleCredit":0,"title":"Child-Centric Social Work"} +{"moduleCode":"ES1541","moduleCredit":0,"title":"Exploring Science Communication through Popular Science"} +{"moduleCode":"MKT3701","moduleCredit":0,"title":"Marketing Strategy: Analysis and Practice"} +{"moduleCode":"YSS4249","moduleCredit":0,"title":"The Economics of Inequality"} +{"moduleCode":"YSS4248","moduleCredit":0,"title":"Conducting Qualitative Socio-Legal Research"} +{"moduleCode":"MKT3702","moduleCredit":0,"title":"Consumer Behaviour"} +{"moduleCode":"CS4350","moduleCredit":0,"title":"Game Development Project"} +{"moduleCode":"DSA2361","moduleCredit":0,"title":"Data Analytics for Customer Insights"} +{"moduleCode":"SE5219R","moduleCredit":0,"title":"Technopolitics in Southeast As"} +{"moduleCode":"DMY1401ELC","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"TS5212R","moduleCredit":0,"title":"Asian International Cinema"} +{"moduleCode":"ES5001A","moduleCredit":0,"title":"Graduate English Course (Intermediate Level)"} +{"moduleCode":"LL4102","moduleCredit":0,"title":"Advanced Torts"} +{"moduleCode":"CS4347","moduleCredit":0,"title":"Sound and Music Computing"} +{"moduleCode":"MLE6103","moduleCredit":0,"title":"Structures of Materials"} +{"moduleCode":"MT6999","moduleCredit":0,"title":"Doctoral Seminars"} +{"moduleCode":"EE3131C","moduleCredit":0,"title":"Communication Systems"} +{"moduleCode":"EU4214","moduleCredit":0,"title":"Special Paper in Modern European History"} +{"moduleCode":"GET1048","moduleCredit":0,"title":"Science: From Thinking to Narratives"} +{"moduleCode":"ES1531","moduleCredit":0,"title":"Critical Thinking And Writing"} +{"moduleCode":"GET1047","moduleCredit":0,"title":"Art and Identity"} +{"moduleCode":"MLE6101","moduleCredit":0,"title":"Thermodynamics and Kinetics of Materials"} +{"moduleCode":"GET1046","moduleCredit":0,"title":"I Do Not Think Therefore I Am"} +{"moduleCode":"JS3223","moduleCredit":0,"title":"Japan and the Asia-Pacific Region"} +{"moduleCode":"EE3131E","moduleCredit":0,"title":"Communication Systems"} +{"moduleCode":"GET1043","moduleCredit":0,"title":"Universe, Big Bang, and Unsolved Mysteries"} +{"moduleCode":"GET1042","moduleCredit":0,"title":"Sky and Telescopes"} +{"moduleCode":"JS3226","moduleCredit":0,"title":"Japan: The Green Nation?"} +{"moduleCode":"GET1041","moduleCredit":0,"title":"Disney and the Theme Park World"} +{"moduleCode":"GET1040","moduleCredit":0,"title":"Communicating about the Arts"} +{"moduleCode":"PF1101","moduleCredit":0,"title":"Fundamentals of Project Management"} +{"moduleCode":"YSS4220","moduleCredit":0,"title":"Housing and Social Inequality"} +{"moduleCode":"EN5660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"AUD5104","moduleCredit":0,"title":"Perception of Sound & Speech"} +{"moduleCode":"PF1107","moduleCredit":0,"title":"Project And Facilities Management Law"} +{"moduleCode":"YSS4229","moduleCredit":0,"title":"The Anthropology of Human Rights"} +{"moduleCode":"AUD5105","moduleCredit":0,"title":"Hearing Devices and Rehabilitation A - Part 1"} +{"moduleCode":"PF1106","moduleCredit":0,"title":"Introduction to Measurement"} +{"moduleCode":"AUD5106","moduleCredit":0,"title":"Clinical Audiology A - Part 1"} +{"moduleCode":"DMC1401","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"YSS4227","moduleCredit":0,"title":"Topics in Applied Econometrics"} +{"moduleCode":"AUD5107","moduleCredit":0,"title":"Paediatric Audiology A - Part 1"} +{"moduleCode":"CM5161","moduleCredit":0,"title":"Advanced Chemical Laboratory Safety"} +{"moduleCode":"PF1108","moduleCredit":0,"title":"Introduction to Building Performance"} +{"moduleCode":"AUD5108","moduleCredit":0,"title":"Electrophysiological Assessment A"} +{"moduleCode":"PF1103","moduleCredit":0,"title":"Digital Construction"} +{"moduleCode":"AUD5109","moduleCredit":0,"title":"Professional Practice Issues & Community Audiology"} +{"moduleCode":"YSS4226","moduleCredit":0,"title":"Migration Policy"} +{"moduleCode":"YSS4223","moduleCredit":0,"title":"Politics of Identity in Developing Countries"} +{"moduleCode":"YSS4224","moduleCredit":0,"title":"Political Order and One-Party Rule"} +{"moduleCode":"ID5951A","moduleCredit":0,"title":"Topics in Industrial Design: Product Development"} +{"moduleCode":"ID5951B","moduleCredit":0,"title":"Topics in Industrial Design: Interaction Design"} +{"moduleCode":"CS4330","moduleCredit":0,"title":"Combinatorial Methods in Bioinformatics"} +{"moduleCode":"AUD5101","moduleCredit":0,"title":"Acoustics"} +{"moduleCode":"AUD5102","moduleCredit":0,"title":"Anatomy & Physiology"} +{"moduleCode":"EU4226","moduleCredit":0,"title":"Imperialism and Empires"} +{"moduleCode":"AUD5103","moduleCredit":0,"title":"Pathologies of the Auditory System"} +{"moduleCode":"LL5412","moduleCredit":0,"title":"Securities and Capital Markets Regulation"} +{"moduleCode":"BSE3711","moduleCredit":0,"title":"Strategic Thinking: Economic Applications"} +{"moduleCode":"JS3213","moduleCredit":0,"title":"Alternative Lives in Contemporary Japan"} +{"moduleCode":"ID5951E","moduleCredit":0,"title":"Topics in Industrial Design: Sustainability"} +{"moduleCode":"JS3216","moduleCredit":0,"title":"Japanese Film and Literature"} +{"moduleCode":"ID5951C","moduleCredit":0,"title":"Topics in Industrial Design: Healthcare Design"} +{"moduleCode":"GET1050","moduleCredit":0,"title":"Computational Reasoning"} +{"moduleCode":"ID5951D","moduleCredit":0,"title":"Topics in Industrial Design: Design Education"} +{"moduleCode":"PF4202","moduleCredit":0,"title":"Safety, Health and Environmental Mgt"} +{"moduleCode":"PF4203","moduleCredit":0,"title":"Project Dispute Management"} +{"moduleCode":"PY1131","moduleCredit":0,"title":"Human Anatomy & Physiology II"} +{"moduleCode":"ECA5103","moduleCredit":0,"title":"Quantitative & Computing Methods"} +{"moduleCode":"PF4207","moduleCredit":0,"title":"Project Risk Management"} +{"moduleCode":"ECA5102","moduleCredit":0,"title":"Macroeconomics"} +{"moduleCode":"TG2415","moduleCredit":0,"title":"Ethics In Engineering"} +{"moduleCode":"ECA5101","moduleCredit":0,"title":"Microeconomics"} +{"moduleCode":"LSM4210","moduleCredit":0,"title":"Topics in Biomedical Science"} +{"moduleCode":"NM4660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"LSM4211","moduleCredit":0,"title":"Toxicology"} +{"moduleCode":"LSM4214","moduleCredit":0,"title":"Cancer Pharmacology"} +{"moduleCode":"EG5911R","moduleCredit":0,"title":"Information Literacy Skills for Research"} +{"moduleCode":"IE5999","moduleCredit":0,"title":"Graduate Seminars"} +{"moduleCode":"LSM4213","moduleCredit":0,"title":"System Neurobiology"} +{"moduleCode":"BSE3701","moduleCredit":0,"title":"Macroeconomic Principles in the Global Economy"} +{"moduleCode":"LSM4216","moduleCredit":0,"title":"Molecular Nutrition and Metabolic Biology"} +{"moduleCode":"EC4401","moduleCredit":0,"title":"Honours Thesis"} +{"moduleCode":"LL5402","moduleCredit":0,"title":"Corporate Insolvency Law"} +{"moduleCode":"LSM4215","moduleCredit":0,"title":"Extreme Physiology"} +{"moduleCode":"BSE3703","moduleCredit":0,"title":"Econometrics for Business I"} +{"moduleCode":"LL5403","moduleCredit":0,"title":"Family Law"} +{"moduleCode":"LSM4218","moduleCredit":0,"title":"Biotechnology and Biotherapeutics"} +{"moduleCode":"BSE3702","moduleCredit":0,"title":"Economics of Strategy"} +{"moduleCode":"LSM4217","moduleCredit":0,"title":"Functional Ageing"} +{"moduleCode":"LL5407","moduleCredit":0,"title":"Law of Insurance"} +{"moduleCode":"FMA1206H","moduleCredit":0,"title":"FS: Travel and the Historian"} +{"moduleCode":"LC2013","moduleCredit":0,"title":"Corporate Deals"} +{"moduleCode":"LC2012","moduleCredit":0,"title":"Trial Advocacy"} +{"moduleCode":"PHS2143","moduleCredit":0,"title":"Analytical Techniques and Pharmaceutical Applications"} +{"moduleCode":"EL2101","moduleCredit":0,"title":"Structure of Sentences and Meanings"} +{"moduleCode":"SC3551","moduleCredit":0,"title":"FASS Undergraduate Research Opportunity (UROP)"} +{"moduleCode":"SC4882","moduleCredit":0,"title":"Issues in State and Society"} +{"moduleCode":"SC4883","moduleCredit":0,"title":"Selected Topics in Law and Justice"} +{"moduleCode":"SC2221","moduleCredit":0,"title":"Humans and Natures"} +{"moduleCode":"SC4880","moduleCredit":0,"title":"Selected Topics in Socio'gy & Anthrop'gy"} +{"moduleCode":"SPH2106","moduleCredit":0,"title":"Health in the Later Years"} +{"moduleCode":"SC2220","moduleCredit":0,"title":"Gender Studies"} +{"moduleCode":"SPH2107","moduleCredit":0,"title":"Social Determinants of Health"} +{"moduleCode":"FST4102","moduleCredit":0,"title":"Advanced Food Processing Technology"} +{"moduleCode":"FST4103","moduleCredit":0,"title":"Food Colloids and Components Science"} +{"moduleCode":"CM5100","moduleCredit":0,"title":"M.sc. Project"} +{"moduleCode":"EL2102","moduleCredit":0,"title":"Sound Patterns in Language"} +{"moduleCode":"CM5101","moduleCredit":0,"title":"Advanced Analysis and Characterization Techniques"} +{"moduleCode":"LSM4221","moduleCredit":0,"title":"Drug Discovery and Clinical Trials"} +{"moduleCode":"EC5322R","moduleCredit":0,"title":"Industrial Organisation"} +{"moduleCode":"LSM4223","moduleCredit":0,"title":"Advances in Antimicrobial Strategies"} +{"moduleCode":"TEE3207","moduleCredit":0,"title":"Computer Architecture"} +{"moduleCode":"LSM4222","moduleCredit":0,"title":"Advanced Immunology"} +{"moduleCode":"LSM4225","moduleCredit":0,"title":"Genetic Medicine in the Post-Genomic Era"} +{"moduleCode":"LSM4227","moduleCredit":0,"title":"Stem Cell Biology"} +{"moduleCode":"SPH2104","moduleCredit":0,"title":"Public Health Nutrition"} +{"moduleCode":"LSM4226","moduleCredit":0,"title":"Infection and Immunity"} +{"moduleCode":"SC2222","moduleCredit":0,"title":"Sports and Society"} +{"moduleCode":"SPH2105","moduleCredit":0,"title":"Introduction to Global Health"} +{"moduleCode":"LSM4229","moduleCredit":0,"title":"Therapeutic and diagnostic agents from animal toxins"} +{"moduleCode":"SC2225","moduleCredit":0,"title":"The Social Life of Art"} +{"moduleCode":"SPH2102","moduleCredit":0,"title":"Lifestyle, Behaviour and Public Health"} +{"moduleCode":"TEE3201","moduleCredit":0,"title":"Software Engineering"} +{"moduleCode":"LSM4228","moduleCredit":0,"title":"Experimental Models for Human Disease and Therapy"} +{"moduleCode":"SPH2103","moduleCredit":0,"title":"Systems and Policies to improve Health"} +{"moduleCode":"SC2227","moduleCredit":0,"title":"Sociology of Religion"} +{"moduleCode":"SC2226","moduleCredit":0,"title":"Sociology of Mental Health"} +{"moduleCode":"SPH2101","moduleCredit":0,"title":"Public Health and Epidemiology"} +{"moduleCode":"EE4001","moduleCredit":0,"title":"B.Eng. Dissertation"} +{"moduleCode":"YSS4254","moduleCredit":0,"title":"Punishment, Politics and Culture"} +{"moduleCode":"YSS4255","moduleCredit":0,"title":"The Origins of Morality and Bigotry"} +{"moduleCode":"EL2111","moduleCredit":0,"title":"Historical Variation in English"} +{"moduleCode":"YSS4252","moduleCredit":0,"title":"Theory from the South: Critical Perspectives"} +{"moduleCode":"YSS4253","moduleCredit":0,"title":"Ethnography as Theory and Method: Classical and Contemporary Readings"} +{"moduleCode":"YSS4250","moduleCredit":0,"title":"Gender and Sexuality in South Asia"} +{"moduleCode":"LL6173V","moduleCredit":0,"title":"Comparative Corporate Law"} +{"moduleCode":"MDG5771","moduleCredit":0,"title":"Graduate Research Seminar and Workshop"} +{"moduleCode":"SC2210","moduleCredit":0,"title":"Sociology of Popular Culture"} +{"moduleCode":"LC2009","moduleCredit":0,"title":"Pro Bono Service"} +{"moduleCode":"LC2007","moduleCredit":0,"title":"Constitutional & Administrative Law"} +{"moduleCode":"FIN3761A","moduleCredit":0,"title":"TIF: Transaction Banking"} +{"moduleCode":"LC2004","moduleCredit":0,"title":"Principles Of Property Law"} +{"moduleCode":"YSS4256","moduleCredit":0,"title":"Empirical Qualitative Analysis in Global Affairs"} +{"moduleCode":"BN2102","moduleCredit":0,"title":"Bioengineering Data Analysis"} +{"moduleCode":"GEK2050","moduleCredit":0,"title":"Computers and the Humanities"} +{"moduleCode":"MT5010A","moduleCredit":0,"title":"Technology Intelligence Process and Methods"} +{"moduleCode":"SC2212","moduleCredit":0,"title":"Sociology of Deviance"} +{"moduleCode":"MT5010B","moduleCredit":0,"title":"Technology Intelligence with IP Strategies"} +{"moduleCode":"SC2211","moduleCredit":0,"title":"Medical Sociology"} +{"moduleCode":"SC2214","moduleCredit":0,"title":"Media and Culture"} +{"moduleCode":"SC2213","moduleCredit":0,"title":"Childhood and Youth"} +{"moduleCode":"SC2216","moduleCredit":0,"title":"Emotions and Social Life"} +{"moduleCode":"SC2215","moduleCredit":0,"title":"The Sociology of Food"} +{"moduleCode":"SC2218","moduleCredit":0,"title":"Anthropology and the Human Condition"} +{"moduleCode":"SC2217","moduleCredit":0,"title":"Sociology of Tourism"} +{"moduleCode":"PHS2120","moduleCredit":0,"title":"Drug Product Development and Lifecycle Management"} +{"moduleCode":"SW4202","moduleCredit":0,"title":"Special Areas of Social Work Practice"} +{"moduleCode":"BN2111","moduleCredit":0,"title":"Biomedical Engineering Principles and Practice II"} +{"moduleCode":"MS4101","moduleCredit":0,"title":"Theory and Practice in Malay Studies"} +{"moduleCode":"SW4208","moduleCredit":0,"title":"Social Gerontology"} +{"moduleCode":"SC2209","moduleCredit":0,"title":"Money, Business and Social Networks"} +{"moduleCode":"GE5660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"EC3102","moduleCredit":0,"title":"Macroeconomic Analysis II"} +{"moduleCode":"EC3101","moduleCredit":0,"title":"Microeconomic Analysis II"} +{"moduleCode":"SC2202","moduleCredit":0,"title":"Sociology of Work"} +{"moduleCode":"SC2205","moduleCredit":0,"title":"Sociology of Family"} +{"moduleCode":"SC2204","moduleCredit":0,"title":"Social Inequalities : Who Gets Ahead?"} +{"moduleCode":"SC2207","moduleCredit":0,"title":"Peoples & Cultures of Southeast Asia"} +{"moduleCode":"SC2206","moduleCredit":0,"title":"Culture & Society"} +{"moduleCode":"TS3238","moduleCredit":0,"title":"Acting for the Screen"} +{"moduleCode":"RE3803","moduleCredit":0,"title":"Strategic Asset Management"} +{"moduleCode":"RE3802","moduleCredit":0,"title":"Real Estate Finance Law"} +{"moduleCode":"RE3805","moduleCredit":0,"title":"Corporate Investment in Real Estate"} +{"moduleCode":"RE3804","moduleCredit":0,"title":"Real Estate Development Law"} +{"moduleCode":"RE3806","moduleCredit":0,"title":"Advanced Real Estate Valuation"} +{"moduleCode":"TCE3001","moduleCredit":0,"title":"Water Quality Engineering"} +{"moduleCode":"GES1002T","moduleCredit":0,"title":"Global Economic Dimensions Of Singapore"} +{"moduleCode":"MNO2705","moduleCredit":0,"title":"Leadership and Decision Making under Uncertainty"} +{"moduleCode":"SN2283","moduleCredit":0,"title":"China-India Interactions: Changing Perspectives"} +{"moduleCode":"YIR4303G","moduleCredit":0,"title":"Special Project in Science"} +{"moduleCode":"MNO2706","moduleCredit":0,"title":"Business Communication for Leaders (ACC)"} +{"moduleCode":"LSM3288","moduleCredit":0,"title":"Advanced UROPS in Life Sciences I"} +{"moduleCode":"LSM3289","moduleCredit":0,"title":"Advanced UROPS in Life Sciences II"} +{"moduleCode":"SN2280","moduleCredit":0,"title":"Marriage, Sex, Love in South Asia"} +{"moduleCode":"ID3106","moduleCredit":0,"title":"Design Platforms 3"} +{"moduleCode":"ID3105","moduleCredit":0,"title":"Design Platforms 2"} +{"moduleCode":"DBA3702","moduleCredit":0,"title":"Descriptive Analytics with R"} +{"moduleCode":"GEK1064","moduleCredit":0,"title":"Psychology in Everyday Life"} +{"moduleCode":"TS3240","moduleCredit":0,"title":"Theatre Criticism"} +{"moduleCode":"DBA3701","moduleCredit":0,"title":"Introduction to Optimization"} +{"moduleCode":"TS3242","moduleCredit":0,"title":"Intercultural Theatre"} +{"moduleCode":"GEK1067","moduleCredit":0,"title":"Life, the Universe, and Everything"} +{"moduleCode":"TS3243","moduleCredit":0,"title":"Stage and Screen"} +{"moduleCode":"TS3244","moduleCredit":0,"title":"Voice and Text"} +{"moduleCode":"TS3245","moduleCredit":0,"title":"Professional Theatre Internship"} +{"moduleCode":"TS3246","moduleCredit":0,"title":"Shakespeare and Asian Performances"} +{"moduleCode":"TS3248","moduleCredit":0,"title":"Theatre and Orientalism"} +{"moduleCode":"EC2303","moduleCredit":0,"title":"Foundations for Econometrics"} +{"moduleCode":"DMB1202BSP","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"PS4401","moduleCredit":0,"title":"Honours Thesis"} +{"moduleCode":"GES1000T","moduleCredit":0,"title":"Singapore Employment Law"} +{"moduleCode":"IS3103","moduleCredit":0,"title":"Information Systems Leadership and Communication"} +{"moduleCode":"PL3232","moduleCredit":0,"title":"Biological Psychology"} +{"moduleCode":"PL3233","moduleCredit":0,"title":"Cognitive Psychology"} +{"moduleCode":"PL3231","moduleCredit":0,"title":"Independent Research Project"} +{"moduleCode":"PL3236","moduleCredit":0,"title":"Abnormal Psychology"} +{"moduleCode":"IS3106","moduleCredit":0,"title":"Enterprise Systems Interface Design and Development"} +{"moduleCode":"PL3237","moduleCredit":0,"title":"Language & Cognitive Processes"} +{"moduleCode":"PL3234","moduleCredit":0,"title":"Developmental Psychology"} +{"moduleCode":"PL3235","moduleCredit":0,"title":"Social Psychology"} +{"moduleCode":"SSA2220T","moduleCredit":0,"title":"Global Economic Dimensions Of Singapore"} +{"moduleCode":"GEK1048","moduleCredit":0,"title":"Gandhi's Life, Thought And Legacy"} +{"moduleCode":"GEK1049","moduleCredit":0,"title":"Narrative"} +{"moduleCode":"LL4350V","moduleCredit":0,"title":"Privacy & Data Protection Law"} +{"moduleCode":"ES5610","moduleCredit":0,"title":"Academic Communication for Business"} +{"moduleCode":"UD5221","moduleCredit":0,"title":"Theory and Elements of Urban Design"} +{"moduleCode":"LSM3262","moduleCredit":0,"title":"Environmental Animal Physiology"} +{"moduleCode":"SN6660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"LSM3265","moduleCredit":0,"title":"Entomology"} +{"moduleCode":"YIR4301G","moduleCredit":0,"title":"Special Project in Science"} +{"moduleCode":"BT5110","moduleCredit":0,"title":"Data Management and Warehousing"} +{"moduleCode":"LSM3266","moduleCredit":0,"title":"Avian Biology and Evolution"} +{"moduleCode":"LSM3267","moduleCredit":0,"title":"Behavioural Biology"} +{"moduleCode":"GEK1041","moduleCredit":0,"title":"Understanding Globalisation"} +{"moduleCode":"PR1111","moduleCredit":0,"title":"Pharmaceutical biochemistry"} +{"moduleCode":"GEK1045","moduleCredit":0,"title":"World Religions"} +{"moduleCode":"IPS3550","moduleCredit":0,"title":"Extended Political Science Internship"} +{"moduleCode":"PR1110","moduleCredit":0,"title":"Foundations for Medicinal Chemistry"} +{"moduleCode":"BT5126","moduleCredit":0,"title":"Hands-on with Business Analytics"} +{"moduleCode":"DMX1301","moduleCredit":0,"title":"DYOM via edX MOOC"} +{"moduleCode":"DMX1302","moduleCredit":0,"title":"DYOM via edX MOOC"} +{"moduleCode":"LSM3272","moduleCredit":0,"title":"Global Change Biology"} +{"moduleCode":"YIR4302G","moduleCredit":0,"title":"Special Project in Science"} +{"moduleCode":"EU1101E","moduleCredit":0,"title":"Making of Modern Europe"} +{"moduleCode":"GEK1054","moduleCredit":0,"title":"Social and Cultural Studies through Music"} +{"moduleCode":"TME2401","moduleCredit":0,"title":"Engineering Mathematics II"} +{"moduleCode":"GEK1055","moduleCredit":0,"title":"The Theatre Experience"} +{"moduleCode":"PR1120","moduleCredit":0,"title":"Microbiology in Pharmacy"} +{"moduleCode":"GSS6886","moduleCredit":0,"title":"NGS Seminars"} +{"moduleCode":"PR1140","moduleCredit":0,"title":"Pharmacy Professional Skills Development I"} +{"moduleCode":"IE5121","moduleCredit":0,"title":"Quality Planning And Management"} +{"moduleCode":"CH2141","moduleCredit":0,"title":"General History of China"} +{"moduleCode":"LL4045V","moduleCredit":0,"title":"Negotiation"} +{"moduleCode":"EN5241R","moduleCredit":0,"title":"Literature and New Worlds: 1590-1750"} +{"moduleCode":"LL4178V","moduleCredit":0,"title":"Law and Practice of Investment Treaties"} +{"moduleCode":"ST3232","moduleCredit":0,"title":"Design & Analysis of Experiments"} +{"moduleCode":"MUA5161","moduleCredit":0,"title":"Major Study 5A"} +{"moduleCode":"LL6317V","moduleCredit":0,"title":"International Arbitration in Asian Centres"} +{"moduleCode":"MUA5162","moduleCredit":0,"title":"Major Study 5B"} +{"moduleCode":"IE5123","moduleCredit":0,"title":"Reliability Engineering"} +{"moduleCode":"YCC2121","moduleCredit":0,"title":"Modern Social Thought"} +{"moduleCode":"CN4122E","moduleCredit":0,"title":"Process Synthesis and Simulation"} +{"moduleCode":"IS3150","moduleCredit":0,"title":"Digital Media Marketing"} +{"moduleCode":"MA2108S","moduleCredit":0,"title":"Mathematical Analysis I (S)"} +{"moduleCode":"BIS3001","moduleCredit":0,"title":"Independent Study Module in Business"} +{"moduleCode":"GEK1022","moduleCredit":0,"title":"Geopolitics:Geographies of War & Peace"} +{"moduleCode":"ME2114E","moduleCredit":0,"title":"Mechanics of Materials II"} +{"moduleCode":"PH6243","moduleCredit":0,"title":"Advanced Aesthetics"} +{"moduleCode":"EE4511","moduleCredit":0,"title":"Renewable Generation and Smart Grid"} +{"moduleCode":"ESE5203","moduleCredit":0,"title":"Aerosol Science and Technology"} +{"moduleCode":"PH6241","moduleCredit":0,"title":"Advanced Philosophical Logic"} +{"moduleCode":"PH6240","moduleCredit":0,"title":"Advanced Metaphysics"} +{"moduleCode":"PP5903","moduleCredit":0,"title":"International Political Economy"} +{"moduleCode":"ST3241","moduleCredit":0,"title":"Categorical Data Analysis I"} +{"moduleCode":"PP5902","moduleCredit":0,"title":"International Security - Concepts, Issues & Policies"} +{"moduleCode":"ST3240","moduleCredit":0,"title":"Multivariate Statistical Analysis"} +{"moduleCode":"PP5901","moduleCredit":0,"title":"Introduction to International Relations Theory"} +{"moduleCode":"LL4044V","moduleCredit":0,"title":"Mediation"} +{"moduleCode":"ST3242","moduleCredit":0,"title":"Introduction to Survival Analysis"} +{"moduleCode":"PP5906","moduleCredit":0,"title":"International Economic Development in Asia"} +{"moduleCode":"PP5905","moduleCredit":0,"title":"Foreign Policy Analysis"} +{"moduleCode":"PP5904","moduleCredit":0,"title":"Research Methods in International Affairs"} +{"moduleCode":"ESE5205","moduleCredit":0,"title":"Sludge and Solid Waste Management"} +{"moduleCode":"PP5909","moduleCredit":0,"title":"Geopolitics of the Asia-Pacific"} +{"moduleCode":"PP5908","moduleCredit":0,"title":"Global Governance in a Changing World"} +{"moduleCode":"CN4123E","moduleCredit":0,"title":"Design Project"} +{"moduleCode":"IE5108","moduleCredit":0,"title":"Facility Layout And Location"} +{"moduleCode":"ST3233","moduleCredit":0,"title":"Applied Time Series Analysis"} +{"moduleCode":"ST3236","moduleCredit":0,"title":"Stochastic Processes I"} +{"moduleCode":"GEK1035","moduleCredit":0,"title":"Nations & Nationalisms in South Asia"} +{"moduleCode":"ST3239","moduleCredit":0,"title":"Survey Methodology"} +{"moduleCode":"PP5910","moduleCredit":0,"title":"MIA Thesis"} +{"moduleCode":"CH2121","moduleCredit":0,"title":"History of Chinese Literature"} +{"moduleCode":"GEK1005","moduleCredit":0,"title":"Cultural Diversity in the Contemporary World"} +{"moduleCode":"GEK1007","moduleCredit":0,"title":"Chinese Heritage: History and Literature"} +{"moduleCode":"GEK1008","moduleCredit":0,"title":"Southeast Asia: A Changing Region"} +{"moduleCode":"ESP2107","moduleCredit":0,"title":"Numerical Methods and Statistics"} +{"moduleCode":"PP5911","moduleCredit":0,"title":"MIA Capstone Project"} +{"moduleCode":"SSB1204","moduleCredit":0,"title":"Singapore Employment Law"} +{"moduleCode":"ESP2106","moduleCredit":0,"title":"Principles of Continua"} +{"moduleCode":"IE5107","moduleCredit":0,"title":"Material Flow Systems"} +{"moduleCode":"EN1101E","moduleCredit":0,"title":"An Introduction to Literary Studies"} +{"moduleCode":"IE5105","moduleCredit":0,"title":"Modelling for Supply Chain Systems"} +{"moduleCode":"IFS4102","moduleCredit":0,"title":"Digital Forensics"} +{"moduleCode":"BT5151","moduleCredit":0,"title":"Foundation in Data Analytics II"} +{"moduleCode":"IFS4103","moduleCredit":0,"title":"Penetration Testing Practice"} +{"moduleCode":"BT5153","moduleCredit":0,"title":"Applied Machine Learning for Business Analytics"} +{"moduleCode":"FIN4112G","moduleCredit":0,"title":"SIF: Private Equity"} +{"moduleCode":"ID3125","moduleCredit":0,"title":"Colours, Materials & Finishing"} +{"moduleCode":"GEK1000","moduleCredit":0,"title":"An Introduction to Literary Studies"} +{"moduleCode":"ID3124","moduleCredit":0,"title":"Creative Communication & Design Argumentation"} +{"moduleCode":"EC5361R","moduleCredit":0,"title":"Labour Economics"} +{"moduleCode":"GEK1003","moduleCredit":0,"title":"Introduction to Politics"} +{"moduleCode":"GEK1018","moduleCredit":0,"title":"Economic Issues in the Developing World"} +{"moduleCode":"EN5242R","moduleCredit":0,"title":"Women Novelists"} +{"moduleCode":"FIN4112L","moduleCredit":0,"title":"SIF: Family Business & Wealth Management"} +{"moduleCode":"BAA6002","moduleCredit":0,"title":"Accounting Research Seminars II"} +{"moduleCode":"BAA6001","moduleCredit":0,"title":"Accounting Research Seminars I"} +{"moduleCode":"TEE3506","moduleCredit":0,"title":"Electrical Energy Systems"} +{"moduleCode":"DBA3711","moduleCredit":0,"title":"Stochastic Models in Management"} +{"moduleCode":"PL4501","moduleCredit":0,"title":"Integrated Thesis"} +{"moduleCode":"TEE3501","moduleCredit":0,"title":"Power Electronics"} +{"moduleCode":"YCC2137","moduleCredit":0,"title":"Scientific Inquiry 2"} +{"moduleCode":"DBA3712","moduleCredit":0,"title":"Dynamic Pricing & Revenue Management"} +{"moduleCode":"CP2202","moduleCredit":0,"title":"Work Experience Internship"} +{"moduleCode":"GEK1011","moduleCredit":0,"title":"The Nature of Language"} +{"moduleCode":"CP2201","moduleCredit":0,"title":"Journey of the Innovator"} +{"moduleCode":"ID5770","moduleCredit":0,"title":"Graduate Seminar Module in Industrial Design"} +{"moduleCode":"CH5213","moduleCredit":0,"title":"Cognitive Linguistics & Chinese Language"} +{"moduleCode":"PP5018","moduleCredit":0,"title":"Disaster Scenarios and Resilience Building"} +{"moduleCode":"CM1111","moduleCredit":0,"title":"Inorganic Chemistry 1"} +{"moduleCode":"PP5017","moduleCredit":0,"title":"Climate Change and Managing Uncertainty"} +{"moduleCode":"GSN6501","moduleCredit":0,"title":"Neuronal Signalling"} +{"moduleCode":"LL6002V","moduleCredit":0,"title":"Admiralty Law & Practice"} +{"moduleCode":"PP5016","moduleCredit":0,"title":"Environmental Threats and Management Response"} +{"moduleCode":"GSN6504","moduleCredit":0,"title":"Behavioral & Cognitive Neuroscience"} +{"moduleCode":"CH5210","moduleCredit":0,"title":"Chinese Lexical Semantics"} +{"moduleCode":"CH5211","moduleCredit":0,"title":"Seminar in Chinese Pragmatics"} +{"moduleCode":"CFG1002","moduleCredit":0,"title":"Career Catalyst"} +{"moduleCode":"LI5001","moduleCredit":0,"title":"Research Project"} +{"moduleCode":"ME2121","moduleCredit":0,"title":"Engineering Thermodynamics and Heat Transfer"} +{"moduleCode":"RE6005","moduleCredit":0,"title":"Real Estate Economics Research Seminar"} +{"moduleCode":"MUA5115","moduleCredit":0,"title":"Ensemble Study 5A"} +{"moduleCode":"MUA5116","moduleCredit":0,"title":"Ensemble Study 5B"} +{"moduleCode":"IT2002","moduleCredit":0,"title":"Database Technology and Management"} +{"moduleCode":"RE6004","moduleCredit":0,"title":"Research Methodology in Real Estate"} +{"moduleCode":"EE5801","moduleCredit":0,"title":"Electromagnetic Compatibility"} +{"moduleCode":"LL4359Z","moduleCredit":0,"title":"SIAC and Institutional Arbitration"} +{"moduleCode":"ASP1201MS","moduleCredit":0,"title":"H3 Humanities & Soc Sci Research Prog"} +{"moduleCode":"ESP2110","moduleCredit":0,"title":"Design Project 2"} +{"moduleCode":"DMY1401PSP","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"ME2134","moduleCredit":0,"title":"Fluid Mechanics I"} +{"moduleCode":"ME2135","moduleCredit":0,"title":"Intermediate Fluid Mechanics"} +{"moduleCode":"CM1131","moduleCredit":0,"title":"Physical Chemistry 1"} +{"moduleCode":"EE4502","moduleCredit":0,"title":"Electric Drives & Control"} +{"moduleCode":"EE4501","moduleCredit":0,"title":"Power System Management And Protection"} +{"moduleCode":"CH2162","moduleCredit":0,"title":"Reading Classical Chinese Texts"} +{"moduleCode":"EE5831","moduleCredit":0,"title":"Electromagnetic Wave Theory"} +{"moduleCode":"TG3002","moduleCredit":0,"title":"Industrial Practice"} +{"moduleCode":"CN4123R","moduleCredit":0,"title":"Final Year Design Project"} +{"moduleCode":"LL4358Z","moduleCredit":0,"title":"ICC Arbitration"} +{"moduleCode":"TG3001","moduleCredit":0,"title":"Industrial Practice"} +{"moduleCode":"EE4503","moduleCredit":0,"title":"Power Electronics for Sustainable Energy Technologies"} +{"moduleCode":"EE4509","moduleCredit":0,"title":"Silicon Micro Systems"} +{"moduleCode":"FIN3701B","moduleCredit":0,"title":"Corporate Finance"} +{"moduleCode":"FIN3701A","moduleCredit":0,"title":"Corporate Finance"} +{"moduleCode":"TE2101","moduleCredit":0,"title":"Programming Methodology"} +{"moduleCode":"PL3287","moduleCredit":0,"title":"Lab in Clinical/Abnormal Psychology"} +{"moduleCode":"ME2102","moduleCredit":0,"title":"Engineering Innovation and Modelling"} +{"moduleCode":"SW4202A","moduleCredit":0,"title":"Healthcare Issues and Policies"} +{"moduleCode":"ME2104","moduleCredit":0,"title":"Engineering Principles and Practice II"} +{"moduleCode":"CN4124E","moduleCredit":0,"title":"Final Year Design Project"} +{"moduleCode":"LL5242S","moduleCredit":0,"title":"Financial Regulation and Central Banking"} +{"moduleCode":"LAV2201","moduleCredit":0,"title":"Vietnamese 2"} +{"moduleCode":"PL3289","moduleCredit":0,"title":"Lab in Decision Science"} +{"moduleCode":"LL5242V","moduleCredit":0,"title":"Financial Regulation and Central Banking"} +{"moduleCode":"PC1143","moduleCredit":0,"title":"Introduction to Electricity & Magnetism"} +{"moduleCode":"PC1144","moduleCredit":0,"title":"Introduction to Modern Physics"} +{"moduleCode":"ST3244","moduleCredit":0,"title":"Demographic Methods"} +{"moduleCode":"PC1141","moduleCredit":0,"title":"Introduction to Classical Mechanics"} +{"moduleCode":"ST3247","moduleCredit":0,"title":"Simulation"} +{"moduleCode":"PC1142","moduleCredit":0,"title":"Introduction to Thermodynamics and Optics"} +{"moduleCode":"ST3246","moduleCredit":0,"title":"Statistical Models for Actuarial Science"} +{"moduleCode":"PL3284","moduleCredit":0,"title":"Lab in Applied Psychology (Scale Construction)"} +{"moduleCode":"ST3248","moduleCredit":0,"title":"Statistical Learning I"} +{"moduleCode":"MA5198","moduleCredit":0,"title":"Graduate Seminar Module in Mathematics"} +{"moduleCode":"PL3281","moduleCredit":0,"title":"Lab in Cognitive Psychology"} +{"moduleCode":"CG3207","moduleCredit":0,"title":"Computer Architecture"} +{"moduleCode":"PL3282","moduleCredit":0,"title":"Lab in Social Psychology"} +{"moduleCode":"CM1121","moduleCredit":0,"title":"Organic Chemistry 1"} +{"moduleCode":"CN3109","moduleCredit":0,"title":"Chemical Engineering Process Laboratory III"} +{"moduleCode":"CN3108","moduleCredit":0,"title":"Chemical Engineering Process Laboratory II"} +{"moduleCode":"LL6190","moduleCredit":0,"title":"Freedom of Speech: Critical & Comparative Perspectives"} +{"moduleCode":"LL4357V","moduleCredit":0,"title":"Regulation & Political Economy"} +{"moduleCode":"LL6191","moduleCredit":0,"title":"Wealth Management Law"} +{"moduleCode":"LAB3202","moduleCredit":0,"title":"Bahasa Indonesia 4"} +{"moduleCode":"ME2112","moduleCredit":0,"title":"Strength of Materials"} +{"moduleCode":"ME2114","moduleCredit":0,"title":"Mechanics of Materials"} +{"moduleCode":"LAB3201","moduleCredit":0,"title":"Bahasa Indonesia 3"} +{"moduleCode":"ME2115","moduleCredit":0,"title":"Mechanics Of Machines"} +{"moduleCode":"LL5243V","moduleCredit":0,"title":"Law, Economics, Development, and Geography"} +{"moduleCode":"BT2010","moduleCredit":0,"title":"Business Analytics Immersion Programme"} +{"moduleCode":"CN3102","moduleCredit":0,"title":"Chemical Engineering Process Lab II"} +{"moduleCode":"GS6889B","moduleCredit":0,"title":"Academic Skills and Research Ethics"} +{"moduleCode":"CH2161","moduleCredit":0,"title":"Traditional Chinese Taxonomy of Learning"} +{"moduleCode":"CN3101","moduleCredit":0,"title":"Chemical Engineering Process Lab I"} +{"moduleCode":"FIN3751","moduleCredit":0,"title":"Independent Study in Finance"} +{"moduleCode":"PC4230","moduleCredit":0,"title":"Quantum Mechanics III"} +{"moduleCode":"FE5221","moduleCredit":0,"title":"Trading Principles & Fundamentals"} +{"moduleCode":"FE5222","moduleCredit":0,"title":"Advanced Derivatives Pricing"} +{"moduleCode":"FE5223","moduleCredit":0,"title":"Introduction to Electronic Financial Market"} +{"moduleCode":"BS5770","moduleCredit":0,"title":"Graduate Seminar"} +{"moduleCode":"FE5224","moduleCredit":0,"title":"Current Topics In Applied Risk Management"} +{"moduleCode":"FE5225","moduleCredit":0,"title":"Machine Learning and FinTech"} +{"moduleCode":"LL4356V","moduleCredit":0,"title":"International Economic Law Clinic"} +{"moduleCode":"FIN3703B","moduleCredit":0,"title":"Financial Markets"} +{"moduleCode":"LL6006V","moduleCredit":0,"title":"Banking Law"} +{"moduleCode":"FAS2552","moduleCredit":0,"title":"FASS Extended Internship"} +{"moduleCode":"FAS2553","moduleCredit":0,"title":"Work Experience Internship"} +{"moduleCode":"FIN3703A","moduleCredit":0,"title":"Financial Markets"} +{"moduleCode":"LL5244V","moduleCredit":0,"title":"Criminal Practice"} +{"moduleCode":"GS6882A","moduleCredit":0,"title":"Biology of Disease"} +{"moduleCode":"ASP1201HY","moduleCredit":0,"title":"H3 Humanities & Soc Sci Research Prog"} +{"moduleCode":"BMA5102","moduleCredit":0,"title":"Legal Issues in Business"} +{"moduleCode":"PL3261","moduleCredit":0,"title":"Statistical Techniques in Psychological Research"} +{"moduleCode":"FAS2551","moduleCredit":0,"title":"FASS Internship"} +{"moduleCode":"EE4305E","moduleCredit":0,"title":"Introduction To Fuzzy/Neural Systems"} +{"moduleCode":"PC4240","moduleCredit":0,"title":"Solid State Physics II"} +{"moduleCode":"PC4241","moduleCredit":0,"title":"Statistical Mechanics"} +{"moduleCode":"LL6177","moduleCredit":0,"title":"Entertainment Law: Pop Iconography & Celebrity"} +{"moduleCode":"PC4242","moduleCredit":0,"title":"Electricity and Magnetism III"} +{"moduleCode":"CH5245","moduleCredit":0,"title":"Seminar in Early Taoism"} +{"moduleCode":"FIN3702C","moduleCredit":0,"title":"Investment Analysis and Portfolio Management"} +{"moduleCode":"FIN3702B","moduleCredit":0,"title":"Investment Analysis and Portfolio Management"} +{"moduleCode":"FIN3702A","moduleCredit":0,"title":"Investment Analysis and Portfolio Management"} +{"moduleCode":"NM1101X","moduleCredit":0,"title":"Communications, New Media and Society"} +{"moduleCode":"LL6172","moduleCredit":0,"title":"Japanese Corporate Law & Governance"} +{"moduleCode":"TIE4101","moduleCredit":0,"title":"B.Tech. Dissertation"} +{"moduleCode":"ME5205","moduleCredit":0,"title":"Energy Engineering"} +{"moduleCode":"NM1101E","moduleCredit":0,"title":"Communications, New Media and Society"} +{"moduleCode":"EE3104C","moduleCredit":0,"title":"Introduction to RF and Microwave Systems & Circuits"} +{"moduleCode":"ME5204","moduleCredit":0,"title":"Air Conditioning and Building Automation"} +{"moduleCode":"LL5245V","moduleCredit":0,"title":"Regulatory Foundations of Public Law"} +{"moduleCode":"GS6883A","moduleCredit":0,"title":"Interface Science and Engineering"} +{"moduleCode":"FE5226","moduleCredit":0,"title":"C++ in Financial Engineering"} +{"moduleCode":"FE5227","moduleCredit":0,"title":"Commodities: Fundamentals and Modelling"} +{"moduleCode":"PC4248","moduleCredit":0,"title":"General Relativity"} +{"moduleCode":"PC4249","moduleCredit":0,"title":"Astrophysics II"} +{"moduleCode":"PC4243","moduleCredit":0,"title":"Atomic & Molecular Physics II"} +{"moduleCode":"MA2101S","moduleCredit":0,"title":"Linear Algebra II (S)"} +{"moduleCode":"PC4245","moduleCredit":0,"title":"Particle Physics"} +{"moduleCode":"PC4246","moduleCredit":0,"title":"Quantum Optics"} +{"moduleCode":"UTW1001F","moduleCredit":0,"title":"The Internationalisation of Higher Education: Impact and Challenges"} +{"moduleCode":"EE4435E","moduleCredit":0,"title":"Modern Transistors and Memory Devices"} +{"moduleCode":"UTW1001D","moduleCredit":0,"title":"Self, Society, and the Digital Tsunami era"} +{"moduleCode":"UTW1001B","moduleCredit":0,"title":"What is a nation? Texts, images and national identity"} +{"moduleCode":"UTW1001C","moduleCredit":0,"title":"At the Edges of the Law: Ethics, Morality and Society"} +{"moduleCode":"LAK2201","moduleCredit":0,"title":"Korean 2"} +{"moduleCode":"PL3239","moduleCredit":0,"title":"Industrial and Organisational Psychology"} +{"moduleCode":"ESE2102","moduleCredit":0,"title":"Principles & Practice in Infrastructure and Environment"} +{"moduleCode":"ME6504","moduleCredit":0,"title":"Defects & Dislocations in Solids"} +{"moduleCode":"PL3244","moduleCredit":0,"title":"Adolescent Psychology"} +{"moduleCode":"UTW1001W","moduleCredit":0,"title":"The Online Politician: The Use of Social Media in Political Communication"} +{"moduleCode":"PL3241","moduleCredit":0,"title":"Personality & Individual Differences"} +{"moduleCode":"PL3242","moduleCredit":0,"title":"Health Psychology"} +{"moduleCode":"UTW1001S","moduleCredit":0,"title":"Women in Film"} +{"moduleCode":"ASP1201GE","moduleCredit":0,"title":"H3 Humanities & Soc Sci Research Prog"} +{"moduleCode":"ME6505","moduleCredit":0,"title":"Engineering Materials in Medicine"} +{"moduleCode":"UTW1001P","moduleCredit":0,"title":"Heroes"} +{"moduleCode":"CS2113T","moduleCredit":0,"title":"Software Engineering & Object-Oriented Programming"} +{"moduleCode":"ST3289","moduleCredit":0,"title":"Advanced UROPS in Statistics & Applied Probability II"} +{"moduleCode":"UTW1001N","moduleCredit":0,"title":"Public Persona and Self-presentations"} +{"moduleCode":"ST3288","moduleCredit":0,"title":"Advanced UROPS in Statistics & Applied Probability I"} +{"moduleCode":"LL5379V","moduleCredit":0,"title":"Future of Int'l Commercial Arbitration in APAC Region"} +{"moduleCode":"ME2142","moduleCredit":0,"title":"Feedback Control Systems"} +{"moduleCode":"PL3240","moduleCredit":0,"title":"Group Dynamics"} +{"moduleCode":"ME2143","moduleCredit":0,"title":"Sensors & Actuators"} +{"moduleCode":"ESP1104B","moduleCredit":0,"title":"Sensor System Electronics"} +{"moduleCode":"CH5224","moduleCredit":0,"title":"Prescribed Texts in Literature"} +{"moduleCode":"CH5225","moduleCredit":0,"title":"Topics in SE Asian Chinese Literature and Film"} +{"moduleCode":"CLC3301","moduleCredit":0,"title":"Communicating Social Issues in Singapore"} +{"moduleCode":"EE4303E","moduleCredit":0,"title":"Industrial Control Systems"} +{"moduleCode":"LL6029AV","moduleCredit":0,"title":"International Commercial Arbitration"} +{"moduleCode":"EE4436E","moduleCredit":0,"title":"Fabrication Process Technology"} +{"moduleCode":"CLC3303","moduleCredit":0,"title":"Community Leadership"} +{"moduleCode":"FE5211","moduleCredit":0,"title":"Seminar In Financial Engineering"} +{"moduleCode":"FIN3720","moduleCredit":0,"title":"Financial Statement Analysis"} +{"moduleCode":"CLC3302","moduleCredit":0,"title":"Diversity and Inclusion"} +{"moduleCode":"CH5222","moduleCredit":0,"title":"Topics in Modern Chinese Literature"} +{"moduleCode":"CH5223","moduleCredit":0,"title":"Selected Authors"} +{"moduleCode":"LL6009V","moduleCredit":0,"title":"Chinese Legal Tradition And Legal Chinese"} +{"moduleCode":"UTW1001Z","moduleCredit":0,"title":"Colour: Theory, meaning and practice"} +{"moduleCode":"PL3252","moduleCredit":0,"title":"Social-Cognitive Perspectives on Emotion"} +{"moduleCode":"PL3257","moduleCredit":0,"title":"Introduction to Clinical Psychology"} +{"moduleCode":"ME2151","moduleCredit":0,"title":"Principles of Mechanical Eng. Materials"} +{"moduleCode":"PC4228","moduleCredit":0,"title":"Device Physics for Quantum Technology"} +{"moduleCode":"FE5208","moduleCredit":0,"title":"Term Structure and Interest Rate Derivatives"} +{"moduleCode":"PL3250","moduleCredit":0,"title":"Human Performance"} +{"moduleCode":"FE5209","moduleCredit":0,"title":"Financial Econometrics"} +{"moduleCode":"PL3251","moduleCredit":0,"title":"Atypical Development and Language"} +{"moduleCode":"RE4212","moduleCredit":0,"title":"Real Estate Securitization"} +{"moduleCode":"MUA2131","moduleCredit":0,"title":"Contemporary Music Performance"} +{"moduleCode":"RE4213","moduleCredit":0,"title":"Real Estate Risk Analysis and Management"} +{"moduleCode":"EB5201","moduleCredit":0,"title":"Campaign Management"} +{"moduleCode":"PC4274","moduleCredit":0,"title":"Mathematical Methods in Physics III"} +{"moduleCode":"RE4210","moduleCredit":0,"title":"Real Estate Finance Seminar"} +{"moduleCode":"RE4211","moduleCredit":0,"title":"Reit Management"} +{"moduleCode":"EB5203","moduleCredit":0,"title":"Customer Relationship Management"} +{"moduleCode":"EB5202","moduleCredit":0,"title":"Web Analytics"} +{"moduleCode":"EB5205","moduleCredit":0,"title":"Clinical Health Analytics"} +{"moduleCode":"FIN3711","moduleCredit":0,"title":"International Financial Management"} +{"moduleCode":"EB5204","moduleCredit":0,"title":"New Media and Sentiment Mining"} +{"moduleCode":"GE4219","moduleCredit":0,"title":"Development and Environment in Southeast Asia"} +{"moduleCode":"PH3203","moduleCredit":0,"title":"Moral Philosophy"} +{"moduleCode":"SPH5307","moduleCredit":0,"title":"Principles of Workplace Health"} +{"moduleCode":"PH3201","moduleCredit":0,"title":"Philosophy of Social Science"} +{"moduleCode":"BN5514","moduleCredit":0,"title":"Medical Device Regulatory Process Strategy and Planning"} +{"moduleCode":"PH3207","moduleCredit":0,"title":"Continental European Philosophy"} +{"moduleCode":"TR3204S","moduleCredit":0,"title":"Entrepreneurship Practicum (Short)"} +{"moduleCode":"BN5513","moduleCredit":0,"title":"Medical Device Regulation in ASEAN and AsiaPacific"} +{"moduleCode":"TR3204T","moduleCredit":0,"title":"Entrepreneurship Practicum (Short)"} +{"moduleCode":"BN5512","moduleCredit":0,"title":"Medical Device Regulation in the US and EU"} +{"moduleCode":"GE4217","moduleCredit":0,"title":"Political Geographies: Space and Power"} +{"moduleCode":"BN5511","moduleCredit":0,"title":"Introduction to Global Medical Device Regulation"} +{"moduleCode":"PH3206","moduleCredit":0,"title":"Recent Philosophy"} +{"moduleCode":"GE4222","moduleCredit":0,"title":"Advanced Geomorphology"} +{"moduleCode":"GE4223","moduleCredit":0,"title":"Development of Geographic Thought"} +{"moduleCode":"SPH5301","moduleCredit":0,"title":"Occupational Health Practice"} +{"moduleCode":"GE4225","moduleCredit":0,"title":"Young People and Children: Global Perspectives"} +{"moduleCode":"SPH5302","moduleCredit":0,"title":"Occupational Toxicology and Industrial Hygiene"} +{"moduleCode":"SSA2222","moduleCredit":0,"title":"Public Administration in Singapore"} +{"moduleCode":"LL5074V","moduleCredit":0,"title":"Mergers & Acquisitions"} +{"moduleCode":"SPH5305","moduleCredit":0,"title":"Clinical Occupational Medicine"} +{"moduleCode":"GE4221","moduleCredit":0,"title":"Field Investigation in Human Geography"} +{"moduleCode":"FIN3713","moduleCredit":0,"title":"Bank Management"} +{"moduleCode":"MUH3203","moduleCredit":0,"title":"The Evolution of Music for the Stage"} +{"moduleCode":"FIN3712","moduleCredit":0,"title":"Options and Futures"} +{"moduleCode":"FIN3715","moduleCredit":0,"title":"Risk and Insurance"} +{"moduleCode":"LAT1201","moduleCredit":0,"title":"Thai 1"} +{"moduleCode":"FIN3714","moduleCredit":0,"title":"Financial Risk Management"} +{"moduleCode":"FIN3717","moduleCredit":0,"title":"Fixed Income Securities"} +{"moduleCode":"FIN3716","moduleCredit":0,"title":"Financial Modelling"} +{"moduleCode":"FIN3719","moduleCredit":0,"title":"Household Finance"} +{"moduleCode":"MUH3205","moduleCredit":0,"title":"Chamber Music Since 1740"} +{"moduleCode":"LL6094CV","moduleCredit":0,"title":"Law & Practice - The Law Clinic"} +{"moduleCode":"BSN4811","moduleCredit":0,"title":"Innovation and Productivity"} +{"moduleCode":"RE4223","moduleCredit":0,"title":"Urban Planning in Asian Cities"} +{"moduleCode":"RE4221","moduleCredit":0,"title":"Advanced Urban Planning Theories and Practice"} +{"moduleCode":"LL4405A","moduleCredit":0,"title":"Law of Intellectual Property (a)"} +{"moduleCode":"RE4222","moduleCredit":0,"title":"Public Policy and Real Estate Markets"} +{"moduleCode":"YLS3202","moduleCredit":0,"title":"Advanced Spanish: Latin America, Borders and Identities"} +{"moduleCode":"LL6140V","moduleCredit":0,"title":"Law of the Sea: Theory and Practice"} +{"moduleCode":"EE3408C","moduleCredit":0,"title":"Integrated Analog Design"} +{"moduleCode":"PH3213","moduleCredit":0,"title":"Knowledge, Modernity and Global Change"} +{"moduleCode":"GE4226","moduleCredit":0,"title":"Mobile Spaces: Making Social Worlds"} +{"moduleCode":"YHU2293","moduleCredit":0,"title":"Introduction to Fiction Writing"} +{"moduleCode":"GE4227","moduleCredit":0,"title":"Climate Change: Processes, Impact and Responses"} +{"moduleCode":"SSA2220","moduleCredit":0,"title":"Global Economic Dimensions of Singapore"} +{"moduleCode":"YHU2294","moduleCredit":0,"title":"Mean Streets: The Detective and the City"} +{"moduleCode":"GE4228","moduleCredit":0,"title":"Gender and the City"} +{"moduleCode":"EE3408E","moduleCredit":0,"title":"Integrated Analog Design"} +{"moduleCode":"GE4229","moduleCredit":0,"title":"Earth Systems Science"} +{"moduleCode":"GE4233","moduleCredit":0,"title":"Geography in the Contemporary World"} +{"moduleCode":"GE4230","moduleCredit":0,"title":"Greater China"} +{"moduleCode":"NM5660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"SSA2214","moduleCredit":0,"title":"Singapore and India: Emerging Relations"} +{"moduleCode":"SSA2215","moduleCredit":0,"title":"The Biophysical Environment of Singapore"} +{"moduleCode":"FIN3702","moduleCredit":0,"title":"Investment Analysis and Portfolio Management"} +{"moduleCode":"FIN3701","moduleCredit":0,"title":"Corporate Finance"} +{"moduleCode":"BMA5017","moduleCredit":0,"title":"Managerial Operations and Analytics"} +{"moduleCode":"SSA2218","moduleCredit":0,"title":"Singapore Film: Performance of Identity"} +{"moduleCode":"BMA5016","moduleCredit":0,"title":"Leading with Impact"} +{"moduleCode":"SSA2219","moduleCredit":0,"title":"South Asia in Singapore"} +{"moduleCode":"BMA5013","moduleCredit":0,"title":"Corporate Strategy"} +{"moduleCode":"MUA2110","moduleCredit":0,"title":"Chamber Music in Mixed Ensemble"} +{"moduleCode":"PC4253","moduleCredit":0,"title":"Thin Film Technology"} +{"moduleCode":"LSM1401","moduleCredit":0,"title":"Fundamentals of Biochemistry"} +{"moduleCode":"PH4550","moduleCredit":0,"title":"Internship: Philosophy for Teaching"} +{"moduleCode":"PS5312R","moduleCredit":0,"title":"Seminar in Comparative Politics"} +{"moduleCode":"EN2202","moduleCredit":0,"title":"Critical Reading"} +{"moduleCode":"SWD5286","moduleCredit":0,"title":"Common Psychiatric Disorders in Adults"} +{"moduleCode":"TR3202S","moduleCredit":0,"title":"Start-up Internship Programme"} +{"moduleCode":"EN2201","moduleCredit":0,"title":"Backgrounds to Western Literature and Culture"} +{"moduleCode":"TR3202T","moduleCredit":0,"title":"Start-up Internship Programme"} +{"moduleCode":"EN2203","moduleCredit":0,"title":"Introduction to Film Studies"} +{"moduleCode":"BN4203","moduleCredit":0,"title":"Robotics in Rehabilitation"} +{"moduleCode":"BN4202","moduleCredit":0,"title":"Biofluids Dynamics"} +{"moduleCode":"EN2207","moduleCredit":0,"title":"Gender and Sexuality in Literature"} +{"moduleCode":"MLE4201","moduleCredit":0,"title":"Advanced Materials Characterisation"} +{"moduleCode":"SSA2202","moduleCredit":0,"title":"Changing Landscapes of Singapore"} +{"moduleCode":"TR3202N","moduleCredit":0,"title":"Start-up Internship Programme"} +{"moduleCode":"MLE4202","moduleCredit":0,"title":"Selected Advanced Topics on Polymers"} +{"moduleCode":"BMA5008","moduleCredit":0,"title":"Financial Management"} +{"moduleCode":"SSA2206","moduleCredit":0,"title":"Islam and Contemporary Malay Society"} +{"moduleCode":"MUA2109","moduleCredit":0,"title":"Chamber Music"} +{"moduleCode":"BMA5009","moduleCredit":0,"title":"Marketing Management"} +{"moduleCode":"LL5076V","moduleCredit":0,"title":"IT Law I"} +{"moduleCode":"MUA2108","moduleCredit":0,"title":"Large Ensembles 2B"} +{"moduleCode":"MLE4208","moduleCredit":0,"title":"Photovoltaics Materials"} +{"moduleCode":"SSA2209","moduleCredit":0,"title":"Government and Politics of Singapore"} +{"moduleCode":"BMA5003","moduleCredit":0,"title":"Financial Accounting"} +{"moduleCode":"SSA2207","moduleCredit":0,"title":"Politics in Southeast Asia"} +{"moduleCode":"MLE4205","moduleCredit":0,"title":"Theory and Modelling of Materials Properties"} +{"moduleCode":"UIS3911PS","moduleCredit":0,"title":"Independent Study Module"} +{"moduleCode":"BMA5002","moduleCredit":0,"title":"Analytics For Managers"} +{"moduleCode":"MLE4206","moduleCredit":0,"title":"Current topics on Nanomaterials"} +{"moduleCode":"BMA5001","moduleCredit":0,"title":"Managerial Economics"} +{"moduleCode":"TEE4001","moduleCredit":0,"title":"BTech Dissertation"} +{"moduleCode":"PC4262","moduleCredit":0,"title":"Remote Sensing"} +{"moduleCode":"YSS4206C","moduleCredit":0,"title":"Topics in Psychology: The Pursuit of Happiness"} +{"moduleCode":"PH3230","moduleCredit":0,"title":"Normative Ethical Theory"} +{"moduleCode":"RE4203","moduleCredit":0,"title":"Topics in Real Estate (Summer Programme)"} +{"moduleCode":"RE4204","moduleCredit":0,"title":"Advanced Real Estate Marketing"} +{"moduleCode":"MUA2107","moduleCredit":0,"title":"Large Ensembles 2A"} +{"moduleCode":"BDC6306","moduleCredit":0,"title":"Stochastic Processes II"} +{"moduleCode":"TR3203T","moduleCredit":0,"title":"Start-up Case Study & Analysis"} +{"moduleCode":"ESE3401","moduleCredit":0,"title":"Sustainable Urban Water Technologies"} +{"moduleCode":"MUA2102","moduleCredit":0,"title":"Composition Major Study 2B"} +{"moduleCode":"MUA2101","moduleCredit":0,"title":"Composition Major Study 2A"} +{"moduleCode":"TR3203P","moduleCredit":0,"title":"Start-up Case Study & Analysis"} +{"moduleCode":"TR3203N","moduleCredit":0,"title":"Start-up Case Study & Analysis"} +{"moduleCode":"MLE4212","moduleCredit":0,"title":"Advanced Structural Materials"} +{"moduleCode":"SPH5311","moduleCredit":0,"title":"Workplace Safety and Health"} +{"moduleCode":"MLE4213","moduleCredit":0,"title":"Innovation & Product Development for Material Engineers"} +{"moduleCode":"SPH5312","moduleCredit":0,"title":"Assessment and Control of Occupational Hazards"} +{"moduleCode":"MLE4210","moduleCredit":0,"title":"Materials for energy storage and conversion"} +{"moduleCode":"TR3203E","moduleCredit":0,"title":"Start-up Case Study & Analysis"} +{"moduleCode":"CE5104A","moduleCredit":0,"title":"Tunnelling in Soils"} +{"moduleCode":"PC4267","moduleCredit":0,"title":"Biophysics III"} +{"moduleCode":"YSS3220","moduleCredit":0,"title":"Political Economy"} +{"moduleCode":"CE5104B","moduleCredit":0,"title":"Tunnelling in Rocks"} +{"moduleCode":"YSS3221","moduleCredit":0,"title":"Politics of Southeast Asia"} +{"moduleCode":"BT2102","moduleCredit":0,"title":"Data Management and Visualisation"} +{"moduleCode":"YHU2268","moduleCredit":0,"title":"Money"} +{"moduleCode":"BT2101","moduleCredit":0,"title":"Decision Making Methods and Tools"} +{"moduleCode":"EN3551","moduleCredit":0,"title":"FASS Undergraduate Research Opportunity (UROP)"} +{"moduleCode":"PF2306","moduleCredit":0,"title":"Event Management Case Studies"} +{"moduleCode":"PF2305","moduleCredit":0,"title":"Event Management"} +{"moduleCode":"YHU2260","moduleCredit":0,"title":"Late 20th Century French Philosophy"} +{"moduleCode":"YSS3225","moduleCredit":0,"title":"Global Governance"} +{"moduleCode":"PF2304","moduleCredit":0,"title":"Operations and Maintenance Management"} +{"moduleCode":"YSS3222","moduleCredit":0,"title":"Urban Theory"} +{"moduleCode":"UIS3911NM","moduleCredit":0,"title":"Independent Study Module"} +{"moduleCode":"HY4660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"YSS3219","moduleCredit":0,"title":"Developmental Psychology"} +{"moduleCode":"CE5312","moduleCredit":0,"title":"River Mechanics"} +{"moduleCode":"CE5314","moduleCredit":0,"title":"HEWRM Project"} +{"moduleCode":"EE5064","moduleCredit":0,"title":"Dynamics and Control of Robot Manipulators"} +{"moduleCode":"LL6219","moduleCredit":0,"title":"The Trial of Jesus in Western Legal Thought"} +{"moduleCode":"EC3880F","moduleCredit":0,"title":"Topics in Economics: Miracle and Crisis in East Asia"} +{"moduleCode":"YSS3231","moduleCredit":0,"title":"Methods in the Social Sciences"} +{"moduleCode":"PP5105","moduleCredit":0,"title":"Cost Benefit Analysis in Public Policy"} +{"moduleCode":"LAF3202","moduleCredit":0,"title":"French 4"} +{"moduleCode":"LL6011V","moduleCredit":0,"title":"Civil Justice & Process"} +{"moduleCode":"CE5310","moduleCredit":0,"title":"Hydroinformatics"} +{"moduleCode":"LAF3201","moduleCredit":0,"title":"French 3"} +{"moduleCode":"LL6214","moduleCredit":0,"title":"International and Comparative Oil and Gas Law"} +{"moduleCode":"YSS3238","moduleCredit":0,"title":"US Foreign Policy"} +{"moduleCode":"YSS3235","moduleCredit":0,"title":"Urban Spatial Representation"} +{"moduleCode":"YSS3236","moduleCredit":0,"title":"Foreign Policy and Diplomacy: Issues and Practice"} +{"moduleCode":"SE5294R","moduleCredit":0,"title":"The Politics of Environment in Se Asia"} +{"moduleCode":"YHU2252","moduleCredit":0,"title":"Ancient Greek Philosophy"} +{"moduleCode":"CE5308","moduleCredit":0,"title":"Coastal Processes & Sediment Transport"} +{"moduleCode":"CN5666","moduleCredit":0,"title":"Industrial Attachment"} +{"moduleCode":"CN6999","moduleCredit":0,"title":"Doctoral Seminars"} +{"moduleCode":"CE5106A","moduleCredit":0,"title":"Ground Improvement for Soft Soils"} +{"moduleCode":"CE5106B","moduleCredit":0,"title":"Advanced Ground Improvement for Difficult Ground"} +{"moduleCode":"SC6770","moduleCredit":0,"title":"Graduate Research Seminar"} +{"moduleCode":"LL6012V","moduleCredit":0,"title":"Comparative Constitutional Law"} +{"moduleCode":"LL6203","moduleCredit":0,"title":"International Moots and Other Competitions"} +{"moduleCode":"YSS3206","moduleCredit":0,"title":"Law and Economics"} +{"moduleCode":"YHU2287","moduleCredit":0,"title":"Neo-Confucianism and Chinese Buddhism"} +{"moduleCode":"AR5221","moduleCredit":0,"title":"Contemporary Theories"} +{"moduleCode":"DMB1203FIN","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"GL4102","moduleCredit":0,"title":"Task Force"} +{"moduleCode":"YSS3205","moduleCredit":0,"title":"International Trade"} +{"moduleCode":"GL4101","moduleCredit":0,"title":"Research in Global Issues"} +{"moduleCode":"YHU2282","moduleCredit":0,"title":"Can Consciousness Be Explained?"} +{"moduleCode":"YSS3203","moduleCredit":0,"title":"Behavioral Economics"} +{"moduleCode":"YSS3201","moduleCredit":0,"title":"International Migration"} +{"moduleCode":"YHU2291","moduleCredit":0,"title":"Introduction to Arts"} +{"moduleCode":"YHU2292","moduleCredit":0,"title":"Introduction to Writing Poetry"} +{"moduleCode":"GEM1535","moduleCredit":0,"title":"Clean Energy and Storage"} +{"moduleCode":"GEM1536","moduleCredit":0,"title":"Darwin and Evolution"} +{"moduleCode":"EG2401","moduleCredit":0,"title":"Engineering Professionalism"} +{"moduleCode":"CE5107B","moduleCredit":0,"title":"Pile Foundation Problems and EC7 Impact"} +{"moduleCode":"CE5107A","moduleCredit":0,"title":"Principles of Pile Foundation Design"} +{"moduleCode":"SC4101","moduleCredit":0,"title":"Practising Anthropology and Sociology"} +{"moduleCode":"YSS3218","moduleCredit":0,"title":"Urban ASEAN: The Changing Southeast Asian City"} +{"moduleCode":"YSS3214","moduleCredit":0,"title":"Abnormal Psychology"} +{"moduleCode":"DE4201","moduleCredit":0,"title":"Seminars in Sustainable Cities"} +{"moduleCode":"YSS3212","moduleCredit":0,"title":"Chinese Politics"} +{"moduleCode":"CL2103","moduleCredit":0,"title":"Chinese Grammar"} +{"moduleCode":"CL2102","moduleCredit":0,"title":"Chinese Phonetics"} +{"moduleCode":"LL5251V","moduleCredit":0,"title":"International Humanitarian Law"} +{"moduleCode":"YSS3208","moduleCredit":0,"title":"Advanced Microeconomics"} +{"moduleCode":"CL2104","moduleCredit":0,"title":"Reading/Writing Chinese"} +{"moduleCode":"EB5207","moduleCredit":0,"title":"Service Analytics"} +{"moduleCode":"EB5206","moduleCredit":0,"title":"Supply Chain Analytics"} +{"moduleCode":"CE5108A","moduleCredit":0,"title":"Lateral Earth Pressures and Retaining Wall Design via Eurocode 7"} +{"moduleCode":"EB5208","moduleCredit":0,"title":"Geospatial Analytics"} +{"moduleCode":"CE5108B","moduleCredit":0,"title":"Deep Excavations Design Using Eurocode 7"} +{"moduleCode":"TME4102","moduleCredit":0,"title":"B.Tech. Dissertation"} +{"moduleCode":"YSS3264","moduleCredit":0,"title":"Bubbles, Crashes, Panics and Crises"} +{"moduleCode":"MA3310","moduleCredit":0,"title":"Undergraduate Professional Internship Programme"} +{"moduleCode":"YSS3263","moduleCredit":0,"title":"Emotions and Politics"} +{"moduleCode":"MA3312","moduleCredit":0,"title":"Enhanced Undergraduate Professional Internship Programme"} +{"moduleCode":"GEK1900","moduleCredit":0,"title":"Public Health in Action"} +{"moduleCode":"MA3311","moduleCredit":0,"title":"Undergraduate Professional Internship Programme"} +{"moduleCode":"YHU2222","moduleCredit":0,"title":"Digital Narratives"} +{"moduleCode":"YHU2223","moduleCredit":0,"title":"Documentary Photography"} +{"moduleCode":"LC1016","moduleCredit":0,"title":"Legal Analysis, Research & Communication"} +{"moduleCode":"LC1015","moduleCredit":0,"title":"Singapore Law in Context"} +{"moduleCode":"CH5211R","moduleCredit":0,"title":"Seminar In Chinese Pragmatics"} +{"moduleCode":"BN2403","moduleCredit":0,"title":"Fundamentals of Biosignals and Bioinstrumentation"} +{"moduleCode":"LSM3201","moduleCredit":0,"title":"Research and Communication in Life Sciences"} +{"moduleCode":"EE5022","moduleCredit":0,"title":"Cyber Security for Internet of Things"} +{"moduleCode":"PR4207","moduleCredit":0,"title":"Applied Pharmacokinetics and Toxicokinetics"} +{"moduleCode":"ST5241A","moduleCredit":0,"title":"Topics IA"} +{"moduleCode":"EE5021","moduleCredit":0,"title":"Cloud based Services for Internet of Things"} +{"moduleCode":"CN6163","moduleCredit":0,"title":"Inorganic Nanomaterials for Sustainability"} +{"moduleCode":"EE5020","moduleCredit":0,"title":"Data Science for Internet of Things"} +{"moduleCode":"PR4205","moduleCredit":0,"title":"Bioorganic Principles of Medicinal Chemistry"} +{"moduleCode":"CN6162","moduleCredit":0,"title":"Advanced Polymeric Materials"} +{"moduleCode":"EC2383","moduleCredit":0,"title":"Environmental Economics"} +{"moduleCode":"EE5026","moduleCredit":0,"title":"Machine Learning for Data Analytics"} +{"moduleCode":"EE5025","moduleCredit":0,"title":"Intellectual Property: Innovations in IoT"} +{"moduleCode":"EE5024","moduleCredit":0,"title":"IoT Sensor Networks"} +{"moduleCode":"PR4201","moduleCredit":0,"title":"Pharmaceutical Marketing"} +{"moduleCode":"EE5023","moduleCredit":0,"title":"Wireless Networks"} +{"moduleCode":"YHU2218","moduleCredit":0,"title":"Chinese Migrations to Southeast Asia"} +{"moduleCode":"YSS3273","moduleCredit":0,"title":"Geospatial & Demographic Methods"} +{"moduleCode":"YSS3274","moduleCredit":0,"title":"Urban Singapore"} +{"moduleCode":"DMB1204ACC","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"YHU2215","moduleCredit":0,"title":"Drawing Methods"} +{"moduleCode":"YHU2212","moduleCredit":0,"title":"Classical Chinese"} +{"moduleCode":"YSS3279","moduleCredit":0,"title":"Social Psychology Lab"} +{"moduleCode":"LC1004","moduleCredit":0,"title":"Law Of Torts"} +{"moduleCode":"LC1003","moduleCredit":0,"title":"Law Of Contract"} +{"moduleCode":"YSS3277","moduleCredit":0,"title":"The Anthropological Imagination"} +{"moduleCode":"YSS3278","moduleCredit":0,"title":"Social Psychology"} +{"moduleCode":"CH5210R","moduleCredit":0,"title":"Chinese Lexical Semantics"} +{"moduleCode":"LSM3211","moduleCredit":0,"title":"Fundamental Pharmacology"} +{"moduleCode":"LSM3212","moduleCredit":0,"title":"Human Physiology: Cardiopulmonary System"} +{"moduleCode":"LL6094V","moduleCredit":0,"title":"Law & Practice - The Law Clinic"} +{"moduleCode":"LSM3214","moduleCredit":0,"title":"Human Physiology - Hormones and Health"} +{"moduleCode":"LSM3215","moduleCredit":0,"title":"Neuronal Signaling and Memory Mechanisms"} +{"moduleCode":"SN2213","moduleCredit":0,"title":"Governance and Politics in South Asia"} +{"moduleCode":"LSM3216","moduleCredit":0,"title":"Neuronal Development and Diseases"} +{"moduleCode":"LSM3217","moduleCredit":0,"title":"Human Ageing"} +{"moduleCode":"LSM3219","moduleCredit":0,"title":"Neuropharmacology"} +{"moduleCode":"DMB1203DO","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"PHS1120","moduleCredit":0,"title":"Essential Topics in Pharmaceutical Chemistry"} +{"moduleCode":"YSS3241","moduleCredit":0,"title":"Chinese Political Philosophy: Confucianism & its Rivals"} +{"moduleCode":"FSC4206","moduleCredit":0,"title":"Advanced Criminal Litigation – Forensics on Trial"} +{"moduleCode":"YHU2248","moduleCredit":0,"title":"Introduction to 2D Animation"} +{"moduleCode":"YSS3248","moduleCredit":0,"title":"Advanced Macroeconomics"} +{"moduleCode":"YSS3249","moduleCredit":0,"title":"Human Neuroscience"} +{"moduleCode":"YSS3246","moduleCredit":0,"title":"Cities of the Global South"} +{"moduleCode":"CH5213R","moduleCredit":0,"title":"Cognitive Linguistics & Chinese Language"} +{"moduleCode":"YSS3245","moduleCredit":0,"title":"Key Debates in Urban Planning and Policy"} +{"moduleCode":"CS2040","moduleCredit":0,"title":"Data Structures and Algorithms"} +{"moduleCode":"TIC2601","moduleCredit":0,"title":"Database and Web Applications"} +{"moduleCode":"CE5377","moduleCredit":0,"title":"Numerical Methods in Mechanics & Envr. Flows"} +{"moduleCode":"SN3550","moduleCredit":0,"title":"Internship"} +{"moduleCode":"UPI2213","moduleCredit":0,"title":"Making Sense of Colonial Ideology and Its Legacies"} +{"moduleCode":"YSS3254","moduleCredit":0,"title":"Globalization on the Ground"} +{"moduleCode":"EN2271","moduleCredit":0,"title":"Introduction to Playwriting"} +{"moduleCode":"LL4050V","moduleCredit":0,"title":"Public International Law"} +{"moduleCode":"EE5027","moduleCredit":0,"title":"Statistical Pattern Recognition"} +{"moduleCode":"PR5234A","moduleCredit":0,"title":"Concepts in Pharmacogenomics"} +{"moduleCode":"YSS3250","moduleCredit":0,"title":"Cityscapes and Urban Form"} +{"moduleCode":"LL6097V","moduleCredit":0,"title":"Islamic Law"} +{"moduleCode":"FST3310","moduleCredit":0,"title":"Undergraduate Professional Internship Programme"} +{"moduleCode":"EN2276","moduleCredit":0,"title":"Literature, Media and Theory"} +{"moduleCode":"FST3311","moduleCredit":0,"title":"Undergraduate Professional Internship Programme"} +{"moduleCode":"MS4660","moduleCredit":0,"title":"Independent Study Module"} +{"moduleCode":"YSS3258","moduleCredit":0,"title":"Early Stage Private Equity Investing"} +{"moduleCode":"YSS3255","moduleCredit":0,"title":"International Development"} +{"moduleCode":"JS4660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"CS2030","moduleCredit":0,"title":"Programming Methodology II"} +{"moduleCode":"SN2234","moduleCredit":0,"title":"Gender and Society in South Asia"} +{"moduleCode":"UAR2208","moduleCredit":0,"title":"From Lab to Stage: Writing the Science Play"} +{"moduleCode":"UAR2207","moduleCredit":0,"title":"Intercultural Exchanges through Theatre"} +{"moduleCode":"SPH2201","moduleCredit":0,"title":"Health of the Poor in Asia"} +{"moduleCode":"UPI2212","moduleCredit":0,"title":"Technologies of the Self: from Socrates to Self-Help"} +{"moduleCode":"EC6770","moduleCredit":0,"title":"Graduate Research Seminar"} +{"moduleCode":"UPI2211","moduleCredit":0,"title":"Utopia: Ideal Places from Plato to the Smart City"} +{"moduleCode":"BZD6011","moduleCredit":0,"title":"Advanced Quantitative Research Methods"} +{"moduleCode":"YIR3412G","moduleCredit":0,"title":"Independent Language Study and Research"} +{"moduleCode":"BZD6012","moduleCredit":0,"title":"Experimental Methods for Behavioral Research"} +{"moduleCode":"EN6660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"BZD6010","moduleCredit":0,"title":"Seminar in Research Methodology"} +{"moduleCode":"PH3243","moduleCredit":0,"title":"Chance and Uncertainty"} +{"moduleCode":"BMF5323","moduleCredit":0,"title":"Accounting for Finance Professionals"} +{"moduleCode":"BMF5322","moduleCredit":0,"title":"Introduction to Finance"} +{"moduleCode":"PH3245","moduleCredit":0,"title":"Language and Thought"} +{"moduleCode":"BMF5321","moduleCredit":0,"title":"Financial Modelling"} +{"moduleCode":"IE2130","moduleCredit":0,"title":"Quality Engineering I"} +{"moduleCode":"BN1111","moduleCredit":0,"title":"Biomedical Engineering Principles and Practice I"} +{"moduleCode":"BMA5903","moduleCredit":0,"title":"MBA Internship"} +{"moduleCode":"BMA5902","moduleCredit":0,"title":"Entrepreneurship Practicum"} +{"moduleCode":"LSM3241","moduleCredit":0,"title":"Genomic Data Analysis"} +{"moduleCode":"SE3214","moduleCredit":0,"title":"Heritage and Heritagescapes in Southeast Asia"} +{"moduleCode":"LSM3242","moduleCredit":0,"title":"Translational Microbiology"} +{"moduleCode":"LSM3243","moduleCredit":0,"title":"Molecular Biophysics"} +{"moduleCode":"LC5285V","moduleCredit":0,"title":"International Dispute Settlement"} +{"moduleCode":"LSM3244","moduleCredit":0,"title":"Molecular Biotechnology"} +{"moduleCode":"BMA5901","moduleCredit":0,"title":"MBA Consulting Project"} +{"moduleCode":"LSM3245","moduleCredit":0,"title":"RNA Biology and Technology"} +{"moduleCode":"LSM3246","moduleCredit":0,"title":"Synthetic Biology"} +{"moduleCode":"SE3211","moduleCredit":0,"title":"Religion, Society & Politics in SE Asia"} +{"moduleCode":"EE6310","moduleCredit":0,"title":"Communication Networking Fundamentals (Advanced)"} +{"moduleCode":"LSM3247","moduleCredit":0,"title":"Practical Synthetic Biology"} +{"moduleCode":"ESE5402B","moduleCredit":0,"title":"Biotechnologies for Industrial Wastewater Control"} +{"moduleCode":"ESE5402A","moduleCredit":0,"title":"Physico-Chemical Treatment for Industrial Wastewater"} +{"moduleCode":"LL5070V","moduleCredit":0,"title":"Foundations Of Intellectual Property Law"} +{"moduleCode":"EL4401","moduleCredit":0,"title":"Honours Thesis"} +{"moduleCode":"TIC3901","moduleCredit":0,"title":"Industrial Practice"} +{"moduleCode":"LSM3252","moduleCredit":0,"title":"Evolution and Comparative Genomics"} +{"moduleCode":"AR2102","moduleCredit":0,"title":"Design 4"} +{"moduleCode":"LSM3254","moduleCredit":0,"title":"Ecology of Aquatic Environments"} +{"moduleCode":"LSM3255","moduleCredit":0,"title":"Ecology of Terrestrial Environments"} +{"moduleCode":"LSM3256","moduleCredit":0,"title":"Tropical Horticulture"} +{"moduleCode":"AR2101","moduleCredit":0,"title":"Design 3"} +{"moduleCode":"SP3172","moduleCredit":0,"title":"Integrated Science Project"} +{"moduleCode":"LSM3258","moduleCredit":0,"title":"Comparative Botany"} +{"moduleCode":"MT4002","moduleCredit":0,"title":"Technology Management Strategy"} +{"moduleCode":"SP3175","moduleCredit":0,"title":"The Earth"} +{"moduleCode":"LSM3259","moduleCredit":0,"title":"Fungal Biology"} +{"moduleCode":"MT4001","moduleCredit":0,"title":"Innovation and Entrepreneurial Strategy"} +{"moduleCode":"TS4660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"SP3176","moduleCredit":0,"title":"The Universe"} +{"moduleCode":"PH3261","moduleCredit":0,"title":"Kant's Critique of Pure Reason"} +{"moduleCode":"YHU2206","moduleCredit":0,"title":"Introduction to Mathematical Logic"} +{"moduleCode":"YSS3285","moduleCredit":0,"title":"Organisational Psychology"} +{"moduleCode":"BMF5342","moduleCredit":0,"title":"Technological Disruptions in Finance and Data Analytics"} +{"moduleCode":"YHU2202","moduleCredit":0,"title":"Introduction to Creative Nonfiction"} +{"moduleCode":"YHU2203","moduleCredit":0,"title":"Masterpieces of Western Art: Renaissance to the Present"} +{"moduleCode":"BMF5346","moduleCredit":0,"title":"Venture Capital and Private Equity"} +{"moduleCode":"RE3702","moduleCredit":0,"title":"Property Tax and Statutory Valuation"} +{"moduleCode":"BMF5345","moduleCredit":0,"title":"Analytical Portfolio Management"} +{"moduleCode":"RE3701","moduleCredit":0,"title":"Real Estate Investment Analysis"} +{"moduleCode":"BMF5344","moduleCredit":0,"title":"Financial Statement Analysis and Value Investing"} +{"moduleCode":"RE3704","moduleCredit":0,"title":"Real Estate Marketing"} +{"moduleCode":"BMF5343","moduleCredit":0,"title":"Banks and Non-Traditional Financial Intermediaries"} +{"moduleCode":"RE3703","moduleCredit":0,"title":"Advanced Real Estate Economics"} +{"moduleCode":"IE2111","moduleCredit":0,"title":"Industrial & Systems Engrg Principles & Practice II"} +{"moduleCode":"IE2110","moduleCredit":0,"title":"Operations Research I"} +{"moduleCode":"GE4202","moduleCredit":0,"title":"Remaking the Global Economy"} +{"moduleCode":"SN2261","moduleCredit":0,"title":"The Emergence of Contemporary South Asia"} +{"moduleCode":"TMA1001","moduleCredit":0,"title":"Introductory Mathematics"} +{"moduleCode":"SE3234","moduleCredit":0,"title":"Sea, Islands, Vessels: A Voyage of Exploration"} +{"moduleCode":"LSM3222","moduleCredit":0,"title":"Human Neuroanatomy"} +{"moduleCode":"SE3235","moduleCredit":0,"title":"Southeast Asia Laboratory: Power and Markets"} +{"moduleCode":"LL4412","moduleCredit":0,"title":"Securities and Capital Markets Regulation"} +{"moduleCode":"LSM3223","moduleCredit":0,"title":"Immunology"} +{"moduleCode":"SE3232","moduleCredit":0,"title":"Death and Dying in Southeast Asia"} +{"moduleCode":"ISD5101","moduleCredit":0,"title":"Integrated Studio Project 1"} +{"moduleCode":"LSM3224","moduleCredit":0,"title":"Molecular Basis of Human Diseases"} +{"moduleCode":"ISD5102","moduleCredit":0,"title":"Integrated Studio Project 2"} +{"moduleCode":"LSM3225","moduleCredit":0,"title":"Molecular Microbiology in Human Diseases"} +{"moduleCode":"ISD5103","moduleCredit":0,"title":"Green Buildings in the Tropics"} +{"moduleCode":"LSM3226","moduleCredit":0,"title":"Medical Mycology and Drug Discovery"} +{"moduleCode":"ISD5104","moduleCredit":0,"title":"Energy and Ecology"} +{"moduleCode":"LSM3227","moduleCredit":0,"title":"General Virology"} +{"moduleCode":"ISD5105","moduleCredit":0,"title":"Principles of Sustainable Urbanism"} +{"moduleCode":"ISD5106","moduleCredit":0,"title":"Sustainability Models and Blueprints"} +{"moduleCode":"EE5003","moduleCredit":0,"title":"Electrical Engineering Project"} +{"moduleCode":"EE5002","moduleCredit":0,"title":"Independent Study Module Ii"} +{"moduleCode":"EE5001","moduleCredit":0,"title":"Independent Study Module I"} +{"moduleCode":"YLN1201","moduleCredit":0,"title":"Beginning Singapore Sign Language"} +{"moduleCode":"BZD6001","moduleCredit":0,"title":"Model Building Workshop I: Static Models"} +{"moduleCode":"YSS3298","moduleCredit":0,"title":"The Mental Lives of Infants and Animals"} +{"moduleCode":"YSS3295","moduleCredit":0,"title":"Comparative International Education"} +{"moduleCode":"BMF5331","moduleCredit":0,"title":"Applied Corporate Finance"} +{"moduleCode":"YSS3291","moduleCredit":0,"title":"Economics of Globalisation"} +{"moduleCode":"PR5230A","moduleCredit":0,"title":"Pharmacoeconomics"} +{"moduleCode":"YIR3411G","moduleCredit":0,"title":"Independent Language Study and Research"} +{"moduleCode":"YSS3292","moduleCredit":0,"title":"Palestinian Politics in Changing Middle East"} +{"moduleCode":"ES2531","moduleCredit":0,"title":"Critical Thinking And Writing"} +{"moduleCode":"BMF5334","moduleCredit":0,"title":"International Finance and Economics"} +{"moduleCode":"BMF5333","moduleCredit":0,"title":"Options and Fixed Income"} +{"moduleCode":"BZD6006","moduleCredit":0,"title":"Organization Theory"} +{"moduleCode":"BMF5332","moduleCredit":0,"title":"Foundation of Investments"} +{"moduleCode":"BZD6004","moduleCredit":0,"title":"Applied Econometrics II"} +{"moduleCode":"BN5501","moduleCredit":0,"title":"The Singapore-Stanford Biodesign Process"} +{"moduleCode":"IE2100","moduleCredit":0,"title":"Probability Models With Applications"} +{"moduleCode":"LC1025","moduleCredit":0,"title":"Singapore Law in Context"} +{"moduleCode":"YSS3299","moduleCredit":0,"title":"Money and Banking"} +{"moduleCode":"GE4211","moduleCredit":0,"title":"Advanced Hydrology and Water Resources Management"} +{"moduleCode":"LL4407","moduleCredit":0,"title":"Law Of Insurance"} +{"moduleCode":"GE4212","moduleCredit":0,"title":"Environmental Modelling"} +{"moduleCode":"GE4213","moduleCredit":0,"title":"Cultural Geographies"} +{"moduleCode":"GE4214","moduleCredit":0,"title":"Remote Sensing of Environment"} +{"moduleCode":"LSM3231","moduleCredit":0,"title":"Protein Structure and Function"} +{"moduleCode":"LL4403","moduleCredit":0,"title":"Family Law"} +{"moduleCode":"LSM3232","moduleCredit":0,"title":"Microbiology"} +{"moduleCode":"LL4402","moduleCredit":0,"title":"Corporate Insolvency Law"} +{"moduleCode":"LSM3233","moduleCredit":0,"title":"Developmental Biology"} +{"moduleCode":"LSM3234","moduleCredit":0,"title":"Biological Imaging of Growth and Form"} +{"moduleCode":"LSM3235","moduleCredit":0,"title":"Epigenetics in Human Health and Diseases"} +{"moduleCode":"YSS3290","moduleCredit":0,"title":"Culture and Reproductive Health and Medicine"} +{"moduleCode":"EC2374","moduleCredit":0,"title":"Economy of Modern China I"} +{"moduleCode":"SW5660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"PX2108","moduleCredit":0,"title":"Basic Human Pathology"} +{"moduleCode":"SN2277","moduleCredit":0,"title":"Indian Communities in Southeast Asia"} +{"moduleCode":"EE2026","moduleCredit":0,"title":"Digital Design"} +{"moduleCode":"FIN4123","moduleCredit":0,"title":"FinTech Management"} +{"moduleCode":"EE2027","moduleCredit":0,"title":"Electronic Circuits"} +{"moduleCode":"FIN4122","moduleCredit":0,"title":"Entrepreneurial Finance"} +{"moduleCode":"EL3222","moduleCredit":0,"title":"Cinematic Discourse and Language"} +{"moduleCode":"FIN4124","moduleCredit":0,"title":"FinTech and Financial Data Analytics"} +{"moduleCode":"FIN4126","moduleCredit":0,"title":"AI, Blockchain and Quantum Computing"} +{"moduleCode":"EE2028","moduleCredit":0,"title":"Microcontroller Programming and Interfacing"} +{"moduleCode":"LL4364V","moduleCredit":0,"title":"Principles of Civil Law: Law of Obligations & Property"} +{"moduleCode":"IE5205","moduleCredit":0,"title":"Healthcare System and Analytics"} +{"moduleCode":"IE5203","moduleCredit":0,"title":"Decision Analysis"} +{"moduleCode":"IE5202","moduleCredit":0,"title":"Applied Forecasting Methods"} +{"moduleCode":"AR4955","moduleCredit":0,"title":"Topics in Architectural Design"} +{"moduleCode":"TCE3121","moduleCredit":0,"title":"Transportation Engineering"} +{"moduleCode":"EE2033","moduleCredit":0,"title":"Integrated System Lab"} +{"moduleCode":"SN4101","moduleCredit":0,"title":"Approaches to the Study of South Asia"} +{"moduleCode":"EL3231","moduleCredit":0,"title":"Phonetics"} +{"moduleCode":"FIN4116","moduleCredit":0,"title":"Valuation and Mergers & Acquisitions"} +{"moduleCode":"FIN4115","moduleCredit":0,"title":"Advanced Portfolio Mgt: Security Analysis & Valuation"} +{"moduleCode":"EL3230","moduleCredit":0,"title":"Phonology"} +{"moduleCode":"FIN4118","moduleCredit":0,"title":"Equity Research Seminar"} +{"moduleCode":"FIN4117","moduleCredit":0,"title":"Measuring Success in Philanthropy and Impact Investing"} +{"moduleCode":"DMX1204","moduleCredit":0,"title":"DYOM via edX MOOC"} +{"moduleCode":"DMX1201","moduleCredit":0,"title":"DYOM via edX MOOC"} +{"moduleCode":"DMX1202","moduleCredit":0,"title":"DYOM via edX MOOC"} +{"moduleCode":"DMX1203","moduleCredit":0,"title":"DYOM via edX MOOC"} +{"moduleCode":"IS3221","moduleCredit":0,"title":"ERP Systems with Analytics Solutions"} +{"moduleCode":"SN6770","moduleCredit":0,"title":"South Asia Graduate Research Seminar"} +{"moduleCode":"TCE3132","moduleCredit":0,"title":"Water Resources Engineering"} +{"moduleCode":"ST3311","moduleCredit":0,"title":"Undergraduate Professional Internship"} +{"moduleCode":"FIN4119","moduleCredit":0,"title":"Advanced Independent Study in Finance"} +{"moduleCode":"ST3310","moduleCredit":0,"title":"Undergraduate Professional Internship Programme"} +{"moduleCode":"ST3312","moduleCredit":0,"title":"Enhanced Undergraduate Professional Internship Programme"} +{"moduleCode":"EE2023","moduleCredit":0,"title":"Signals and Systems"} +{"moduleCode":"GMS5011","moduleCredit":0,"title":"Fundamentals of Pharmaceutical Regulation"} +{"moduleCode":"GMS5012","moduleCredit":0,"title":"Chemistry, Manufacturing and Controls (CMC)"} +{"moduleCode":"LL4362V","moduleCredit":0,"title":"Advanced Criminal Litigation - Forensics on Trial"} +{"moduleCode":"IE6511","moduleCredit":0,"title":"Surrogate and Metaheuristic Global Optimization"} +{"moduleCode":"MS5101","moduleCredit":0,"title":"Social Science and Malay Studies"} +{"moduleCode":"LL6327V","moduleCredit":0,"title":"Mergers and Acquisitions: A Practitioner’s Perspective"} +{"moduleCode":"TE4001","moduleCredit":0,"title":"BTech Dissertation"} +{"moduleCode":"XFA4402","moduleCredit":0,"title":"Integrated Honours Thesis"} +{"moduleCode":"XFA4401","moduleCredit":0,"title":"Integrated Honours Project"} +{"moduleCode":"DBA3803","moduleCredit":0,"title":"Predictive Analytics in Business"} +{"moduleCode":"XFA4405","moduleCredit":0,"title":"Integrated Honours Thesis"} +{"moduleCode":"YSC4224","moduleCredit":0,"title":"Data Science Accelerator"} +{"moduleCode":"YSC4223","moduleCredit":0,"title":"Physics in Curved Spacetime"} +{"moduleCode":"IS3251","moduleCredit":0,"title":"Principles of Technology Entrepreneurship"} +{"moduleCode":"LL4361Z","moduleCredit":0,"title":"Complex Arbitrations: Multiparty – Multicontract"} +{"moduleCode":"SSD2210","moduleCredit":0,"title":"Managing Singapore's Built Environment"} +{"moduleCode":"YSC4225","moduleCredit":0,"title":"Stochastic Processes and Models (SPaM)"} +{"moduleCode":"EL3254","moduleCredit":0,"title":"Media, Discourse and Society"} +{"moduleCode":"YIL1202I","moduleCredit":0,"title":"Directed Language Study: Beginning Italian 2"} +{"moduleCode":"EL3251","moduleCredit":0,"title":"Language, Society and Identity"} +{"moduleCode":"EL3258","moduleCredit":0,"title":"The Sociolinguistics of Humour: Jokes and Comedies"} +{"moduleCode":"ME5106","moduleCredit":0,"title":"Engineering Acoustics"} +{"moduleCode":"AR2327","moduleCredit":0,"title":"Architectural Tectonics"} +{"moduleCode":"ISE3550","moduleCredit":0,"title":"Extended Internship"} +{"moduleCode":"ENV4101","moduleCredit":0,"title":"Environmental Management in Singapore"} +{"moduleCode":"YSC4216","moduleCredit":0,"title":"Machine Learning"} +{"moduleCode":"TCE3115","moduleCredit":0,"title":"Geotechnical Engineering"} +{"moduleCode":"ME5103","moduleCredit":0,"title":"Plates and Shells"} +{"moduleCode":"TCE3116","moduleCredit":0,"title":"Foundation Engineering"} +{"moduleCode":"IS3240","moduleCredit":0,"title":"Digital Platform Strategy and Architecture"} +{"moduleCode":"LL4360Z","moduleCredit":0,"title":"Current Challenges to Investment Arbitration"} +{"moduleCode":"UTC1417","moduleCredit":0,"title":"Jr Sem: Bioethics in the 21st Century"} +{"moduleCode":"UTC1416","moduleCredit":0,"title":"Jr Sem: Games, Game Communities and Society"} +{"moduleCode":"EN5253R","moduleCredit":0,"title":"Writing in the Aftermath"} +{"moduleCode":"UTC1415","moduleCredit":0,"title":"Jr Sem: Family in a Changing Singapore"} +{"moduleCode":"UTC1414","moduleCredit":0,"title":"Jr Sem: Discovering Singapore’s Natural History and Heritage"} +{"moduleCode":"SW5211R","moduleCredit":0,"title":"Risk Assessment & Management: Mental Health"} +{"moduleCode":"TM4102","moduleCredit":0,"title":"B.Tech. Dissertation"} +{"moduleCode":"SPH6201A","moduleCredit":0,"title":"Independent Study (Epidemiology and Disease Control)"} +{"moduleCode":"SPH6201C","moduleCredit":0,"title":"Independent Study (Environmental / Occupational Health)"} +{"moduleCode":"SPH6201B","moduleCredit":0,"title":"Independent Study (Biostatistics)"} +{"moduleCode":"TM4101","moduleCredit":0,"title":"B.Tech. Dissertation"} +{"moduleCode":"SPH6201E","moduleCredit":0,"title":"Independent Study (Health Services Research)"} +{"moduleCode":"SPH6201D","moduleCredit":0,"title":"Independent Study (Health Policy and Systems)"} +{"moduleCode":"SPH6201G","moduleCredit":0,"title":"Independent Study (Global Health)"} +{"moduleCode":"SPH6201F","moduleCredit":0,"title":"Independent Study (Health Promotion)"} +{"moduleCode":"CP2106","moduleCredit":0,"title":"Independent Software Development Project (Orbital)"} +{"moduleCode":"EE3305","moduleCredit":0,"title":"Robotic System Design"} +{"moduleCode":"PL4401","moduleCredit":0,"title":"Honours Thesis"} +{"moduleCode":"IS3261","moduleCredit":0,"title":"Mobile Apps Development for Enterprise"} +{"moduleCode":"CH4660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"EE5999","moduleCredit":0,"title":"Graduate Seminars"} +{"moduleCode":"SG4210","moduleCredit":0,"title":"Enterprise .NET"} +{"moduleCode":"BPM1702","moduleCredit":0,"title":"Microsoft Excel Skills for Business"} +{"moduleCode":"BPM1701","moduleCredit":0,"title":"Calculus and Statistics"} +{"moduleCode":"JS5201","moduleCredit":0,"title":"Readings in Japanese Studies I"} +{"moduleCode":"JS5203","moduleCredit":0,"title":"Japanese Literary & Performance Studies"} +{"moduleCode":"BPM1705","moduleCredit":0,"title":"Understanding How Business Works"} +{"moduleCode":"EG2606B","moduleCredit":0,"title":"Independent Work"} +{"moduleCode":"EG2606A","moduleCredit":0,"title":"Independent Work"} +{"moduleCode":"EE2012","moduleCredit":0,"title":"Analytical Methods in Electrical and Computer Engineering"} +{"moduleCode":"PP5804","moduleCredit":0,"title":"Governance Study Project"} +{"moduleCode":"PP5803","moduleCredit":0,"title":"Public Management"} +{"moduleCode":"PP5802","moduleCredit":0,"title":"Policy Analysis"} +{"moduleCode":"EN5254R","moduleCredit":0,"title":"Rethinking Failure in the 21st Century"} +{"moduleCode":"PP5801","moduleCredit":0,"title":"Economic Analysis"} +{"moduleCode":"IE5213","moduleCredit":0,"title":"Service Innovation And Management"} +{"moduleCode":"IE5211","moduleCredit":0,"title":"New Product Management"} +{"moduleCode":"SG4205","moduleCredit":0,"title":"Information Systems Security"} +{"moduleCode":"CS3281","moduleCredit":0,"title":"Thematic Systems Project I"} +{"moduleCode":"CS3282","moduleCredit":0,"title":"Thematic Systems Project II"} +{"moduleCode":"IE5208","moduleCredit":0,"title":"Systems Approach To Project Management"} +{"moduleCode":"LAJ3204","moduleCredit":0,"title":"Business Japanese 2"} +{"moduleCode":"LAJ3202","moduleCredit":0,"title":"Japanese 6"} +{"moduleCode":"LAJ3201","moduleCredit":0,"title":"Japanese 5"} +{"moduleCode":"SG4207","moduleCredit":0,"title":"Mobile Wireless Solution Design"} +{"moduleCode":"SG4206","moduleCredit":0,"title":"Enterprise Integration"} +{"moduleCode":"LL6014V","moduleCredit":0,"title":"Construction Law"} +{"moduleCode":"UTC2707","moduleCredit":0,"title":"Understanding Health and Social Care in Singapore"} +{"moduleCode":"UTC2708","moduleCredit":0,"title":"Singapore - A Smart Nation in Context : IoT & Big Data"} +{"moduleCode":"LAT4201","moduleCredit":0,"title":"Thai 5"} +{"moduleCode":"LAT4202","moduleCredit":0,"title":"Thai 6"} +{"moduleCode":"EE4603","moduleCredit":0,"title":"Biomedical Imaging Systems"} +{"moduleCode":"EE5934","moduleCredit":0,"title":"Deep Learning"} +{"moduleCode":"IE3110E","moduleCredit":0,"title":"Simulation"} +{"moduleCode":"PL6208","moduleCredit":0,"title":"Empirical Research Project"} +{"moduleCode":"RE1901","moduleCredit":0,"title":"Real Estate Wealth Management"} +{"moduleCode":"IFS4201","moduleCredit":0,"title":"Information Security Industry Capstone Project"} +{"moduleCode":"IFS4202","moduleCredit":0,"title":"Information Security Practicum Programme"} +{"moduleCode":"IE3110R","moduleCredit":0,"title":"Simulation"} +{"moduleCode":"ME5999","moduleCredit":0,"title":"Graduate Seminars"} +{"moduleCode":"PL6215","moduleCredit":0,"title":"Selected Applications in Psychology"} +{"moduleCode":"UTC2700","moduleCredit":0,"title":"An Undefeated Mind: An Experiential Inner Reengineering Approach"} +{"moduleCode":"OT5206A","moduleCredit":0,"title":"Shallow Offshore Foundations"} +{"moduleCode":"UTC2703","moduleCredit":0,"title":"Infectious Diseases: Dynamics, Strategies and Policies"} +{"moduleCode":"IFS4205","moduleCredit":0,"title":"Information Security Capstone Project."} +{"moduleCode":"UTC2704","moduleCredit":0,"title":"Projects in Systems Thinking and System Dynamics"} +{"moduleCode":"OT5206B","moduleCredit":0,"title":"Deep Offshore Foundations"} +{"moduleCode":"UTC2706","moduleCredit":0,"title":"Committed to Changing Our World: The Systems Pioneers"} +{"moduleCode":"UTC2718","moduleCredit":0,"title":"Energy and Singapore: Dynamics, Dilemmas and Decisions"} +{"moduleCode":"UTC2719","moduleCredit":0,"title":"Society and Economy in Singapore: A Systems View"} +{"moduleCode":"LL6099","moduleCredit":0,"title":"Maritime Law"} +{"moduleCode":"CS1231S","moduleCredit":0,"title":"Discrete Structures"} +{"moduleCode":"FST5199","moduleCredit":0,"title":"MSc research project"} +{"moduleCode":"SW5216R","moduleCredit":0,"title":"Family and Interpersonal Violence"} +{"moduleCode":"UIT2208","moduleCredit":0,"title":"Thinking 4.0"} +{"moduleCode":"DMB1203MNO","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"UTC2712","moduleCredit":0,"title":"Hard to secure easy to waste - Singapore’s food story"} +{"moduleCode":"UTC2713","moduleCredit":0,"title":"Modelling Singlehood, Marriage & Fertility in Singapore"} +{"moduleCode":"UTC2714","moduleCredit":0,"title":"A social critique of markets in Singapore"} +{"moduleCode":"UTC2715","moduleCredit":0,"title":"Decoding Complexity"} +{"moduleCode":"UIT2205","moduleCredit":0,"title":"Quantum computation"} +{"moduleCode":"UTC2717","moduleCredit":0,"title":"Navigation in Singapore Waters-Bridges and Barriers"} +{"moduleCode":"NUR5503","moduleCredit":0,"title":"Advanced Critical Care Nursing II"} +{"moduleCode":"TBA2104","moduleCredit":0,"title":"Predictive Analytics"} +{"moduleCode":"TBA2105","moduleCredit":0,"title":"Web Mining"} +{"moduleCode":"LL6088","moduleCredit":0,"title":"Chinese Contract Law"} +{"moduleCode":"TBA2102","moduleCredit":0,"title":"Introduction to Business Analytics"} +{"moduleCode":"NUR5502","moduleCredit":0,"title":"Advanced Critical Care Nursing I"} +{"moduleCode":"TBA2103","moduleCredit":0,"title":"Data Visualisation"} +{"moduleCode":"TBA2101","moduleCredit":0,"title":"Building an Analytics Organisation"} +{"moduleCode":"LL4237V","moduleCredit":0,"title":"Law, Institutions, and Business in Greater China"} +{"moduleCode":"NM6101","moduleCredit":0,"title":"Advanced Theories in Cnm"} +{"moduleCode":"NM6103","moduleCredit":0,"title":"Quantitative Research Methods in Communications and New Media"} +{"moduleCode":"NM6104","moduleCredit":0,"title":"Qualitative Research Methods in Communications and New Media"} +{"moduleCode":"CS1101S","moduleCredit":0,"title":"Programming Methodology"} +{"moduleCode":"LAS2201","moduleCredit":0,"title":"Spanish 2"} +{"moduleCode":"LL5254V","moduleCredit":0,"title":"Developing States in a Changing World Order"} +{"moduleCode":"SW5217R","moduleCredit":0,"title":"Continuum of Care and Healthy Ageing"} +{"moduleCode":"OT5204B","moduleCredit":0,"title":"Moorings and Risers - Dynamics"} +{"moduleCode":"GS5101","moduleCredit":0,"title":"Research Immersion module"} +{"moduleCode":"YLL2201","moduleCredit":0,"title":"Intermediate Latin"} +{"moduleCode":"DMB1203MKT","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"OT5204A","moduleCredit":0,"title":"Moorings and Risers - Statics"} +{"moduleCode":"SP1541","moduleCredit":0,"title":"Exploring Science Communication through Popular Science"} +{"moduleCode":"UTC1408","moduleCredit":0,"title":"Jr Sem: Technology and Human Progress"} +{"moduleCode":"MUA3275","moduleCredit":0,"title":"Sonic Circuits"} +{"moduleCode":"MUA3274","moduleCredit":0,"title":"Sonic Environments"} +{"moduleCode":"ESE5301","moduleCredit":0,"title":"Environmental Biological Principles"} +{"moduleCode":"UTC1404","moduleCredit":0,"title":"Jr Sem: Power and Ideas"} +{"moduleCode":"MUA3271","moduleCredit":0,"title":"Acoustics and Sound Production for Performers"} +{"moduleCode":"UTC1403","moduleCredit":0,"title":"Jr Sem: Hidden Communities"} +{"moduleCode":"UTC1402","moduleCredit":0,"title":"Jr Sem: Generation Y: Transitions to Adulthood"} +{"moduleCode":"LC5265","moduleCredit":0,"title":"Chinese Business Law"} +{"moduleCode":"LC5264","moduleCredit":0,"title":"WTO and Regional Integration"} +{"moduleCode":"LL6071","moduleCredit":0,"title":"International Patent Law, Policy and Practice"} +{"moduleCode":"OT5203B","moduleCredit":0,"title":"Design of Floating Offshore Structures"} +{"moduleCode":"OT5203A","moduleCredit":0,"title":"Analysis of Floating Offshore Structures"} +{"moduleCode":"ME2121E","moduleCredit":0,"title":"Engineering Thermodynamics"} +{"moduleCode":"UTC1409","moduleCredit":0,"title":"Jr Sem: The Pursuit of Happiness"} +{"moduleCode":"MUA3265","moduleCredit":0,"title":"Career Development Independent Project 2"} +{"moduleCode":"NUR1123","moduleCredit":0,"title":"Anatomy, Physiology and Physical Assessment I"} +{"moduleCode":"MUA3264","moduleCredit":0,"title":"Career Development Independent Project"} +{"moduleCode":"NUR1124","moduleCredit":0,"title":"Anatomy, Physiology and Physical Assessment II"} +{"moduleCode":"MUA3263","moduleCredit":0,"title":"Internship in Music Related Pathways 2"} +{"moduleCode":"NUR1125","moduleCredit":0,"title":"Pathophysiology, Pharmacology and Nursing Practice I"} +{"moduleCode":"NUR1126","moduleCredit":0,"title":"Pathophysiology, Pharmacology and Nursing Practice II"} +{"moduleCode":"MUA3261","moduleCredit":0,"title":"Career Development Group Project"} +{"moduleCode":"MUA3260","moduleCredit":0,"title":"Internship in Music Related Pathways"} +{"moduleCode":"YSC4209","moduleCredit":0,"title":"Physical Sciences Research Seminar"} +{"moduleCode":"ZB3289","moduleCredit":0,"title":"Advanced UROPS in Computational Biology II"} +{"moduleCode":"LL4235V","moduleCredit":0,"title":"International Contract Law: Principles and Practice"} +{"moduleCode":"ZB3288","moduleCredit":0,"title":"Advanced UROPS in Computational Biology I"} +{"moduleCode":"LL4102V","moduleCredit":0,"title":"Advanced Torts"} +{"moduleCode":"PR2115A","moduleCredit":0,"title":"Medicinal Chemistry for Drug Design"} +{"moduleCode":"YIL1201B","moduleCredit":0,"title":"Directed Language Study: Beginning Bangla 1"} +{"moduleCode":"YSC4200","moduleCredit":0,"title":"Special Project in Science"} +{"moduleCode":"IL5102","moduleCredit":0,"title":"IT Innovation Leadership"} +{"moduleCode":"IL5101","moduleCredit":0,"title":"Strategic Alignment of Business and IT"} +{"moduleCode":"IL5104","moduleCredit":0,"title":"Process and Operational Excellence"} +{"moduleCode":"IL5103","moduleCredit":0,"title":"Business and IT Financial Management"} +{"moduleCode":"IL5106","moduleCredit":0,"title":"Leading Change for IT Leaders"} +{"moduleCode":"NUR1127","moduleCredit":0,"title":"Psychology for Nurses"} +{"moduleCode":"YIL1201S","moduleCredit":0,"title":"Directed Language Study: Beginning Sanskrit"} +{"moduleCode":"IL5105","moduleCredit":0,"title":"Fundamentals of IT Leadership Transformation"} +{"moduleCode":"ME6401","moduleCredit":0,"title":"Topics in Mechatronics 1"} +{"moduleCode":"IL5107","moduleCredit":0,"title":"IT Leadership Capstone Project"} +{"moduleCode":"LL6322V","moduleCredit":0,"title":"Trade Finance Law"} +{"moduleCode":"PC5204A","moduleCredit":0,"title":"Soft Materials and Flexible Devices"} +{"moduleCode":"PC5204B","moduleCredit":0,"title":"Selected Topics in Physics: Analytic Approximations"} +{"moduleCode":"LL4367V","moduleCredit":0,"title":"Singapore at the UN - A Clinical Externship"} +{"moduleCode":"PR2114A","moduleCredit":0,"title":"Formulation & Technology I"} +{"moduleCode":"DOS4712","moduleCredit":0,"title":"Co-ordination and Flexibility in SCM"} +{"moduleCode":"DOS4713","moduleCredit":0,"title":"Operations Strategy"} +{"moduleCode":"LL6019V","moduleCredit":0,"title":"Credit & Security"} +{"moduleCode":"MA1505","moduleCredit":0,"title":"Mathematics I"} +{"moduleCode":"DOS4714","moduleCredit":0,"title":"Service Design"} +{"moduleCode":"MUA3256","moduleCredit":0,"title":"Applied Secondary D"} +{"moduleCode":"MA1507","moduleCredit":0,"title":"Advanced Calculus"} +{"moduleCode":"MUA3255","moduleCredit":0,"title":"Applied Secondary C"} +{"moduleCode":"CM1417X","moduleCredit":0,"title":"Fundamentals of Chemistry"} +{"moduleCode":"BLD3002","moduleCredit":0,"title":"CEOs as Leaders"} +{"moduleCode":"BLD3004","moduleCredit":0,"title":"Topics in Leadership Development"} +{"moduleCode":"BLD3003","moduleCredit":0,"title":"Personal Leadership Development"} +{"moduleCode":"DY5190","moduleCredit":0,"title":"Graduate Seminar module"} +{"moduleCode":"MUA3243","moduleCredit":0,"title":"Collaborative Piano - Chamber Music"} +{"moduleCode":"LL6043","moduleCredit":0,"title":"Law Of Marine Insurance"} +{"moduleCode":"MUA3242","moduleCredit":0,"title":"Collaborative Piano - Instrumental Accompaniment"} +{"moduleCode":"MUA3241","moduleCredit":0,"title":"Collaborative Piano - Vocal Accompaniment"} +{"moduleCode":"MUA3240","moduleCredit":0,"title":"Collaborative Piano - Piano Ensemble"} +{"moduleCode":"PM5101","moduleCredit":0,"title":"Project Management"} +{"moduleCode":"PM5103","moduleCredit":0,"title":"Contract Management"} +{"moduleCode":"LL4233V","moduleCredit":0,"title":"European Company Law"} +{"moduleCode":"PM5106","moduleCredit":0,"title":"Design Management"} +{"moduleCode":"PM5105","moduleCredit":0,"title":"Development Finance"} +{"moduleCode":"BMK5300A","moduleCredit":0,"title":"Experiential Learning: Industry Internship"} +{"moduleCode":"MA1511","moduleCredit":0,"title":"Engineering Calculus"} +{"moduleCode":"MA1512","moduleCredit":0,"title":"Differential Equations for Engineering"} +{"moduleCode":"PS5603","moduleCredit":0,"title":"Introduction to Qualitative Methods"} +{"moduleCode":"MA1513","moduleCredit":0,"title":"Linear Algebra with Differential Equations"} +{"moduleCode":"BMK5300B","moduleCredit":0,"title":"Experiential Learning: Marketing Analytics Project"} +{"moduleCode":"NUR1201C","moduleCredit":0,"title":"Health Continuum for Older Adults"} +{"moduleCode":"CE1101A","moduleCredit":0,"title":"Civil Engineering Principles and Practice"} +{"moduleCode":"ID5021","moduleCredit":0,"title":"Design Research"} +{"moduleCode":"RE6770","moduleCredit":0,"title":"Phd Seminar"} +{"moduleCode":"PM5111","moduleCredit":0,"title":"Special Topics in Project Management"} +{"moduleCode":"LL6032","moduleCredit":0,"title":"International Investment Law"} +{"moduleCode":"MUA3230","moduleCredit":0,"title":"Music Cognition"} +{"moduleCode":"NUR1114","moduleCredit":0,"title":"Fundamentals of Nursing"} +{"moduleCode":"PM5113","moduleCredit":0,"title":"Managing Projects using BIM"} +{"moduleCode":"PM5112","moduleCredit":0,"title":"Research Methods"} +{"moduleCode":"EE5903","moduleCredit":0,"title":"Real-Time Systems"} +{"moduleCode":"PM5115","moduleCredit":0,"title":"Project Finance Contracts and Agreements"} +{"moduleCode":"EE5902","moduleCredit":0,"title":"Multiprocessor Systems"} +{"moduleCode":"PM5114","moduleCredit":0,"title":"Managing Complex Projects"} +{"moduleCode":"NUR1110","moduleCredit":0,"title":"Effective Communication for Health Professionals"} +{"moduleCode":"MA1521","moduleCredit":0,"title":"Calculus for Computing"} +{"moduleCode":"PM5116","moduleCredit":0,"title":"Project Finance Case Studies"} +{"moduleCode":"EE5907","moduleCredit":0,"title":"Pattern Recognition"} +{"moduleCode":"EE5904","moduleCredit":0,"title":"Neural Networks"} +{"moduleCode":"NUR1202C","moduleCredit":0,"title":"Clinical Experience I"} +{"moduleCode":"LL5259V","moduleCredit":0,"title":"Alternative Investments"} +{"moduleCode":"PM5107","moduleCredit":0,"title":"Time and Cost Management"} +{"moduleCode":"PM5109","moduleCredit":0,"title":"Project Management Law"} +{"moduleCode":"NUR1117","moduleCredit":0,"title":"Anatomy and Physiology I"} +{"moduleCode":"NUR1118","moduleCredit":0,"title":"Anatomy and Physiology II"} +{"moduleCode":"LC5337","moduleCredit":0,"title":"Singapore Common Law of Contract"} +{"moduleCode":"LSM1307","moduleCredit":0,"title":"Waste and Our Environment"} +{"moduleCode":"NUR2106B","moduleCredit":0,"title":"Clinical Practice: Medical/Surgical II"} +{"moduleCode":"LC5336","moduleCredit":0,"title":"Topics in Int'l Arbitration & Dispute Resolution"} +{"moduleCode":"LSM1306","moduleCredit":0,"title":"Forensic Science"} +{"moduleCode":"CM2289","moduleCredit":0,"title":"Basic UROPS In Chemistry II"} +{"moduleCode":"CM2288","moduleCredit":0,"title":"Basic UROPS in Chemistry I"} +{"moduleCode":"NUR2106A","moduleCredit":0,"title":"Nursing Practice Experience 2.1"} +{"moduleCode":"LSM1303","moduleCredit":0,"title":"Animal Behaviour"} +{"moduleCode":"SC4212","moduleCredit":0,"title":"Social Memory"} +{"moduleCode":"LSM1301","moduleCredit":0,"title":"General Biology"} +{"moduleCode":"FST5227","moduleCredit":0,"title":"Advanced Current Topics in Food Science III"} +{"moduleCode":"SC4210","moduleCredit":0,"title":"Sociology of Migration"} +{"moduleCode":"FST5225","moduleCredit":0,"title":"Advanced Current Topics in Food Science I"} +{"moduleCode":"HY3257","moduleCredit":0,"title":"The Philippines: A Social and Cultural History"} +{"moduleCode":"HY3256","moduleCredit":0,"title":"Brides of the Sea: Asia's Port Cities"} +{"moduleCode":"SE5151","moduleCredit":0,"title":"Approaches to the Study of Southeast Asia"} +{"moduleCode":"MLE4101","moduleCredit":0,"title":"B.Eng. Dissertation"} +{"moduleCode":"MLE4102","moduleCredit":0,"title":"Design Project"} +{"moduleCode":"CN3421E","moduleCredit":0,"title":"Process Modeling & Numerical Simulation"} +{"moduleCode":"LL6150V","moduleCredit":0,"title":"International Investment Law and Arbitration"} +{"moduleCode":"SC4219","moduleCredit":0,"title":"Social Origins and Consequences of Financial Crises"} +{"moduleCode":"SC4217","moduleCredit":0,"title":"Social Movements and Collective Behaviour"} +{"moduleCode":"SC4218","moduleCredit":0,"title":"Religions, Secularity, Post-Secularity"} +{"moduleCode":"CE5113A","moduleCredit":0,"title":"Geotechnical Investigation according to EC7"} +{"moduleCode":"MA3288","moduleCredit":0,"title":"Advanced UROPS in Mathematics I"} +{"moduleCode":"NUR2107A","moduleCredit":0,"title":"Nursing Practice Experience 2.2"} +{"moduleCode":"CE5113B","moduleCredit":0,"title":"Geophysical Methods & Geotechnical Monitoring"} +{"moduleCode":"MA3289","moduleCredit":0,"title":"Advanced UROPS in Mathematics II"} +{"moduleCode":"SC4201","moduleCredit":0,"title":"Contemporary Social Theory"} +{"moduleCode":"LL6285V","moduleCredit":0,"title":"International Dispute Settlement"} +{"moduleCode":"SPH5410","moduleCredit":0,"title":"Developing health proposals using DME skills & tools"} +{"moduleCode":"SPH5411","moduleCredit":0,"title":"Information Technology in Healthcare"} +{"moduleCode":"SPH5412","moduleCredit":0,"title":"Economic Methods in Health Technology Assessment"} +{"moduleCode":"SPH5413","moduleCredit":0,"title":"Women’s, Children’s and Adolescents’ Health"} +{"moduleCode":"GE6770","moduleCredit":0,"title":"Graduate Research Seminar"} +{"moduleCode":"SPH5414","moduleCredit":0,"title":"Informatics for Health"} +{"moduleCode":"SPH5415","moduleCredit":0,"title":"Healthcare Operations & Performance"} +{"moduleCode":"SPH5416","moduleCredit":0,"title":"Introduction to Integrated Care"} +{"moduleCode":"SC4204","moduleCredit":0,"title":"Social Policy & Social Planning"} +{"moduleCode":"SC4205","moduleCredit":0,"title":"Sociology of Language & Communication"} +{"moduleCode":"CE2112","moduleCredit":0,"title":"Soil Mechanics"} +{"moduleCode":"SC4202","moduleCredit":0,"title":"Reading Ethnographies"} +{"moduleCode":"BMA5132","moduleCredit":0,"title":"Emerging Tech and the Value of Data"} +{"moduleCode":"CN4250","moduleCredit":0,"title":"Chemical Product Design"} +{"moduleCode":"BMA5131","moduleCredit":0,"title":"Micro-National Champions in the Digital Economy"} +{"moduleCode":"CN4251","moduleCredit":0,"title":"Troubleshooting with Case Studies for Process Engineers"} +{"moduleCode":"SC4209","moduleCredit":0,"title":"Interpretive Sociology"} +{"moduleCode":"SC4206","moduleCredit":0,"title":"Urban Anthropology"} +{"moduleCode":"MW5200","moduleCredit":0,"title":"MSc Science Communication Project"} +{"moduleCode":"PR4198","moduleCredit":0,"title":"Pharmacy Internship II"} +{"moduleCode":"PR4197","moduleCredit":0,"title":"Pharmacy Internship I"} +{"moduleCode":"PR4196","moduleCredit":0,"title":"Pharmacy Research Project and Scientific Communication"} +{"moduleCode":"GE1101E","moduleCredit":0,"title":"Geographical Journeys: Exploring World Environments"} +{"moduleCode":"LA5702","moduleCredit":0,"title":"MLA Studio: Region"} +{"moduleCode":"PR4195","moduleCredit":0,"title":"Scientific Evaluation, Analysis and Communication"} +{"moduleCode":"LL6286V","moduleCredit":0,"title":"Transnational Terrorism and International Law"} +{"moduleCode":"FST5205","moduleCredit":0,"title":"Frontier of Food Processing and Engineering"} +{"moduleCode":"FST5202","moduleCredit":0,"title":"Advanced Food Fermentation"} +{"moduleCode":"HY3236","moduleCredit":0,"title":"The Struggle for India, 1920-1964"} +{"moduleCode":"FST5203","moduleCredit":0,"title":"Advanced Food Microbiology and Safety"} +{"moduleCode":"FST5201","moduleCredit":0,"title":"Rheology and Textural Properties of Biomaterials"} +{"moduleCode":"MW5203","moduleCredit":0,"title":"Frontier Topics in Science"} +{"moduleCode":"MW5202","moduleCredit":0,"title":"Innovations in Science Teaching"} +{"moduleCode":"MW5201","moduleCredit":0,"title":"Essentials of Science Communication"} +{"moduleCode":"PL5304R","moduleCredit":0,"title":"Advanced Developmental Psychology"} +{"moduleCode":"TME4251","moduleCredit":0,"title":"Thermal Engineering Of Materials"} +{"moduleCode":"BMA5129","moduleCredit":0,"title":"Leading with Strategy in Digital Firms"} +{"moduleCode":"BMA5128","moduleCredit":0,"title":"Venture Capital"} +{"moduleCode":"SPH6770","moduleCredit":0,"title":"Graduate Research Seminar in Public Health"} +{"moduleCode":"SP3203","moduleCredit":0,"title":"Aquatic Ecology Research"} +{"moduleCode":"TME4256","moduleCredit":0,"title":"Functional Materials and Devices"} +{"moduleCode":"SP3202","moduleCredit":0,"title":"Evidence in Forensic Science"} +{"moduleCode":"LL6287V","moduleCredit":0,"title":"ASEAN Law and Policy"} +{"moduleCode":"SW4401","moduleCredit":0,"title":"Honours Thesis"} +{"moduleCode":"LL6021V","moduleCredit":0,"title":"Environmental Law"} +{"moduleCode":"MCI5008","moduleCredit":0,"title":"Research Project"} +{"moduleCode":"MDG5102","moduleCredit":0,"title":"Techniques in Biomedical Research"} +{"moduleCode":"XFE4401","moduleCredit":0,"title":"Integrated Honours Project"} +{"moduleCode":"MCI5009","moduleCredit":0,"title":"Health Services Research Methods for Clinicians"} +{"moduleCode":"MCI5006","moduleCredit":0,"title":"Clinical Epidemiology and Biostatistics Ii"} +{"moduleCode":"MCI5007","moduleCredit":0,"title":"Scientific Writing"} +{"moduleCode":"HY3245","moduleCredit":0,"title":"Engendering History/Historicising Gender"} +{"moduleCode":"PL5303R","moduleCredit":0,"title":"Advanced Cognitive Psychology"} +{"moduleCode":"TME4261","moduleCredit":0,"title":"Tool Engineering"} +{"moduleCode":"LL5089V","moduleCredit":0,"title":"Chinese Corporate & Securities Law"} +{"moduleCode":"ESE4502R","moduleCredit":0,"title":"B. Eng. Dissertation"} +{"moduleCode":"TME4263","moduleCredit":0,"title":"Manufact'G Simulat'N & Data Communicat'N"} +{"moduleCode":"BDC5101","moduleCredit":0,"title":"Deterministic Operations Research Models"} +{"moduleCode":"TME4262","moduleCredit":0,"title":"Automation in Manufacturing"} +{"moduleCode":"HY3243","moduleCredit":0,"title":"China and Southeast Asia: Past & Present"} +{"moduleCode":"HY3242","moduleCredit":0,"title":"Modern Imperialism"} +{"moduleCode":"BMA5119","moduleCredit":0,"title":"Family Business"} +{"moduleCode":"EU2204","moduleCredit":0,"title":"Modern Western Political Thought"} +{"moduleCode":"CE2134","moduleCredit":0,"title":"Hydraulics"} +{"moduleCode":"ACC2707","moduleCredit":0,"title":"Corporate Accounting & Reporting I"} +{"moduleCode":"ACC2706","moduleCredit":0,"title":"Managerial Accounting"} +{"moduleCode":"MCI5001","moduleCredit":0,"title":"Clinical Epidemiology I"} +{"moduleCode":"TME4264","moduleCredit":0,"title":"Fundamentals of Automotive Engineering"} +{"moduleCode":"ACC2709","moduleCredit":0,"title":"Accounting Information Systems"} +{"moduleCode":"BMA5112","moduleCredit":0,"title":"Asian Business Environments"} +{"moduleCode":"MDG5108","moduleCredit":0,"title":"Biostatistics For Basic Research"} +{"moduleCode":"ACC2708","moduleCredit":0,"title":"Corporate Accounting & Reporting II"} +{"moduleCode":"ISY5001","moduleCredit":0,"title":"Intelligent Reasoning Systems"} +{"moduleCode":"ISY5002","moduleCredit":0,"title":"Pattern Recognition Systems"} +{"moduleCode":"ISY5003","moduleCredit":0,"title":"Intelligent Robotic Systems"} +{"moduleCode":"LL6102","moduleCredit":0,"title":"Advanced Torts"} +{"moduleCode":"YSC1218","moduleCredit":0,"title":"Molecular Perspectives"} +{"moduleCode":"ISY5004","moduleCredit":0,"title":"Intelligent Sensing Systems"} +{"moduleCode":"YSC1219","moduleCredit":0,"title":"Introduction to Black Holes"} +{"moduleCode":"ISY5005","moduleCredit":0,"title":"Intelligent Software Agents"} +{"moduleCode":"AR5322","moduleCredit":0,"title":"Renewable Resources and Architecture"} +{"moduleCode":"BN4102","moduleCredit":0,"title":"Gerontechnology in Ageing"} +{"moduleCode":"MKT3513","moduleCredit":0,"title":"Game Theory And Strategic Analysis"} +{"moduleCode":"AR5321","moduleCredit":0,"title":"Advanced Architectural Integration"} +{"moduleCode":"BN4101","moduleCredit":0,"title":"B.Eng. Dissertation"} +{"moduleCode":"NM6201","moduleCredit":0,"title":"Communication as Culture"} +{"moduleCode":"HY3217","moduleCredit":0,"title":"The Making of Colonial Indochina"} +{"moduleCode":"MUA3301","moduleCredit":0,"title":"Preparing for International Competition"} +{"moduleCode":"DEP5103A","moduleCredit":0,"title":"Quantitative Methods for Urban Planning"} +{"moduleCode":"CN5555","moduleCredit":0,"title":"Chemical Engineering Project"} +{"moduleCode":"LL5260V","moduleCredit":0,"title":"Chinese Commercial Law"} +{"moduleCode":"YSC1213","moduleCredit":0,"title":"General Physics"} +{"moduleCode":"ISY5007","moduleCredit":0,"title":"Capstone Project in Intelligent Systems"} +{"moduleCode":"YSC1216","moduleCredit":0,"title":"Calculus"} +{"moduleCode":"PC4199","moduleCredit":0,"title":"Honours Project in Physics"} +{"moduleCode":"YSC1212","moduleCredit":0,"title":"Introduction to Computer Science"} +{"moduleCode":"BSP3011","moduleCredit":0,"title":"Family Business"} +{"moduleCode":"TCN2116","moduleCredit":0,"title":"Chemical Kinetics And Reactor Design"} +{"moduleCode":"LL6289V","moduleCredit":0,"title":"The Evolution of International Arbitration"} +{"moduleCode":"YSC1207","moduleCredit":0,"title":"General Chemistry"} +{"moduleCode":"HY3225","moduleCredit":0,"title":"Minorities in Southeast Asia"} +{"moduleCode":"AR4002","moduleCredit":0,"title":"Advanced Architectural Study 2"} +{"moduleCode":"LL4398","moduleCredit":0,"title":"University Research Opportunities Program"} +{"moduleCode":"LL4397","moduleCredit":0,"title":"University Research Opportunities Program"} +{"moduleCode":"PF3504","moduleCredit":0,"title":"Energy Management"} +{"moduleCode":"LL4396","moduleCredit":0,"title":"University Research Opportunities Program"} +{"moduleCode":"PF3502","moduleCredit":0,"title":"Smart Facilities"} +{"moduleCode":"LL4109V","moduleCredit":0,"title":"International Law & Asia"} +{"moduleCode":"HY3227","moduleCredit":0,"title":"Europe of the Dictators"} +{"moduleCode":"HY3226","moduleCredit":0,"title":"Memory, Heritage & History"} +{"moduleCode":"CE2155","moduleCredit":0,"title":"Structural Mechanics and Materials"} +{"moduleCode":"TCN2122","moduleCredit":0,"title":"Fluid Mechanics"} +{"moduleCode":"TME4245","moduleCredit":0,"title":"Robot Mechanics and Control"} +{"moduleCode":"TCN2121","moduleCredit":0,"title":"Chemical Engineering Thermodynamics"} +{"moduleCode":"BSP3001","moduleCredit":0,"title":"Strategic Management"} +{"moduleCode":"LAM1201","moduleCredit":0,"title":"Malay 1"} +{"moduleCode":"LL6024V","moduleCredit":0,"title":"Indonesian Law"} +{"moduleCode":"UBM2202","moduleCredit":0,"title":"Creating Wolverine in Real Life"} +{"moduleCode":"UBM2201","moduleCredit":0,"title":"Hormesis and Life"} +{"moduleCode":"LA5742","moduleCredit":0,"title":"Dissertation"} +{"moduleCode":"YHU4102","moduleCredit":0,"title":"Literature Capstone Project"} +{"moduleCode":"YHU4101","moduleCredit":0,"title":"History Capstone Project"} +{"moduleCode":"YHU4104","moduleCredit":0,"title":"Arts and Humanities Capstone Project"} +{"moduleCode":"SWD5120","moduleCredit":0,"title":"Social Work Practicum"} +{"moduleCode":"YHU4103","moduleCredit":0,"title":"Philosophy Capstone Project"} +{"moduleCode":"CN4248","moduleCredit":0,"title":"Sustainable Process Development"} +{"moduleCode":"DEP5101A","moduleCredit":0,"title":"Qualitative Methods for Urban Planning"} +{"moduleCode":"MLE1010","moduleCredit":0,"title":"Materials Engineering Principles & Practices"} +{"moduleCode":"TCN3421","moduleCredit":0,"title":"Process Modeling & Numerical Simulation"} +{"moduleCode":"CSA6101","moduleCredit":0,"title":"Cultural Studies Theory and Analysis"} +{"moduleCode":"BSN4711","moduleCredit":0,"title":"Product Validation"} +{"moduleCode":"LL6158V","moduleCredit":0,"title":"Climate Change Law"} +{"moduleCode":"CE2183","moduleCredit":0,"title":"Construction Project Management"} +{"moduleCode":"SC4222","moduleCredit":0,"title":"Body and Society"} +{"moduleCode":"ZB3311","moduleCredit":0,"title":"Undergraduate Professional Internship"} +{"moduleCode":"SC4221","moduleCredit":0,"title":"Comparative Analysis of Human Rights"} +{"moduleCode":"ZB3312","moduleCredit":0,"title":"Enhanced Undergraduate Professional Internship Programme"} +{"moduleCode":"MKT4812","moduleCredit":0,"title":"Marketing Analytics"} +{"moduleCode":"LL4376","moduleCredit":0,"title":"Regulation & Private Law in Banking & Financial Service"} +{"moduleCode":"MKT4811","moduleCredit":0,"title":"Pricing Strategy"} +{"moduleCode":"ZB3310","moduleCredit":0,"title":"Undergraduate Professional Internship Programme"} +{"moduleCode":"LL4375","moduleCredit":0,"title":"Traditional Chinese Legal Thought"} +{"moduleCode":"PE3101P","moduleCredit":0,"title":"Decision and Social Choice"} +{"moduleCode":"LL4374","moduleCredit":0,"title":"Water Rights & Resources: Issues in Law & Development"} +{"moduleCode":"PH4401","moduleCredit":0,"title":"Honours Thesis"} +{"moduleCode":"LL4373","moduleCredit":0,"title":"Advanced Copyright"} +{"moduleCode":"LL4372","moduleCredit":0,"title":"International Intellectual Property Law"} +{"moduleCode":"LL4371","moduleCredit":0,"title":"Charity Law Today"} +{"moduleCode":"HY3204","moduleCredit":0,"title":"Southeast Asia: Decolonization & After"} +{"moduleCode":"LL4370","moduleCredit":0,"title":"The Law of Cybersecurity, Privacy and Data Compliance"} +{"moduleCode":"MKT4813","moduleCredit":0,"title":"Design Thinking & Business Innovations"} +{"moduleCode":"LL5263V","moduleCredit":0,"title":"Intellectual Property Rights and Competition Policy"} +{"moduleCode":"SWD5105","moduleCredit":0,"title":"Skills in Advanced Social Work Practice"} +{"moduleCode":"SWD5104","moduleCredit":0,"title":"Human Development in Context"} +{"moduleCode":"LL4369","moduleCredit":0,"title":"Constitutionalism in Asia"} +{"moduleCode":"LL4368","moduleCredit":0,"title":"Comparative Constitutionalism"} +{"moduleCode":"LL5396V","moduleCredit":0,"title":"International Arbitration & Dispute Resolution Research"} +{"moduleCode":"PP5011","moduleCredit":0,"title":"Leading Stakeholders"} +{"moduleCode":"SC4226","moduleCredit":0,"title":"Cultural Production: Power, Voice, Policies"} +{"moduleCode":"TME4225","moduleCredit":0,"title":"Applied Heat Transfer"} +{"moduleCode":"PP5010","moduleCredit":0,"title":"The LKY School Course"} +{"moduleCode":"SC4227","moduleCredit":0,"title":"Gender, Sex and Power"} +{"moduleCode":"CE5204","moduleCredit":0,"title":"Pavement Design & Rehabilitation"} +{"moduleCode":"SC4224","moduleCredit":0,"title":"Welfare and Social Justice"} +{"moduleCode":"CE5203","moduleCredit":0,"title":"Traffic Flow & Control"} +{"moduleCode":"CE5206","moduleCredit":0,"title":"Urban Public Transportation Systems"} +{"moduleCode":"PP5015","moduleCredit":0,"title":"Principles and Applications of Risk Management"} +{"moduleCode":"CE5205","moduleCredit":0,"title":"Transportation Planning"} +{"moduleCode":"PP5014","moduleCredit":0,"title":"Leading Collaboration"} +{"moduleCode":"CE5208","moduleCredit":0,"title":"Transport Infrastructure Asset Management"} +{"moduleCode":"PP5013","moduleCredit":0,"title":"Ethical Leadership"} +{"moduleCode":"SC4228","moduleCredit":0,"title":"Making Sense of Violence"} +{"moduleCode":"TME4223","moduleCredit":0,"title":"Thermal Environmental Engineering"} +{"moduleCode":"PP5012","moduleCredit":0,"title":"Leading Innovation and Change"} +{"moduleCode":"QF4102","moduleCredit":0,"title":"Financial Modelling and Computation"} +{"moduleCode":"EE5139","moduleCredit":0,"title":"Information Theory for Communication Systems"} +{"moduleCode":"EE5138","moduleCredit":0,"title":"Optimization for Communication Systems"} +{"moduleCode":"EE5137","moduleCredit":0,"title":"Stochastic Processes"} +{"moduleCode":"LL5094CV","moduleCredit":0,"title":"Law & Practice - The Law Clinic"} +{"moduleCode":"GES1021","moduleCredit":0,"title":"Natural Heritage of Singapore"} +{"moduleCode":"GES1020","moduleCredit":0,"title":"Western Music within a Singaporean Context"} +{"moduleCode":"GES1023","moduleCredit":0,"title":"Representing Singapore"} +{"moduleCode":"GES1025","moduleCredit":0,"title":"Singapore Literature in English: Selected Texts"} +{"moduleCode":"GES1024","moduleCredit":0,"title":"Real Estate Development & Investment Law"} +{"moduleCode":"GES1026","moduleCredit":0,"title":"Urban Planning in Singapore"} +{"moduleCode":"GES1029","moduleCredit":0,"title":"Singapore Film: Performance of Identity"} +{"moduleCode":"GES1028","moduleCredit":0,"title":"Singapore Society"} +{"moduleCode":"LL4064V","moduleCredit":0,"title":"Competition Law and Policy"} +{"moduleCode":"MA3201","moduleCredit":0,"title":"Algebra II"} +{"moduleCode":"LL5094BV","moduleCredit":0,"title":"Law & Practice - The Law Clinic"} +{"moduleCode":"MA3205","moduleCredit":0,"title":"Set Theory"} +{"moduleCode":"MA3209","moduleCredit":0,"title":"Mathematical Analysis III"} +{"moduleCode":"IS5007","moduleCredit":0,"title":"Strategising for Global IT-enabled Business Success"} +{"moduleCode":"IS5008","moduleCredit":0,"title":"Technology Risk & Cyber Resilience"} +{"moduleCode":"IS5009","moduleCredit":0,"title":"Topics in Financial Technology Solutions"} +{"moduleCode":"GES1031","moduleCredit":0,"title":"Culture and Communication in Singapore"} +{"moduleCode":"TEE3408","moduleCredit":0,"title":"Integrated Analog Design"} +{"moduleCode":"GES1034","moduleCredit":0,"title":"We the Citizens - Understanding Singapore’s Politics"} +{"moduleCode":"IS5003","moduleCredit":0,"title":"Platform Design and Economy"} +{"moduleCode":"GES1033","moduleCredit":0,"title":"Who moved my OB markers?"} +{"moduleCode":"IS5004","moduleCredit":0,"title":"Enterprise Architecture"} +{"moduleCode":"IS5005","moduleCredit":0,"title":"Digital Engagement"} +{"moduleCode":"GES1035","moduleCredit":0,"title":"Singapore: Imagining the Next 50 Years"} +{"moduleCode":"IS5006","moduleCredit":0,"title":"Intelligent System Deployment"} +{"moduleCode":"EE5132","moduleCredit":0,"title":"Wireless and Sensor Networks"} +{"moduleCode":"GES1038","moduleCredit":0,"title":"La Kopi: Forging of the Chinese Singaporean Community"} +{"moduleCode":"GES1039","moduleCredit":0,"title":"Cultural Performances and Practices in Singapore"} +{"moduleCode":"IS5002","moduleCredit":0,"title":"Digital Transformation"} +{"moduleCode":"EC5342R","moduleCredit":0,"title":"International Trade"} +{"moduleCode":"EE5135","moduleCredit":0,"title":"Digital Communications"} +{"moduleCode":"EE5134","moduleCredit":0,"title":"Optical Communications and Networks"} +{"moduleCode":"LL4063V","moduleCredit":0,"title":"Business & Finance For Lawyers"} +{"moduleCode":"PH6210","moduleCredit":0,"title":"Topics in History of Western Philosophy"} +{"moduleCode":"TCN2125","moduleCredit":0,"title":"Heat And Mass Transfer"} +{"moduleCode":"LL5094AV","moduleCredit":0,"title":"Law & Practice - The Law Clinic"} +{"moduleCode":"TTG1401","moduleCredit":0,"title":"Engineering Mathematics I"} +{"moduleCode":"EE4002R","moduleCredit":0,"title":"Research Capstone"} +{"moduleCode":"MA3218","moduleCredit":0,"title":"Applied Algebra"} +{"moduleCode":"BN2301","moduleCredit":0,"title":"Biochemistry and Biomaterials for Bioengineers"} +{"moduleCode":"PF2203","moduleCredit":0,"title":"Quality and Productivity Management"} +{"moduleCode":"PF2205","moduleCredit":0,"title":"Project Finance"} +{"moduleCode":"LL4339","moduleCredit":0,"title":"Comparative Evidence in International Arbitration"} +{"moduleCode":"GES1000","moduleCredit":0,"title":"Singapore Employment Law"} +{"moduleCode":"GES1003","moduleCredit":0,"title":"Changing Landscapes of Singapore"} +{"moduleCode":"GES1002","moduleCredit":0,"title":"Global EC Dimensions of S'pore"} +{"moduleCode":"GES1005","moduleCredit":0,"title":"Everyday Life of Chinese Singaporeans: Past & Present (taught in English)"} +{"moduleCode":"EE4002D","moduleCredit":0,"title":"Design Capstone"} +{"moduleCode":"GES1004","moduleCredit":0,"title":"The Biophysical Env of S'pore"} +{"moduleCode":"TEE2101","moduleCredit":0,"title":"Programming Methodology"} +{"moduleCode":"GES1007","moduleCredit":0,"title":"South Asia in Singapore"} +{"moduleCode":"EC6884","moduleCredit":0,"title":"Behavioral and Experimental Economics"} +{"moduleCode":"GES1006","moduleCredit":0,"title":"Singapore and India: Emerging Relations"} +{"moduleCode":"EC6883","moduleCredit":0,"title":"Advanced Topics in Applied Economics"} +{"moduleCode":"GES1009","moduleCredit":0,"title":"Singapore’s Business History"} +{"moduleCode":"GES1008","moduleCredit":0,"title":"Ethnicity and Nation-Building: Singapore and Malaysia"} +{"moduleCode":"TEE3431","moduleCredit":0,"title":"Microelectronics Materials and Devices"} +{"moduleCode":"FST2107","moduleCredit":0,"title":"Food Analysis and Lab"} +{"moduleCode":"MA3220","moduleCredit":0,"title":"Ordinary Differential Equations"} +{"moduleCode":"FST2106","moduleCredit":0,"title":"Post Harvest Food Processing"} +{"moduleCode":"BX5101","moduleCredit":0,"title":"Business and the Environment"} +{"moduleCode":"FST2108","moduleCredit":0,"title":"Food Safety Assurance"} +{"moduleCode":"DSA2102","moduleCredit":0,"title":"Essential Data Analytics Tools: Numerical Computation"} +{"moduleCode":"LAH2201","moduleCredit":0,"title":"Hindi 2"} +{"moduleCode":"DSA2101","moduleCredit":0,"title":"Essential Data Analytics Tools: Data Visualisation"} +{"moduleCode":"MA3227","moduleCredit":0,"title":"Numerical Analysis II"} +{"moduleCode":"CS3249","moduleCredit":0,"title":"User Interface Development"} +{"moduleCode":"CS3247","moduleCredit":0,"title":"Game Development"} +{"moduleCode":"SSE1201","moduleCredit":0,"title":"Building a Dynamic Singapore - Role of Engineers"} +{"moduleCode":"CS3245","moduleCredit":0,"title":"Information Retrieval"} +{"moduleCode":"TR3001","moduleCredit":0,"title":"New Product Development"} +{"moduleCode":"TR3002","moduleCredit":0,"title":"New Venture Creation"} +{"moduleCode":"CS3243","moduleCredit":0,"title":"Introduction to Artificial Intelligence"} +{"moduleCode":"MNO4861C","moduleCredit":0,"title":"SILHCM: Corp Entrepreneurship & Busi Model Evaluation"} +{"moduleCode":"CS3244","moduleCredit":0,"title":"Machine Learning"} +{"moduleCode":"CS3241","moduleCredit":0,"title":"Computer Graphics"} +{"moduleCode":"GES1010","moduleCredit":0,"title":"Nation-Building in Singapore"} +{"moduleCode":"LL4328","moduleCredit":0,"title":"Sports Law"} +{"moduleCode":"CS3242","moduleCredit":0,"title":"3D Modeling and Animation"} +{"moduleCode":"GES1012","moduleCredit":0,"title":"Popular Culture in Singapore"} +{"moduleCode":"CS3240","moduleCredit":0,"title":"Interaction Design"} +{"moduleCode":"GES1011","moduleCredit":0,"title":"The Evolution of a Global City-State"} +{"moduleCode":"GES1014","moduleCredit":0,"title":"Islam and Contemporary Malay Society"} +{"moduleCode":"GES1013","moduleCredit":0,"title":"Singapore Urban History & Architecture"} +{"moduleCode":"GES1015","moduleCredit":0,"title":"Singapore and Japan: Historical and Contemporary Relationships"} +{"moduleCode":"GES1017","moduleCredit":0,"title":"Building a Dynamic Singapore - Role of Engineers"} +{"moduleCode":"LSE6101","moduleCredit":0,"title":"Fundamentals of Environmental Life Sciences Engineering"} +{"moduleCode":"LL5308V","moduleCredit":0,"title":"Behavioural Economics, Law & Regulation"} +{"moduleCode":"GES1019","moduleCredit":0,"title":"Managing Singapore's Built Environment"} +{"moduleCode":"SP3277","moduleCredit":0,"title":"Nano: from Research Bench to Industrial Applications"} +{"moduleCode":"YHU2305","moduleCredit":0,"title":"Bad Love in 20C Literature"} +{"moduleCode":"MA3233","moduleCredit":0,"title":"Combinatorics and Graphs II"} +{"moduleCode":"YHU2307","moduleCredit":0,"title":"History of Crises: Europe's 20th Century"} +{"moduleCode":"YHU2308","moduleCredit":0,"title":"Introduction to Vocal Technique and Performance"} +{"moduleCode":"DSA5203","moduleCredit":0,"title":"Visual Data Processing and Interpretation"} +{"moduleCode":"DSA5204","moduleCredit":0,"title":"Deep Learning and Applications"} +{"moduleCode":"YHU2302","moduleCredit":0,"title":"Realism and Naturalism"} +{"moduleCode":"YHU2303","moduleCredit":0,"title":"The Aesthetics of Fear: Horror & the Philosophy of Art"} +{"moduleCode":"MA3236","moduleCredit":0,"title":"Non-Linear Programming"} +{"moduleCode":"MA3238","moduleCredit":0,"title":"Stochastic Processes I"} +{"moduleCode":"SE4660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"CS3236","moduleCredit":0,"title":"Introduction to Information Theory"} +{"moduleCode":"GL3551","moduleCredit":0,"title":"FASS Undergraduate Research Opportunity"} +{"moduleCode":"CS3237","moduleCredit":0,"title":"Introduction to Internet of Things"} +{"moduleCode":"GL3550","moduleCredit":0,"title":"Global Studies Internship"} +{"moduleCode":"CS3234","moduleCredit":0,"title":"Logic for Proofs and Programs"} +{"moduleCode":"CS3235","moduleCredit":0,"title":"Computer Security"} +{"moduleCode":"TCE3166","moduleCredit":0,"title":"Structural Steel Design and System"} +{"moduleCode":"TIC2701","moduleCredit":0,"title":"Principles of Programming Languages"} +{"moduleCode":"CS3233","moduleCredit":0,"title":"Competitive Programming"} +{"moduleCode":"CS3230","moduleCredit":0,"title":"Design and Analysis of Algorithms"} +{"moduleCode":"MNO1001X","moduleCredit":0,"title":"Management And Organisation"} +{"moduleCode":"TCE3165","moduleCredit":0,"title":"Structural Concrete Design"} +{"moduleCode":"EE5103","moduleCredit":0,"title":"Computer Control Systems"} +{"moduleCode":"YHU2309","moduleCredit":0,"title":"Medieval Romance: Magic and the Supernatural"} +{"moduleCode":"EE5101","moduleCredit":0,"title":"Linear Systems"} +{"moduleCode":"EN6770","moduleCredit":0,"title":"Graduate Research Seminar"} +{"moduleCode":"JS2101","moduleCredit":0,"title":"Approaches to Japanese Studies I"} +{"moduleCode":"MNO1001A","moduleCredit":0,"title":"Management And Organisation"} +{"moduleCode":"EU2221","moduleCredit":0,"title":"Empires, Colonies and Imperialism"} +{"moduleCode":"MNO1001B","moduleCredit":0,"title":"Management And Organisation"} +{"moduleCode":"LC6009GRSII","moduleCredit":0,"title":"Graduate Research Seminar II (Research Methods)"} +{"moduleCode":"MNO1001C","moduleCredit":0,"title":"Management And Organisation"} +{"moduleCode":"CS3223","moduleCredit":0,"title":"Database Systems Implementation"} +{"moduleCode":"MNO1001D","moduleCredit":0,"title":"Management And Organisation"} +{"moduleCode":"MNO1001E","moduleCredit":0,"title":"Management And Organisation"} +{"moduleCode":"NM4401","moduleCredit":0,"title":"Honours Thesis"} +{"moduleCode":"LL4060B","moduleCredit":0,"title":"World Trade Law"} +{"moduleCode":"LL4307","moduleCredit":0,"title":"EU Maritime Law"} +{"moduleCode":"AR2225","moduleCredit":0,"title":"Reading Visual Images"} +{"moduleCode":"ID5951","moduleCredit":0,"title":"Topics in Industrial Design"} +{"moduleCode":"AR2224","moduleCredit":0,"title":"Ideas and Approaches in Design"} +{"moduleCode":"AR2221","moduleCredit":0,"title":"History and Theory of Southeast Asia Architecture"} +{"moduleCode":"AR2222","moduleCredit":0,"title":"History & Theory Of Western Architecture"} +{"moduleCode":"PR4138","moduleCredit":0,"title":"Pharmacy Professional Skills Development IV"} +{"moduleCode":"MA3252","moduleCredit":0,"title":"Linear and Network Optimisation"} +{"moduleCode":"SW3104","moduleCredit":0,"title":"Social Work Field Practice (II)"} +{"moduleCode":"SW3105","moduleCredit":0,"title":"Community Work Practice"} +{"moduleCode":"MA3259","moduleCredit":0,"title":"Mathematical Methods in Genomics"} +{"moduleCode":"SW3101","moduleCredit":0,"title":"Social Work Research Methods"} +{"moduleCode":"SPH5406","moduleCredit":0,"title":"Contemporary Global Health Issues"} +{"moduleCode":"CS3219","moduleCredit":0,"title":"Software Engineering Principles and Patterns"} +{"moduleCode":"SPH5407","moduleCredit":0,"title":"Programme Evaluation"} +{"moduleCode":"CS3216","moduleCredit":0,"title":"Software Product Engineering for Digital Markets"} +{"moduleCode":"EL3209","moduleCredit":0,"title":"Language, Culture, and Mind"} +{"moduleCode":"SPH5408","moduleCredit":0,"title":"Public Health and Ageing"} +{"moduleCode":"CS3217","moduleCredit":0,"title":"Software Engineering on Modern Application Platforms"} +{"moduleCode":"EL3208","moduleCredit":0,"title":"Bilingualism"} +{"moduleCode":"ES2660","moduleCredit":0,"title":"Communicating in the Information Age"} +{"moduleCode":"SPH5409","moduleCredit":0,"title":"Qualitative Methods in Public Health"} +{"moduleCode":"EL3203","moduleCredit":0,"title":"Semantics and Pragmatics"} +{"moduleCode":"CS3210","moduleCredit":0,"title":"Parallel Computing"} +{"moduleCode":"GES1041","moduleCredit":0,"title":"Everyday Ethics in Singapore"} +{"moduleCode":"CS3211","moduleCredit":0,"title":"Parallel and Concurrent Programming"} +{"moduleCode":"GES1040","moduleCredit":0,"title":"Prominent Chinese in Colonial Singapore"} +{"moduleCode":"GES1042","moduleCredit":0,"title":"Public Health in Singapore: Challenges and Changes"} +{"moduleCode":"SPH5401","moduleCredit":0,"title":"Health Economics and Financing"} +{"moduleCode":"SPH5402","moduleCredit":0,"title":"Management of Healthcare Organisations"} +{"moduleCode":"SPH5403","moduleCredit":0,"title":"Medical & Humanitarian Emergencies"} +{"moduleCode":"MS1102E","moduleCredit":0,"title":"Malays - Tradition, Conflict and Change"} +{"moduleCode":"SPH5404","moduleCredit":0,"title":"Measuring and Managing Quality of Care"} +{"moduleCode":"SPH5405","moduleCredit":0,"title":"Introduction to Health Services Research"} +{"moduleCode":"QF4199","moduleCredit":0,"title":"Honours Project in Quantitative Finance"} +{"moduleCode":"CN6020","moduleCredit":0,"title":"Advanced Reaction Engineering"} +{"moduleCode":"TS3222","moduleCredit":0,"title":"Applied Theatre"} +{"moduleCode":"EE6439","moduleCredit":0,"title":"Micro/Nano Electromechanical Systems (Advanced)"} +{"moduleCode":"EL3210","moduleCredit":0,"title":"Topics in the Psychology of Language"} +{"moduleCode":"MA3264","moduleCredit":0,"title":"Mathematical Modelling"} +{"moduleCode":"EE5106","moduleCredit":0,"title":"Advanced Robotics"} +{"moduleCode":"BSN4811A","moduleCredit":0,"title":"Innovation and Productivity (with Econometrics)"} +{"moduleCode":"EE5104","moduleCredit":0,"title":"Adaptive Control Systems"} +{"moduleCode":"MA3265","moduleCredit":0,"title":"Introduction to Number Theory"} +{"moduleCode":"EE6436","moduleCredit":0,"title":"Advanced Characterization of Materials and Devices"} +{"moduleCode":"LL6283V","moduleCredit":0,"title":"Artificial Intelligence, Information Science & Law"} +{"moduleCode":"EE6437","moduleCredit":0,"title":"Advanced Semiconductor Devices"} +{"moduleCode":"EE6438","moduleCredit":0,"title":"Magnetic materials and devices"} +{"moduleCode":"MA3269","moduleCredit":0,"title":"Mathematical Finance I"} +{"moduleCode":"YHU2310","moduleCredit":0,"title":"A Reporters Toolbox: The Practice of Daily Journalism"} +{"moduleCode":"CS3203","moduleCredit":0,"title":"Software Engineering Project"} +{"moduleCode":"EL3214","moduleCredit":0,"title":"Language Documentation"} +{"moduleCode":"EL3216","moduleCredit":0,"title":"Language and the Internet"} +{"moduleCode":"TCE3155","moduleCredit":0,"title":"Structural Analysis"} +{"moduleCode":"UTC3101","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"UTC3102","moduleCredit":0,"title":"Tembusu Undergraduate Research Opportunity (UROP)"} +{"moduleCode":"EE5110","moduleCredit":0,"title":"Special Topics in Automation and Control"} +{"moduleCode":"DMB1204DO","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"EE6440","moduleCredit":0,"title":"Advanced Topics in Photonics"} +{"moduleCode":"TS3233","moduleCredit":0,"title":"Southeast Asian Performance"} +{"moduleCode":"EE5111","moduleCredit":0,"title":"Selected Topics in Industrial Control & Instrumentation"} +{"moduleCode":"TS3234","moduleCredit":0,"title":"Performance and Popular Culture"} +{"moduleCode":"BL5222","moduleCredit":0,"title":"Cellular Mechanisms"} +{"moduleCode":"BL5221","moduleCredit":0,"title":"Plant and Microbial Development"} +{"moduleCode":"BL5220","moduleCredit":0,"title":"Advanced Animal Development"} +{"moduleCode":"SH5003","moduleCredit":0,"title":"Fundamentals in Environmental Protection"} +{"moduleCode":"SH5002","moduleCredit":0,"title":"Fundamentals in Industrial Safety"} +{"moduleCode":"PS5506","moduleCredit":0,"title":"Globalization and Public Governance"} +{"moduleCode":"LAK4201","moduleCredit":0,"title":"Korean 5"} +{"moduleCode":"LLD5307","moduleCredit":0,"title":"EU Maritime Law"} +{"moduleCode":"SPH5890C","moduleCredit":0,"title":"Independent Study in Environmental / Occupational Health"} +{"moduleCode":"BL5229","moduleCredit":0,"title":"Fundamentals in Biophysical Sciences"} +{"moduleCode":"EL5216R","moduleCredit":0,"title":"Corpus Linguistics"} +{"moduleCode":"SPH5890D","moduleCredit":0,"title":"Independent Study in Health Policy and Systems"} +{"moduleCode":"BL5228","moduleCredit":0,"title":"Advances in Cell and Molecular Biology"} +{"moduleCode":"LAK4203","moduleCredit":0,"title":"Korean 7"} +{"moduleCode":"SPH5890A","moduleCredit":0,"title":"Independent Study in Epidemiology and Disease Control"} +{"moduleCode":"CS3245R","moduleCredit":0,"title":"Information Retrieval"} +{"moduleCode":"LAK4202","moduleCredit":0,"title":"Korean 6"} +{"moduleCode":"LL4158V","moduleCredit":0,"title":"Climate Change Law"} +{"moduleCode":"SPH5890B","moduleCredit":0,"title":"Independent Study in Quantitative Methods"} +{"moduleCode":"BL5224","moduleCredit":0,"title":"Special topics in Biological Sciences"} +{"moduleCode":"BL5223","moduleCredit":0,"title":"Advanced Molecular Genetics"} +{"moduleCode":"ECA5396","moduleCredit":0,"title":"Economics of Business and Law of Intellectual Assets"} +{"moduleCode":"MT5007","moduleCredit":0,"title":"Management of Technological Innovation"} +{"moduleCode":"MT5006","moduleCredit":0,"title":"Strategic & New Product Development"} +{"moduleCode":"MT5008","moduleCredit":0,"title":"Corporate Entrepreneurship"} +{"moduleCode":"MT5003","moduleCredit":0,"title":"Creativity and Innovation"} +{"moduleCode":"TM4263","moduleCredit":0,"title":"Manufact'G Simulat'N & Data Communicat'N"} +{"moduleCode":"TM4264","moduleCredit":0,"title":"Fundamentals of Automotive Engineering"} +{"moduleCode":"LL5357V","moduleCredit":0,"title":"Regulation & Political Economy"} +{"moduleCode":"SN4221","moduleCredit":0,"title":"Regional Conflict & Cooperation in Asia"} +{"moduleCode":"EE6990","moduleCredit":0,"title":"Research Attachment"} +{"moduleCode":"MT5001","moduleCredit":0,"title":"IP Management"} +{"moduleCode":"LC5262AV","moduleCredit":0,"title":"International Commercial Arbitration"} +{"moduleCode":"BL5210","moduleCredit":0,"title":"Biogeography"} +{"moduleCode":"EE2011E","moduleCredit":0,"title":"Engineering Electromagnetics"} +{"moduleCode":"LL4024V","moduleCredit":0,"title":"Indonesian Law"} +{"moduleCode":"BL5218","moduleCredit":0,"title":"Directed Studies in Behavioural Ecology"} +{"moduleCode":"BL5217","moduleCredit":0,"title":"Population Genomics and Phylogenomics"} +{"moduleCode":"BL5216","moduleCredit":0,"title":"Advanced Genetics and Genome Sciences"} +{"moduleCode":"EL4203","moduleCredit":0,"title":"Semantics"} +{"moduleCode":"SPH5890G","moduleCredit":0,"title":"Independent Study in Global Health Programs: Planning and Evaluation"} +{"moduleCode":"LL5358Z","moduleCredit":0,"title":"ICC Arbitration"} +{"moduleCode":"SPH5890E","moduleCredit":0,"title":"Independent Study in Health Services Research"} +{"moduleCode":"IE5307","moduleCredit":0,"title":"Topics in Human Factors Engineering"} +{"moduleCode":"SPH5890F","moduleCredit":0,"title":"Independent Study in Health Promotion"} +{"moduleCode":"CE5603B","moduleCredit":0,"title":"Evaluating Economic Risks in Projects"} +{"moduleCode":"MT5010","moduleCredit":0,"title":"Technology Forecasting & Intelligence"} +{"moduleCode":"MT5012","moduleCredit":0,"title":"Marketing of High-Technology Products and Innovations"} +{"moduleCode":"CE5603A","moduleCredit":0,"title":"Evaluating Economic Feasibility of Projects"} +{"moduleCode":"MT5011","moduleCredit":0,"title":"Engineering Business Finance Fundamentals"} +{"moduleCode":"SN1101E","moduleCredit":0,"title":"South Asia : People, Culture, Develop'm"} +{"moduleCode":"FIN3134","moduleCredit":0,"title":"Household Finance"} +{"moduleCode":"CE6077","moduleCredit":0,"title":"Advanced Numerical Methods in Mechanics & Envr. Flows"} +{"moduleCode":"DSA5102","moduleCredit":0,"title":"Foundations of Machine Learning"} +{"moduleCode":"ESP4901A","moduleCredit":0,"title":"Research Project"} +{"moduleCode":"UCV2209","moduleCredit":0,"title":"The Heterogeneous Indians of Contemporary Singapore"} +{"moduleCode":"FIN2704X","moduleCredit":0,"title":"Finance"} +{"moduleCode":"LL4289V","moduleCredit":0,"title":"The Evolution of International Arbitration"} +{"moduleCode":"BL5204","moduleCredit":0,"title":"Graduate Bootcamp for Biotechnology Industry"} +{"moduleCode":"BL5203","moduleCredit":0,"title":"Molecular Recognition and Interactions"} +{"moduleCode":"IE5301","moduleCredit":0,"title":"Human Factors In Engineering And Design"} +{"moduleCode":"FIN3131","moduleCredit":0,"title":"Fixed Income Securities"} +{"moduleCode":"BL5201","moduleCredit":0,"title":"Structural Biology And Proteomics"} +{"moduleCode":"EL4216","moduleCredit":0,"title":"Lexicology and Lexicography"} +{"moduleCode":"FIN3130","moduleCredit":0,"title":"Financial Modelling"} +{"moduleCode":"YSC3252","moduleCredit":0,"title":"Statistical Computing"} +{"moduleCode":"YSC3253","moduleCredit":0,"title":"Coral Reef Ecology and Environmental Change"} +{"moduleCode":"LL5359Z","moduleCredit":0,"title":"SIAC and Institutional Arbitration"} +{"moduleCode":"AR1102","moduleCredit":0,"title":"Design 2"} +{"moduleCode":"LAJ2203","moduleCredit":0,"title":"Japanese 4"} +{"moduleCode":"AR1101","moduleCredit":0,"title":"Design I"} +{"moduleCode":"LAJ2201","moduleCredit":0,"title":"Japanese 2"} +{"moduleCode":"LAJ2202","moduleCredit":0,"title":"Japanese 3"} +{"moduleCode":"PR2202","moduleCredit":0,"title":"Cosmetics & Perfumes"} +{"moduleCode":"MT5021","moduleCredit":0,"title":"Problem Solving Skills for Engineering Managers"} +{"moduleCode":"MT5020","moduleCredit":0,"title":"Managing the Human elements of Technology Management"} +{"moduleCode":"MT5022","moduleCredit":0,"title":"Digital Disruption and Technology Strategy"} +{"moduleCode":"EL4222","moduleCredit":0,"title":"Stylistics and Drama"} +{"moduleCode":"EE5666","moduleCredit":0,"title":"Industrial Attachment"} +{"moduleCode":"GMS5121","moduleCredit":0,"title":"Advanced Topics in Regulatory Policy"} +{"moduleCode":"ME5608A","moduleCredit":0,"title":"Principles and Processes of Additive Manufacturing"} +{"moduleCode":"EL6884","moduleCredit":0,"title":"Topics in Applied Linguistics"} +{"moduleCode":"ME5608B","moduleCredit":0,"title":"Hybrid Manufacturing"} +{"moduleCode":"EL6881","moduleCredit":0,"title":"Topics in Language and Cognition"} +{"moduleCode":"EL6882","moduleCredit":0,"title":"Topics in Language and Society"} +{"moduleCode":"EE6999","moduleCredit":0,"title":"Doctoral Seminars"} +{"moduleCode":"EL6880","moduleCredit":0,"title":"Topics in Grammatical Theory"} +{"moduleCode":"CS3244R","moduleCredit":0,"title":"Machine Learning"} +{"moduleCode":"ES1000","moduleCredit":0,"title":"Foundation Academic English"} +{"moduleCode":"ES2331","moduleCredit":0,"title":"Communicating Engineering"} +{"moduleCode":"LSM2191","moduleCredit":0,"title":"Laboratory Techniques in Life Sciences"} +{"moduleCode":"YSC3240","moduleCredit":0,"title":"Foundations of Applied Mathematics"} +{"moduleCode":"YSC3241","moduleCredit":0,"title":"Computational and Systems Biology"} +{"moduleCode":"YSC3248","moduleCredit":0,"title":"Parallel, Concurrent and Distributed Programming"} +{"moduleCode":"FIN3129","moduleCredit":0,"title":"Independent Study in Finance"} +{"moduleCode":"YSC3249","moduleCredit":0,"title":"Statistical Inference"} +{"moduleCode":"TS5212","moduleCredit":0,"title":"Asian International Cinema"} +{"moduleCode":"SSB1204T","moduleCredit":0,"title":"Singapore Employment Law"} +{"moduleCode":"YSC3246","moduleCredit":0,"title":"Modern Astrophysics"} +{"moduleCode":"PS1101E","moduleCredit":0,"title":"Introduction to Politics"} +{"moduleCode":"YSC3247","moduleCredit":0,"title":"The Genomics of Human History"} +{"moduleCode":"GMS5113","moduleCredit":0,"title":"Post-market Surveillance and Enforcement"} +{"moduleCode":"FIN3113","moduleCredit":0,"title":"Financial Statement Analysis"} +{"moduleCode":"GMS5111","moduleCredit":0,"title":"Pharmacovigilance Principles and Frameworks"} +{"moduleCode":"FIN3115","moduleCredit":0,"title":"International Financial Management"} +{"moduleCode":"FIN3117","moduleCredit":0,"title":"Bank Management"} +{"moduleCode":"LL4021V","moduleCredit":0,"title":"Environmental Law"} +{"moduleCode":"MS4880A","moduleCredit":0,"title":"Orientations in Muslim Resurgence Movements"} +{"moduleCode":"FIN3116","moduleCredit":0,"title":"Options and Futures"} +{"moduleCode":"LL4287V","moduleCredit":0,"title":"ASEAN Law and Policy"} +{"moduleCode":"PS4216","moduleCredit":0,"title":"The Study of War"} +{"moduleCode":"CS3241R","moduleCredit":0,"title":"Computer Graphics"} +{"moduleCode":"LL4008AV","moduleCredit":0,"title":"Carriage of Goods By Sea"} +{"moduleCode":"SN4262","moduleCredit":0,"title":"Hindutva Nationalism"} +{"moduleCode":"PS4220","moduleCredit":0,"title":"Rhetoric and Politics"} +{"moduleCode":"FIN3119","moduleCredit":0,"title":"Risk and Insurance"} +{"moduleCode":"FIN3118","moduleCredit":0,"title":"Financial Risk Management"} +{"moduleCode":"CH2391","moduleCredit":0,"title":"Strangers in Chinese Fiction and Film (in English)"} +{"moduleCode":"ST2137","moduleCredit":0,"title":"Computer Aided Data Analysis"} +{"moduleCode":"BSP3701B","moduleCredit":0,"title":"Strategic Management"} +{"moduleCode":"EE6934","moduleCredit":0,"title":"Deep Learning (Advanced)"} +{"moduleCode":"GMS5101","moduleCredit":0,"title":"Clinical Trial Design and Data Analysis"} +{"moduleCode":"BSP3701C","moduleCredit":0,"title":"Strategic Management"} +{"moduleCode":"FIN3102","moduleCredit":0,"title":"Investment Analysis and Portfolio Management"} +{"moduleCode":"BSP3701A","moduleCredit":0,"title":"Strategic Management"} +{"moduleCode":"FIN3101","moduleCredit":0,"title":"Corporate Finance"} +{"moduleCode":"GMS5105","moduleCredit":0,"title":"Generic Medicines"} +{"moduleCode":"LL4286V","moduleCredit":0,"title":"Transnational Terrorism and International Law"} +{"moduleCode":"PS4208","moduleCredit":0,"title":"Theories of International Relations"} +{"moduleCode":"MA2311","moduleCredit":0,"title":"Techniques in Advanced Calculus"} +{"moduleCode":"GMS5103","moduleCredit":0,"title":"Regulation of Cell, Tissue and Gene Therapies"} +{"moduleCode":"GMS5104","moduleCredit":0,"title":"Biotherapeutics and Biosimilars"} +{"moduleCode":"PS4205","moduleCredit":0,"title":"Contemporary Politics of Southeast Asia"} +{"moduleCode":"ID2042","moduleCredit":0,"title":"Work Experience Internship"} +{"moduleCode":"DMB1201DO","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"ID2041","moduleCredit":0,"title":"Design Internship"} +{"moduleCode":"JS6660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"MS4880B","moduleCredit":0,"title":"Malays Encountering Globalization: Culture and Identity"} +{"moduleCode":"TS5232","moduleCredit":0,"title":"Performance, History and Cultural Memory"} +{"moduleCode":"EC5386R","moduleCredit":0,"title":"Issues in Port Economics"} +{"moduleCode":"EE4303","moduleCredit":0,"title":"Industrial Control Systems"} +{"moduleCode":"EE4302","moduleCredit":0,"title":"Advanced Control Systems"} +{"moduleCode":"EE4308","moduleCredit":0,"title":"Autonomous Robot Systems"} +{"moduleCode":"EL4251","moduleCredit":0,"title":"Social Thought in Language"} +{"moduleCode":"EE4307","moduleCredit":0,"title":"Control Systems Design And Simulation"} +{"moduleCode":"LL4285V","moduleCredit":0,"title":"International Dispute Settlement"} +{"moduleCode":"EE4305","moduleCredit":0,"title":"Fuzzy/Neural Systems for Intelligent Robotics"} +{"moduleCode":"EL4252","moduleCredit":0,"title":"Interactional Discourse"} +{"moduleCode":"PS4237","moduleCredit":0,"title":"Capitalism and Political Theory"} +{"moduleCode":"BSP3701X","moduleCredit":0,"title":"Strategic Management"} +{"moduleCode":"PS4239","moduleCredit":0,"title":"Seminar in International Relations of Southeast Asia"} +{"moduleCode":"PS4233","moduleCredit":0,"title":"Existentialist Political Theory"} +{"moduleCode":"EL4258","moduleCredit":0,"title":"Metapragmatics and Language Ideology"} +{"moduleCode":"IS5117","moduleCredit":0,"title":"Digital Government"} +{"moduleCode":"AR3721","moduleCredit":0,"title":"Building Environmental System Modelling"} +{"moduleCode":"IS5114","moduleCredit":0,"title":"Global IT Project and Vendor Management"} +{"moduleCode":"IS5116","moduleCredit":0,"title":"Digital Entrepreneurship"} +{"moduleCode":"IS5110","moduleCredit":0,"title":"Software Project Management"} +{"moduleCode":"IS5111","moduleCredit":0,"title":"IT Strategy and Governance"} +{"moduleCode":"MUA3195","moduleCredit":0,"title":"Voice Literature 2"} +{"moduleCode":"MUA3194","moduleCredit":0,"title":"Voice Literature 1"} +{"moduleCode":"ST2132","moduleCredit":0,"title":"Mathematical Statistics"} +{"moduleCode":"EE4101E","moduleCredit":0,"title":"Radio-Frequency (RF) Communications"} +{"moduleCode":"ST2131","moduleCredit":0,"title":"Probability"} +{"moduleCode":"PS4228","moduleCredit":0,"title":"Comparative Democratic Politics"} +{"moduleCode":"PS4224","moduleCredit":0,"title":"State and Society"} +{"moduleCode":"TIE2100","moduleCredit":0,"title":"Probability Models with Applications"} +{"moduleCode":"CS5346","moduleCredit":0,"title":"Information Visualisation"} +{"moduleCode":"CS5344","moduleCredit":0,"title":"Big-Data Analytics Technology"} +{"moduleCode":"LL4008BV","moduleCredit":0,"title":"Charterparties"} +{"moduleCode":"PS4231","moduleCredit":0,"title":"Social Theory and International Relations"} +{"moduleCode":"PS4230","moduleCredit":0,"title":"Public Sector Reforms in China"} +{"moduleCode":"CS5340","moduleCredit":0,"title":"Uncertainty Modelling in AI"} +{"moduleCode":"MUA3191","moduleCredit":0,"title":"Junior Recital in Voice"} +{"moduleCode":"MUA3190","moduleCredit":0,"title":"Applied Voice Major Study 3B"} +{"moduleCode":"LL6244V","moduleCredit":0,"title":"Criminal Practice"} +{"moduleCode":"MUA3188","moduleCredit":0,"title":"Live Sound Reinforcement"} +{"moduleCode":"ST5211","moduleCredit":0,"title":"Sampling from Finite Populations"} +{"moduleCode":"MUA3181","moduleCredit":0,"title":"Advanced Concepts in Orchestral Repertoire"} +{"moduleCode":"QF5206A","moduleCredit":0,"title":"Topics in Quantitative Finance II"} +{"moduleCode":"BMC5002B","moduleCredit":0,"title":"Contemporary Issues in Strategy"} +{"moduleCode":"SWD5103","moduleCredit":0,"title":"Contemporary Social Work Practice"} +{"moduleCode":"BMC5002A","moduleCredit":0,"title":"Corporate Strategy"} +{"moduleCode":"BMO6010A","moduleCredit":0,"title":"Organizational Behavior Seminar: Leadership"} +{"moduleCode":"MUA3189","moduleCredit":0,"title":"Live Sound Reinforcement Project"} +{"moduleCode":"SWD5102","moduleCredit":0,"title":"Social Work With Groups and Community"} +{"moduleCode":"TIE2110","moduleCredit":0,"title":"Operations Research I"} +{"moduleCode":"CN5999","moduleCredit":0,"title":"Graduate Seminars"} +{"moduleCode":"ME2134E","moduleCredit":0,"title":"Fluid Mechanics I"} +{"moduleCode":"ST5202","moduleCredit":0,"title":"Applied Regression Analysis"} +{"moduleCode":"GS5002","moduleCredit":0,"title":"Academic Professional Skills and Techniques"} +{"moduleCode":"ST5203","moduleCredit":0,"title":"Design of Experiments for Product Design and Process Improvements"} +{"moduleCode":"LL4203C","moduleCredit":0,"title":"International Moots and Other Competitions"} +{"moduleCode":"ST5208","moduleCredit":0,"title":"Analytics for Quality Control and Productivity Improvements"} +{"moduleCode":"ST5209","moduleCredit":0,"title":"Analysis of Time Series Data"} +{"moduleCode":"IE4259E","moduleCredit":0,"title":"Selected Topics in Systems Engineering"} +{"moduleCode":"LL4203A","moduleCredit":0,"title":"International Moots and Other Competitions"} +{"moduleCode":"LL4203B","moduleCredit":0,"title":"International Moots and Other Competitions"} +{"moduleCode":"ST5207","moduleCredit":0,"title":"Nonparametric Regression"} +{"moduleCode":"TME3101","moduleCredit":0,"title":"Mechanical Systems Design"} +{"moduleCode":"MUA3176","moduleCredit":0,"title":"AAS Project 4"} +{"moduleCode":"ESE5401","moduleCredit":0,"title":"Water Quality Management"} +{"moduleCode":"GER1000H","moduleCredit":0,"title":"Quantitative Reasoning"} +{"moduleCode":"MUA3175","moduleCredit":0,"title":"AAS Project 3"} +{"moduleCode":"LL6245V","moduleCredit":0,"title":"Regulatory Foundations of Public Law"} +{"moduleCode":"MUA3173","moduleCredit":0,"title":"Electroacoustics"} +{"moduleCode":"ST5222","moduleCredit":0,"title":"Advanced Topics in Applied Statistics"} +{"moduleCode":"MUA3172","moduleCredit":0,"title":"Audio Postproduction 2"} +{"moduleCode":"ST5223","moduleCredit":0,"title":"Statistical Models:Theory/Applications"} +{"moduleCode":"MUA3170","moduleCredit":0,"title":"Audio Postproduction I"} +{"moduleCode":"BMM5001","moduleCredit":0,"title":"Leadership and Management"} +{"moduleCode":"ESE5407","moduleCredit":0,"title":"Membrane Technology for Water Management"} +{"moduleCode":"LL4202V","moduleCredit":0,"title":"ASEAN Economic Community Law and Policy"} +{"moduleCode":"BMM5002","moduleCredit":0,"title":"Asia-Pacific Economic and Business Environment"} +{"moduleCode":"BMC5001B","moduleCredit":0,"title":"Managerial Skills"} +{"moduleCode":"YSC4211B","moduleCredit":0,"title":"Adv Topics Molecular, Cell & Developmental Bio: Stem Cells"} +{"moduleCode":"BMC5001A","moduleCredit":0,"title":"Leadership"} +{"moduleCode":"ESE5405","moduleCredit":0,"title":"Water Treatment Processes"} +{"moduleCode":"MUA3178","moduleCredit":0,"title":"MS / MCP 3rd Year Project"} +{"moduleCode":"ME5403","moduleCredit":0,"title":"Computer Control Systems"} +{"moduleCode":"LL5350V","moduleCredit":0,"title":"Privacy & Data Protection Law"} +{"moduleCode":"ME5404","moduleCredit":0,"title":"Neural Networks"} +{"moduleCode":"ME5401","moduleCredit":0,"title":"Linear Systems"} +{"moduleCode":"ME5402","moduleCredit":0,"title":"Advanced Robotics"} +{"moduleCode":"ME5405","moduleCredit":0,"title":"Machine Vision"} +{"moduleCode":"GER1000B","moduleCredit":0,"title":"Quantitative Reasoning"} +{"moduleCode":"ST5215","moduleCredit":0,"title":"Advanced Statistical Theory"} +{"moduleCode":"ME2135E","moduleCredit":0,"title":"Fluid Mechanics II"} +{"moduleCode":"ST5214","moduleCredit":0,"title":"Advanced Probability Theory"} +{"moduleCode":"PC2267","moduleCredit":0,"title":"Biophysics I"} +{"moduleCode":"TME3112","moduleCredit":0,"title":"Mechanics of Machines"} +{"moduleCode":"EE4415E","moduleCredit":0,"title":"Integrated Digital Design"} +{"moduleCode":"BMS5511","moduleCredit":0,"title":"Sustainability Marketing"} +{"moduleCode":"BMS5512","moduleCredit":0,"title":"Marketing Analytics"} +{"moduleCode":"MUA3163","moduleCredit":0,"title":"Musical Pathways"} +{"moduleCode":"MUA3162","moduleCredit":0,"title":"Intermediate Studies on Principal Instrument"} +{"moduleCode":"MUA3161","moduleCredit":0,"title":"Junior Recital"} +{"moduleCode":"BMC5004B","moduleCredit":0,"title":"Asian Markets and Industries"} +{"moduleCode":"BMC5004A","moduleCredit":0,"title":"Managerial Economics"} +{"moduleCode":"BMO6012A","moduleCredit":0,"title":"Organizational Behavior Seminar: Interpersonal Relations"} +{"moduleCode":"NUR1108A","moduleCredit":0,"title":"Nursing Practice Experience 1.2"} +{"moduleCode":"NUR1108B","moduleCredit":0,"title":"Clinical Practice: Medical/Surgical I"} +{"moduleCode":"BMS5510","moduleCredit":0,"title":"Marketing Strategies in the New Economy"} +{"moduleCode":"LL6379V","moduleCredit":0,"title":"Future of Int'l Commercial Arbitration in APAC Region"} +{"moduleCode":"TIE2130","moduleCredit":0,"title":"Quality Engineering I"} +{"moduleCode":"MUT3201","moduleCredit":0,"title":"Modern Music"} +{"moduleCode":"PC2239","moduleCredit":0,"title":"Special Problems in Undergrad Physics I"} +{"moduleCode":"CM5100A","moduleCredit":0,"title":"Advanced MSc Project"} +{"moduleCode":"BMM5003","moduleCredit":0,"title":"Business Finance & Growth Economics for Policy Makers"} +{"moduleCode":"CH6770","moduleCredit":0,"title":"Graduate Research Seminar"} +{"moduleCode":"PC2230","moduleCredit":0,"title":"Thermodynamics and Statistical Mechanics"} +{"moduleCode":"LAT3202","moduleCredit":0,"title":"Thai 4"} +{"moduleCode":"XFS4199S","moduleCredit":0,"title":"Integrated Honours Project"} +{"moduleCode":"BMS5503","moduleCredit":0,"title":"Pricing"} +{"moduleCode":"MUA3154","moduleCredit":0,"title":"Noon Recital Series 3B"} +{"moduleCode":"CH2393","moduleCredit":0,"title":"Chinese Business Enterprises and Management (in English)"} +{"moduleCode":"MUA3153","moduleCredit":0,"title":"Noon Recital Series 3A"} +{"moduleCode":"LAT3201","moduleCredit":0,"title":"Thai 3"} +{"moduleCode":"BMS5506","moduleCredit":0,"title":"Consumer Behaviour"} +{"moduleCode":"BMS5507","moduleCredit":0,"title":"Behavioral Economics"} +{"moduleCode":"PS5111R","moduleCredit":0,"title":"Research Design in Political Science"} +{"moduleCode":"ST5201","moduleCredit":0,"title":"Statistical Foundations of Data Science"} +{"moduleCode":"BMS5504","moduleCredit":0,"title":"Marketing Analysis and Decision Making"} +{"moduleCode":"BMS5505","moduleCredit":0,"title":"Marketing in the Digital Age"} +{"moduleCode":"BMC5003A","moduleCredit":0,"title":"Decision Making"} +{"moduleCode":"BMO6011A","moduleCredit":0,"title":"Organizational Behavior Seminar: Work, employee and organizational well-being"} +{"moduleCode":"TIE2140","moduleCredit":0,"title":"Engineering Economy"} +{"moduleCode":"MUT3215","moduleCredit":0,"title":"Fundamentals of Composition"} +{"moduleCode":"TC1411","moduleCredit":0,"title":"Mathematics for Chemical Engineers 1"} +{"moduleCode":"MUT3213","moduleCredit":0,"title":"Romantic Styles"} +{"moduleCode":"BMC5003B","moduleCredit":0,"title":"Information Management"} +{"moduleCode":"SPH6003","moduleCredit":0,"title":"Nutritional Epidemiology"} +{"moduleCode":"SPH6004","moduleCredit":0,"title":"Advanced Statistical Learning"} +{"moduleCode":"ESP5402","moduleCredit":0,"title":"Transport Phenomena in Energy Systems"} +{"moduleCode":"MUT3216","moduleCredit":0,"title":"Bach Suites"} +{"moduleCode":"SPH6006","moduleCredit":0,"title":"Advanced Health Behaviour and Communication"} +{"moduleCode":"ESP5403","moduleCredit":0,"title":"Nanomaterials for Energy Systems"} +{"moduleCode":"SPH6007","moduleCredit":0,"title":"Health Systems and Policy Analysis"} +{"moduleCode":"MNO4712","moduleCredit":0,"title":"Experiencing Work: Effects on Behaviour & Well-Being"} +{"moduleCode":"BMS5508","moduleCredit":0,"title":"Design Thinking & Business Innovations"} +{"moduleCode":"MNO4711","moduleCredit":0,"title":"Consulting to Management"} +{"moduleCode":"XFS4199M","moduleCredit":0,"title":"Integrated Honours Project"} +{"moduleCode":"BMS5509","moduleCredit":0,"title":"Consumer Culture Theory"} +{"moduleCode":"CN3121E","moduleCredit":0,"title":"Process Dynamics & Control"} +{"moduleCode":"ME4225E","moduleCredit":0,"title":"Applied Heat Transfer"} +{"moduleCode":"SPH6001","moduleCredit":0,"title":"Advanced Epidemiology II"} +{"moduleCode":"SPH6002","moduleCredit":0,"title":"Advanced Quantitative Methods II"} +{"moduleCode":"PM5000","moduleCredit":0,"title":"Dissertation"} +{"moduleCode":"LL5099","moduleCredit":0,"title":"Maritime Law"} +{"moduleCode":"TIE2150","moduleCredit":0,"title":"Human Factors Engineering"} +{"moduleCode":"TC1422","moduleCredit":0,"title":"Materials for Chemical Engineers"} +{"moduleCode":"LAS1201","moduleCredit":0,"title":"Spanish 1"} +{"moduleCode":"MUT3225","moduleCredit":0,"title":"Teaching Music Online 2"} +{"moduleCode":"LL4029V","moduleCredit":0,"title":"International Commercial Arbitration"} +{"moduleCode":"MUT3224","moduleCredit":0,"title":"Teaching Music Online"} +{"moduleCode":"MUT3223","moduleCredit":0,"title":"Early Twentieth-Century Music"} +{"moduleCode":"LI5202","moduleCredit":0,"title":"Supply Chain Management Strategies and Case Studies"} +{"moduleCode":"ME4103","moduleCredit":0,"title":"Mechanical Engineering and Society"} +{"moduleCode":"LI5204","moduleCredit":0,"title":"Supply Chain Simulation and Optimization"} +{"moduleCode":"ME4105","moduleCredit":0,"title":"Specialization Study Module"} +{"moduleCode":"YSC3232","moduleCredit":0,"title":"Software Engineering"} +{"moduleCode":"DMB1201FIN","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"LI5201","moduleCredit":0,"title":"Special Topics in Logistics"} +{"moduleCode":"YSC3237","moduleCredit":0,"title":"Introduction to Modern Algebra"} +{"moduleCode":"YSC3239","moduleCredit":0,"title":"Geometry and the Emergence of Perspective"} +{"moduleCode":"YSC3233","moduleCredit":0,"title":"Molecular Cell Biology"} +{"moduleCode":"ME4102","moduleCredit":0,"title":"Standards in Mechanical Engineering"} +{"moduleCode":"DAO1704","moduleCredit":0,"title":"Decision Analytics using Spreadsheets"} +{"moduleCode":"ME4101","moduleCredit":0,"title":"Bachelor Of Engineering Dissertation"} +{"moduleCode":"YSC3236","moduleCredit":0,"title":"Functional Programming and Proving"} +{"moduleCode":"MUA3133","moduleCredit":0,"title":"Compositional Discourse"} +{"moduleCode":"LL5088","moduleCredit":0,"title":"Chinese Contract Law"} +{"moduleCode":"NUR5612","moduleCredit":0,"title":"Clinical Practicum II (Paediatrics)"} +{"moduleCode":"BT4016","moduleCredit":0,"title":"Risk Analytics for Financial Services"} +{"moduleCode":"BT4015","moduleCredit":0,"title":"Geospatial Analytics"} +{"moduleCode":"BT4014","moduleCredit":0,"title":"Analytics Driven Design of Adaptive Systems"} +{"moduleCode":"BT4013","moduleCredit":0,"title":"Analytics for Capital Market Trading and Investment"} +{"moduleCode":"PL3281B","moduleCredit":0,"title":"Lab in Memory and Cognition"} +{"moduleCode":"BPS5000","moduleCredit":0,"title":"Dissertation"} +{"moduleCode":"QT5198","moduleCredit":0,"title":"Graduate Seminar in Quantum Information"} +{"moduleCode":"NUR1107B","moduleCredit":0,"title":"Clinical Practice: Community Care I"} +{"moduleCode":"SW5208R","moduleCredit":0,"title":"Using Play Therapy with Children and Families"} +{"moduleCode":"BT4012","moduleCredit":0,"title":"Fraud Analytics"} +{"moduleCode":"BT4011","moduleCredit":0,"title":"Business Analytics Capstone Industry Project"} +{"moduleCode":"PL3281D","moduleCredit":0,"title":"Lab in Music Perception and Cognition"} +{"moduleCode":"BT4010","moduleCredit":0,"title":"Business Analytics Internship Programme"} +{"moduleCode":"ID5151","moduleCredit":0,"title":"Design Innovation"} +{"moduleCode":"ME4223E","moduleCredit":0,"title":"Thermal Environmental Engineering"} +{"moduleCode":"YSC3224","moduleCredit":0,"title":"Statistical Thermodynamics"} +{"moduleCode":"IE3100E","moduleCredit":0,"title":"Systems Design Project"} +{"moduleCode":"PL3282A","moduleCredit":0,"title":"Lab in Interpersonal Relationships"} +{"moduleCode":"LL5071","moduleCredit":0,"title":"International Patent Law, Policy and Practice"} +{"moduleCode":"MT5902","moduleCredit":0,"title":"Management Extended Practicum"} +{"moduleCode":"MT5901","moduleCredit":0,"title":"Management Practicum"} +{"moduleCode":"SDM5990","moduleCredit":0,"title":"Sdm Research Project"} +{"moduleCode":"YSC3210","moduleCredit":0,"title":"Introduction to Quantum Mechanics"} +{"moduleCode":"SW5209R","moduleCredit":0,"title":"Theory and Practice of Social Work Supervision"} +{"moduleCode":"MT5900","moduleCredit":0,"title":"Mot Research Project"} +{"moduleCode":"IL5201","moduleCredit":0,"title":"Measuring and Demonstrating Value from IT Investments"} +{"moduleCode":"YSC3215","moduleCredit":0,"title":"Research Seminar"} +{"moduleCode":"IE3100M","moduleCredit":0,"title":"System Design Project"} +{"moduleCode":"ST5227","moduleCredit":0,"title":"Applied Data Mining"} +{"moduleCode":"CE5611","moduleCredit":0,"title":"Precast Concrete Technology"} +{"moduleCode":"IL5203","moduleCredit":0,"title":"IT Organisation Development and Talent Management"} +{"moduleCode":"ST5224","moduleCredit":0,"title":"Advanced Statistical Theory II"} +{"moduleCode":"YSC3217","moduleCredit":0,"title":"Programming Operating Systems, Interfaces & eXtras"} +{"moduleCode":"CE5610","moduleCredit":0,"title":"Assessment and Retrofit of Concrete Structures"} +{"moduleCode":"CN3124E","moduleCredit":0,"title":"Particle Technology"} +{"moduleCode":"IL5202","moduleCredit":0,"title":"IT Governance and Risk Management"} +{"moduleCode":"PC3232B","moduleCredit":0,"title":"Applied Nuclear Physics"} +{"moduleCode":"PL5660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"YSC3211","moduleCredit":0,"title":"Introduction to Electrodynamics"} +{"moduleCode":"IL5204","moduleCredit":0,"title":"Stakeholder Relationship Management in the IT Eco-System"} +{"moduleCode":"YSC3214","moduleCredit":0,"title":"Biochemistry"} +{"moduleCode":"BL5233","moduleCredit":0,"title":"Data Analysis for Conservation Biology with R"} +{"moduleCode":"IE3101E","moduleCredit":0,"title":"Statistics for Engineering Applications"} +{"moduleCode":"MUA4443","moduleCredit":0,"title":"Collaborative Piano - Chamber Music 5"} +{"moduleCode":"MUA3110","moduleCredit":0,"title":"Chamber Music in Mixed Ensemble"} +{"moduleCode":"LL6396","moduleCredit":0,"title":"University Research Opportunities Programme"} +{"moduleCode":"PL3283A","moduleCredit":0,"title":"Lab in Adolescent Psychology"} +{"moduleCode":"RE4001","moduleCredit":0,"title":"Real Estate Case Study"} +{"moduleCode":"BL5230","moduleCredit":0,"title":"Biological Invasions"} +{"moduleCode":"LL6397","moduleCredit":0,"title":"University Research Opportunities Progra"} +{"moduleCode":"ST5243","moduleCredit":0,"title":"Topics III"} +{"moduleCode":"MUA3116","moduleCredit":0,"title":"Pedagogy for Orchestral Instrumentalists"} +{"moduleCode":"BL5237","moduleCredit":0,"title":"Computational Biology: Sequences, Structures, Functions"} +{"moduleCode":"MUA3115","moduleCredit":0,"title":"Orchestral Studies for Pianists"} +{"moduleCode":"BL5236","moduleCredit":0,"title":"Introduction to Electron Microscopy for Life Sciences"} +{"moduleCode":"MUA4440","moduleCredit":0,"title":"Collaborative Piano - Piano Ensemble 5"} +{"moduleCode":"MUA3113","moduleCredit":0,"title":"Keyboard Skills For Piano Majors III"} +{"moduleCode":"MUA4441","moduleCredit":0,"title":"Collaborative Piano - Vocal Accompaniment 5"} +{"moduleCode":"BL5234","moduleCredit":0,"title":"Theoretical Biology"} +{"moduleCode":"MUA4442","moduleCredit":0,"title":"Collaborative Piano - Instrumental Accompaniment 5"} +{"moduleCode":"MT5913","moduleCredit":0,"title":"TechLaunch - Experiential Entrepreneurship"} +{"moduleCode":"MT5912","moduleCredit":0,"title":"Frugal Innovation"} +{"moduleCode":"MT5911","moduleCredit":0,"title":"Venture Funding"} +{"moduleCode":"MUA3109","moduleCredit":0,"title":"Chamber Music"} +{"moduleCode":"PC2288","moduleCredit":0,"title":"Basic UROPS in Physics I"} +{"moduleCode":"YSC3206","moduleCredit":0,"title":"Introduction to Real Analysis"} +{"moduleCode":"LL5356V","moduleCredit":0,"title":"International Economic Law Clinic"} +{"moduleCode":"RE4000","moduleCredit":0,"title":"Dissertation"} +{"moduleCode":"CE5604","moduleCredit":0,"title":"Advanced Concrete Technology"} +{"moduleCode":"CE5603","moduleCredit":0,"title":"Engineering Economics & Project Evaluation"} +{"moduleCode":"PC2289","moduleCredit":0,"title":"Basic UROPS in Physics II"} +{"moduleCode":"YSC3203","moduleCredit":0,"title":"Advanced Algorithms and Data Structures"} +{"moduleCode":"MDG5230","moduleCredit":0,"title":"Bioethics: Core Philosophical and Empirical Approaches"} +{"moduleCode":"MUA3221","moduleCredit":0,"title":"Intensive Music Engagement Practicum"} +{"moduleCode":"YID4101","moduleCredit":0,"title":"Environmental Studies Capstone Project"} +{"moduleCode":"BSP2011","moduleCredit":0,"title":"Asian Business Environments"} +{"moduleCode":"MUA3220","moduleCredit":0,"title":"World Music Ensemble"} +{"moduleCode":"LL5177","moduleCredit":0,"title":"Entertainment Law: Pop Iconography & Celebrity"} +{"moduleCode":"MDG5234","moduleCredit":0,"title":"Independent Study Module (CBmE)"} +{"moduleCode":"YHU4249","moduleCredit":0,"title":"The Self and Society: The Novel of Development"} +{"moduleCode":"MDG5232","moduleCredit":0,"title":"Case studies in the biotechnology industry"} +{"moduleCode":"MKT1705X","moduleCredit":0,"title":"Principles of Marketing"} +{"moduleCode":"MDG5233","moduleCredit":0,"title":"Current Topics in Drug Design and Development"} +{"moduleCode":"MUA3228","moduleCredit":0,"title":"Re-imagining Pianism through Analysis"} +{"moduleCode":"MUA3227","moduleCredit":0,"title":"Collaboratory B"} +{"moduleCode":"YHU4247","moduleCredit":0,"title":"Museums and Libraries as Cultural Institutions"} +{"moduleCode":"MUA3226","moduleCredit":0,"title":"Collaboratory"} +{"moduleCode":"YHU4246","moduleCredit":0,"title":"Human Lives: From Biopolitics to Geopolitics"} +{"moduleCode":"MUA3225","moduleCredit":0,"title":"Early Advanced Keyboard Studies"} +{"moduleCode":"MUA3224","moduleCredit":0,"title":"Intermediate Keyboard Studies"} +{"moduleCode":"YHU4240","moduleCredit":0,"title":"American Modernist Poetry"} +{"moduleCode":"MUA3223","moduleCredit":0,"title":"Cultural Encounters - Bali Excursion and Study Tour"} +{"moduleCode":"LL5172","moduleCredit":0,"title":"Japanese Corporate Law & Governance"} +{"moduleCode":"MUA3222","moduleCredit":0,"title":"SEAsian Regional Creative Project"} +{"moduleCode":"MKT1705B","moduleCredit":0,"title":"Principles of Marketing"} +{"moduleCode":"MKT1705A","moduleCredit":0,"title":"Principles of Marketing"} +{"moduleCode":"NM4102","moduleCredit":0,"title":"Advanced Communications & New Media Research"} +{"moduleCode":"MKT1705D","moduleCredit":0,"title":"Principles of Marketing"} +{"moduleCode":"CS2220","moduleCredit":0,"title":"Introduction to Computational Biology"} +{"moduleCode":"MKT1705C","moduleCredit":0,"title":"Principles of Marketing"} +{"moduleCode":"MT5920","moduleCredit":0,"title":"Enterprise Development"} +{"moduleCode":"MUA3219","moduleCredit":0,"title":"World Music Ensemble"} +{"moduleCode":"NUR1114A","moduleCredit":0,"title":"Fundamentals of Care"} +{"moduleCode":"TM2401","moduleCredit":0,"title":"Engineering Mathematics II"} +{"moduleCode":"ACC1701","moduleCredit":0,"title":"Accounting for Decision Makers"} +{"moduleCode":"CE5510","moduleCredit":0,"title":"Advanced Structural Concrete Design"} +{"moduleCode":"MDG5238","moduleCredit":0,"title":"Clinical Pharmacology and Pharmacotherapeutics I"} +{"moduleCode":"MDG5239","moduleCredit":0,"title":"Clinical Pharmacology and Pharmacotherapeutics II"} +{"moduleCode":"MDG5236","moduleCredit":0,"title":"Pathways to Biomedical Innovation and Enterprise"} +{"moduleCode":"MDG5237","moduleCredit":0,"title":"Biomedical Innovation Capstone"} +{"moduleCode":"CE5513","moduleCredit":0,"title":"Plastic Analysis Of Structures"} +{"moduleCode":"LL4056BV","moduleCredit":0,"title":"Tax Planning And Policy"} +{"moduleCode":"BSP2005","moduleCredit":0,"title":"Asian Business Environments"} +{"moduleCode":"MUA4542","moduleCredit":0,"title":"Collaborative Piano - Instrumental Accompaniment 6"} +{"moduleCode":"MUA4543","moduleCredit":0,"title":"Collaborative Piano - Chamber Music 6"} +{"moduleCode":"DSC4215","moduleCredit":0,"title":"Data Visualisation"} +{"moduleCode":"PE3551P","moduleCredit":0,"title":"FASS Undergraduate Research Opportunity (UROP)"} +{"moduleCode":"DSC4213","moduleCredit":0,"title":"Analytical Tools for Consulting"} +{"moduleCode":"MKT4751","moduleCredit":0,"title":"Advanced Independent Study in Marketing"} +{"moduleCode":"DSC4214","moduleCredit":0,"title":"Co-ordination and Flexibility in SCM"} +{"moduleCode":"MKT3420","moduleCredit":0,"title":"Advertising & Promotion Management"} +{"moduleCode":"DSC4219","moduleCredit":0,"title":"Advanced Independent Study in Ops & Supply Chain Mgt"} +{"moduleCode":"MUA3218","moduleCredit":0,"title":"Introduction to Piano Technology"} +{"moduleCode":"BN3101","moduleCredit":0,"title":"Biomedical Engineering Design"} +{"moduleCode":"DSC4217","moduleCredit":0,"title":"Business Analytics with R"} +{"moduleCode":"MUA3216","moduleCredit":0,"title":"Performance and Interaction"} +{"moduleCode":"LL5050V","moduleCredit":0,"title":"Public International Law"} +{"moduleCode":"MKT3429","moduleCredit":0,"title":"Independent Study in Marketing"} +{"moduleCode":"MKT3427","moduleCredit":0,"title":"Research for Marketing Insights"} +{"moduleCode":"MUA4540","moduleCredit":0,"title":"Collaborative Piano - Piano Ensemble 6"} +{"moduleCode":"MKT3428","moduleCredit":0,"title":"Wealth Management Marketing"} +{"moduleCode":"MUA4541","moduleCredit":0,"title":"Collaborative Piano Vocal Accompaniment 6"} +{"moduleCode":"YHU4231","moduleCredit":0,"title":"Ancient Economies of the Mediterranean and Western Asia"} +{"moduleCode":"FST3181","moduleCredit":0,"title":"Professional Placement"} +{"moduleCode":"CE5509","moduleCredit":0,"title":"Advanced Structural Steel Design"} +{"moduleCode":"MUA3209","moduleCredit":0,"title":"Business for Musicians"} +{"moduleCode":"TEE4214","moduleCredit":0,"title":"Real-Time Embedded Systems"} +{"moduleCode":"TEE4211","moduleCredit":0,"title":"Data Science for the Internet of Things"} +{"moduleCode":"TEE4210","moduleCredit":0,"title":"Network Protocols and Applications"} +{"moduleCode":"MNO3330","moduleCredit":0,"title":"Social Entrepreneurship"} +{"moduleCode":"BSN3713","moduleCredit":0,"title":"Entrepreneurial Boot Camp"} +{"moduleCode":"BSN3714","moduleCredit":0,"title":"Co-Creating Value (Tools for Collaborative Innovation)"} +{"moduleCode":"MNO3334","moduleCredit":0,"title":"Principles of Global Management"} +{"moduleCode":"BSN3715","moduleCredit":0,"title":"Digital Strategy"} +{"moduleCode":"MNO3333","moduleCredit":0,"title":"Human Capital Management"} +{"moduleCode":"BSN3716","moduleCredit":0,"title":"360-Degree Business Innovation Strategy"} +{"moduleCode":"MNO3332","moduleCredit":0,"title":"Leading Groups and Teams"} +{"moduleCode":"UNL2201","moduleCredit":0,"title":"Space, Time & Matter: The Shape and Size of the Cosmos"} +{"moduleCode":"MNO3331","moduleCredit":0,"title":"Business with a Social Conscience"} +{"moduleCode":"MKT3415","moduleCredit":0,"title":"Marketing in a Digital Age"} +{"moduleCode":"MKT3412","moduleCredit":0,"title":"Services Marketing"} +{"moduleCode":"MUA3205","moduleCredit":0,"title":"Jazz Study and Performance 1"} +{"moduleCode":"UNL2206","moduleCredit":0,"title":"Nature's Threads"} +{"moduleCode":"MKT3418","moduleCredit":0,"title":"Product And Brand Management"} +{"moduleCode":"MUA3202","moduleCredit":0,"title":"Advanced Contemporary Music Performance"} +{"moduleCode":"SE5294","moduleCredit":0,"title":"The Politics of Environment in Se Asia"} +{"moduleCode":"MUA3201","moduleCredit":0,"title":"Advanced Contemporary Music Performance"} +{"moduleCode":"MKT3417","moduleCredit":0,"title":"Customer Relationship Management"} +{"moduleCode":"DMB1203DAO","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"LL4209V","moduleCredit":0,"title":"Legal Argument & Narrative"} +{"moduleCode":"NUR3206D","moduleCredit":0,"title":"Transition to Practice"} +{"moduleCode":"GE6660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"MNO2007","moduleCredit":0,"title":"Leadership and Ethics"} +{"moduleCode":"MDG5214","moduleCredit":0,"title":"Research Skills"} +{"moduleCode":"MDG5215","moduleCredit":0,"title":"Applied Bioethics and Biolaw"} +{"moduleCode":"CN5010","moduleCredit":0,"title":"Mathematical & Computing Methods for Chemical Engineers"} +{"moduleCode":"MDG5218","moduleCredit":0,"title":"Biochemical and genetic approaches to understanding cell biology"} +{"moduleCode":"MNO2009","moduleCredit":0,"title":"Entrepreneurship"} +{"moduleCode":"UNL2210","moduleCredit":0,"title":"Mathematics and Reality"} +{"moduleCode":"BSN3702","moduleCredit":0,"title":"New Venture Creation"} +{"moduleCode":"BSN3703","moduleCredit":0,"title":"Entrepreneurial Strategy"} +{"moduleCode":"LL6251V","moduleCredit":0,"title":"International Humanitarian Law"} +{"moduleCode":"MDG5223","moduleCredit":0,"title":"Stem Cells and Regenerative Medicine"} +{"moduleCode":"MDG5224","moduleCredit":0,"title":"Animal Models of Human Diseases"} +{"moduleCode":"MDG5221","moduleCredit":0,"title":"Viral vectors for manipulating gene expression"} +{"moduleCode":"MDG5222","moduleCredit":0,"title":"Cardiovascular and Metabolic Diseases"} +{"moduleCode":"MKT3401","moduleCredit":0,"title":"Marketing Strategy: Analysis and Practice"} +{"moduleCode":"MKT3402","moduleCredit":0,"title":"Consumer Behaviour"} +{"moduleCode":"TIC1101","moduleCredit":0,"title":"Professional, Ethical, and Social Issues in Computing"} +{"moduleCode":"YHU4252","moduleCredit":0,"title":"Culturing Nature: Ecological Art and the Garden"} +{"moduleCode":"YHU4251","moduleCredit":0,"title":"Advanced 2D Animation and Storytelling"} +{"moduleCode":"LL4208V","moduleCredit":0,"title":"Advanced Criminal Legal Process"} +{"moduleCode":"MLE5301","moduleCredit":0,"title":"Metallic & Ceramic Materials in Additive Manufacturing"} +{"moduleCode":"NUR1113A","moduleCredit":0,"title":"Healthy Ageing and Well-being"} +{"moduleCode":"MLE5302","moduleCredit":0,"title":"Polymer Materials in Additive Manufacturing"} +{"moduleCode":"NUR3205C","moduleCredit":0,"title":"Clinical Experience IV"} +{"moduleCode":"UIS3902S","moduleCredit":0,"title":"Independent Study Module (ST)"} +{"moduleCode":"MDG5226","moduleCredit":0,"title":"Antimicrobial resistance and drug discovery"} +{"moduleCode":"MDG5229","moduleCredit":0,"title":"Advanced Topics in Signal Transduction"} +{"moduleCode":"EB5001","moduleCredit":0,"title":"Big Data Engineering for Analytics"} +{"moduleCode":"EB5002","moduleCredit":0,"title":"Text Processing Using Machine Learning"} +{"moduleCode":"QF5202A","moduleCredit":0,"title":"Structured Products"} +{"moduleCode":"NUR2441A","moduleCredit":0,"title":"Cross-cultural Experience for Nursing Students I"} +{"moduleCode":"YHU4207","moduleCredit":0,"title":"Critical Approaches to Art History"} +{"moduleCode":"YHU4206","moduleCredit":0,"title":"The History of History"} +{"moduleCode":"AR6770","moduleCredit":0,"title":"Phd Seminar"} +{"moduleCode":"MKT4718","moduleCredit":0,"title":"The Business of Happiness"} +{"moduleCode":"NUR1110A","moduleCredit":0,"title":"Communication and Cultural Diversity"} +{"moduleCode":"NUR3204C","moduleCredit":0,"title":"Clinical Experience III"} +{"moduleCode":"MT5966","moduleCredit":0,"title":"Overseas Industrial Project and Attachment"} +{"moduleCode":"UIS3901S","moduleCredit":0,"title":"Independent Study Module (ST)"} +{"moduleCode":"DSC5211A","moduleCredit":0,"title":"Supply Chain Coordination and Risk Management"} +{"moduleCode":"DSC5211B","moduleCredit":0,"title":"Analytical Tools for Consulting"} +{"moduleCode":"DSC5211C","moduleCredit":0,"title":"Quantitative Risk Management"} +{"moduleCode":"NUR2501","moduleCredit":0,"title":"Clinical Health Assessment and Reasoning"} +{"moduleCode":"QF5203A","moduleCredit":0,"title":"Risk Management"} +{"moduleCode":"NUR2500","moduleCredit":0,"title":"Applied Pathophysiology and Clinical Pharmacology"} +{"moduleCode":"MNO3323","moduleCredit":0,"title":"Management of Employee Relations"} +{"moduleCode":"MNO3322","moduleCredit":0,"title":"Negotiations and Bargaining"} +{"moduleCode":"SE5244","moduleCredit":0,"title":"Country Studies: The Philippines"} +{"moduleCode":"SE5243","moduleCredit":0,"title":"Country Studies: Indonesia"} +{"moduleCode":"SE5242","moduleCredit":0,"title":"Country Studies: Thailand"} +{"moduleCode":"MKT4716","moduleCredit":0,"title":"Consumer Culture Theory"} +{"moduleCode":"MKT4714","moduleCredit":0,"title":"Consumer Decision Making"} +{"moduleCode":"ME3162E","moduleCredit":0,"title":"Manufacturing Processes"} +{"moduleCode":"EG3301R","moduleCredit":0,"title":"DCP Project"} +{"moduleCode":"SE5247","moduleCredit":0,"title":"Country Studies: Vietnam"} +{"moduleCode":"NUR3203C","moduleCredit":0,"title":"Pathophysiology, Pharmacology and Nursing Practice III"} +{"moduleCode":"SE5246","moduleCredit":0,"title":"Country Studies: Myanmar"} +{"moduleCode":"NUR2503","moduleCredit":0,"title":"Global and Community Health"} +{"moduleCode":"NUR2502","moduleCredit":0,"title":"Healthcare Policy"} +{"moduleCode":"MNO3329","moduleCredit":0,"title":"Independent Study in Leadership & Human Capital Mgmt"} +{"moduleCode":"LL6254V","moduleCredit":0,"title":"Developing States in a Changing World Order"} +{"moduleCode":"ST5198","moduleCredit":0,"title":"Graduate Seminar Module"} +{"moduleCode":"EN4660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"ST5199","moduleCredit":0,"title":"Coursework Track Ii Project"} +{"moduleCode":"HY4401","moduleCredit":0,"title":"Honours Thesis"} +{"moduleCode":"LL4338V","moduleCredit":0,"title":"Advanced Practicum in International Arbitration"} +{"moduleCode":"LL4205V","moduleCredit":0,"title":"Maritime Conflict of Laws"} +{"moduleCode":"TIC2401","moduleCredit":0,"title":"Introduction to Computer Systems"} +{"moduleCode":"NUR3202C","moduleCredit":0,"title":"Research and Evidence-based Healthcare"} +{"moduleCode":"DMB1202ACC","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"LLD5397","moduleCredit":0,"title":"University Research Opportunities Programme"} +{"moduleCode":"MNO3301","moduleCredit":0,"title":"Organisational Behaviour"} +{"moduleCode":"YHU4216","moduleCredit":0,"title":"Advanced Poetry Writing"} +{"moduleCode":"YHU4215","moduleCredit":0,"title":"Advanced Fiction Writing"} +{"moduleCode":"LL5102","moduleCredit":0,"title":"Advanced Torts"} +{"moduleCode":"YHU4217","moduleCredit":0,"title":"Novel Evidence:19th-Century British Fiction and the Law"} +{"moduleCode":"NM6770","moduleCredit":0,"title":"Graduate Research Seminar"} +{"moduleCode":"BDC6114","moduleCredit":0,"title":"Logistics and Supply Chain"} +{"moduleCode":"MT5999","moduleCredit":0,"title":"Graduate Seminars"} +{"moduleCode":"QF5311","moduleCredit":0,"title":"Advanced Methods in Risk Management"} +{"moduleCode":"MIC2000","moduleCredit":0,"title":"Infection and Immunology"} +{"moduleCode":"QF5315","moduleCredit":0,"title":"Selected Topics in FinTech"} +{"moduleCode":"QF5314","moduleCredit":0,"title":"Basic Mathematics in Finance"} +{"moduleCode":"TG1401","moduleCredit":0,"title":"Engineering Mathematics I"} +{"moduleCode":"PF2102","moduleCredit":0,"title":"Structural Systems"} +{"moduleCode":"PR5304","moduleCredit":0,"title":"Fundamental Topics in Pharmaceutical Science"} +{"moduleCode":"PF2108","moduleCredit":0,"title":"Project Cost Management"} +{"moduleCode":"PF2107","moduleCredit":0,"title":"Construction Technology"} +{"moduleCode":"CS5339","moduleCredit":0,"title":"Theory and Algorithms for Machine Learning"} +{"moduleCode":"PF2109","moduleCredit":0,"title":"Project Feasibility"} +{"moduleCode":"PF2103","moduleCredit":0,"title":"Measurement (Building Works)"} +{"moduleCode":"UD5521","moduleCredit":0,"title":"Planning Process: Quantitative & Policy Dimensions"} +{"moduleCode":"EU3227","moduleCredit":0,"title":"Continental European Philosophy"} +{"moduleCode":"CS5332","moduleCredit":0,"title":"Biometric Authentication"} +{"moduleCode":"CS5331","moduleCredit":0,"title":"Web Security"} +{"moduleCode":"CS5330","moduleCredit":0,"title":"Randomized Algorithms"} +{"moduleCode":"BSE4711","moduleCredit":0,"title":"Econometrics for Business II"} +{"moduleCode":"EU3224","moduleCredit":0,"title":"Social Thought & Social Theory"} +{"moduleCode":"CH1101E","moduleCredit":0,"title":"Retelling Chinese Stories: Change and Continuity"} +{"moduleCode":"ESE5204B","moduleCredit":0,"title":"Physico-Chemical Treatment for Hazardous Chemicals"} +{"moduleCode":"EE6110","moduleCredit":0,"title":"Special Topics in Automation and Control (Advanced)"} +{"moduleCode":"ESE5204A","moduleCredit":0,"title":"Bioremediation of Hazardous Chemicals in Soil & Water"} +{"moduleCode":"LLD5396","moduleCredit":0,"title":"University Research Opportunities Programme"} +{"moduleCode":"YIR3308G","moduleCredit":0,"title":"Independent Reading and Research"} +{"moduleCode":"PP5701","moduleCredit":0,"title":"Economic Applications for Public Organizations"} +{"moduleCode":"PP5705","moduleCredit":0,"title":"Comparative Public Policy and Management: Singapore and Asia"} +{"moduleCode":"PP5704","moduleCredit":0,"title":"Policy Analysis and Programme Evaluation"} +{"moduleCode":"PP5703","moduleCredit":0,"title":"Public Finance and Budgeting"} +{"moduleCode":"LL6412","moduleCredit":0,"title":"Securities and Capital Markets Regulation"} +{"moduleCode":"PP5702","moduleCredit":0,"title":"Public Administration in Theory and Practice"} +{"moduleCode":"MS4401","moduleCredit":0,"title":"Honours Thesis"} +{"moduleCode":"SWD5880A","moduleCredit":0,"title":"Service User Involvement"} +{"moduleCode":"EU3231","moduleCredit":0,"title":"Modern Imperialism"} +{"moduleCode":"GE2204","moduleCredit":0,"title":"Cities in Transition"} +{"moduleCode":"GE2202","moduleCredit":0,"title":"Economy & Space"} +{"moduleCode":"NM2302","moduleCredit":0,"title":"Mobility and New Media"} +{"moduleCode":"NM2303","moduleCredit":0,"title":"Fake News, Lies and Spin: How to Sift Fact from Fiction"} +{"moduleCode":"GE2206","moduleCredit":0,"title":"Geographies of Life and Death"} +{"moduleCode":"IS5128","moduleCredit":0,"title":"Digital Innovation"} +{"moduleCode":"CS5322","moduleCredit":0,"title":"Database Security"} +{"moduleCode":"CS5321","moduleCredit":0,"title":"Network Security"} +{"moduleCode":"SE5201","moduleCredit":0,"title":"Supervised Research Project"} +{"moduleCode":"LL6402","moduleCredit":0,"title":"Corporate Insolvency Law"} +{"moduleCode":"LL6403","moduleCredit":0,"title":"Family Law"} +{"moduleCode":"CE4258","moduleCredit":0,"title":"Structural Stability & Dynamics"} +{"moduleCode":"LL6070V","moduleCredit":0,"title":"Foundations Of Intellectual Property Law"} +{"moduleCode":"CE4257","moduleCredit":0,"title":"Linear Finite Element Analysis"} +{"moduleCode":"EE3031E","moduleCredit":0,"title":"Innovation & Enterprise I"} +{"moduleCode":"EE6104","moduleCredit":0,"title":"Adaptive Control Systems (Advanced)"} +{"moduleCode":"LL6407","moduleCredit":0,"title":"Law Of Insurance"} +{"moduleCode":"YIR3309G","moduleCredit":0,"title":"Independent Reading and Research"} +{"moduleCode":"PP5711","moduleCredit":0,"title":"Urban Development and Policy"} +{"moduleCode":"YIR3305G","moduleCredit":0,"title":"Independent Reading and Research"} +{"moduleCode":"PP5714","moduleCredit":0,"title":"International Financial Policy and Issues"} +{"moduleCode":"GE2215","moduleCredit":0,"title":"Introduction to GIS"} +{"moduleCode":"GE2218","moduleCredit":0,"title":"Leisure, Recreation and Tourism"} +{"moduleCode":"GE3551","moduleCredit":0,"title":"FASS Undergraduate Research Opportunity (UROP)"} +{"moduleCode":"LL5405A","moduleCredit":0,"title":"Law of Intellectual Property (a)"} +{"moduleCode":"SE5219","moduleCredit":0,"title":"Technopolitics in Southeast Asia"} +{"moduleCode":"GE2222","moduleCredit":0,"title":"Politics and Space"} +{"moduleCode":"AR5423","moduleCredit":0,"title":"Architectural Practice"} +{"moduleCode":"GE2221","moduleCredit":0,"title":"Nature and Society"} +{"moduleCode":"GE2220","moduleCredit":0,"title":"Terrestrial and Coastal Environments"} +{"moduleCode":"EE6135","moduleCredit":0,"title":"Digital Communications (Advanced)"} +{"moduleCode":"PR2288","moduleCredit":0,"title":"Basic UROPS in Pharmacy I"} +{"moduleCode":"YIR3306G","moduleCredit":0,"title":"Independent Reading and Research"} +{"moduleCode":"EE6131","moduleCredit":0,"title":"Wireless Communications (Advanced)"} +{"moduleCode":"PR2289","moduleCredit":0,"title":"Basic UROPS in Pharmacy II"} +{"moduleCode":"IS5151","moduleCredit":0,"title":"Information Security Policy and Management"} +{"moduleCode":"IS5152","moduleCredit":0,"title":"Data-Driven Decision Making"} +{"moduleCode":"PP5723","moduleCredit":0,"title":"Political Economy of Taiwan, Hong Kong and Singapore"} +{"moduleCode":"DSA3313","moduleCredit":0,"title":"Undergraduate Professional Internship Programme Extended"} +{"moduleCode":"PP5722","moduleCredit":0,"title":"Strategic Management"} +{"moduleCode":"EG3611A","moduleCredit":0,"title":"Industrial Attachment"} +{"moduleCode":"DSA3310","moduleCredit":0,"title":"Undergraduate Professional Internship Programme"} +{"moduleCode":"DSA3312","moduleCredit":0,"title":"Enhanced Undergraduate Professional Internship Programme"} +{"moduleCode":"DSA3311","moduleCredit":0,"title":"Undergraduate Professional Internship Programme"} +{"moduleCode":"GE2227","moduleCredit":0,"title":"Cartography and Visualisation"} +{"moduleCode":"SE5222","moduleCredit":0,"title":"The Arts in Contemporary Southeast Asia"} +{"moduleCode":"GE2226","moduleCredit":0,"title":"Southeast Asia"} +{"moduleCode":"SE5221","moduleCredit":0,"title":"Landscapes of Southeast Asia"} +{"moduleCode":"ME5600A","moduleCredit":0,"title":"Project in Advanced Manufacturing I"} +{"moduleCode":"ME5600B","moduleCredit":0,"title":"Project in Advanced Manufacturing II"} +{"moduleCode":"GE2229","moduleCredit":0,"title":"Water and the Environment"} +{"moduleCode":"PF3401","moduleCredit":0,"title":"Practical Training Scheme"} +{"moduleCode":"GE2228","moduleCredit":0,"title":"Weather and Climate"} +{"moduleCode":"GE2230","moduleCredit":0,"title":"Energy Futures: Environment and Sustainability"} +{"moduleCode":"GE2231","moduleCredit":0,"title":"Introduction to Social and Cultural Geographies"} +{"moduleCode":"TS3551","moduleCredit":0,"title":"FASS Undergraduate Research Opportunity (UROP)"} +{"moduleCode":"YIR3307G","moduleCredit":0,"title":"Independent Reading and Research"} +{"moduleCode":"TS2221","moduleCredit":0,"title":"Global Theatres"} +{"moduleCode":"PH5660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"YIR3303G","moduleCredit":0,"title":"Independent Reading and Research"} +{"moduleCode":"LL6074V","moduleCredit":0,"title":"Mergers & Acquisitions"} +{"moduleCode":"GL2102","moduleCredit":0,"title":"Global Political Economy"} +{"moduleCode":"SW3209","moduleCredit":0,"title":"Counselling Theories & Practice"} +{"moduleCode":"GL2103","moduleCredit":0,"title":"Global Governance"} +{"moduleCode":"IE5404","moduleCredit":0,"title":"Large Scale Systems Engineering"} +{"moduleCode":"JS2230","moduleCredit":0,"title":"Itadakimasu - Food In Japan"} +{"moduleCode":"GL2101","moduleCredit":0,"title":"Origins of the Modern World"} +{"moduleCode":"SW3207","moduleCredit":0,"title":"Social Work in Medical Settings"} +{"moduleCode":"JS2880A","moduleCredit":0,"title":"Field Exposure Japan: Fashion Business"} +{"moduleCode":"SPH5501","moduleCredit":0,"title":"Public Health Communication"} +{"moduleCode":"CE6006","moduleCredit":0,"title":"Advanced Finite Element Analysis"} +{"moduleCode":"EC2101","moduleCredit":0,"title":"Microeconomic Analysis I"} +{"moduleCode":"EC2102","moduleCredit":0,"title":"Macroeconomic Analysis I"} +{"moduleCode":"CN5030","moduleCredit":0,"title":"Advanced Chemical Engineering Thermodynamics"} +{"moduleCode":"TS2232","moduleCredit":0,"title":"Asian Theatres: Tradition and the Contemporary"} +{"moduleCode":"LL4290V","moduleCredit":0,"title":"Legal Research: Method & Design"} +{"moduleCode":"TS2233","moduleCredit":0,"title":"Making Contemporary Performance"} +{"moduleCode":"JS2228","moduleCredit":0,"title":"Gender and Sexuality in Japan"} +{"moduleCode":"TS2235","moduleCredit":0,"title":"Marketing the Arts and Leisure Services"} +{"moduleCode":"YIR3304G","moduleCredit":0,"title":"Independent Reading and Research"} +{"moduleCode":"JS2225","moduleCredit":0,"title":"Marketing and Consumer Culture in Japan"} +{"moduleCode":"TS2237","moduleCredit":0,"title":"As If: Actors and Acting"} +{"moduleCode":"TS2239","moduleCredit":0,"title":"Major Playwrights of the 20th Century"} +{"moduleCode":"JS2222","moduleCredit":0,"title":"Japanese Society and Social Institutions"} +{"moduleCode":"CE6001","moduleCredit":0,"title":"Operations & Management of Infrastructure Systems"} +{"moduleCode":"EC2104","moduleCredit":0,"title":"Quantitative Methods for Economic Analysis"} +{"moduleCode":"SW3217","moduleCredit":0,"title":"Mental Health and Illness"} +{"moduleCode":"YIR3412","moduleCredit":0,"title":"Independent Language Study and Research"} +{"moduleCode":"YIR3411","moduleCredit":0,"title":"Independent Language Study and Research"} +{"moduleCode":"MDG5205","moduleCredit":0,"title":"Neuroscience"} +{"moduleCode":"EE3031","moduleCredit":0,"title":"Innovation & Enterprise I"} +{"moduleCode":"SW5880","moduleCredit":0,"title":"Special Topics in Social Work"} +{"moduleCode":"MDG5204","moduleCredit":0,"title":"Advanced Topics in Pharmacology"} +{"moduleCode":"TS2240","moduleCredit":0,"title":"Voice Studies and Production"} +{"moduleCode":"CN5020","moduleCredit":0,"title":"Advanced Reaction Engineering"} +{"moduleCode":"TS2243","moduleCredit":0,"title":"Film Genres: Stars and Styles"} +{"moduleCode":"OT5403","moduleCredit":0,"title":"Petrophysics and Downhole Measurements"} +{"moduleCode":"VM5103","moduleCredit":0,"title":"Symptom Management in Palliative Care II"} +{"moduleCode":"JS2216","moduleCredit":0,"title":"Postwar Japanese Film and Anime"} +{"moduleCode":"OT5402","moduleCredit":0,"title":"Geophysical Imaging of the Earth Interior"} +{"moduleCode":"VM5104","moduleCredit":0,"title":"Psychiatry, Psychosocial Care & Spiritual Issues in Palliative Care"} +{"moduleCode":"OT5401","moduleCredit":0,"title":"Geoscience for Petroleum Exploration"} +{"moduleCode":"VM5101","moduleCredit":0,"title":"Introduction of Palliative Care"} +{"moduleCode":"VM5102","moduleCredit":0,"title":"Symptom Management in Palliative Care I"} +{"moduleCode":"FST3105","moduleCredit":0,"title":"Food Product Development and Packaging"} +{"moduleCode":"LL6076V","moduleCredit":0,"title":"IT Law I"} +{"moduleCode":"MA2288","moduleCredit":0,"title":"Basic UROPS in Mathematics I"} +{"moduleCode":"FST3106","moduleCredit":0,"title":"Sensory and Flavour Science"} +{"moduleCode":"JS2212","moduleCredit":0,"title":"Introduction to Japanese Literature"} +{"moduleCode":"MA2289","moduleCredit":0,"title":"Basic UROPS in Mathematics II"} +{"moduleCode":"FST3103","moduleCredit":0,"title":"Advanced Food Engineering"} +{"moduleCode":"YIR3301G","moduleCredit":0,"title":"Independent Reading and Research"} +{"moduleCode":"FST3101","moduleCredit":0,"title":"Food Microbiology & Fermentation"} +{"moduleCode":"OT5409","moduleCredit":0,"title":"Drilling and Completion Engineering"} +{"moduleCode":"OT5408","moduleCredit":0,"title":"Unconventional and Renewable Energy Resources"} +{"moduleCode":"XD3103","moduleCredit":0,"title":"Planet Earth"} +{"moduleCode":"VM5105","moduleCredit":0,"title":"Communication and Ethical Issues"} +{"moduleCode":"VM5106","moduleCredit":0,"title":"Practices of Palliative Medicine"} +{"moduleCode":"BN4406","moduleCredit":0,"title":"Biophotonics And Bioimaging"} +{"moduleCode":"MNO4761C","moduleCredit":0,"title":"SILHCM: Talent Development and Performing with Impact"} +{"moduleCode":"BN4404","moduleCredit":0,"title":"Bioelectromechanical Systems - Biomems"} +{"moduleCode":"TEE4204","moduleCredit":0,"title":"Computer Networks"} +{"moduleCode":"CN5050","moduleCredit":0,"title":"Advanced Separation Processes"} +{"moduleCode":"SN5103R","moduleCredit":0,"title":"Contemporary India: Contexts & Narratives"} +{"moduleCode":"YIR3302G","moduleCredit":0,"title":"Independent Reading and Research"} +{"moduleCode":"PF2110","moduleCredit":0,"title":"Fundamentals of Facilities Management"} +{"moduleCode":"JS2203","moduleCredit":0,"title":"Sound, Grammar and Meaning"} +{"moduleCode":"NUR6005","moduleCredit":0,"title":"Measurement Theory and Instrument Validation"} +{"moduleCode":"LA4701","moduleCredit":0,"title":"MLA Studio: Quarter"} +{"moduleCode":"NUR6006","moduleCredit":0,"title":"Intervention Research in Nursing and Health Sciences"} +{"moduleCode":"LA4702","moduleCredit":0,"title":"MLA Studio: City"} +{"moduleCode":"NUR6003","moduleCredit":0,"title":"Research Methods"} +{"moduleCode":"NUR6004","moduleCredit":0,"title":"Systematic Review and Meta-Analysis"} +{"moduleCode":"NUR6001","moduleCredit":0,"title":"Graduate Research Seminar"} +{"moduleCode":"RE4801","moduleCredit":0,"title":"Real Estate Internship Programme"} +{"moduleCode":"RE4805","moduleCredit":0,"title":"International Real Estate Development and Investment"} +{"moduleCode":"BL5232C","moduleCredit":0,"title":"Practical Bioimaging C: Hands-on Microscopy"} +{"moduleCode":"BL5232B","moduleCredit":0,"title":"Practical Bioimaging B: Light Microscopy"} +{"moduleCode":"EU3212","moduleCredit":0,"title":"Europe of the Dictators"} +{"moduleCode":"CN5040","moduleCredit":0,"title":"Advanced Transport Phenomena"} +{"moduleCode":"CH3550","moduleCredit":0,"title":"Chinese Studies Internship (taught in English)"} +{"moduleCode":"LL4340V","moduleCredit":0,"title":"International Refugee Law"} +{"moduleCode":"CH2221","moduleCredit":0,"title":"Modern Chinese Literature"} +{"moduleCode":"EN5253","moduleCredit":0,"title":"Writing in the Aftermath"} +{"moduleCode":"YIR3311G","moduleCredit":0,"title":"Independent Reading and Research"} +{"moduleCode":"EN5254","moduleCredit":0,"title":"Rethinking Failure in the 21st Century"} +{"moduleCode":"EL5204R","moduleCredit":0,"title":"Linguistic Typology"} +{"moduleCode":"BL5102","moduleCredit":0,"title":"Environmental Science"} +{"moduleCode":"BME5044","moduleCredit":0,"title":"Communications, Influence and Negotiations"} +{"moduleCode":"BME5043","moduleCredit":0,"title":"Financial Management and Markets"} +{"moduleCode":"BME5046","moduleCredit":0,"title":"Managing Organisations"} +{"moduleCode":"BME5045","moduleCredit":0,"title":"Leadership: Exploration, Assessment & Development"} +{"moduleCode":"BME5040","moduleCredit":0,"title":"Business Analytics and Decision Making"} +{"moduleCode":"BME5042","moduleCredit":0,"title":"Accounting and Information Management"} +{"moduleCode":"BME5041","moduleCredit":0,"title":"Value Chains, Logistics and Operations"} +{"moduleCode":"USE2304","moduleCredit":0,"title":"Singapore: The Making Of A Nation"} +{"moduleCode":"BME5048","moduleCredit":0,"title":"Managing Human Capital"} +{"moduleCode":"BME5049","moduleCredit":0,"title":"Marketing Strategy"} +{"moduleCode":"DMB1201MKT","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"EE4436","moduleCredit":0,"title":"Fabrication Process Technology"} +{"moduleCode":"EE4435","moduleCredit":0,"title":"Modern Transistors and Memory Devices"} +{"moduleCode":"EN5241","moduleCredit":0,"title":"Literature and New Worlds: 1590-1750"} +{"moduleCode":"SH5110","moduleCredit":0,"title":"Chemical Hazard Evaluation"} +{"moduleCode":"EE4434","moduleCredit":0,"title":"Integrated Circuit Technology, Design and Testing"} +{"moduleCode":"EE2023E","moduleCredit":0,"title":"Signals and Systems"} +{"moduleCode":"EE4438","moduleCredit":0,"title":"Solar Cells and Modules"} +{"moduleCode":"EN5242","moduleCredit":0,"title":"Women Novelists"} +{"moduleCode":"EE4437","moduleCredit":0,"title":"Photonics - Principles and Applications"} +{"moduleCode":"YIR3312G","moduleCredit":0,"title":"Independent Reading and Research"} +{"moduleCode":"MUA6162","moduleCredit":0,"title":"Major Study 6B"} +{"moduleCode":"IE4102","moduleCredit":0,"title":"Independent Study Module"} +{"moduleCode":"TR3301","moduleCredit":0,"title":"Summer Programme in Entrepreneurship"} +{"moduleCode":"ACC2002","moduleCredit":0,"title":"Managerial Accounting"} +{"moduleCode":"BME5033","moduleCredit":0,"title":"Leadership: Exploration, Assessment & Development"} +{"moduleCode":"PL4201","moduleCredit":0,"title":"Psychometrics and Psychological Testing"} +{"moduleCode":"PLC5011A","moduleCredit":0,"title":"Clinical Placement 1"} +{"moduleCode":"SE2213","moduleCredit":0,"title":"Politics in Southeast Asia"} +{"moduleCode":"SE2214","moduleCredit":0,"title":"Arts of Southeast Asia"} +{"moduleCode":"PL4205","moduleCredit":0,"title":"Developmental Processes"} +{"moduleCode":"SE2211","moduleCredit":0,"title":"Southeast Asian Social History"} +{"moduleCode":"DMS1401SP","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"UTC3400","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"IE4240E","moduleCredit":0,"title":"Project Management"} +{"moduleCode":"MUA6161","moduleCredit":0,"title":"Major Study 6A"} +{"moduleCode":"PL4203","moduleCredit":0,"title":"Cognition"} +{"moduleCode":"UTC3401","moduleCredit":0,"title":"CAPT Undergraduate Research Opportunity (UROP)"} +{"moduleCode":"SC1101E","moduleCredit":0,"title":"Making Sense of Society"} +{"moduleCode":"LL5237V","moduleCredit":0,"title":"Law, Institutions, and Business in Greater China"} +{"moduleCode":"QF5299","moduleCredit":0,"title":"Quantitative Finance Project"} +{"moduleCode":"ME5361","moduleCredit":0,"title":"Advanced Computational Fluid Dynamics"} +{"moduleCode":"SE2219","moduleCredit":0,"title":"Culture and Power in Southeast Asia"} +{"moduleCode":"ID2122","moduleCredit":0,"title":"Ecodesign And Sustainability"} +{"moduleCode":"SE2217","moduleCredit":0,"title":"War and Southeast Asia"} +{"moduleCode":"SE2218","moduleCredit":0,"title":"Changing Economic Landscape of SE Asia"} +{"moduleCode":"EL5660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"ID2106","moduleCredit":0,"title":"Design Platforms 1"} +{"moduleCode":"UTS2114","moduleCredit":0,"title":"Technologies and Ageing in Singapore"} +{"moduleCode":"SE3550","moduleCredit":0,"title":"Southeast Asian Studies Internship"} +{"moduleCode":"EL4880B","moduleCredit":0,"title":"Exploring Second Language Writing"} +{"moduleCode":"EL5202R","moduleCredit":0,"title":"The Grammar of Modern English"} +{"moduleCode":"BMA5803","moduleCredit":0,"title":"C-Suite Life"} +{"moduleCode":"PLC5012B","moduleCredit":0,"title":"Clinical Placement 2"} +{"moduleCode":"SE2225","moduleCredit":0,"title":"Forbidden Pleasures: Vice in Southeast Asia"} +{"moduleCode":"BMA5802","moduleCredit":0,"title":"MBA Survival Kit"} +{"moduleCode":"BMA5801","moduleCredit":0,"title":"Launch Your Transformation"} +{"moduleCode":"CS5272","moduleCredit":0,"title":"Embedded Software Design"} +{"moduleCode":"FE5116","moduleCredit":0,"title":"Programming and Advanced Numerical Methods"} +{"moduleCode":"ID2116","moduleCredit":0,"title":"Computing for Design"} +{"moduleCode":"ID2115","moduleCredit":0,"title":"Digital Sketching and Painting"} +{"moduleCode":"ID2114","moduleCredit":0,"title":"The Appreciation of Wood Craft"} +{"moduleCode":"ID2113","moduleCredit":0,"title":"Visual Communication Design"} +{"moduleCode":"ID2111","moduleCredit":0,"title":"Computer Aided Industrial Design"} +{"moduleCode":"UTS2100","moduleCredit":0,"title":"Intelligence and Singapore Society"} +{"moduleCode":"EC2204","moduleCredit":0,"title":"Financial Accounting for Economists"} +{"moduleCode":"LL4034V","moduleCredit":0,"title":"International Regulation of Shipping"} +{"moduleCode":"EC2205","moduleCredit":0,"title":"Economic Analysis of Business"} +{"moduleCode":"UTS2101","moduleCredit":0,"title":"Biomedicine and Singapore Society"} +{"moduleCode":"YIR3310G","moduleCredit":0,"title":"Independent Reading and Research"} +{"moduleCode":"BSP1004X","moduleCredit":0,"title":"Legal Environment Of Business"} +{"moduleCode":"EL5203R","moduleCredit":0,"title":"Sociophonetics"} +{"moduleCode":"ENV3202A","moduleCredit":0,"title":"Environmental Studies Internship Programme"} +{"moduleCode":"UTS2109","moduleCredit":0,"title":"Asia Now! The Archaeology of the Future City"} +{"moduleCode":"BME5055","moduleCredit":0,"title":"Technology, Innovation and Entrepreneurship"} +{"moduleCode":"BME5054","moduleCredit":0,"title":"Strategy"} +{"moduleCode":"PLC5013C","moduleCredit":0,"title":"Clinical Placement 3"} +{"moduleCode":"MS6201","moduleCredit":0,"title":"Literature and Art in Malay Society"} +{"moduleCode":"BME5051","moduleCredit":0,"title":"Economic Analysis for Managers"} +{"moduleCode":"BME5050","moduleCredit":0,"title":"Asia and the Global Economy"} +{"moduleCode":"BME5053","moduleCredit":0,"title":"International Business and Internationalisation"} +{"moduleCode":"CS5260","moduleCredit":0,"title":"Neural Networks and Deep Learning II"} +{"moduleCode":"ID2105","moduleCredit":0,"title":"Design for Context and Sustainability"} +{"moduleCode":"SW5104","moduleCredit":0,"title":"Management of Human Service Organizations"} +{"moduleCode":"SW5107","moduleCredit":0,"title":"Program Development and Evaluation"} +{"moduleCode":"EE5731","moduleCredit":0,"title":"Visual Computing"} +{"moduleCode":"SW5106","moduleCredit":0,"title":"Social Policy and Welfare Services"} +{"moduleCode":"UIS4911GL","moduleCredit":0,"title":"Independent Study Module"} +{"moduleCode":"EE4407","moduleCredit":0,"title":"Analog Electronics"} +{"moduleCode":"DMB1203BSP","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"LAH1201","moduleCredit":0,"title":"Hindi 1"} +{"moduleCode":"LL4033V","moduleCredit":0,"title":"International Legal Process"} +{"moduleCode":"EE4409","moduleCredit":0,"title":"Modern Microelectronic Devices & Sensors"} +{"moduleCode":"RE1701","moduleCredit":0,"title":"Urban Land Use and Development"} +{"moduleCode":"RE1702","moduleCredit":0,"title":"Real Estate Data Analytics"} +{"moduleCode":"RE1703","moduleCredit":0,"title":"Principles of Law for Real Estate"} +{"moduleCode":"RE1704","moduleCredit":0,"title":"Principles of Real Estate Economics"} +{"moduleCode":"RE1705","moduleCredit":0,"title":"Real Estate Finance and Accounting"} +{"moduleCode":"RE1706","moduleCredit":0,"title":"Design and Construction"} +{"moduleCode":"LAS4202","moduleCredit":0,"title":"Spanish 6"} +{"moduleCode":"ACC4611","moduleCredit":0,"title":"Advanced Taxation"} +{"moduleCode":"LAS4201","moduleCredit":0,"title":"Spanish 5"} +{"moduleCode":"ACC4614","moduleCredit":0,"title":"Financial Institution Audit & Compliance"} +{"moduleCode":"ACC4615","moduleCredit":0,"title":"Advanced Assurance and Attestation"} +{"moduleCode":"CS5250","moduleCredit":0,"title":"Advanced Operating Systems"} +{"moduleCode":"ACC4619","moduleCredit":0,"title":"Advanced Independent Study in Accounting"} +{"moduleCode":"ACC4616","moduleCredit":0,"title":"Accounting Theory"} +{"moduleCode":"TS5101","moduleCredit":0,"title":"Text and Performance"} +{"moduleCode":"CH2252","moduleCredit":0,"title":"History of Chinese Philosophy"} +{"moduleCode":"SW5116","moduleCredit":0,"title":"Skills in Advanced Social Work Practice"} +{"moduleCode":"SW5115","moduleCredit":0,"title":"Human Development in Context"} +{"moduleCode":"SW5112","moduleCredit":0,"title":"Supervised Project"} +{"moduleCode":"SW5111","moduleCredit":0,"title":"Advanced Practicum"} +{"moduleCode":"SW5114","moduleCredit":0,"title":"Contemporary Social Work Practice"} +{"moduleCode":"SW5113","moduleCredit":0,"title":"Social Work With Groups and Community"} +{"moduleCode":"CS5248","moduleCredit":0,"title":"Systems Support for Continuous Media"} +{"moduleCode":"CS5242","moduleCredit":0,"title":"Neural Networks and Deep Learning"} +{"moduleCode":"CS5240","moduleCredit":0,"title":"Theoretical Foundations in MultiMedia"} +{"moduleCode":"PR2114","moduleCredit":0,"title":"Formulation & Technology I"} +{"moduleCode":"PR2115","moduleCredit":0,"title":"Medicinal Chemistry for Drug Design"} +{"moduleCode":"MUA6116","moduleCredit":0,"title":"Ensemble Study 6B"} +{"moduleCode":"LL4031V","moduleCredit":0,"title":"International Environmental Law & Policy"} +{"moduleCode":"MUA6115","moduleCredit":0,"title":"Ensemble Study 6A"} +{"moduleCode":"PR2131","moduleCredit":0,"title":"Pharmacy Professional Skills Development II"} +{"moduleCode":"SH5102","moduleCredit":0,"title":"Occupational Ergonomics"} +{"moduleCode":"SH5101","moduleCredit":0,"title":"Industrial Toxicology"} +{"moduleCode":"TR4049N","moduleCredit":0,"title":"Seminars in Entrepreneurship - Lean Startup: Market Validation"} +{"moduleCode":"CH2243","moduleCredit":0,"title":"Chinese in Southeast Asia"} +{"moduleCode":"LL4164V","moduleCredit":0,"title":"International Projects Law & Practice"} +{"moduleCode":"MA2202","moduleCredit":0,"title":"Algebra I"} +{"moduleCode":"SH5106","moduleCredit":0,"title":"Radiation"} +{"moduleCode":"EE4112E","moduleCredit":0,"title":"Radio Frequency Design and Systems"} +{"moduleCode":"SH5105","moduleCredit":0,"title":"Noise and Other Physical Hazards"} +{"moduleCode":"SH5108","moduleCredit":0,"title":"Chemical Hazard Management"} +{"moduleCode":"SH5107","moduleCredit":0,"title":"Industrial Ventilation"} +{"moduleCode":"SH5109","moduleCredit":0,"title":"Biostatistics and Epidemiology"} +{"moduleCode":"CS5239","moduleCredit":0,"title":"Computer System Performance Analysis"} +{"moduleCode":"YLG1201","moduleCredit":0,"title":"Beginning Ancient Greek"} +{"moduleCode":"BME5022","moduleCredit":0,"title":"Business Strategy Simulation"} +{"moduleCode":"CS5234","moduleCredit":0,"title":"Algorithms at Scale"} +{"moduleCode":"CS5233","moduleCredit":0,"title":"Simulation and Modelling Techniques"} +{"moduleCode":"JS6770","moduleCredit":0,"title":"Graduate Research Seminar"} +{"moduleCode":"CS5232","moduleCredit":0,"title":"Formal Specification and Design Techniques"} +{"moduleCode":"PS5603R","moduleCredit":0,"title":"Introduction to Qualitative Methods"} +{"moduleCode":"CS5231","moduleCredit":0,"title":"Systems Security"} +{"moduleCode":"CS5230","moduleCredit":0,"title":"Computational Complexity"} +{"moduleCode":"STR2000","moduleCredit":0,"title":"Career Creation Starter Clinics"} +{"moduleCode":"BSP2701","moduleCredit":0,"title":"Global Economy"} +{"moduleCode":"TR4049T","moduleCredit":0,"title":"Seminars in Entrepreneurship - Lean Startup: Market Validation"} +{"moduleCode":"LL5109V","moduleCredit":0,"title":"International Law & Asia"} +{"moduleCode":"ESE5202B","moduleCredit":0,"title":"Air Quality Engineering"} +{"moduleCode":"ESE5202A","moduleCredit":0,"title":"Technologies for Air Quality Control"} +{"moduleCode":"PR2122","moduleCredit":0,"title":"Biotechnology for Pharmacy"} +{"moduleCode":"LL4030V","moduleCredit":0,"title":"International Commercial Litigation"} +{"moduleCode":"LAR2201","moduleCredit":0,"title":"Arabic 2"} +{"moduleCode":"MA2213","moduleCredit":0,"title":"Numerical Analysis I"} +{"moduleCode":"EE4415","moduleCredit":0,"title":"Integrated Digital Design"} +{"moduleCode":"MA2214","moduleCredit":0,"title":"Combinatorics and Graphs I"} +{"moduleCode":"DMS1401ZB","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"MA2216","moduleCredit":0,"title":"Probability"} +{"moduleCode":"CS5229","moduleCredit":0,"title":"Advanced Computer Networks"} +{"moduleCode":"LL6308V","moduleCredit":0,"title":"Behavioural Economics, Law & Regulation"} +{"moduleCode":"CS5228","moduleCredit":0,"title":"Knowledge Discovery and Data Mining"} +{"moduleCode":"MA2219","moduleCredit":0,"title":"Introduction to Geometry"} +{"moduleCode":"AR2524","moduleCredit":0,"title":"Spatial Computational Thinking"} +{"moduleCode":"CS5224","moduleCredit":0,"title":"Cloud Computing"} +{"moduleCode":"CS5223","moduleCredit":0,"title":"Distributed Systems"} +{"moduleCode":"AR2522","moduleCredit":0,"title":"Computational Thinking: Performance Based Design"} +{"moduleCode":"CS5222","moduleCredit":0,"title":"Advanced Computer Architecture"} +{"moduleCode":"BME5012","moduleCredit":0,"title":"Scenario Planning"} +{"moduleCode":"IE2150E","moduleCredit":0,"title":"Human Factors Engineering"} +{"moduleCode":"IE4242E","moduleCredit":0,"title":"Cost Analysis And Management"} +{"moduleCode":"DMB1201MNO","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"TBA3241","moduleCredit":0,"title":"Social Media Analytics"} +{"moduleCode":"BME5018","moduleCredit":0,"title":"Managing Business For Sustainability"} +{"moduleCode":"PR2134","moduleCredit":0,"title":"Self Care"} +{"moduleCode":"SDM5001","moduleCredit":0,"title":"Systems Architecture"} +{"moduleCode":"PR2135","moduleCredit":0,"title":"Pharmacotherapeutics II"} +{"moduleCode":"SDM5002","moduleCredit":0,"title":"Systems Engineering"} +{"moduleCode":"SDM5003","moduleCredit":0,"title":"Knowledge Management"} +{"moduleCode":"PR2133","moduleCredit":0,"title":"Pharmacotherapeutics I"} +{"moduleCode":"SDM5004","moduleCredit":0,"title":"Systems Engineering Project Management"} +{"moduleCode":"CAS5101","moduleCredit":0,"title":"Theorizing from Asia"} +{"moduleCode":"PC2130","moduleCredit":0,"title":"Quantum Mechanics I"} +{"moduleCode":"YID2201","moduleCredit":0,"title":"Theory and Practice of Environmental Policymaking"} +{"moduleCode":"YID2207","moduleCredit":0,"title":"Social Theory and the Environment"} +{"moduleCode":"LL5360Z","moduleCredit":0,"title":"Current Challenges to Investment Arbitration"} +{"moduleCode":"YID2209","moduleCredit":0,"title":"Biogeophysical Systems"} +{"moduleCode":"MA3111S","moduleCredit":0,"title":"Complex Analysis I (S)"} +{"moduleCode":"CE2407","moduleCredit":0,"title":"Engineering & Uncertainty Analyses"} +{"moduleCode":"BMM5105","moduleCredit":0,"title":"Real Estate Fundamentals and City Planning"} +{"moduleCode":"CE2409","moduleCredit":0,"title":"Computer Applications in Civil Engineering"} +{"moduleCode":"ME6604","moduleCredit":0,"title":"Modelling of Machining Processes"} +{"moduleCode":"PC2134","moduleCredit":0,"title":"Mathematical Mtds in Physics I"} +{"moduleCode":"CS2103T","moduleCredit":0,"title":"Software Engineering"} +{"moduleCode":"PC2133","moduleCredit":0,"title":"Applied Solid State Physics"} +{"moduleCode":"PC2132","moduleCredit":0,"title":"Classical Mechanics"} +{"moduleCode":"PC2131","moduleCredit":0,"title":"Electricity & Magnetism I"} +{"moduleCode":"MA5295","moduleCredit":0,"title":"Dissertation For Msc By Coursework"} +{"moduleCode":"NUR3114","moduleCredit":0,"title":"Leadership and Management"} +{"moduleCode":"NUR3117","moduleCredit":0,"title":"Community Integrated Health Care"} +{"moduleCode":"TBA3222","moduleCredit":0,"title":"Marketing Analytics"} +{"moduleCode":"NUR3113","moduleCredit":0,"title":"Medical-Surgical Nursing III"} +{"moduleCode":"SC6102","moduleCredit":0,"title":"Sociological Theory"} +{"moduleCode":"CH2299","moduleCredit":0,"title":"Art of Modern and Contemporary China (in English)"} +{"moduleCode":"ME3211E","moduleCredit":0,"title":"Mechanics of Solids"} +{"moduleCode":"TS2880A","moduleCredit":0,"title":"Modern Drama in Asia"} +{"moduleCode":"LL5361Z","moduleCredit":0,"title":"Complex Arbitrations: Multiparty – Multicontract"} +{"moduleCode":"BDC6248","moduleCredit":0,"title":"Seminars In Operations Management I"} +{"moduleCode":"LL5056BV","moduleCredit":0,"title":"Tax Planning And Policy"} +{"moduleCode":"CG2027","moduleCredit":0,"title":"Transistor-level Digital Circuits"} +{"moduleCode":"ENV2103","moduleCredit":0,"title":"The Environment and Public Health"} +{"moduleCode":"ENV2102","moduleCredit":0,"title":"Environmental Law"} +{"moduleCode":"ENV2101","moduleCredit":0,"title":"Global Environmental Change"} +{"moduleCode":"CG2023","moduleCredit":0,"title":"Signals and Systems"} +{"moduleCode":"CN3135E","moduleCredit":0,"title":"Process Safety, Health and Environment"} +{"moduleCode":"CG2028","moduleCredit":0,"title":"Computer Organization"} +{"moduleCode":"NUR3118","moduleCredit":0,"title":"Consolidated Clinical Simulation Nursing Practice"} +{"moduleCode":"TME3233","moduleCredit":0,"title":"Unsteady Flow in Fluid Systems"} +{"moduleCode":"DTS5703","moduleCredit":0,"title":"Operations Research"} +{"moduleCode":"EE5711","moduleCredit":0,"title":"Power Electronic Systems"} +{"moduleCode":"IT1001","moduleCredit":0,"title":"Introduction to Computing"} +{"moduleCode":"UIS3911HY","moduleCredit":0,"title":"Independent Study Module"} +{"moduleCode":"EC1101E","moduleCredit":0,"title":"Introduction to Economic Analysis"} +{"moduleCode":"TIE2010","moduleCredit":0,"title":"Introduction to Industrial System"} +{"moduleCode":"DTS5702","moduleCredit":0,"title":"C3 Systems"} +{"moduleCode":"DTS5701","moduleCredit":0,"title":"Large Scale Systems Engineering"} +{"moduleCode":"HY6101","moduleCredit":0,"title":"Historiography: Theory & Archive"} +{"moduleCode":"LI5101","moduleCredit":0,"title":"Supply Chain Mgt Thinking & Practice"} +{"moduleCode":"CN3132E","moduleCredit":0,"title":"Separation Processes"} +{"moduleCode":"GEM2025","moduleCredit":0,"title":"Introduction to Philosophy Of Science"} +{"moduleCode":"GEM2027","moduleCredit":0,"title":"Public Speaking and Critical Reasoning"} +{"moduleCode":"EE5701","moduleCredit":0,"title":"High Voltage Testing and Switchgear"} +{"moduleCode":"CH2275","moduleCredit":0,"title":"Chinese Pop Music in East Asia"} +{"moduleCode":"TBA3204","moduleCredit":0,"title":"Web Analytics"} +{"moduleCode":"CS2105R","moduleCredit":0,"title":"Introduction to Computer Networks"} +{"moduleCode":"EE5703","moduleCredit":0,"title":"Industrial Drives"} +{"moduleCode":"EE5702","moduleCredit":0,"title":"Advanced Power System Analysis"} +{"moduleCode":"TIC3002","moduleCredit":0,"title":"User Interface Design and Implementation"} +{"moduleCode":"TIC3001","moduleCredit":0,"title":"Software Requirements Analysis and Design"} +{"moduleCode":"LL6259V","moduleCredit":0,"title":"Alternative Investments"} +{"moduleCode":"TIE2020","moduleCredit":0,"title":"Probability and Statistics"} +{"moduleCode":"LL5364V","moduleCredit":0,"title":"Principles of Civil Law: Law of Obligations & Property"} +{"moduleCode":"ST2288","moduleCredit":0,"title":"Basic UROPS in Statistics and Applied Probability I"} +{"moduleCode":"ST2289","moduleCredit":0,"title":"Basic UROPS in Statistics and Applied Probability II"} +{"moduleCode":"TME3211","moduleCredit":0,"title":"Mechanics of Solids"} +{"moduleCode":"LAM3202","moduleCredit":0,"title":"Malay 4"} +{"moduleCode":"LAM3201","moduleCredit":0,"title":"Malay 3"} +{"moduleCode":"GEM2001","moduleCredit":0,"title":"Asian Theatres: Tradition and the Contemporary"} +{"moduleCode":"FE5101","moduleCredit":0,"title":"Derivatives And Fixed Income"} +{"moduleCode":"TTG3002","moduleCredit":0,"title":"Industrial Practice"} +{"moduleCode":"ME2142E","moduleCredit":0,"title":"Feedback Control Systems"} +{"moduleCode":"FE5103","moduleCredit":0,"title":"Equity Products and Exotics"} +{"moduleCode":"LC1002H","moduleCredit":0,"title":"Introduction to Legal Theory (H)"} +{"moduleCode":"TTG3001","moduleCredit":0,"title":"Industrial Practice"} +{"moduleCode":"BPS5111","moduleCredit":0,"title":"Integrated Building Design"} +{"moduleCode":"PR1110A","moduleCredit":0,"title":"Foundations for Medicinal Chemistry"} +{"moduleCode":"PL4229","moduleCredit":0,"title":"Psychological Therapies"} +{"moduleCode":"TIE2030","moduleCredit":0,"title":"Programming Methodology with Python"} +{"moduleCode":"BPS5112","moduleCredit":0,"title":"Green Building Integration and Evaluation Studio"} +{"moduleCode":"PL4228","moduleCredit":0,"title":"Criminal Forensic Psychology"} +{"moduleCode":"IS2101","moduleCredit":0,"title":"Business and Technical Communication"} +{"moduleCode":"IS2102","moduleCredit":0,"title":"Enterprise Systems Architecture and Design"} +{"moduleCode":"PL4233","moduleCredit":0,"title":"Psychology of Negotiation"} +{"moduleCode":"PL4238","moduleCredit":0,"title":"Social Neuroscience"} +{"moduleCode":"PC5209","moduleCredit":0,"title":"Accelerator Based Materials Characterisation"} +{"moduleCode":"IS2103","moduleCredit":0,"title":"Enterprise Systems Server-side Design and Development"} +{"moduleCode":"PR1111A","moduleCredit":0,"title":"Pharmaceutical Biochemistry"} +{"moduleCode":"PL4235","moduleCredit":0,"title":"The Psychology of Moral Judgments"} +{"moduleCode":"CE5307A","moduleCredit":0,"title":"Ocean Waves"} +{"moduleCode":"LC1002G","moduleCredit":0,"title":"Introduction to Legal Theory (G)"} +{"moduleCode":"PC5204","moduleCredit":0,"title":"Magnetism and Spintronics"} +{"moduleCode":"CE5307B","moduleCredit":0,"title":"Hydrodynamic Loads on Offshore Structures"} +{"moduleCode":"LC1002F","moduleCredit":0,"title":"Introduction to Legal Theory (F)"} +{"moduleCode":"PC5205","moduleCredit":0,"title":"Topics in Surface Physics"} +{"moduleCode":"LC1002E","moduleCredit":0,"title":"Introduction to Legal Theory (E)"} +{"moduleCode":"PC5206","moduleCredit":0,"title":"Selected Topics in Quantum Field Theory"} +{"moduleCode":"CE5610A","moduleCredit":0,"title":"Concrete and Cementitious Composites"} +{"moduleCode":"LC1002C","moduleCredit":0,"title":"Introduction to Legal Theory (C)"} +{"moduleCode":"SW3103A","moduleCredit":0,"title":"Social Work Field Practice (I)"} +{"moduleCode":"FAS1102","moduleCredit":0,"title":"Public Writing and Communication"} +{"moduleCode":"PC5201","moduleCredit":0,"title":"Advanced Quantum Mechanics"} +{"moduleCode":"CE5307C","moduleCredit":0,"title":"Finite Amplitude Wave Theories & Their Applications"} +{"moduleCode":"FAS1101","moduleCredit":0,"title":"Writing Academically: Arts and Social Sciences"} +{"moduleCode":"GEM2006","moduleCredit":0,"title":"Logic"} +{"moduleCode":"LC1002A","moduleCredit":0,"title":"Introduction To Legal Theory (A)"} +{"moduleCode":"PC5202","moduleCredit":0,"title":"Advanced Statistical Mechanics"} +{"moduleCode":"FE5110","moduleCredit":0,"title":"Financial Engineering Project"} +{"moduleCode":"LAC2201","moduleCredit":0,"title":"Chinese 2"} +{"moduleCode":"PC5210","moduleCredit":0,"title":"Advanced Dynamics"} +{"moduleCode":"CE5610B","moduleCredit":0,"title":"Repair and Retrofit of Concrete Structures"} +{"moduleCode":"FE5112","moduleCredit":0,"title":"Stochastic Calculus and Quantitative Methods"} +{"moduleCode":"LL6299","moduleCredit":0,"title":"Advanced Issues in the Law & Practice of Int’l Arbitration"} +{"moduleCode":"LL4343V","moduleCredit":0,"title":"International Regulation of the Global Commons"} +{"moduleCode":"DMX1402","moduleCredit":0,"title":"DYOM via edX MOOC"} +{"moduleCode":"CN4203R","moduleCredit":0,"title":"Polymer Engineering"} +{"moduleCode":"PL4239","moduleCredit":0,"title":"Social Psychology of the Unconscious"} +{"moduleCode":"DTS5711","moduleCredit":0,"title":"Integration Project"} +{"moduleCode":"MUA4340","moduleCredit":0,"title":"Collaborative Piano - Piano Ensemble 4"} +{"moduleCode":"MUA4341","moduleCredit":0,"title":"Collaborative Piano - Vocal Accompaniment 4"} +{"moduleCode":"UIS4911PS","moduleCredit":0,"title":"Independent Study Module"} +{"moduleCode":"MUA4342","moduleCredit":0,"title":"Collaborative Piano - Instrumental Accompaniment 4"} +{"moduleCode":"TR3201N","moduleCredit":0,"title":"Entrepreneurship Practicum"} +{"moduleCode":"DMX1401","moduleCredit":0,"title":"DYOM via edX MOOC"} +{"moduleCode":"DTS5712","moduleCredit":0,"title":"Thesis Project"} +{"moduleCode":"MUA4343","moduleCredit":0,"title":"Collaborative Piano - Chamber Music 4"} +{"moduleCode":"MUT3113","moduleCredit":0,"title":"Orchestration A"} +{"moduleCode":"PL4244","moduleCredit":0,"title":"Sleep: A Cognitive Neuroscience Perspective"} +{"moduleCode":"EL4880D","moduleCredit":0,"title":"Experimental Syntax"} +{"moduleCode":"LL5233V","moduleCredit":0,"title":"European Company Law"} +{"moduleCode":"UIS3911GE","moduleCredit":0,"title":"Independent Study Module"} +{"moduleCode":"FE5105","moduleCredit":0,"title":"Corporate Financing and Risk"} +{"moduleCode":"LC1001F","moduleCredit":0,"title":"Criminal Law (F)"} +{"moduleCode":"PC5215","moduleCredit":0,"title":"Numerical Recipes With Applications"} +{"moduleCode":"SC5103R","moduleCredit":0,"title":"Qualitative Data Analysis"} +{"moduleCode":"LC1001E","moduleCredit":0,"title":"Criminal Law (E)"} +{"moduleCode":"PC5216","moduleCredit":0,"title":"Advanced Atomic & Molecular Physics"} +{"moduleCode":"CE5611A","moduleCredit":0,"title":"Specifying Concrete to EN 206"} +{"moduleCode":"FE5107","moduleCredit":0,"title":"Risk Analyses And Management"} +{"moduleCode":"ME2143E","moduleCredit":0,"title":"Sensors and Actuators"} +{"moduleCode":"CE5611B","moduleCredit":0,"title":"Precast Concrete Design"} +{"moduleCode":"LC1001C","moduleCredit":0,"title":"Criminal Law (C)"} +{"moduleCode":"LAC2202","moduleCredit":0,"title":"Chinese Characters Writing & Composition"} +{"moduleCode":"LC1001B","moduleCredit":0,"title":"Criminal Law (B)"} +{"moduleCode":"PL4241","moduleCredit":0,"title":"Exploring Consciousness – Theory and Neuroscience"} +{"moduleCode":"LC1001A","moduleCredit":0,"title":"Criminal Law (A)"} +{"moduleCode":"PC5212","moduleCredit":0,"title":"Physics of Nanostructures"} +{"moduleCode":"EE2028A","moduleCredit":0,"title":"C Programming"} +{"moduleCode":"PC5213","moduleCredit":0,"title":"Advanced Biophysics"} +{"moduleCode":"PC5214","moduleCredit":0,"title":"Essential techniques in experimental physics"} +{"moduleCode":"USS2105","moduleCredit":0,"title":"University Scholars Seminar"} +{"moduleCode":"LL4342V","moduleCredit":0,"title":"Taxation of Cross-Border Commercial Transactions"} +{"moduleCode":"PL4207","moduleCredit":0,"title":"Social Psychology: Theories and Methods"} +{"moduleCode":"PL4206","moduleCredit":0,"title":"Cognitive Neuroscience"} +{"moduleCode":"UPC2211","moduleCredit":0,"title":"Re-examining the Deterministic World of Matter"} +{"moduleCode":"PL4214","moduleCredit":0,"title":"Evolutionary Psychology"} +{"moduleCode":"ME4101A","moduleCredit":0,"title":"Bachelor Of Engineering Dissertation"} +{"moduleCode":"KE5006","moduleCredit":0,"title":"Applied Research"} +{"moduleCode":"LL6094AV","moduleCredit":0,"title":"Law & Practice - The Law Clinic"} +{"moduleCode":"DTS5736","moduleCredit":0,"title":"Systems Design Project"} +{"moduleCode":"LL6276","moduleCredit":0,"title":"Advanced Contract Law"} +{"moduleCode":"CP4106","moduleCredit":0,"title":"Computing Project"} +{"moduleCode":"CN4201R","moduleCredit":0,"title":"Petroleum Refining"} +{"moduleCode":"PL4219","moduleCredit":0,"title":"Advanced Abnormal Psychology"} +{"moduleCode":"DTS5731","moduleCredit":0,"title":"Fundamentals of Systems Engineering"} +{"moduleCode":"DTS5733","moduleCredit":0,"title":"Sensors and Intelligence"} +{"moduleCode":"UPC2209","moduleCredit":0,"title":"Pollution Control Engineering in Singapore"} +{"moduleCode":"DTS5732","moduleCredit":0,"title":"Artificial Intelligence and Data Analytics"} +{"moduleCode":"EN5238R","moduleCredit":0,"title":"Twentieth-Century Literary Production"} +{"moduleCode":"UPC2208","moduleCredit":0,"title":"Molecular Courtship"} +{"moduleCode":"DTS5735","moduleCredit":0,"title":"Cybersecurity"} +{"moduleCode":"DTS5734","moduleCredit":0,"title":"Guided Systems"} +{"moduleCode":"ME5304","moduleCredit":0,"title":"Experimental Fluid Mechanics"} +{"moduleCode":"PL4222","moduleCredit":0,"title":"Neuroscience of Memory"} +{"moduleCode":"LL5102V","moduleCredit":0,"title":"Advanced Torts"} +{"moduleCode":"PL6889","moduleCredit":0,"title":"Selected Topics in Emotion Psychology"} +{"moduleCode":"UPC2206","moduleCredit":0,"title":"Nanoscale Science And Technology"} +{"moduleCode":"PL4227","moduleCredit":0,"title":"Behavioral Genetics for Social Scientists"} +{"moduleCode":"ME5309","moduleCredit":0,"title":"Aircraft Engines and Rocket Propulsion"} +{"moduleCode":"PL4226","moduleCredit":0,"title":"Correctional Psychology"} +{"moduleCode":"PL4225","moduleCredit":0,"title":"Psychology of Gender"} +{"moduleCode":"UIS3911EC","moduleCredit":0,"title":"Independent Study Module"} +{"moduleCode":"PL4224","moduleCredit":0,"title":"Child Abnormal Psychology"} +{"moduleCode":"UIS3911EL","moduleCredit":0,"title":"Independent Study Module"} +{"moduleCode":"CHC5102","moduleCredit":0,"title":"Contemporary Research in Chinese Language"} +{"moduleCode":"LL5235V","moduleCredit":0,"title":"International Contract Law: Principles and Practice"} +{"moduleCode":"UIS3911EN","moduleCredit":0,"title":"Independent Study Module"} +{"moduleCode":"CHC5101","moduleCredit":0,"title":"Contemporary Research in Chinese Studies"} +{"moduleCode":"LL6094BV","moduleCredit":0,"title":"Law & Practice - The Law Clinic"} +{"moduleCode":"CP4101","moduleCredit":0,"title":"B.Comp. Dissertation"} +{"moduleCode":"AR5959A","moduleCredit":0,"title":"Topics in Design Technology 1"} +{"moduleCode":"CM4225","moduleCredit":0,"title":"Organic Spectroscopy"} +{"moduleCode":"AR5959C","moduleCredit":0,"title":"Topics in Design Technology 3"} +{"moduleCode":"AR5959D","moduleCredit":0,"title":"Topics in Design Technology 4"} +{"moduleCode":"LL5055","moduleCredit":0,"title":"Securities Regulation"} +{"moduleCode":"CM4228","moduleCredit":0,"title":"Catalysis"} +{"moduleCode":"GEQ1000X","moduleCredit":0,"title":"Asking Questions"} +{"moduleCode":"CM4227","moduleCredit":0,"title":"Chemical Biology"} +{"moduleCode":"MA5216","moduleCredit":0,"title":"Differential Geometry"} +{"moduleCode":"CS2106","moduleCredit":0,"title":"Introduction to Operating Systems"} +{"moduleCode":"FST3288","moduleCredit":0,"title":"Advanced UROPS in Food Science & Technology I"} +{"moduleCode":"MUA3108","moduleCredit":0,"title":"Large Ensembles 3B"} +{"moduleCode":"CS2105","moduleCredit":0,"title":"Introduction to Computer Networks"} +{"moduleCode":"FST3289","moduleCredit":0,"title":"Advanced UROPS in Food Science & Technology II"} +{"moduleCode":"MA5218","moduleCredit":0,"title":"Graduate Algebra IIB"} +{"moduleCode":"MUA3107","moduleCredit":0,"title":"Large Ensembles 3A"} +{"moduleCode":"CM1191","moduleCredit":0,"title":"Experiments in Chemistry 1"} +{"moduleCode":"CS2108","moduleCredit":0,"title":"Introduction to Media Computing"} +{"moduleCode":"NM4219","moduleCredit":0,"title":"New Media in Health Communication"} +{"moduleCode":"CS2107","moduleCredit":0,"title":"Introduction to Information Security"} +{"moduleCode":"CS2102","moduleCredit":0,"title":"Database Systems"} +{"moduleCode":"CS2101","moduleCredit":0,"title":"Effective Communication for Computing Professionals"} +{"moduleCode":"CS2104","moduleCredit":0,"title":"Programming Language Concepts"} +{"moduleCode":"ESE2401","moduleCredit":0,"title":"Water Science & Technology"} +{"moduleCode":"MUA3102","moduleCredit":0,"title":"Composition Major Study 3B"} +{"moduleCode":"CS2103","moduleCredit":0,"title":"Software Engineering"} +{"moduleCode":"MUA3101","moduleCredit":0,"title":"Composition Major Study 3A"} +{"moduleCode":"YSS3300","moduleCredit":0,"title":"Research Tutorial: Lab in Developmental Psychology"} +{"moduleCode":"NM4223","moduleCredit":0,"title":"New Media and Organizations"} +{"moduleCode":"CS2100","moduleCredit":0,"title":"Computer Organisation"} +{"moduleCode":"PP5660","moduleCredit":0,"title":"Independent Study Module"} +{"moduleCode":"EG2301","moduleCredit":0,"title":"Case Studies in Engineering"} +{"moduleCode":"TEE4101","moduleCredit":0,"title":"Radio-Frequency (RF) Communications"} +{"moduleCode":"PC5247","moduleCredit":0,"title":"Photonics II"} +{"moduleCode":"LL6372","moduleCredit":0,"title":"International Intellectual Property Law"} +{"moduleCode":"SC5770","moduleCredit":0,"title":"Graduate Research Seminar for Masters students"} +{"moduleCode":"AR5958A","moduleCredit":0,"title":"Topics in Urbanism 1"} +{"moduleCode":"CM4214","moduleCredit":0,"title":"Structural Methods in Inorganic Chem"} +{"moduleCode":"LL6373","moduleCredit":0,"title":"Advanced Copyright"} +{"moduleCode":"CM4211","moduleCredit":0,"title":"Advanced Coordination Chemistry"} +{"moduleCode":"LL5043","moduleCredit":0,"title":"Law of Marine Insurance"} +{"moduleCode":"LL6374","moduleCredit":0,"title":"Water Rights & Resources: Issues in Law & Development"} +{"moduleCode":"CM4212","moduleCredit":0,"title":"Advanced Organometallic Chemistry"} +{"moduleCode":"LL6375","moduleCredit":0,"title":"Traditional Chinese Legal Thought"} +{"moduleCode":"LL6376","moduleCredit":0,"title":"Regulation & Private Law in Banking & Financial Service"} +{"moduleCode":"DMS1401CM","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"ME2151E","moduleCredit":0,"title":"Principles of Mechanical Eng. Materials"} +{"moduleCode":"NM4208","moduleCredit":0,"title":"Strategic Communication Design"} +{"moduleCode":"NM4207","moduleCredit":0,"title":"Managing Communication Campaigns"} +{"moduleCode":"NM4206","moduleCredit":0,"title":"Media Regulation and Governance"} +{"moduleCode":"TR5049","moduleCredit":0,"title":"Lean Startup Practicum"} +{"moduleCode":"LL6370","moduleCredit":0,"title":"The Law of Cybersecurity, Privacy and Data Compliance"} +{"moduleCode":"NM4204","moduleCredit":0,"title":"Media Ethics - Principles and Practices"} +{"moduleCode":"LL6371","moduleCredit":0,"title":"Charity Law Today"} +{"moduleCode":"NM4203","moduleCredit":0,"title":"Infocomm Technology Policy"} +{"moduleCode":"NM4213","moduleCredit":0,"title":"Digital Economies"} +{"moduleCode":"NM4212","moduleCredit":0,"title":"Race, Media and Representation"} +{"moduleCode":"NM4211","moduleCredit":0,"title":"Online Journalism"} +{"moduleCode":"NM4210","moduleCredit":0,"title":"User Experience Design"} +{"moduleCode":"LL5063V","moduleCredit":0,"title":"Business & Finance For Lawyers"} +{"moduleCode":"LL6369","moduleCredit":0,"title":"Constitutionalism in Asia"} +{"moduleCode":"LL6260V","moduleCredit":0,"title":"Chinese Commercial Law"} +{"moduleCode":"CN4208E","moduleCredit":0,"title":"Biochemical Engineering"} +{"moduleCode":"EC5386","moduleCredit":0,"title":"Issues in Port Economics"} +{"moduleCode":"MA5220","moduleCredit":0,"title":"Logic and Foundation of Mathematics II"} +{"moduleCode":"MA5233","moduleCredit":0,"title":"Computational Mathematics"} +{"moduleCode":"MUA4410","moduleCredit":0,"title":"Chamber Music in Mixed Ensemble 6"} +{"moduleCode":"MA5232","moduleCredit":0,"title":"Modeling and Numerical Simulations"} +{"moduleCode":"LL5032","moduleCredit":0,"title":"International Investment Law"} +{"moduleCode":"AR5957C","moduleCredit":0,"title":"Topics in History and Theory of Architecture 3"} +{"moduleCode":"AR5957D","moduleCredit":0,"title":"Topics in History and Theory of Architecture 4"} +{"moduleCode":"SC3101","moduleCredit":0,"title":"Social Thought & Social Theory"} +{"moduleCode":"LL6368","moduleCredit":0,"title":"Comparative Constitutionalism"} +{"moduleCode":"MA5238","moduleCredit":0,"title":"Fourier Analysis"} +{"moduleCode":"PC2193","moduleCredit":0,"title":"Experimental Physics I"} +{"moduleCode":"BMF5341A","moduleCredit":0,"title":"Advanced Investment Strategies"} +{"moduleCode":"DMY1401TH","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"ME5300A","moduleCredit":0,"title":"Special Project in Computation and Modelling I"} +{"moduleCode":"CM4242","moduleCredit":0,"title":"Advanced Analytical Techniques"} +{"moduleCode":"ME5300B","moduleCredit":0,"title":"Special Project in Computation and Modelling II"} +{"moduleCode":"GL4660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"BMF5341B","moduleCredit":0,"title":"Applied Investment Strategies"} +{"moduleCode":"CM4241","moduleCredit":0,"title":"Trace Analysis"} +{"moduleCode":"GE5215","moduleCredit":0,"title":"The Politics of Environment in Se Asia"} +{"moduleCode":"TME3162","moduleCredit":0,"title":"Manufacturing Processes"} +{"moduleCode":"GE5214","moduleCredit":0,"title":"Landscapes of Southeast Asia"} +{"moduleCode":"LAL1201","moduleCredit":0,"title":"Tamil 1"} +{"moduleCode":"LL5064V","moduleCredit":0,"title":"Competition Law and Policy"} +{"moduleCode":"DMY1401TT","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"CN4205E","moduleCredit":0,"title":"Pinch Analysis and Process Integration"} +{"moduleCode":"MUA4409","moduleCredit":0,"title":"Chamber Music 6"} +{"moduleCode":"PC5228","moduleCredit":0,"title":"Quantum Information and Computation"} +{"moduleCode":"MA5243","moduleCredit":0,"title":"Advanced Mathematical Programming"} +{"moduleCode":"AR5956A","moduleCredit":0,"title":"Topics in Design and Built Environment 1"} +{"moduleCode":"MA5245","moduleCredit":0,"title":"Advanced Financial Mathematics"} +{"moduleCode":"AR5956B","moduleCredit":0,"title":"Topics in Design and Built Environment 2"} +{"moduleCode":"MA5248","moduleCredit":0,"title":"Stochastic Analysis in Mathematical Finance"} +{"moduleCode":"AR5956C","moduleCredit":0,"title":"Topics in Design and Built Environment 3"} +{"moduleCode":"AR5956D","moduleCredit":0,"title":"Topics in Design and Built Environment 4"} +{"moduleCode":"AR5956E","moduleCredit":0,"title":"Topics in Design and Built Environment 5"} +{"moduleCode":"CM4238","moduleCredit":0,"title":"Selected Topics in Physical Chemistry"} +{"moduleCode":"LL6263V","moduleCredit":0,"title":"Intellectual Property Rights and Competition Policy"} +{"moduleCode":"PH4202","moduleCredit":0,"title":"Political Philosophy"} +{"moduleCode":"BN6999","moduleCredit":0,"title":"Doctoral Seminars"} +{"moduleCode":"CN4205R","moduleCredit":0,"title":"Pinch Analysis and Process Integration"} +{"moduleCode":"GE5217","moduleCredit":0,"title":"Research Methods in Environmental Sciences"} +{"moduleCode":"GE5216","moduleCredit":0,"title":"Geography and Social Theory"} +{"moduleCode":"BN5666","moduleCredit":0,"title":"Industrial Attachment"} +{"moduleCode":"GE5219","moduleCredit":0,"title":"Spatial Programming"} +{"moduleCode":"GE5218","moduleCredit":0,"title":"Research Methods in Human Geography"} +{"moduleCode":"HY5660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"GE5223","moduleCredit":0,"title":"Introduction to Applied GIS"} +{"moduleCode":"GE5226","moduleCredit":0,"title":"GIS Applications"} +{"moduleCode":"GE5225","moduleCredit":0,"title":"Thesis Planning and Implementation"} +{"moduleCode":"PE2101P","moduleCredit":0,"title":"Introduction to Philosophy, Politics, and Economics"} +{"moduleCode":"EG2312","moduleCredit":0,"title":"Radar Theory and Techniques"} +{"moduleCode":"EG2310","moduleCredit":0,"title":"Fundamentals of Systems Design"} +{"moduleCode":"TEE4112","moduleCredit":0,"title":"Radio Frequency Design and Systems"} +{"moduleCode":"EG2311","moduleCredit":0,"title":"Introduction to Space Systems"} +{"moduleCode":"MA5259","moduleCredit":0,"title":"Probability Theory I"} +{"moduleCode":"LL5008AV","moduleCredit":0,"title":"Carriage of Goods By Sea"} +{"moduleCode":"EC5326","moduleCredit":0,"title":"Policy Impact Evaluation Methods"} +{"moduleCode":"BDC6218","moduleCredit":0,"title":"Seminars in Optimization I"} +{"moduleCode":"GE5228","moduleCredit":0,"title":"Spatial Big Data and Analytics"} +{"moduleCode":"GE5227","moduleCredit":0,"title":"Internet GIS"} +{"moduleCode":"MA4269A","moduleCredit":0,"title":"Mathematical Finance II"} +{"moduleCode":"CE4104","moduleCredit":0,"title":"B. Eng. Dissertation"} +{"moduleCode":"CE4103","moduleCredit":0,"title":"Design Project"} +{"moduleCode":"LL6339","moduleCredit":0,"title":"Comparative Evidence in International Arbitration"} +{"moduleCode":"CN3135","moduleCredit":0,"title":"Process Safety, Health and Environment"} +{"moduleCode":"PC5288","moduleCredit":0,"title":"M.sc Coursework Thesis For Physics"} +{"moduleCode":"PC5289","moduleCredit":0,"title":"M.sc.(coursework) Thesis For Applied Physics"} +{"moduleCode":"MA5253","moduleCredit":0,"title":"Riemann Surfaces"} +{"moduleCode":"CN3132","moduleCredit":0,"title":"Separation Processes"} +{"moduleCode":"MA5252","moduleCredit":0,"title":"Methods of Applied Mathematics"} +{"moduleCode":"BMS5602","moduleCredit":0,"title":"Business Analysis and Valuation"} +{"moduleCode":"MA5268","moduleCredit":0,"title":"Theory and algorithms for nonlinear optimization"} +{"moduleCode":"LL5001","moduleCredit":0,"title":"Administration of Criminal Justice"} +{"moduleCode":"CN2116E","moduleCredit":0,"title":"Chemical Kinetics And Reactor Design"} +{"moduleCode":"MA5269","moduleCredit":0,"title":"Optimal Stopping and Stochastic Control in Finance"} +{"moduleCode":"LL5004","moduleCredit":0,"title":"Aviation Law & Policy"} +{"moduleCode":"DMB1204FIN","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"LL5008BV","moduleCredit":0,"title":"Charterparties"} +{"moduleCode":"EN3880B","moduleCredit":0,"title":"Reader-Responsibility"} +{"moduleCode":"NM4249","moduleCredit":0,"title":"Media & Audiences"} +{"moduleCode":"NM4247","moduleCredit":0,"title":"Creative Writing in the Marketplace"} +{"moduleCode":"TIC1201","moduleCredit":0,"title":"Discrete Structures"} +{"moduleCode":"LL6328","moduleCredit":0,"title":"Sports Law"} +{"moduleCode":"EC5342","moduleCredit":0,"title":"International Trade"} +{"moduleCode":"CN3121","moduleCredit":0,"title":"Process Dynamics & Control"} +{"moduleCode":"EB5102","moduleCredit":0,"title":"Data Analytics"} +{"moduleCode":"EB5104","moduleCredit":0,"title":"Decision Making and Optimization"} +{"moduleCode":"EB5103","moduleCredit":0,"title":"Advanced Analytics"} +{"moduleCode":"USP3501","moduleCredit":0,"title":"The Problematic Concept Of 'Gender'"} +{"moduleCode":"EB5105","moduleCredit":0,"title":"Enterprise Business Analytics Project"} +{"moduleCode":"NM4239","moduleCredit":0,"title":"Digital Propaganda and Public Opinion"} +{"moduleCode":"NM4238","moduleCredit":0,"title":"Software Studies"} +{"moduleCode":"NM4246","moduleCredit":0,"title":"Learning Innovation in the Digital Age"} +{"moduleCode":"NM4245","moduleCredit":0,"title":"Political Communication and Digital Media"} +{"moduleCode":"QF5208","moduleCredit":0,"title":"AI and FinTech"} +{"moduleCode":"NM4244","moduleCredit":0,"title":"Sex in the Media"} +{"moduleCode":"QF5207","moduleCredit":0,"title":"Investment and Portfolio Selection"} +{"moduleCode":"MLE2102","moduleCredit":0,"title":"Thermodynamics and Phase Diagrams"} +{"moduleCode":"NM4242","moduleCredit":0,"title":"Critical Perspectives on Technology"} +{"moduleCode":"MLE2101","moduleCredit":0,"title":"Introduction to Structure of Materials"} +{"moduleCode":"NM4240","moduleCredit":0,"title":"Risk Perception and Communication"} +{"moduleCode":"EG3612","moduleCredit":0,"title":"Vacation Internship Programme"} +{"moduleCode":"QF5201","moduleCredit":0,"title":"Interest Rate Theory and Credit Risk"} +{"moduleCode":"MLE2105","moduleCredit":0,"title":"Electronic Properties of Materials"} +{"moduleCode":"MLE2104","moduleCredit":0,"title":"Mechanical Properties of Materials"} +{"moduleCode":"EG3611","moduleCredit":0,"title":"Industrial Attachment"} +{"moduleCode":"MLE2103","moduleCredit":0,"title":"Phase Transformation and Kinetics"} +{"moduleCode":"QF5205","moduleCredit":0,"title":"Topics in Quantitative Finance I"} +{"moduleCode":"DSC5221A","moduleCredit":0,"title":"Managing the Financial Supply Chain"} +{"moduleCode":"QF5204","moduleCredit":0,"title":"Numerical Methods in Quantitative Finance"} +{"moduleCode":"QF5203","moduleCredit":0,"title":"Risk Management"} +{"moduleCode":"TME3122","moduleCredit":0,"title":"Heat Transfer"} +{"moduleCode":"QF5202","moduleCredit":0,"title":"Structured Products"} +{"moduleCode":"MNO2705A","moduleCredit":0,"title":"Leadership and Decision Making under Uncertainty"} +{"moduleCode":"TCN1005","moduleCredit":0,"title":"MATLAB Programming for Chemical Engineers"} +{"moduleCode":"BL5198","moduleCredit":0,"title":"Graduate Seminar Module in Biological Sciences"} +{"moduleCode":"MNO2705C","moduleCredit":0,"title":"Leadership and Decision Making under Uncertainty"} +{"moduleCode":"MNO2705B","moduleCredit":0,"title":"Leadership and Decision Making under Uncertainty"} +{"moduleCode":"MNO2705D","moduleCredit":0,"title":"Leadership and Decision Making under Uncertainty"} +{"moduleCode":"MNO4751","moduleCredit":0,"title":"Adv Independent Study in Leadership & Human Capital Mgt"} +{"moduleCode":"BMM5101","moduleCredit":0,"title":"Judgment and Decision-Making for Modern Policy Makers"} +{"moduleCode":"LL4349V","moduleCredit":0,"title":"Energy Arbitration"} +{"moduleCode":"NM4228","moduleCredit":0,"title":"Crisis Communication"} +{"moduleCode":"NM4227","moduleCredit":0,"title":"Game Studies"} +{"moduleCode":"NM4225","moduleCredit":0,"title":"Speculative and Critical Design"} +{"moduleCode":"EC5361","moduleCredit":0,"title":"Labour Economics"} +{"moduleCode":"YLC1201","moduleCredit":0,"title":"Beginning Chinese 1"} +{"moduleCode":"YLC1202","moduleCredit":0,"title":"Beginning Chinese 2"} +{"moduleCode":"MA3110S","moduleCredit":0,"title":"Mathematical Analysis II (S)"} +{"moduleCode":"NM4231","moduleCredit":0,"title":"Advanced Digital Storytelling"} +{"moduleCode":"GEQ1000H","moduleCredit":0,"title":"Asking Questions"} +{"moduleCode":"NM4230","moduleCredit":0,"title":"Communication for Social Change"} +{"moduleCode":"MUH4204","moduleCredit":0,"title":"Music History for Post-Graduate Placement"} +{"moduleCode":"LL6307","moduleCredit":0,"title":"EU Maritime Law"} +{"moduleCode":"CL3550","moduleCredit":0,"title":"Chinese Language Internship"} +{"moduleCode":"FIN3101B","moduleCredit":0,"title":"Corporate Finance"} +{"moduleCode":"MA2101","moduleCredit":0,"title":"Linear Algebra II"} +{"moduleCode":"FST3202","moduleCredit":0,"title":"Nutrition and Disease Prevention"} +{"moduleCode":"MA2104","moduleCredit":0,"title":"Multivariable Calculus"} +{"moduleCode":"FST3201","moduleCredit":0,"title":"Independent Study (Food Science & Tech)"} +{"moduleCode":"CS5219","moduleCredit":0,"title":"Automated Software Validation"} +{"moduleCode":"CS5218","moduleCredit":0,"title":"Principles and Practice of Program Analysis"} +{"moduleCode":"MA2108","moduleCredit":0,"title":"Mathematical Analysis I"} +{"moduleCode":"CS5215","moduleCredit":0,"title":"Constraint Processing"} +{"moduleCode":"CH5223R","moduleCredit":0,"title":"Selected Authors"} +{"moduleCode":"FIN3101A","moduleCredit":0,"title":"Corporate Finance"} +{"moduleCode":"EC5101R","moduleCredit":0,"title":"Microeconomic Theory"} +{"moduleCode":"TIC2501","moduleCredit":0,"title":"Computer Networks and Applications"} +{"moduleCode":"SP2171","moduleCredit":0,"title":"Discovering Science"} +{"moduleCode":"AR5951A","moduleCredit":0,"title":"Topics in History and Theory of Architecture 1"} +{"moduleCode":"SP2174","moduleCredit":0,"title":"The Cell"} +{"moduleCode":"AR5951B","moduleCredit":0,"title":"Topics in History & Theory of Architecture 2"} +{"moduleCode":"SP2173","moduleCredit":0,"title":"Atoms to Molecules"} +{"moduleCode":"AR5951C","moduleCredit":0,"title":"Topics in History and Theory of Architecture 3"} +{"moduleCode":"AR5951D","moduleCredit":0,"title":"Topics in History & Theory of Architecture 4"} +{"moduleCode":"AR5951E","moduleCredit":0,"title":"Topics in History & Theory of Architecture 5"} +{"moduleCode":"AR5951F","moduleCredit":0,"title":"Topics in History & Theory of Architecture 6"} +{"moduleCode":"AR5951G","moduleCredit":0,"title":"Topics in History and Theory of Architecture 7"} +{"moduleCode":"PR2143","moduleCredit":0,"title":"Pharmaceutical Analysis for Quality Assurance"} +{"moduleCode":"AR5951H","moduleCredit":0,"title":"Topics in History and Theory of Architecture 8"} +{"moduleCode":"LL4173V","moduleCredit":0,"title":"Comparative Corporate Law"} +{"moduleCode":"PH4262","moduleCredit":0,"title":"Nietzsche"} +{"moduleCode":"MKT3761A","moduleCredit":0,"title":"TIM: Wealth Management Marketing"} +{"moduleCode":"PF3301","moduleCredit":0,"title":"Maintainability of Facilities"} +{"moduleCode":"CM4299","moduleCredit":0,"title":"Applied Project in Chemistry"} +{"moduleCode":"PF3306","moduleCredit":0,"title":"Facilities Management Law And Contracts"} +{"moduleCode":"PF3307","moduleCredit":0,"title":"Strategic Facilities Management"} +{"moduleCode":"DMY1401KE","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"PF3305","moduleCredit":0,"title":"Facilities Planning and Design"} +{"moduleCode":"PF3302","moduleCredit":0,"title":"Energy Management"} +{"moduleCode":"CSA6770","moduleCredit":0,"title":"Graduate Research Seminar"} +{"moduleCode":"QF5210","moduleCredit":0,"title":"Financial Time Series: Theory and Computation"} +{"moduleCode":"MS3209","moduleCredit":0,"title":"The Malays of Singapore"} +{"moduleCode":"FIN6003","moduleCredit":0,"title":"Asset Pricing and Microstructure Theory"} +{"moduleCode":"FIN6004","moduleCredit":0,"title":"Empirical Asset Pricing and Microstructure"} +{"moduleCode":"SE6660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"CH5225R","moduleCredit":0,"title":"Topics in Se Asian Chinese Literature"} +{"moduleCode":"FIN3103A","moduleCredit":0,"title":"Financial Markets"} +{"moduleCode":"FIN3103B","moduleCredit":0,"title":"Financial Markets"} +{"moduleCode":"ACC4713","moduleCredit":0,"title":"Financial Institution Audit & Compliance"} +{"moduleCode":"ACC4714","moduleCredit":0,"title":"Advanced Assurance and Attestation"} +{"moduleCode":"GE2101","moduleCredit":0,"title":"Methods and Practices in Geography"} +{"moduleCode":"ACC4711","moduleCredit":0,"title":"Advanced Taxation"} +{"moduleCode":"ACC4715","moduleCredit":0,"title":"Accounting Theory"} +{"moduleCode":"YIR3318G","moduleCredit":0,"title":"Independent Reading and Research"} +{"moduleCode":"ACC1701X","moduleCredit":0,"title":"Accounting for Decision Makers"} +{"moduleCode":"PR5211","moduleCredit":0,"title":"Pharmaceutical Analysis IV"} +{"moduleCode":"FIN3102C","moduleCredit":0,"title":"Investment Analysis and Portfolio Management"} +{"moduleCode":"MS3218","moduleCredit":0,"title":"The Religious Life of the Malays"} +{"moduleCode":"MS3216","moduleCredit":0,"title":"Gender in Malay Societies"} +{"moduleCode":"MS3212","moduleCredit":0,"title":"Text and Ideology in the Malay World"} +{"moduleCode":"MS3213","moduleCredit":0,"title":"Ideology & Ideas on Malay Development"} +{"moduleCode":"MS3210","moduleCredit":0,"title":"Modern Indonesian Literature"} +{"moduleCode":"MS3211","moduleCredit":0,"title":"Political Culture of the Malays"} +{"moduleCode":"FIN3102A","moduleCredit":0,"title":"Investment Analysis and Portfolio Management"} +{"moduleCode":"FIN3102B","moduleCredit":0,"title":"Investment Analysis and Portfolio Management"} +{"moduleCode":"EG2401A","moduleCredit":0,"title":"Engineering Professionalism"} +{"moduleCode":"MA1508E","moduleCredit":0,"title":"Linear Algebra for Engineering"} +{"moduleCode":"LSM3310","moduleCredit":0,"title":"Undergraduate Professional Internship Programme"} +{"moduleCode":"LSM3311","moduleCredit":0,"title":"Undergraduate Professional Internship Programme"} +{"moduleCode":"LSM3312","moduleCredit":0,"title":"Enhanced Undergraduate Professional Internship Programme"} +{"moduleCode":"EC5322","moduleCredit":0,"title":"Industrial Organisation"} +{"moduleCode":"DMR1201GC","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"DMS1401MA","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"YIR3319G","moduleCredit":0,"title":"Independent Reading and Research"} +{"moduleCode":"SLP5113","moduleCredit":0,"title":"Professional Practice 3"} +{"moduleCode":"CM4269","moduleCredit":0,"title":"Sustainable & Green Chemistry"} +{"moduleCode":"PR5224","moduleCredit":0,"title":"Pharmacoepidemiology"} +{"moduleCode":"SLP5112","moduleCredit":0,"title":"Research Project 1"} +{"moduleCode":"PR5225","moduleCredit":0,"title":"Preformulation Science"} +{"moduleCode":"YIR3315G","moduleCredit":0,"title":"Independent Reading and Research"} +{"moduleCode":"AR5955A","moduleCredit":0,"title":"Topics in Research by Design 1"} +{"moduleCode":"AR5955B","moduleCredit":0,"title":"Topics in Research by Design 2"} +{"moduleCode":"AR5955C","moduleCredit":0,"title":"Topics in Research by Design 3"} +{"moduleCode":"SLP5111","moduleCredit":0,"title":"Intervention and Management - Adults 1"} +{"moduleCode":"AR5955D","moduleCredit":0,"title":"Topics in Research by Design 4"} +{"moduleCode":"PH4210","moduleCredit":0,"title":"Topics in Western Philosophy"} +{"moduleCode":"SLP5110","moduleCredit":0,"title":"Intervention and Management - Children 1"} +{"moduleCode":"LX5103","moduleCredit":0,"title":"Environmental Law"} +{"moduleCode":"SLP5117","moduleCredit":0,"title":"Professional Practice Issues"} +{"moduleCode":"YIR3305","moduleCredit":0,"title":"Independent Reading and Research"} +{"moduleCode":"YIR3304","moduleCredit":0,"title":"Independent Reading and Research"} +{"moduleCode":"YIR3303","moduleCredit":0,"title":"Independent Reading and Research"} +{"moduleCode":"YIR3302","moduleCredit":0,"title":"Independent Reading and Research"} +{"moduleCode":"YIR3301","moduleCredit":0,"title":"Independent Reading and Research"} +{"moduleCode":"AR5955E","moduleCredit":0,"title":"Topics in Research by Design 5"} +{"moduleCode":"ESP4901","moduleCredit":0,"title":"Research Project"} +{"moduleCode":"AR5955F","moduleCredit":0,"title":"Topics in Research by Design 6"} +{"moduleCode":"EC3551","moduleCredit":0,"title":"FASS Undergraduate Research Opportunity (UROP)"} +{"moduleCode":"PR5230","moduleCredit":0,"title":"Pharmacoeconomics and Outcomes Research"} +{"moduleCode":"YIR3309","moduleCredit":0,"title":"Independent Reading and Research"} +{"moduleCode":"EC4880","moduleCredit":0,"title":"Topics in Economics"} +{"moduleCode":"YIR3308","moduleCredit":0,"title":"Independent Reading and Research"} +{"moduleCode":"YIR3307","moduleCredit":0,"title":"Independent Reading and Research"} +{"moduleCode":"YIR3306","moduleCredit":0,"title":"Independent Reading and Research"} +{"moduleCode":"GER1000","moduleCredit":0,"title":"Quantitative Reasoning"} +{"moduleCode":"LAH4202","moduleCredit":0,"title":"Hindi 6"} +{"moduleCode":"PR5212","moduleCredit":0,"title":"Advanced Topics in Medicinal Chemistry"} +{"moduleCode":"CM4258","moduleCredit":0,"title":"Advanced Polymer Science"} +{"moduleCode":"LAH4201","moduleCredit":0,"title":"Hindi 5"} +{"moduleCode":"PR5213","moduleCredit":0,"title":"Pharmaceutical Process Validation"} +{"moduleCode":"YIR3316G","moduleCredit":0,"title":"Independent Reading and Research"} +{"moduleCode":"PL1101E","moduleCredit":0,"title":"Introduction to Psychology"} +{"moduleCode":"PR5216","moduleCredit":0,"title":"Advances in Drug Delivery"} +{"moduleCode":"SW4660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"AR5954A","moduleCredit":0,"title":"Topics in Landscape Architecture 1"} +{"moduleCode":"PR5217","moduleCredit":0,"title":"Formulation Science"} +{"moduleCode":"RE4701","moduleCredit":0,"title":"Real Estate Development"} +{"moduleCode":"UWC2101L","moduleCredit":0,"title":"Writing and Critical Thinking: Conditions of Happiness"} +{"moduleCode":"PR5218","moduleCredit":0,"title":"Methodologies in Product Development"} +{"moduleCode":"AR5954C","moduleCredit":0,"title":"Topics in Landscape Architecture"} +{"moduleCode":"ME5614A","moduleCredit":0,"title":"Special Project in Additive Manufacturing"} +{"moduleCode":"UWC2101J","moduleCredit":0,"title":"Writing & Critical Thinking: Sites of Tourism"} +{"moduleCode":"UWC2101G","moduleCredit":0,"title":"Writing & Critical Thinking: Apocalyptic Cultures"} +{"moduleCode":"RE4702","moduleCredit":0,"title":"Professional Practice and Ethics"} +{"moduleCode":"UWC2101F","moduleCredit":0,"title":"Writing and Critical Thinking: Human Trafficking and Labour Migration"} +{"moduleCode":"CM4253","moduleCredit":0,"title":"Materials Chemistry 2"} +{"moduleCode":"CM4254","moduleCredit":0,"title":"Chemistry of Semiconductors"} +{"moduleCode":"UWC2101D","moduleCredit":0,"title":"Writing and Critical Thinking: Narrative in Everyday Life"} +{"moduleCode":"CM4251","moduleCredit":0,"title":"Characterization Techniques in Materials Chemistry"} +{"moduleCode":"CM4252","moduleCredit":0,"title":"Polymer Chemistry 2"} +{"moduleCode":"EC5104R","moduleCredit":0,"title":"Mathematical Economics"} +{"moduleCode":"AH3202","moduleCredit":0,"title":"Time Traveller: The Curatorial in Southeast Asia"} +{"moduleCode":"AH3204","moduleCredit":0,"title":"Methods and Approaches to Art History"} +{"moduleCode":"ES1103","moduleCredit":0,"title":"English for Academic Purposes"} +{"moduleCode":"IE5504","moduleCredit":0,"title":"Systems Modelling And Advanced Simulation"} +{"moduleCode":"UWC2101Z","moduleCredit":0,"title":"Writing & Critical Thinking: Vice, the State & Society"} +{"moduleCode":"AR5954D","moduleCredit":0,"title":"Topics in Landscape Architecture 4"} +{"moduleCode":"CL2281","moduleCredit":0,"title":"Translation and Interpretation"} +{"moduleCode":"CL2280","moduleCredit":0,"title":"Basic Translation"} +{"moduleCode":"SC4401","moduleCredit":0,"title":"Honours Thesis"} +{"moduleCode":"YIR3317G","moduleCredit":0,"title":"Independent Reading and Research"} +{"moduleCode":"PR5220","moduleCredit":0,"title":"Bioprocess Technology"} +{"moduleCode":"AH3201","moduleCredit":0,"title":"A History of Contemporary Art"} +{"moduleCode":"PR5221","moduleCredit":0,"title":"Molecular Targets in Drug Discovery"} +{"moduleCode":"PR5222","moduleCredit":0,"title":"Drug Metabolism"} +{"moduleCode":"UWC2101R","moduleCredit":0,"title":"Writing & Critical Thinking: Multidisciplinary Perspectives on 'Mind'"} +{"moduleCode":"YIR3313G","moduleCredit":0,"title":"Independent Reading and Research"} +{"moduleCode":"AR5953A","moduleCredit":0,"title":"Topics in Design Technology 1"} +{"moduleCode":"LL5060B","moduleCredit":0,"title":"World Trade Law"} +{"moduleCode":"ME5615A","moduleCredit":0,"title":"Design and Pre-Processing for Additive Manufacturing"} +{"moduleCode":"AR5953B","moduleCredit":0,"title":"Topics in Design Technology 2"} +{"moduleCode":"ME5615B","moduleCredit":0,"title":"Post-processing for Additive Manufacturing"} +{"moduleCode":"CM4282","moduleCredit":0,"title":"Energy Resources"} +{"moduleCode":"EN5238","moduleCredit":0,"title":"Twentieth‐Century Literary Production"} +{"moduleCode":"EC5103R","moduleCredit":0,"title":"Econometric Modelling and Applications I"} +{"moduleCode":"MLE5212","moduleCredit":0,"title":"Energy Conversion & Storage"} +{"moduleCode":"MNO4313D","moduleCredit":0,"title":"SILHCM: Corp Entrepreneurship & Busi Model Evaluation"} +{"moduleCode":"MLE5215","moduleCredit":0,"title":"Atomistic Modelling of Molecules and Materials"} +{"moduleCode":"MLE5214","moduleCredit":0,"title":"Advances in Polymeric Materials"} +{"moduleCode":"MLE5211","moduleCredit":0,"title":"Nanomaterials"} +{"moduleCode":"MLE5210","moduleCredit":0,"title":"Modelling and Simulation of Materials"} +{"moduleCode":"YIR3320","moduleCredit":0,"title":"Independent Reading and Research"} +{"moduleCode":"AR5953C","moduleCredit":0,"title":"Topics in Design Technology 3"} +{"moduleCode":"AR5953D","moduleCredit":0,"title":"Topics in Design Technology 4"} +{"moduleCode":"AR5953E","moduleCredit":0,"title":"Topics in Design Technology 5"} +{"moduleCode":"CL2291","moduleCredit":0,"title":"Chinese Anthropolinguistics (taught in English)"} +{"moduleCode":"PR5250","moduleCredit":0,"title":"Elective Clerkship I"} +{"moduleCode":"AR5953F","moduleCredit":0,"title":"Topics in Design Technology 6"} +{"moduleCode":"DMY1401HL","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"PR5251","moduleCredit":0,"title":"Elective Clerkship II"} +{"moduleCode":"AR5953G","moduleCredit":0,"title":"Topics in Design Technology 7"} +{"moduleCode":"PR5252","moduleCredit":0,"title":"Elective Clerkship III"} +{"moduleCode":"USE2325","moduleCredit":0,"title":"Democracy and Inequality"} +{"moduleCode":"AR5953H","moduleCredit":0,"title":"Topics in Design Technology 8"} +{"moduleCode":"USE2324","moduleCredit":0,"title":"Gender and Ecology in Asia"} +{"moduleCode":"AR5953I","moduleCredit":0,"title":"Topics in Design Technology 9"} +{"moduleCode":"USE2323","moduleCredit":0,"title":"Culture and Technology"} +{"moduleCode":"DMS1401PC","moduleCredit":0,"title":"Design Your Own Module"} +{"moduleCode":"LC5010A","moduleCredit":0,"title":"Legal Systems of Asia (A)"} +{"moduleCode":"MNO4313J","moduleCredit":0,"title":"SILHCM: Talent Development and Performing with Impact"} +{"moduleCode":"USE2322","moduleCredit":0,"title":"Situating Singapore in the Wider World"} +{"moduleCode":"PH4240","moduleCredit":0,"title":"Issues in Metaphysics"} +{"moduleCode":"PR5234","moduleCredit":0,"title":"Pharmacogenomics and Pharmacogenetics"} +{"moduleCode":"PH4241","moduleCredit":0,"title":"Issues in Philosophical Logic"} +{"moduleCode":"YIR3314G","moduleCredit":0,"title":"Independent Reading and Research"} +{"moduleCode":"LL6089V","moduleCredit":0,"title":"Chinese Corporate & Securities Law"} +{"moduleCode":"MA5203","moduleCredit":0,"title":"Graduate Algebra I"} +{"moduleCode":"PR5239","moduleCredit":0,"title":"Clinical Pharmacy Research Project"} +{"moduleCode":"MA5206","moduleCredit":0,"title":"Graduate Analysis II"} +{"moduleCode":"PH4242","moduleCredit":0,"title":"Issues in Philosophy of Language"} +{"moduleCode":"AR5952A","moduleCredit":0,"title":"Topics in Urbanism 1"} +{"moduleCode":"MA5205","moduleCredit":0,"title":"Graduate Analysis I"} +{"moduleCode":"PH4243","moduleCredit":0,"title":"Issues in Aesthetics"} +{"moduleCode":"TCN4119","moduleCredit":0,"title":"B.Tech. Dissertation"} +{"moduleCode":"CM4271","moduleCredit":0,"title":"Medicinal Chemistry"} +{"moduleCode":"EU4660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"LLD5002V","moduleCredit":0,"title":"Admiralty Law & Practice"} +{"moduleCode":"MA5208","moduleCredit":0,"title":"Algebraic Geometry"} +{"moduleCode":"SLP5109","moduleCredit":0,"title":"Professional Practice 2"} +{"moduleCode":"CS2113","moduleCredit":0,"title":"Software Engineering & Object-Oriented Programming"} +{"moduleCode":"SLP5106","moduleCredit":0,"title":"Impaired Functioning - Adults 1"} +{"moduleCode":"SLP5105","moduleCredit":0,"title":"Impaired Functioning - Children 1"} +{"moduleCode":"TR3202","moduleCredit":0,"title":"Start-up Internship Programme"} +{"moduleCode":"SLP5108","moduleCredit":0,"title":"Impaired Functioning - Adults 2"} +{"moduleCode":"CM4274","moduleCredit":0,"title":"The Art and Methodology in Total Synthesis"} +{"moduleCode":"SLP5107","moduleCredit":0,"title":"Impaired Functioning - Children 2"} +{"moduleCode":"SN5660","moduleCredit":0,"title":"Independent Study"} +{"moduleCode":"YIR3316","moduleCredit":0,"title":"Independent Reading and Research"} +{"moduleCode":"AR5952K","moduleCredit":0,"title":"Topics in Urbanism 11"} +{"moduleCode":"YIR3315","moduleCredit":0,"title":"Independent Reading and Research"} +{"moduleCode":"AR5952L","moduleCredit":0,"title":"Topics in Urbanism 12"} +{"moduleCode":"EC5102R","moduleCredit":0,"title":"Macroeconomic Theory"} +{"moduleCode":"YIR3314","moduleCredit":0,"title":"Independent Reading and Research"} +{"moduleCode":"AR5952M","moduleCredit":0,"title":"Topics in Urbanism 13"} +{"moduleCode":"YIR3313","moduleCredit":0,"title":"Independent Reading and Research"} +{"moduleCode":"YIR3312","moduleCredit":0,"title":"Independent Reading and Research"} +{"moduleCode":"YIR3311","moduleCredit":0,"title":"Independent Reading and Research"} +{"moduleCode":"YIR3310","moduleCredit":0,"title":"Independent Reading and Research"} +{"moduleCode":"LAG2201","moduleCredit":0,"title":"German 2"} +{"moduleCode":"AR5952B","moduleCredit":0,"title":"Topics in Urbanism 2"} +{"moduleCode":"AR5952C","moduleCredit":0,"title":"Topics in Urbanism 3"} +{"moduleCode":"USE2317","moduleCredit":0,"title":"Multiculturalism in Singapore and Its Contested Meanings"} +{"moduleCode":"AR5952D","moduleCredit":0,"title":"Topics in Urbanism 4"} +{"moduleCode":"CN6251","moduleCredit":0,"title":"Membrane Science & Technology"} +{"moduleCode":"AR5952E","moduleCredit":0,"title":"Topics in Urbanism 5"} +{"moduleCode":"AR5952F","moduleCredit":0,"title":"Topics in Urbanism 6"} +{"moduleCode":"AR5952G","moduleCredit":0,"title":"Topics in Urbanism 7"} +{"moduleCode":"TCN4124","moduleCredit":0,"title":"Final Year Design Project"} +{"moduleCode":"YIR3319","moduleCredit":0,"title":"Independent Reading and Research"} +{"moduleCode":"AR5952H","moduleCredit":0,"title":"Topics in Urbanism 8"} +{"moduleCode":"USE2312","moduleCredit":0,"title":"Nationalism and the Arts"} +{"moduleCode":"YIR3318","moduleCredit":0,"title":"Independent Reading and Research"} +{"moduleCode":"AR5952I","moduleCredit":0,"title":"Topics in Urbanism 9"} +{"moduleCode":"TCN4122","moduleCredit":0,"title":"Process Synthesis and Simulation"} +{"moduleCode":"YIR3317","moduleCredit":0,"title":"Independent Reading and Research"} diff --git a/src/test/java/seedu/duke/DukeTest.java b/src/test/java/seedu/ravi/RaviTest.java similarity index 82% rename from src/test/java/seedu/duke/DukeTest.java rename to src/test/java/seedu/ravi/RaviTest.java index 2dda5fd651..aaaaf7a4ce 100644 --- a/src/test/java/seedu/duke/DukeTest.java +++ b/src/test/java/seedu/ravi/RaviTest.java @@ -1,10 +1,10 @@ -package seedu.duke; - -import static org.junit.jupiter.api.Assertions.assertTrue; +package seedu.ravi; import org.junit.jupiter.api.Test; -class DukeTest { +import static org.junit.jupiter.api.Assertions.assertTrue; + +class RaviTest { @Test public void sampleTest() { assertTrue(true); diff --git a/src/test/java/seedu/ravi/command/add/AddCommandTest.java b/src/test/java/seedu/ravi/command/add/AddCommandTest.java new file mode 100644 index 0000000000..d85f9deeb6 --- /dev/null +++ b/src/test/java/seedu/ravi/command/add/AddCommandTest.java @@ -0,0 +1,55 @@ +//@@author aseanseen + +package seedu.ravi.command.add; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import seedu.ravi.command.CommandResult; +import seedu.ravi.data.storage.InputOutputManager; +import seedu.ravi.exception.NusModsNotLoadedException; +import seedu.ravi.util.ExceptionMessage; + +import java.time.format.DateTimeParseException; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class AddCommandTest { + static final String MOD_CODE_1 = "CS2113T"; + static final String TASK = "test task"; + static final String BAD_DEADLINE = "bad_deadline"; + static final String EMPTY_DEADLINE = ""; + static final String SPACES_DEADLINE = " "; + + @BeforeAll + static void setup() throws NusModsNotLoadedException { + InputOutputManager.tryLoadNusMods(); + } + + @Test + void addModule_duplicateModuleMessage_isShown() { + AddCommand addMod = new AddModuleCommand(MOD_CODE_1); + AddCommand addDupMod = new AddModuleCommand(MOD_CODE_1); + addMod.execute(); + CommandResult commandResult = addDupMod.execute(); + assertEquals(ExceptionMessage.MESSAGE_DUPLICATE_MODULE, commandResult.feedbackToUser); + } + + @Test + void addTask_badDeadline_DateTimeParseException_isThrown() throws DateTimeParseException { + assertThrows(DateTimeParseException.class, + () -> new AddTaskCommand(TASK, BAD_DEADLINE)); + } + + @Test + void addTask_emptyDeadline_DateTimeParseException_isThrown() throws DateTimeParseException { + assertThrows(DateTimeParseException.class, + () -> new AddTaskCommand(TASK, EMPTY_DEADLINE)); + } + + @Test + void addTask_blankDeadline_DateTimeParseException_isThrown() throws DateTimeParseException { + assertThrows(DateTimeParseException.class, + () -> new AddTaskCommand(TASK, SPACES_DEADLINE)); + } +} diff --git a/src/test/java/seedu/ravi/command/delete/DeleteCommandTest.java b/src/test/java/seedu/ravi/command/delete/DeleteCommandTest.java new file mode 100644 index 0000000000..f1ba925556 --- /dev/null +++ b/src/test/java/seedu/ravi/command/delete/DeleteCommandTest.java @@ -0,0 +1,51 @@ +//@@author aseanseen + +package seedu.ravi.command.delete; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import seedu.ravi.command.CommandResult; +import seedu.ravi.command.add.AddCommand; +import seedu.ravi.command.add.AddModuleCommand; +import seedu.ravi.command.add.AddTaskCommand; +import seedu.ravi.data.ModuleManager; +import seedu.ravi.data.TaskManager; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static seedu.ravi.util.ExceptionMessage.MESSAGE_MODULE_NOT_FOUND; +import static seedu.ravi.util.ExceptionMessage.MESSAGE_TASK_NOT_FOUND; + +public class DeleteCommandTest { + static final String MOD_CODE = "CS2113T"; + static final String MOD_CODE_MISSING = "CS2040"; + static final String TASK = "test task"; + static final int TASK_ID_MISSING = 10; + + @BeforeEach + void setupModObjects() { + ModuleManager.clearModules(); + AddCommand addModule = new AddModuleCommand(MOD_CODE); + addModule.execute(); + } + + @BeforeEach + void setupTaskObjects() { + TaskManager.clear(); + AddCommand addModule = new AddTaskCommand(TASK); + addModule.execute(); + } + + @Test + void deleteMissingModuleMessage_isShown() { + DeleteCommand deleteMissingModuleTest = new DeleteModuleCommand(MOD_CODE_MISSING); + CommandResult commandResult = deleteMissingModuleTest.execute(); + assertEquals(MESSAGE_MODULE_NOT_FOUND, commandResult.feedbackToUser); + } + + @Test + void deleteMissingTaskMessage_isShown() { + DeleteCommand deleteMissingTaskTest = new DeleteTaskCommand(TASK_ID_MISSING); + CommandResult commandResult = deleteMissingTaskTest.execute(); + assertEquals(MESSAGE_TASK_NOT_FOUND, commandResult.feedbackToUser); + } +} diff --git a/src/test/java/seedu/ravi/command/done/DoneCommandTest.java b/src/test/java/seedu/ravi/command/done/DoneCommandTest.java new file mode 100644 index 0000000000..9c87287c73 --- /dev/null +++ b/src/test/java/seedu/ravi/command/done/DoneCommandTest.java @@ -0,0 +1,38 @@ +package seedu.ravi.command.done; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import seedu.ravi.command.CommandResult; +import seedu.ravi.data.Task; +import seedu.ravi.data.TaskManager; +import seedu.ravi.util.ExceptionMessage; +import seedu.ravi.util.Message; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +//@@author amalinasani +public class DoneCommandTest { + + @BeforeEach + void setupTaskList() { + TaskManager.clear(); + Task newTask = new Task("read a book"); + TaskManager.add(newTask); + } + + @Test + void doneTask_validIndex_success() { + DoneCommand doneValidTask = new DoneCommand(0); + CommandResult commandResult = doneValidTask.execute(); + Task editedTask = new Task("read a book", true); + assertEquals(String.format(Message.MESSAGE_DONE_TASK_SUCCESS, editedTask.toString()), + commandResult.feedbackToUser); + } + + @Test + void doneTask_invalidIndex_exceptionThrown() { + DoneCommand doneInvalidTask = new DoneCommand(2); + CommandResult commandResult = doneInvalidTask.execute(); + assertEquals(ExceptionMessage.MESSAGE_TASK_NOT_FOUND, commandResult.feedbackToUser); + } +} diff --git a/src/test/java/seedu/ravi/command/edit/EditModuleCommandTest.java b/src/test/java/seedu/ravi/command/edit/EditModuleCommandTest.java new file mode 100644 index 0000000000..1708c25bd4 --- /dev/null +++ b/src/test/java/seedu/ravi/command/edit/EditModuleCommandTest.java @@ -0,0 +1,24 @@ +package seedu.ravi.command.edit; + +import org.junit.jupiter.api.Test; +import seedu.ravi.Executor; +import seedu.ravi.command.CommandResult; +import seedu.ravi.data.ModuleManager; +import seedu.ravi.data.storage.InputOutputManager; +import seedu.ravi.exception.DuplicateModuleException; +import seedu.ravi.exception.ModuleNotFoundException; +import seedu.ravi.exception.ModuleNotProvidedException; +import seedu.ravi.exception.NusModsNotLoadedException; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class EditModuleCommandTest { + @Test + void execute() throws + NusModsNotLoadedException, DuplicateModuleException, ModuleNotProvidedException, ModuleNotFoundException { + InputOutputManager.tryLoadNusMods(); + ModuleManager.add("cs1231"); + CommandResult result1 = Executor.executeCommand("edit -m cs1231 CS1010"); + ModuleManager.getModule("CS1010"); // should not throw exception + } +} \ No newline at end of file diff --git a/src/test/java/seedu/ravi/command/edit/EditTaskCommandTest.java b/src/test/java/seedu/ravi/command/edit/EditTaskCommandTest.java new file mode 100644 index 0000000000..091f1cdc92 --- /dev/null +++ b/src/test/java/seedu/ravi/command/edit/EditTaskCommandTest.java @@ -0,0 +1,64 @@ +package seedu.ravi.command.edit; + +import org.junit.jupiter.api.Test; +import seedu.ravi.Executor; +import seedu.ravi.command.CommandResult; +import seedu.ravi.command.IncorrectCommand; +import seedu.ravi.data.Task; +import seedu.ravi.data.TaskManager; + +import java.time.LocalDateTime; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static seedu.ravi.util.ExceptionMessage.MESSAGE_ADD_TASK_DATE_TIME_UNKNOWN; +import static seedu.ravi.util.Message.MESSAGE_EDIT_TASK_SUCCESS; +import static seedu.ravi.util.ExceptionMessage.MESSAGE_NO_EDIT_TASK; + +public class EditTaskCommandTest { + + @Test + void execute() { + TaskManager.clear(); + Task newTask = new Task("read a book"); + TaskManager.add(newTask); + String newTaskString = newTask.toString(); + + Task editedTask = new Task("return a book"); + //base case + CommandResult result1 = Executor.executeCommand("edit -t 1 return a book"); + assertEquals(String.format(MESSAGE_EDIT_TASK_SUCCESS, newTaskString, editedTask.toString()), + result1.feedbackToUser); + + //invalid parameters + CommandResult result2 = Executor.executeCommand("edit -t 0 return a book"); + assertEquals(MESSAGE_NO_EDIT_TASK, result2.feedbackToUser); + CommandResult result3 = Executor.executeCommand("edit -t 2 return a book"); + assertEquals(MESSAGE_NO_EDIT_TASK, result3.feedbackToUser); + } + + @Test + void execute_withDeadline() { + TaskManager.clear(); + Task newTask = new Task("read a book"); + TaskManager.add(newTask); + String newTaskString = newTask.toString(); + + Task editedTask = new Task("return a book", + LocalDateTime.of(2020, 12, 30, 12, 00)); + + //base case + CommandResult result1 = Executor.executeCommand("edit -t 1 return a book -by 30-12-2020 1200"); + assertEquals(String.format(MESSAGE_EDIT_TASK_SUCCESS, newTaskString, editedTask.toString()), + result1.feedbackToUser); + + //invalid parameters + CommandResult result2 = Executor.executeCommand("edit -t 0 return a book"); + assertEquals(MESSAGE_NO_EDIT_TASK, result2.feedbackToUser); + CommandResult result3 = Executor.executeCommand("edit -t 2 return a book"); + assertEquals(MESSAGE_NO_EDIT_TASK, result3.feedbackToUser); + CommandResult result4 = Executor.executeCommand("edit -t 1 return a book -by 3131313"); + + String dateErrorResult = new IncorrectCommand(MESSAGE_ADD_TASK_DATE_TIME_UNKNOWN).execute().feedbackToUser; + assertEquals(dateErrorResult, result4.feedbackToUser); + } +} \ No newline at end of file diff --git a/src/test/java/seedu/ravi/command/grade/GradeCommandTest.java b/src/test/java/seedu/ravi/command/grade/GradeCommandTest.java new file mode 100644 index 0000000000..e746840b4e --- /dev/null +++ b/src/test/java/seedu/ravi/command/grade/GradeCommandTest.java @@ -0,0 +1,63 @@ +//@@author tobiasceg + +package seedu.ravi.command.grade; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import seedu.ravi.command.CommandResult; +import seedu.ravi.command.IncorrectCommand; +import seedu.ravi.command.add.AddCommand; +import seedu.ravi.command.add.AddModuleCommand; +import seedu.ravi.data.Module; +import seedu.ravi.data.ModuleManager; +import seedu.ravi.data.storage.InputOutputManager; +import seedu.ravi.exception.InvalidModuleCreditException; +import seedu.ravi.exception.ModuleNotFoundException; +import seedu.ravi.exception.NusModsNotLoadedException; +import seedu.ravi.util.ExceptionMessage; +import seedu.ravi.util.Message; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class GradeCommandTest { + static final String MODULE_CODE = "CG2271"; + static final String NON_EXISTENT_MODULE_CODE = "CS2101"; + + @BeforeAll + static void setup() throws NusModsNotLoadedException { + InputOutputManager.tryLoadNusMods(); + } + + @BeforeEach + void setupModObjects() { + ModuleManager.clearModules(); + AddCommand addModule = new AddModuleCommand(MODULE_CODE); + addModule.execute(); + } + + @Test + void gradeCommand_MessageGradeSuccessful_isShown() throws InvalidModuleCreditException, ModuleNotFoundException { + GradeCommand gradeCommand = new GradeCommand(MODULE_CODE, 4, "A+"); + Module moduleGraded = ModuleManager.getModule(MODULE_CODE); + CommandResult commandResult = gradeCommand.execute(); + assertEquals(String.format( + Message.MESSAGE_GRADE_MODULE_SUCCESS, moduleGraded), commandResult.feedbackToUser); + } + + @Test + void gradeCommand_MessageModuleNotFound_isShown() throws InvalidModuleCreditException { + GradeCommand gradeCommand = new GradeCommand(NON_EXISTENT_MODULE_CODE, 4, "A+"); + CommandResult commandResult = gradeCommand.execute(); + CommandResult expectedResult = new IncorrectCommand(ExceptionMessage.MESSAGE_MODULE_NOT_FOUND).execute(); + assertEquals(expectedResult.feedbackToUser, commandResult.feedbackToUser); + } + + @Test + void gradeCommand_MessageInvalidGrade_isShown() throws InvalidModuleCreditException { + GradeCommand gradeCommand = new GradeCommand(MODULE_CODE, 4, "SU"); + CommandResult commandResult = gradeCommand.execute(); + CommandResult expectedResult = new IncorrectCommand(ExceptionMessage.MESSAGE_INVALID_GRADE).execute(); + assertEquals(expectedResult.feedbackToUser, commandResult.feedbackToUser); + } +} diff --git a/src/test/java/seedu/ravi/command/help/HelpCommandTest.java b/src/test/java/seedu/ravi/command/help/HelpCommandTest.java new file mode 100644 index 0000000000..1025931ac2 --- /dev/null +++ b/src/test/java/seedu/ravi/command/help/HelpCommandTest.java @@ -0,0 +1,19 @@ +package seedu.ravi.command.help; + +import org.junit.jupiter.api.Test; +import seedu.ravi.command.CommandResult; +import seedu.ravi.util.Message; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +//@@author amalinasani +public class HelpCommandTest { + static final String HELP_MESSAGE = Message.MESSAGE_GENERAL_HELP; + + @Test + void testHelpCommand() { + HelpCommand helpCommand = new HelpCommand(null); + CommandResult commandResult = helpCommand.execute(); + assertEquals(HELP_MESSAGE, commandResult.feedbackToUser); + } +} diff --git a/src/test/java/seedu/ravi/command/list/ListCommandTest.java b/src/test/java/seedu/ravi/command/list/ListCommandTest.java new file mode 100644 index 0000000000..7fe82845e7 --- /dev/null +++ b/src/test/java/seedu/ravi/command/list/ListCommandTest.java @@ -0,0 +1,47 @@ +package seedu.ravi.command.list; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import seedu.ravi.command.CommandResult; +import seedu.ravi.command.add.AddCommand; +import seedu.ravi.command.add.AddTaskCommand; +import seedu.ravi.data.ModuleManager; +import seedu.ravi.data.TaskManager; +import seedu.ravi.parser.Parser; +import seedu.ravi.util.ExceptionMessage; +import seedu.ravi.util.Message; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +//@@author amalinasani +public class ListCommandTest { + + @BeforeEach + void setupLists() { + TaskManager.clear(); + ModuleManager.clearModules(); + } + + @Test + void listCommand_MessageListEmpty_isShown() { + ListCommand taskListCommand = new ListCommand(Parser.TypeOfEntries.TASK); + CommandResult commandResult1 = taskListCommand.execute(); + assertEquals(ExceptionMessage.MESSAGE_LIST_EMPTY, commandResult1.feedbackToUser); + + ListCommand moduleListCommand = new ListCommand(Parser.TypeOfEntries.MODULE); + CommandResult commandResult2 = moduleListCommand.execute(); + assertEquals(ExceptionMessage.MESSAGE_LIST_EMPTY, commandResult2.feedbackToUser); + } + + @Test + void listCommand_MessageListPrinted_isShown() { + AddCommand addTask = new AddTaskCommand("read a book"); + addTask.execute(); + + ListCommand taskListCommand = new ListCommand(Parser.TypeOfEntries.TASK); + CommandResult commandResult1 = taskListCommand.execute(); + String expectedOutput1 = Message.MESSAGE_LIST_PRINTED + + TaskManager.list(); + assertEquals(expectedOutput1, commandResult1.feedbackToUser); + } +} diff --git a/src/test/java/seedu/ravi/command/misc/UndoCommandTest.java b/src/test/java/seedu/ravi/command/misc/UndoCommandTest.java new file mode 100644 index 0000000000..7df1700833 --- /dev/null +++ b/src/test/java/seedu/ravi/command/misc/UndoCommandTest.java @@ -0,0 +1,76 @@ +package seedu.ravi.command.misc; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import seedu.ravi.Executor; +import seedu.ravi.command.CommandResult; +import seedu.ravi.data.ModuleManager; +import seedu.ravi.data.StateManager; +import seedu.ravi.data.TaskManager; +import seedu.ravi.data.TimeTableManager; +import seedu.ravi.data.storage.InputOutputManager; +import seedu.ravi.exception.NusModsNotLoadedException; +import seedu.ravi.exception.TimeTableInitialiseException; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class UndoCommandTest { + + @BeforeEach + void setupModObjects() throws NusModsNotLoadedException, TimeTableInitialiseException { + ModuleManager.clearModules(); + TaskManager.clear(); + TimeTableManager.clearTimeTable(); + TimeTableManager.initialise(1); + InputOutputManager.tryLoadNusMods(); + StateManager.initialise(); + } + + @Test + void undo_addModule_Success() { + CommandResult result1 = Executor.executeCommand("add -m cs3235"); + assertEquals(1, ModuleManager.getModCodeList().length); + CommandResult result2 = Executor.executeCommand("add -m cs3230"); + assertEquals(2, ModuleManager.getModCodeList().length); + new UndoCommand().execute(); + assertEquals(1, ModuleManager.getModCodeList().length); + CommandResult result3 = Executor.executeCommand("add -m cs1010"); + assertEquals(2, ModuleManager.getModCodeList().length); + } + + @Test + void undo_deleteModule_Success() { + CommandResult result1 = Executor.executeCommand("add -m cs3235"); + assertEquals(1, ModuleManager.getModCodeList().length); + CommandResult result2 = Executor.executeCommand("add -m cs3230"); + assertEquals(2, ModuleManager.getModCodeList().length); + new UndoCommand().execute(); + assertEquals(1, ModuleManager.getModCodeList().length); + CommandResult result3 = Executor.executeCommand("add -m cs1010"); + assertEquals(2, ModuleManager.getModCodeList().length); + //CommandResult result4 = Executor.executeCommand("del -m cs1010"); + //assertEquals(1, ModuleManager.getModCodeList().length); + //new UndoCommand().execute(); + //assertEquals(2, ModuleManager.getModCodeList().length); + } + + @Test + void undo_addLesson_Success() { + CommandResult result1 = Executor.executeCommand("add -m cs3235"); + CommandResult result2 = Executor.executeCommand("timetable -add cs3235 MONDAY 1200 1400 LECTURE 0"); + assertEquals(1, TimeTableManager.getTimetableLessonCount()); + new UndoCommand().execute(); + assertEquals(0, TimeTableManager.getTimetableLessonCount()); + } + + @Test + void undo_delLesson_Success() { + CommandResult result1 = Executor.executeCommand("add -m cs3235"); + CommandResult result2 = Executor.executeCommand("timetable -add cs3235 MONDAY 1200 1400 LECTURE 0"); + assertEquals(1, TimeTableManager.getTimetableLessonCount()); + CommandResult result3 = Executor.executeCommand("timetable -del MONDAY 1"); + assertEquals(0, TimeTableManager.getTimetableLessonCount()); + new UndoCommand().execute(); + assertEquals(1, TimeTableManager.getTimetableLessonCount()); + } +} \ No newline at end of file diff --git a/src/test/java/seedu/ravi/command/summary/SummaryCommandTest.java b/src/test/java/seedu/ravi/command/summary/SummaryCommandTest.java new file mode 100644 index 0000000000..f1127ea8bd --- /dev/null +++ b/src/test/java/seedu/ravi/command/summary/SummaryCommandTest.java @@ -0,0 +1,20 @@ +package seedu.ravi.command.summary; + +import org.junit.jupiter.api.Test; +import seedu.ravi.command.CommandResult; +import seedu.ravi.data.TaskManager; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static seedu.ravi.util.Message.MESSAGE_SUMMARY_PRINTED; + +//@@author amalinasani +public class SummaryCommandTest { + @Test + void listCommand_Summary_isShown() { + TaskManager.clear(); + SummaryCommand summaryCommand = new SummaryCommand(); + CommandResult commandResult = summaryCommand.execute(); + String expectedOutput = MESSAGE_SUMMARY_PRINTED + TaskManager.getSummary(); + assertEquals(expectedOutput, commandResult.feedbackToUser); + } +} diff --git a/src/test/java/seedu/ravi/command/timetable/TimeTableCommandTest.java b/src/test/java/seedu/ravi/command/timetable/TimeTableCommandTest.java new file mode 100644 index 0000000000..be1a3536cf --- /dev/null +++ b/src/test/java/seedu/ravi/command/timetable/TimeTableCommandTest.java @@ -0,0 +1,99 @@ +//@@author aseanseen + +package seedu.ravi.command.timetable; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import seedu.ravi.command.Command; +import seedu.ravi.command.CommandResult; +import seedu.ravi.command.IncorrectCommand; +import seedu.ravi.data.Lesson; +import seedu.ravi.data.LessonType; +import seedu.ravi.data.ModuleManager; +import seedu.ravi.data.TimeTableManager; +import seedu.ravi.data.storage.InputOutputManager; +import seedu.ravi.exception.DuplicateModuleException; +import seedu.ravi.exception.InvalidMatchException; +import seedu.ravi.exception.LessonInvalidTimeException; +import seedu.ravi.exception.ModuleNotProvidedException; +import seedu.ravi.exception.NusModsNotLoadedException; +import seedu.ravi.exception.TimeTableInitialiseException; +import seedu.ravi.parser.TimeTableCommandParser; +import seedu.ravi.util.ExceptionMessage; + +import java.time.DayOfWeek; +import java.time.LocalTime; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class TimeTableCommandTest { + static final int BAD_REPEAT_FREQ = 4; + static final int REPEAT_FREQ_WEEKLY = 1; + static final int BAD_LESSON_INDEX = 5; + + static Lesson LESSON_1; + static Lesson LESSON_1_OVERLAP; + static Lesson LESSON_2; + + static final String MOD_CODE_1 = "CS2113T"; + static final String MOD_CODE_2 = "CG2271"; + static final String MOD_CODE_3 = "MA1511"; + static final String BAD_VIEW_FORMAT = "-no"; + + static final DayOfWeek DAY_OF_WEEK = DayOfWeek.MONDAY; + static final LocalTime LESSON_1_START_TIME = LocalTime.of(14, 0); + static final LocalTime LESSON_1_END_TIME = LocalTime.of(16, 0); + static final LocalTime OTHER_LESSON_START = LocalTime.of(9, 0); + static final LocalTime OTHER_LESSON_END = LocalTime.of(10, 0); + static final LessonType LESSON_TYPE = LessonType.LECTURE; + + @BeforeAll + static void setupUserMods() throws DuplicateModuleException, ModuleNotProvidedException, NusModsNotLoadedException { + InputOutputManager.tryLoadNusMods(); + ModuleManager.clearModules(); + ModuleManager.add(MOD_CODE_1); + ModuleManager.add(MOD_CODE_2); + ModuleManager.add(MOD_CODE_3); + } + + @BeforeEach + void setupTimeTable_andLessons() throws LessonInvalidTimeException, TimeTableInitialiseException { + LESSON_1 = new Lesson(MOD_CODE_1, LESSON_TYPE, DAY_OF_WEEK, LESSON_1_START_TIME, LESSON_1_END_TIME); + LESSON_2 = new Lesson(MOD_CODE_2, LESSON_TYPE, DAY_OF_WEEK, OTHER_LESSON_START, OTHER_LESSON_END); + TimeTableManager.clearTimeTable(); + TimeTableManager.initialise(1); + TimeTableAddCommand timeTableAddCommand = new TimeTableAddCommand(LESSON_1, REPEAT_FREQ_WEEKLY); + timeTableAddCommand.execute(); + } + + @Test + void addLesson_badRepeatFreq_RepeatFrequencyMessage_isShown() { + TimeTableAddCommand timeTableAddCommand = new TimeTableAddCommand(LESSON_2, BAD_REPEAT_FREQ); + CommandResult commandResult = timeTableAddCommand.execute(); + assertEquals(ExceptionMessage.MESSAGE_REPEAT_FREQUENCY_UNKNOWN, commandResult.feedbackToUser); + } + + @Test + void addLesson_overlapLessonTime_LessonOverlapMessage_isShown() throws LessonInvalidTimeException { + LESSON_1_OVERLAP = new Lesson(MOD_CODE_2, LESSON_TYPE, DAY_OF_WEEK, LESSON_1_START_TIME, LESSON_1_END_TIME); + TimeTableAddCommand timeTableAddCommand = new TimeTableAddCommand(LESSON_1_OVERLAP, REPEAT_FREQ_WEEKLY); + CommandResult commandResult = timeTableAddCommand.execute(); + assertEquals(String.format(ExceptionMessage.MESSAGE_LESSON_OVERLAP, LESSON_1.toString()), + commandResult.feedbackToUser); + } + + @Test + void deleteLesson_lessonNotFound_LessonNotFoundMessage_isShown() { + TimeTableDeleteCommand timeTableDeleteCommand = new TimeTableDeleteCommand(DAY_OF_WEEK, BAD_LESSON_INDEX); + CommandResult commandResult = timeTableDeleteCommand.execute(); + assertEquals(ExceptionMessage.MESSAGE_LESSON_NOT_FOUND, commandResult.feedbackToUser); + } + + @Test + void viewTimeTable_badViewFormat_IncorrectCommand_isReturned() throws InvalidMatchException { + Command timeTableviewCommand = TimeTableCommandParser.parseTimeTableCommand(BAD_VIEW_FORMAT); + assertTrue(timeTableviewCommand instanceof IncorrectCommand); + } +} diff --git a/src/test/java/seedu/ravi/data/LessonTest.java b/src/test/java/seedu/ravi/data/LessonTest.java new file mode 100644 index 0000000000..ded556cc1a --- /dev/null +++ b/src/test/java/seedu/ravi/data/LessonTest.java @@ -0,0 +1,83 @@ +package seedu.ravi.data; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import seedu.ravi.exception.LessonInvalidTimeException; +import seedu.ravi.exception.LessonNotFoundException; + +import java.time.DayOfWeek; +import java.time.LocalTime; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class LessonTest { + static LessonManager manager = new LessonManager(); + static Lesson lesson1; + static Lesson lesson2; + static final String MOD_CODE_1 = "CS2113T"; + static final String MOD_CODE_2 = "CG2271"; + static final String MOD_CODE_3 = "MA1511"; + static final LocalTime time_12 = LocalTime.of(12, 0); + static final LocalTime time_13 = LocalTime.of(13, 0); + static final LocalTime time_14 = LocalTime.of(14, 0); + static final LocalTime time_15 = LocalTime.of(15, 0); + + @BeforeEach + void setupLessonObjects() throws LessonInvalidTimeException { + lesson1 = new Lesson(MOD_CODE_1, LessonType.LECTURE, DayOfWeek.MONDAY, time_12, time_13); + lesson2 = new Lesson(MOD_CODE_2, LessonType.LECTURE, DayOfWeek.MONDAY, time_14, time_15); + manager.clearAllLessons(); + manager.addLesson(lesson1); + manager.addLesson(lesson2); + } + + @Test + void getOverlapException_addLesson() throws LessonInvalidTimeException, LessonNotFoundException { + Lesson testLesson1 = new Lesson(MOD_CODE_3, LessonType.LECTURE, DayOfWeek.MONDAY, time_12, time_13); + assertThrows(LessonInvalidTimeException.class, () -> manager.addLesson(testLesson1)); + + Lesson testLesson2 = new Lesson(MOD_CODE_3, LessonType.LECTURE, DayOfWeek.MONDAY, time_12, time_14); + assertThrows(LessonInvalidTimeException.class, () -> manager.addLesson(testLesson2)); + + Lesson testLesson3 = new Lesson(MOD_CODE_3, LessonType.LECTURE, DayOfWeek.MONDAY, time_13, time_15); + assertThrows(LessonInvalidTimeException.class, () -> manager.addLesson(testLesson3)); + } + + @Test + void verify_LessonNotFoundException_isThrown() { + assertThrows(LessonNotFoundException.class, () -> manager.removeLesson(DayOfWeek.TUESDAY, 0)); + assertThrows(LessonNotFoundException.class, () -> manager.removeLesson(DayOfWeek.MONDAY, -1)); + assertThrows(LessonNotFoundException.class, () -> manager.removeLesson(DayOfWeek.MONDAY, 2)); + } + + @Test + void verify_addLesson_sortsLessons() throws LessonNotFoundException, LessonInvalidTimeException { + assertEquals(MOD_CODE_1, manager.getDayLessonList(DayOfWeek.MONDAY).get(0).getModuleCode()); + assertEquals(MOD_CODE_2, manager.getDayLessonList(DayOfWeek.MONDAY).get(1).getModuleCode()); + + String testCode = "Test Code"; + Lesson testLesson = new Lesson(testCode, LessonType.LECTURE, DayOfWeek.MONDAY, time_13, time_14); + manager.addLesson(testLesson); + assertEquals(MOD_CODE_1, manager.getDayLessonList(DayOfWeek.MONDAY).get(0).getModuleCode()); + assertEquals(testCode, manager.getDayLessonList(DayOfWeek.MONDAY).get(1).getModuleCode()); + assertEquals(MOD_CODE_2, manager.getDayLessonList(DayOfWeek.MONDAY).get(2).getModuleCode()); + } + + @Test + void verifyLessonCount_afterDeletingLessons() throws LessonNotFoundException { + assertEquals(2, manager.getLessonCountOnDay(DayOfWeek.MONDAY)); + manager.removeLesson(DayOfWeek.MONDAY, 0); + assertEquals(1, manager.getLessonCountOnDay(DayOfWeek.MONDAY)); + manager.removeLesson(DayOfWeek.MONDAY, 0); + assertEquals(0, manager.getLessonCountOnDay(DayOfWeek.MONDAY)); + } + + @Test + void verifyException_lessonConstruction_withInvalidTime() { + assertThrows(LessonInvalidTimeException.class, + () -> new Lesson(MOD_CODE_1, LessonType.LAB, DayOfWeek.TUESDAY, time_13, time_12)); + assertThrows(LessonInvalidTimeException.class, + () -> new Lesson(MOD_CODE_1, LessonType.LAB, DayOfWeek.TUESDAY, time_12, time_12)); + } +} diff --git a/src/test/java/seedu/ravi/data/ModuleTest.java b/src/test/java/seedu/ravi/data/ModuleTest.java new file mode 100644 index 0000000000..3f93c96f68 --- /dev/null +++ b/src/test/java/seedu/ravi/data/ModuleTest.java @@ -0,0 +1,58 @@ +package seedu.ravi.data; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import seedu.ravi.exception.DuplicateModuleException; +import seedu.ravi.exception.ModuleNotFoundException; +import seedu.ravi.exception.ModuleNotProvidedException; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class ModuleTest { + static final String MOD_CODE_1 = "CS2113T"; + static final String MOD_CODE_2 = "CG2271"; + + @BeforeEach + void setupModObjects() throws DuplicateModuleException, ModuleNotProvidedException { + ModuleManager.clearModules(); + ModuleManager.add(MOD_CODE_1); + ModuleManager.add(MOD_CODE_2); + } + + @Test + void getModuleCount_isEquals2() { + assertEquals(2, ModuleManager.getModCodeList().length); + } + + @Test + void getModule_isCorrect() throws ModuleNotFoundException { + assertEquals(MOD_CODE_1, ModuleManager.getModule(MOD_CODE_1).getModuleCode()); + assertEquals(MOD_CODE_2, ModuleManager.getModule(MOD_CODE_2).getModuleCode()); + } + + @Test + void check_moduleNotFoundException_isThrown() { + assertThrows(ModuleNotFoundException.class, + () -> ModuleManager.getModule("WHAT1010")); + } + + @Test + void editMod_getCode_equalsNewCode() + throws DuplicateModuleException, ModuleNotProvidedException, + ModuleNotFoundException { + String newCode = "MA1512"; + ModuleManager.edit(newCode, MOD_CODE_1); + + assertEquals(newCode, ModuleManager.getModule(newCode).getModuleCode()); + } + + @Test + void deleteTask_getTaskCount_isEquals0() throws ModuleNotFoundException { + ModuleManager.delete(MOD_CODE_1); + ModuleManager.delete(MOD_CODE_2); + + assertEquals(0, ModuleManager.getModCodeList().length); + assertThrows(ModuleNotFoundException.class, () -> ModuleManager.getModule(MOD_CODE_1)); + } +} diff --git a/src/test/java/seedu/ravi/data/TaskTest.java b/src/test/java/seedu/ravi/data/TaskTest.java new file mode 100644 index 0000000000..855f38026a --- /dev/null +++ b/src/test/java/seedu/ravi/data/TaskTest.java @@ -0,0 +1,87 @@ +package seedu.ravi.data; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.time.LocalDateTime; +import java.util.ArrayList; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class TaskTest { + static Task normalTask; + static Task datedTask; + + @BeforeEach + void setupTaskObjects() { + normalTask = new Task("ABC"); + LocalDateTime myDate = LocalDateTime.of(2020, 10, 1, 0, 0); + datedTask = new Task("DEF", myDate); + TaskManager.clear(); + TaskManager.add(normalTask); + TaskManager.add(datedTask); + } + + @Test + void getTaskCount_isEquals2() { + assertEquals(2, TaskManager.getTaskCount()); + } + + @Test + void check_taskNotFoundException_isThrown() { + assertThrows(TaskManager.TaskNotFoundException.class, () -> TaskManager.getTask(2)); + } + + @Test + void editTask_getName_equalsNewName() throws TaskManager.TaskNotFoundException { + String newName1 = "NEW"; + String newName2 = "NAME"; + TaskManager.edit(0, newName1); + TaskManager.edit(1, newName2); + + assertEquals(newName1, TaskManager.getTask(0).getName()); + assertEquals(newName2, TaskManager.getTask(1).getName()); + } + + @Test + void deleteTask_geTaskCount_isEquals0() throws TaskManager.TaskNotFoundException { + TaskManager.delete(1); + TaskManager.delete(0); + + assertEquals(0, TaskManager.getTaskCount()); + assertThrows(TaskManager.TaskNotFoundException.class, () -> TaskManager.getTask(0)); + } + + @Test + void summary_checkTaskOrder_isCorrect() { + LocalDateTime myDate = LocalDateTime.of(2020, 10, 1, 1, 0); + Task laterDatedTask = new Task("LATER", myDate); + TaskManager.add(laterDatedTask); + + ArrayList sortedTaskWithDeadlines = TaskManager.summary().get(0); + Task earlierTask = sortedTaskWithDeadlines.get(0); + Task laterTask = sortedTaskWithDeadlines.get(1); + // Assert that laterTask actually has a later deadline than earlierTask + assertTrue(laterTask.retrieveDeadline().compareTo(earlierTask.retrieveDeadline()) > 0); + assertEquals(2, sortedTaskWithDeadlines.size()); + } + + @Test + void summary_checkNoDeadlineList_isCorrect() { + ArrayList sortedTasksWithoutDeadlines = TaskManager.summary().get(1); + Task taskWithoutDeadline = sortedTasksWithoutDeadlines.get(0); + assertTrue(taskWithoutDeadline.retrieveDeadline() == null); + assertEquals(1, sortedTasksWithoutDeadlines.size()); + } + + @Test + void summary_checkCompletedList_isCorrect() throws TaskManager.TaskNotFoundException { + TaskManager.done(0); + TaskManager.done(1); + ArrayList completedTasks = TaskManager.summary().get(2); + assertTrue(completedTasks.get(0).getStatus()); + assertEquals(2, completedTasks.size()); + } +} \ No newline at end of file diff --git a/src/test/java/seedu/ravi/data/TimeTableTest.java b/src/test/java/seedu/ravi/data/TimeTableTest.java new file mode 100644 index 0000000000..9b02cc068c --- /dev/null +++ b/src/test/java/seedu/ravi/data/TimeTableTest.java @@ -0,0 +1,169 @@ +package seedu.ravi.data; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import seedu.ravi.data.storage.InputOutputManager; +import seedu.ravi.exception.DuplicateModuleException; +import seedu.ravi.exception.LessonInvalidTimeException; +import seedu.ravi.exception.LessonOverlapException; +import seedu.ravi.exception.ModuleNotFoundException; +import seedu.ravi.exception.ModuleNotProvidedException; +import seedu.ravi.exception.NusModsNotLoadedException; +import seedu.ravi.exception.TimeTableInitialiseException; + +import java.time.DayOfWeek; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.temporal.ChronoField; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class TimeTableTest { + static Lesson lesson1; + static Lesson lesson2; + static Lesson lesson3; + static final String MOD_CODE_1 = "CS2113T"; + static final String MOD_CODE_2 = "CG2271"; + static final String MOD_CODE_3 = "MA1511"; + static final LocalTime time_12 = LocalTime.of(12, 0); + static final LocalTime time_13 = LocalTime.of(13, 0); + static final LocalTime time_14 = LocalTime.of(14, 0); + static final LocalTime time_15 = LocalTime.of(15, 0); + static final LocalTime time_16 = LocalTime.of(16, 0); + static final LocalTime time_17 = LocalTime.of(17, 0); + static final LocalDateTime now = LocalDateTime.now(); + static final int CURR_WEEK = now.get(ChronoField.ALIGNED_WEEK_OF_YEAR); + + @BeforeAll + static void setupUserMods() throws DuplicateModuleException, ModuleNotProvidedException, NusModsNotLoadedException { + InputOutputManager.tryLoadNusMods(); + ModuleManager.clearModules(); + ModuleManager.add(MOD_CODE_1); + ModuleManager.add(MOD_CODE_2); + ModuleManager.add(MOD_CODE_3); + } + + @BeforeEach + void setupTimeTable_andLessons() throws LessonInvalidTimeException, TimeTableInitialiseException { + lesson1 = new Lesson(MOD_CODE_1, LessonType.LECTURE, DayOfWeek.MONDAY, time_12, time_13); + lesson2 = new Lesson(MOD_CODE_2, LessonType.LECTURE, DayOfWeek.MONDAY, time_14, time_15); + lesson3 = new Lesson(MOD_CODE_3, LessonType.LECTURE, DayOfWeek.MONDAY, time_16, time_17); + TimeTableManager.clearTimeTable(); + TimeTableManager.initialise(1); + } + + @Test + void verify_addLesson_repeat1() throws LessonInvalidTimeException, ModuleNotFoundException, LessonOverlapException { + TimeTableManager.addLesson(lesson1, 1); + + for (int i = CURR_WEEK; i < CURR_WEEK + 14; i++) { + if (TimeTableManager.isEvenWeek(i)) { + assertEquals(1, TimeTableManager.getWeekLessonCount(i)); + } else if (TimeTableManager.isOddWeek(i)) { + assertEquals(1, TimeTableManager.getWeekLessonCount(i)); + } else { + assertEquals(0, TimeTableManager.getWeekLessonCount(i)); + } + } + } + + @Test + void verify_addLesson_repeat2() throws LessonInvalidTimeException, ModuleNotFoundException, LessonOverlapException { + TimeTableManager.addLesson(lesson1, 2); + + for (int i = CURR_WEEK; i < CURR_WEEK + 14; i++) { + if (TimeTableManager.isEvenWeek(i)) { + assertEquals(1, TimeTableManager.getWeekLessonCount(i)); + } else if (TimeTableManager.isOddWeek(i)) { + assertEquals(0, TimeTableManager.getWeekLessonCount(i)); + } else { + assertEquals(0, TimeTableManager.getWeekLessonCount(i)); + } + } + } + + @Test + void verify_addLesson_repeat3() throws LessonInvalidTimeException, ModuleNotFoundException, LessonOverlapException { + TimeTableManager.addLesson(lesson1, 3); + + for (int i = CURR_WEEK; i < CURR_WEEK + 14; i++) { + if (TimeTableManager.isEvenWeek(i)) { + assertEquals(0, TimeTableManager.getWeekLessonCount(i)); + } else if (TimeTableManager.isOddWeek(i)) { + assertEquals(1, TimeTableManager.getWeekLessonCount(i)); + } else { + assertEquals(0, TimeTableManager.getWeekLessonCount(i)); + } + } + } + + @Test + void verify_removeLesson_inSingleWeek() throws + LessonInvalidTimeException, ModuleNotFoundException, LessonOverlapException { + TimeTableManager.addLesson(lesson1, 1); + TimeTableManager.addLesson(lesson2, 1); + TimeTableManager.addLesson(lesson3, 1); + + assertEquals(3, TimeTableManager.getWeekLessonCount(CURR_WEEK)); + TimeTableManager.deleteLesson(DayOfWeek.MONDAY, 0); + + assertEquals(2, TimeTableManager.getWeekLessonCount(CURR_WEEK)); + TimeTableManager.deleteLesson(DayOfWeek.MONDAY, 0); + + assertEquals(1, TimeTableManager.getWeekLessonCount(CURR_WEEK)); + TimeTableManager.deleteLesson(DayOfWeek.MONDAY, 0); + + assertEquals(0, TimeTableManager.getWeekLessonCount(CURR_WEEK)); + } + + @Test + void verify_removeLesson_overMultipleWeeks() throws + LessonInvalidTimeException, ModuleNotFoundException, LessonOverlapException { + TimeTableManager.addLesson(lesson1, 1); + TimeTableManager.addLesson(lesson2, 2); + TimeTableManager.addLesson(lesson3, 3); + + assertEquals(2, TimeTableManager.getWeekLessonCount(CURR_WEEK)); + assertEquals(2, TimeTableManager.getWeekLessonCount(CURR_WEEK + 1)); + assertEquals(2, TimeTableManager.getWeekLessonCount(CURR_WEEK + 2)); + TimeTableManager.deleteLesson(DayOfWeek.MONDAY, 0); // remove 'repeat 1' lesson + + assertEquals(1, TimeTableManager.getWeekLessonCount(CURR_WEEK)); + assertEquals(1, TimeTableManager.getWeekLessonCount(CURR_WEEK + 1)); + assertEquals(1, TimeTableManager.getWeekLessonCount(CURR_WEEK + 2)); + TimeTableManager.deleteLesson(DayOfWeek.MONDAY, 0); // remove 'repeat 3' lesson + + assertEquals(0, TimeTableManager.getWeekLessonCount(CURR_WEEK)); + assertEquals(1, TimeTableManager.getWeekLessonCount(CURR_WEEK + 1)); + assertEquals(0, TimeTableManager.getWeekLessonCount(CURR_WEEK + 2)); + } + + @Test + void verify_removeLesson_throwsOutOfBounds() { + assertThrows(IndexOutOfBoundsException.class, + () -> TimeTableManager.deleteLesson(DayOfWeek.MONDAY, 1)); + } + + @Test + void verify_lessonOverlap_throwsLessonOverlap() throws + LessonOverlapException, LessonInvalidTimeException, ModuleNotFoundException { + TimeTableManager.addLesson(lesson1, 1); + assertThrows(LessonOverlapException.class, + () -> TimeTableManager.addLesson(lesson1, 0)); + assertThrows(LessonOverlapException.class, + () -> TimeTableManager.addLesson(lesson1, 2)); + assertThrows(LessonOverlapException.class, + () -> TimeTableManager.addLesson(lesson1, 3)); + + TimeTableManager.addLesson(lesson2, 2); + assertThrows(LessonOverlapException.class, + () -> TimeTableManager.addLesson(lesson2, 1)); + assertThrows(LessonOverlapException.class, + () -> TimeTableManager.addLesson(lesson2, 2)); + + TimeTableManager.addLesson(lesson2, 3); // testing whether repeat 2 and 3 clashes (should not) + } + +} diff --git a/src/test/java/seedu/ravi/parser/AddCommandParserTest.java b/src/test/java/seedu/ravi/parser/AddCommandParserTest.java new file mode 100644 index 0000000000..945834bcea --- /dev/null +++ b/src/test/java/seedu/ravi/parser/AddCommandParserTest.java @@ -0,0 +1,30 @@ +//@@author tobiasceg + +package seedu.ravi.parser; + +import org.junit.jupiter.api.Test; +import seedu.ravi.command.IncorrectCommand; +import seedu.ravi.command.add.AddCommand; +import seedu.ravi.exception.InvalidMatchException; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +class AddCommandParserTest { + static final String TASK_TO_ADD_WITH_DEADLINE = "-t project work -by 2-2-2020 1800"; + static final String TASK_TO_ADD_WITHOUT_DEADLINE = "-t do quiz"; + static final String BAD_TASK_TO_ADD = "-t do quiz -by "; + + @Test + void prepareAddCommandTest_returnsAddCommand() throws InvalidMatchException { + assertTrue(new AddCommandParser().prepareAddCommand(TASK_TO_ADD_WITH_DEADLINE) + instanceof AddCommand); + assertTrue(new AddCommandParser().prepareAddCommand(TASK_TO_ADD_WITHOUT_DEADLINE) + instanceof AddCommand); + } + + @Test + void prepareAddCommandTest_returnsIncorrectCommand() throws InvalidMatchException { + assertTrue(new AddCommandParser().prepareAddCommand(BAD_TASK_TO_ADD) + instanceof IncorrectCommand); + } +} diff --git a/src/test/java/seedu/ravi/parser/DeleteCommandParserTest.java b/src/test/java/seedu/ravi/parser/DeleteCommandParserTest.java new file mode 100644 index 0000000000..537cc74fad --- /dev/null +++ b/src/test/java/seedu/ravi/parser/DeleteCommandParserTest.java @@ -0,0 +1,38 @@ +//@@author tobiasceg + +package seedu.ravi.parser; + +import org.junit.jupiter.api.Test; +import seedu.ravi.command.IncorrectCommand; +import seedu.ravi.command.delete.DeleteModuleCommand; +import seedu.ravi.command.delete.DeleteTaskCommand; +import seedu.ravi.exception.InvalidMatchException; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +class DeleteCommandParserTest { + static final String VALID_DELETE_TASK_INPUT = "-t 3"; + static final String VALID_DELETE_MODULE_INPUT = "-m CG2271"; + static final String INVALID_DELETE_MODULE_INPUT = "-t 3 or 5 also can"; + static final String INVALID_DELETE_TASK_INPUT = "-m CG2271 or CS2101"; + + @Test + void getDeleteCommand_returnsDeleteModuleCommand() throws InvalidMatchException { + assertTrue(DeleteCommandParser.getDeleteCommand(VALID_DELETE_MODULE_INPUT) + instanceof DeleteModuleCommand); + } + + @Test + void getDeleteCommand_returnsDeleteTaskCommand() throws InvalidMatchException { + assertTrue(DeleteCommandParser.getDeleteCommand(VALID_DELETE_TASK_INPUT) + instanceof DeleteTaskCommand); + } + + @Test + void getDeleteCommand_returnsInvalidCommand() throws InvalidMatchException { + assertTrue(DeleteCommandParser.getDeleteCommand(INVALID_DELETE_TASK_INPUT) + instanceof IncorrectCommand); + assertTrue(DeleteCommandParser.getDeleteCommand(INVALID_DELETE_MODULE_INPUT) + instanceof IncorrectCommand); + } +} diff --git a/src/test/java/seedu/ravi/parser/DoneCommandParserTest.java b/src/test/java/seedu/ravi/parser/DoneCommandParserTest.java new file mode 100644 index 0000000000..e11bfa0625 --- /dev/null +++ b/src/test/java/seedu/ravi/parser/DoneCommandParserTest.java @@ -0,0 +1,35 @@ +//@@author tobiasceg + +package seedu.ravi.parser; + +import org.junit.jupiter.api.Test; +import seedu.ravi.command.done.DoneCommand; +import seedu.ravi.exception.InvalidMatchException; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class DoneCommandParserTest { + static final String VALID_DONE_INPUT = "5"; + static final String INVALID_DONE_INPUT_STRING = "Five"; + static final String INVALID_DONE_INPUT_EXCESS = "5 or 10"; + + @Test + void prepareDoneCommand_returnsDoneCommand() throws InvalidMatchException { + assertTrue(DoneCommandParser.prepareDoneCommand(VALID_DONE_INPUT) + instanceof DoneCommand); + } + + @Test + void prepareDoneCommand_NumberFormatException_isThrown() { + assertThrows(NumberFormatException.class, + () -> DoneCommandParser.prepareDoneCommand(INVALID_DONE_INPUT_STRING)); + } + + @Test + void prepareDoneCommand_InvalidMatchException_isThrown() { + assertThrows(InvalidMatchException.class, + () -> DoneCommandParser.prepareDoneCommand(INVALID_DONE_INPUT_EXCESS)); + } + +} diff --git a/src/test/java/seedu/ravi/parser/EditCommandParserTest.java b/src/test/java/seedu/ravi/parser/EditCommandParserTest.java new file mode 100644 index 0000000000..0218936760 --- /dev/null +++ b/src/test/java/seedu/ravi/parser/EditCommandParserTest.java @@ -0,0 +1,35 @@ +//@@author tobiasceg + +package seedu.ravi.parser; + +import org.junit.jupiter.api.Test; +import seedu.ravi.command.edit.EditModuleCommand; +import seedu.ravi.command.edit.EditTaskCommand; +import seedu.ravi.exception.InvalidMatchException; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class EditCommandParserTest { + static final String TASK_TO_EDIT = "3 read a book"; + static final String BAD_TASK_TO_EDIT = "read a book"; + static final String MODULE_TO_EDIT = "cs2113 cs3224"; + + @Test + void prepareEditModuleCommandTest_returnsEditModuleCommand() throws InvalidMatchException { + assertTrue(new EditCommandParser().prepareEditModuleCommand(MODULE_TO_EDIT) + instanceof EditModuleCommand); + } + + @Test + void prepareEditTaskCommandTest_returnsEditTaskCommand() throws InvalidMatchException { + assertTrue(new EditCommandParser().prepareEditTaskCommand(TASK_TO_EDIT) + instanceof EditTaskCommand); + } + + @Test + void prepareEditTaskCommandTest_NumberFormatException_isThrown() { + assertThrows(NumberFormatException.class, + () -> new EditCommandParser().prepareEditTaskCommand(BAD_TASK_TO_EDIT)); + } +} diff --git a/src/test/java/seedu/ravi/parser/GradeCommandParserTest.java b/src/test/java/seedu/ravi/parser/GradeCommandParserTest.java new file mode 100644 index 0000000000..0be0e9e25c --- /dev/null +++ b/src/test/java/seedu/ravi/parser/GradeCommandParserTest.java @@ -0,0 +1,38 @@ +//@@author tobiasceg + +package seedu.ravi.parser; + +import org.junit.jupiter.api.Test; +import seedu.ravi.command.grade.GradeCommand; +import seedu.ravi.exception.InvalidMatchException; +import seedu.ravi.exception.InvalidModuleCreditException; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class GradeCommandParserTest { + static final String VALID_GRADE_INPUT = "CG2271 4 A+"; + static final String INVALID_GRADE_INPUT_STRING_SWAP = "CG2271 B+ 4"; + static final String INVALID_GRADE_INPUT_STRING = "CG2271 four B+"; + static final String INVALID_GRADE_INPUT_EXCESS = "CG2271 4 A+ or B+ anything tbh"; + + @Test + void prepareGradeCommand_returnsGradeCommand() throws InvalidMatchException, InvalidModuleCreditException { + assertTrue(GradeCommandParser.prepareGradeCommand(VALID_GRADE_INPUT) + instanceof GradeCommand); + } + + @Test + void prepareGradeCommand_NumberFormatException_isThrown() { + assertThrows(NumberFormatException.class, + () -> GradeCommandParser.prepareGradeCommand(INVALID_GRADE_INPUT_STRING_SWAP)); + assertThrows(NumberFormatException.class, + () -> GradeCommandParser.prepareGradeCommand(INVALID_GRADE_INPUT_STRING)); + } + + @Test + void prepareGradeCommand_InvalidMatchException_isThrown() { + assertThrows(InvalidMatchException.class, + () -> GradeCommandParser.prepareGradeCommand(INVALID_GRADE_INPUT_EXCESS)); + } +} diff --git a/src/test/java/seedu/ravi/parser/HelpCommandParserTest.java b/src/test/java/seedu/ravi/parser/HelpCommandParserTest.java new file mode 100644 index 0000000000..061dfb2afb --- /dev/null +++ b/src/test/java/seedu/ravi/parser/HelpCommandParserTest.java @@ -0,0 +1,22 @@ +//@@author tobiasceg + +package seedu.ravi.parser; + +import org.junit.jupiter.api.Test; +import seedu.ravi.command.help.HelpCommand; +import seedu.ravi.exception.InvalidMatchException; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +class HelpCommandParserTest { + static final String VALID_HELP_INPUT_GENERIC = ""; + static final String VALID_HELP_INPUT_SPECIFIC = "edit"; + + @Test + void prepareHelpCommand_returnHelpCommand() throws InvalidMatchException { + assertTrue(HelpCommandParser.prepareHelpCommand(VALID_HELP_INPUT_GENERIC) + instanceof HelpCommand); + assertTrue(HelpCommandParser.prepareHelpCommand(VALID_HELP_INPUT_SPECIFIC) + instanceof HelpCommand); + } +} diff --git a/src/test/java/seedu/ravi/parser/ListCommandParserTest.java b/src/test/java/seedu/ravi/parser/ListCommandParserTest.java new file mode 100644 index 0000000000..4c3a8fc29a --- /dev/null +++ b/src/test/java/seedu/ravi/parser/ListCommandParserTest.java @@ -0,0 +1,39 @@ +//@@author tobiasceg + +package seedu.ravi.parser; + +import org.junit.jupiter.api.Test; +import seedu.ravi.command.list.ListCommand; +import seedu.ravi.exception.InvalidMatchException; + +import java.security.InvalidParameterException; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class ListCommandParserTest { + static final String VALID_LIST_TASK_INPUT = "-t"; + static final String VALID_LIST_MODULE_INPUT = "-m"; + static final String INVALID_LIST_PREFIX = "-by"; + static final String INVALID_LIST_TASK_INPUT_EXCESS = "-t now"; + + @Test + void getListCommand_returnListCommand() throws InvalidMatchException { + assertTrue(ListCommandParser.getListCommand(VALID_LIST_MODULE_INPUT) + instanceof ListCommand); + assertTrue(ListCommandParser.getListCommand(VALID_LIST_TASK_INPUT) + instanceof ListCommand); + } + + @Test + void getListCommand_InvalidMatcherException_isThrown() throws InvalidMatchException { + assertThrows(InvalidMatchException.class, + () -> ListCommandParser.getListCommand(INVALID_LIST_TASK_INPUT_EXCESS)); + } + + @Test + void getListCommand_InvalidParameterException_isThrown() throws InvalidMatchException { + assertThrows(InvalidParameterException.class, + () -> ListCommandParser.getListCommand(INVALID_LIST_PREFIX)); + } +} diff --git a/src/test/java/seedu/ravi/parser/ParserTest.java b/src/test/java/seedu/ravi/parser/ParserTest.java new file mode 100644 index 0000000000..4d6c0e2850 --- /dev/null +++ b/src/test/java/seedu/ravi/parser/ParserTest.java @@ -0,0 +1,37 @@ +//@@author tobiasceg + +package seedu.ravi.parser; + +import org.junit.jupiter.api.Test; +import seedu.ravi.exception.InvalidMatchException; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; + +class ParserTest { + private static final Pattern TEST_FORMAT = Pattern.compile("(?\\S+)"); + + @Test + void isEmptyParse_emptyString_returnsTrue() { + assertTrue(new Parser().isEmptyParse("")); + assertTrue(new Parser().isEmptyParse("", "", "")); + } + + @Test + void isEmptyParse_nonemptyString_returnsFalse() { + assertFalse(new Parser().isEmptyParse(" ")); + assertFalse(new Parser().isEmptyParse("", "b", "")); + } + + @Test + void matcherMatches_InvalidMatchException_isThrown() { + String userInput = "this mod is time consuming"; + Matcher matcher = TEST_FORMAT.matcher(userInput); + assertThrows(InvalidMatchException.class, + () -> Parser.matcherMatches(matcher, userInput, "", "")); + } +} \ No newline at end of file diff --git a/src/test/java/seedu/ravi/parser/TimeTableCommandParserTest.java b/src/test/java/seedu/ravi/parser/TimeTableCommandParserTest.java new file mode 100644 index 0000000000..5e33a0fef2 --- /dev/null +++ b/src/test/java/seedu/ravi/parser/TimeTableCommandParserTest.java @@ -0,0 +1,119 @@ +//@@author aseanseen + +package seedu.ravi.parser; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import seedu.ravi.command.Command; +import seedu.ravi.command.CommandResult; +import seedu.ravi.command.IncorrectCommand; +import seedu.ravi.data.ModuleManager; +import seedu.ravi.data.TimeTableManager; +import seedu.ravi.data.storage.InputOutputManager; +import seedu.ravi.exception.DuplicateModuleException; +import seedu.ravi.exception.InvalidMatchException; +import seedu.ravi.exception.ModuleNotProvidedException; +import seedu.ravi.exception.NusModsNotLoadedException; +import seedu.ravi.exception.TimeTableInitialiseException; +import seedu.ravi.util.ExceptionMessage; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static seedu.ravi.parser.TimeTableCommandParser.ADD_FORMAT; +import static seedu.ravi.parser.TimeTableCommandParser.DELETE_FORMAT; +import static seedu.ravi.util.ExceptionMessage.MESSAGE_LESSON_NOT_FOUND; + +public class TimeTableCommandParserTest { + static final String REPEAT_FREQ = "1"; + static final String DELETE_INDEX_1 = "1"; + static final String DELETE_INDEX_2 = "5"; + static final String WRONG_TIMETABLE_COMMAND_FORMAT = "-no"; + static final String MOD_CODE_1 = "CS2113T"; + static final String MOD_CODE_2 = "CS111111"; + static final String LESSON_START_TIME_1 = "2pm"; + static final String LESSON_START_TIME_2 = "10"; + static final String LESSON_START_TIME_3 = "1400"; + static final String LESSON_END_TIME_1 = "1500"; + static final String DAY_OF_WEEK_1 = "mon"; + static final String DAY_OF_WEEK_2 = "MONDAY"; + static final String LESSON_TYPE = "LECTURE"; + + static final String WRONG_MOD_TIMETABLE_ADD_COMMAND_FORMAT = ADD_FORMAT + " " + MOD_CODE_2 + " " + DAY_OF_WEEK_1 + + " " + LESSON_START_TIME_3 + " " + LESSON_END_TIME_1 + " " + LESSON_TYPE + " " + REPEAT_FREQ; + static final String WRONG_LESSON_TIME_1_TIMETABLE_ADD_COMMAND_FORMAT = ADD_FORMAT + " " + MOD_CODE_1 + " " + + DAY_OF_WEEK_1 + " " + LESSON_START_TIME_1 + " " + LESSON_END_TIME_1 + " " + LESSON_TYPE + " " + + REPEAT_FREQ; + static final String WRONG_LESSON_TIME_2_TIMETABLE_ADD_COMMAND_FORMAT = ADD_FORMAT + " " + MOD_CODE_1 + " " + + DAY_OF_WEEK_2 + " " + LESSON_START_TIME_2 + " " + LESSON_END_TIME_1 + " " + LESSON_TYPE + " " + + REPEAT_FREQ; + static final String WRONG_DAY_TIMETABLE_ADD_COMMAND_FORMAT = ADD_FORMAT + " " + MOD_CODE_1 + " " + DAY_OF_WEEK_1 + + " " + LESSON_START_TIME_3 + " " + LESSON_END_TIME_1 + " " + LESSON_TYPE + " " + REPEAT_FREQ; + static final String WRONG_DAY_TIMETABLE_DELETE_COMMAND_FORMAT = DELETE_FORMAT + " " + DAY_OF_WEEK_1 + " " + + DELETE_INDEX_1; + static final String WRONG_INDEX_TIMETABLE_DELETE_COMMAND_FORMAT = DELETE_FORMAT + " " + DAY_OF_WEEK_2 + " " + + DELETE_INDEX_2; + + @BeforeAll + static void setupUserMods() throws DuplicateModuleException, ModuleNotProvidedException, NusModsNotLoadedException { + InputOutputManager.tryLoadNusMods(); + ModuleManager.clearModules(); + ModuleManager.add(MOD_CODE_1); + } + + @BeforeEach + void setupTimeTable() throws TimeTableInitialiseException { + TimeTableManager.clearTimeTable(); + TimeTableManager.initialise(1); + } + + @Test + void badTimeTableCommandFlag_IncorrectCommand_isReturned() throws InvalidMatchException { + Command command = TimeTableCommandParser.parseTimeTableCommand(WRONG_TIMETABLE_COMMAND_FORMAT); + assertTrue(command instanceof IncorrectCommand); + } + + @Test + void bad_Module_TimeTableAddCommand_Message_Module_Not_Found_isShown() throws InvalidMatchException { + Command command = TimeTableCommandParser.parseTimeTableCommand(WRONG_MOD_TIMETABLE_ADD_COMMAND_FORMAT); + CommandResult expectedCommandResult = new IncorrectCommand(ExceptionMessage.MESSAGE_MODULE_NOT_FOUND).execute(); + CommandResult actualCommandResult = command.execute(); + assertEquals(expectedCommandResult.feedbackToUser, actualCommandResult.feedbackToUser); + } + + @Test + void bad_Lesson_Time_1_TimeTableAddCommand_InvalidMatchException_isThrown() { + assertThrows(InvalidMatchException.class, + () -> TimeTableCommandParser.parseTimeTableCommand(WRONG_LESSON_TIME_1_TIMETABLE_ADD_COMMAND_FORMAT)); + } + + @Test + void bad_Lesson_Time_2_TimeTableAddCommand_Message_Date_Time_Unknown_isShown() throws InvalidMatchException { + Command command = + TimeTableCommandParser.parseTimeTableCommand(WRONG_LESSON_TIME_2_TIMETABLE_ADD_COMMAND_FORMAT); + CommandResult expectedCommandResult = + new IncorrectCommand(ExceptionMessage.MESSAGE_ADD_LESSON_DATE_TIME_UNKNOWN).execute(); + CommandResult actualCommandResult = command.execute(); + assertEquals(expectedCommandResult.feedbackToUser, actualCommandResult.feedbackToUser); + } + + @Test + void bad_DateTime_TimeTableAddCommand_IllegalArgumentException_isThrown() { + assertThrows(IllegalArgumentException.class, + () -> TimeTableCommandParser.parseTimeTableCommand(WRONG_DAY_TIMETABLE_ADD_COMMAND_FORMAT)); + } + + @Test + void bad_DateTime_TimeTableDeleteCommand_IllegalArgumentException_isThrown() { + assertThrows(IllegalArgumentException.class, + () -> TimeTableCommandParser.parseTimeTableCommand(WRONG_DAY_TIMETABLE_DELETE_COMMAND_FORMAT)); + } + + @Test + void bad_Index_TimeTableDeleteCommand_Message_Lesson_Not_Found_isShown() throws InvalidMatchException { + Command command = TimeTableCommandParser.parseTimeTableCommand(WRONG_INDEX_TIMETABLE_DELETE_COMMAND_FORMAT); + CommandResult commandResult = command.execute(); + assertEquals(MESSAGE_LESSON_NOT_FOUND, commandResult.feedbackToUser); + } +} diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT deleted file mode 100644 index 892cb6cae7..0000000000 --- a/text-ui-test/EXPECTED.TXT +++ /dev/null @@ -1,9 +0,0 @@ -Hello from - ____ _ -| _ \ _ _| | _____ -| | | | | | | |/ / _ \ -| |_| | |_| | < __/ -|____/ \__,_|_|\_\___| - -What is your name? -Hello James Gosling diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt deleted file mode 100644 index f6ec2e9f95..0000000000 --- a/text-ui-test/input.txt +++ /dev/null @@ -1 +0,0 @@ -James Gosling \ No newline at end of file diff --git a/text-ui-test/runtest.bat b/text-ui-test/runtest.bat deleted file mode 100644 index 25ac7a2989..0000000000 --- a/text-ui-test/runtest.bat +++ /dev/null @@ -1,19 +0,0 @@ -@echo off -setlocal enableextensions -pushd %~dp0 - -cd .. -call gradlew clean shadowJar - -cd build\libs -for /f "tokens=*" %%a in ( - 'dir /b *.jar' -) do ( - set jarloc=%%a -) - -java -jar %jarloc% < ..\..\text-ui-test\input.txt > ..\..\text-ui-test\ACTUAL.TXT - -cd ..\..\text-ui-test - -FC ACTUAL.TXT EXPECTED.TXT >NUL && ECHO Test passed! || Echo Test failed! diff --git a/text-ui-test/runtest.sh b/text-ui-test/runtest.sh deleted file mode 100755 index 1dcbd12021..0000000000 --- a/text-ui-test/runtest.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env bash - -# change to script directory -cd "${0%/*}" - -cd .. -./gradlew clean shadowJar - -cd text-ui-test - -java -jar $(find ../build/libs/ -mindepth 1 -print -quit) < input.txt > ACTUAL.TXT - -cp EXPECTED.TXT EXPECTED-UNIX.TXT -dos2unix EXPECTED-UNIX.TXT ACTUAL.TXT -diff EXPECTED-UNIX.TXT ACTUAL.TXT -if [ $? -eq 0 ] -then - echo "Test passed!" - exit 0 -else - echo "Test failed!" - exit 1 -fi diff --git a/unused/CapCommand.java b/unused/CapCommand.java new file mode 100644 index 0000000000..c3337b6307 --- /dev/null +++ b/unused/CapCommand.java @@ -0,0 +1,154 @@ +//@@author tobiasceg + +package seedu.ravi.command.cap; + +import seedu.ravi.command.Command; +import seedu.ravi.command.CommandResult; +import seedu.ravi.command.PromptType; +import seedu.ravi.data.ModuleManager; +import seedu.ravi.exception.InvalidCapCalculatedException; +import seedu.ravi.exception.ModuleNotFoundException; +import seedu.ravi.ui.TextUi; + +import static seedu.ravi.util.ExceptionMessage.MESSAGE_INVALID_CAP_ATTAINED; +import static seedu.ravi.util.ExceptionMessage.MESSAGE_MODULE_NOT_FOUND; +import static seedu.ravi.util.Message.MESSAGE_CAP_DISPLAY; + +public class CapCommand extends Command { + private final int totalMcTaken; + private final double currentCap; + public static final String COMMAND_WORD = "cap"; + public static final String FORMAT = COMMAND_WORD + " "; + public static final String PROMPT_HELP = TextUi.getCommandHelpMessage(COMMAND_WORD); + public static final String HELP = "Calculate your CAP." + + "\n\t@|bold,blue,BG_BLACK Format:|@ " + FORMAT + + "\n\t@|bold,blue,BG_BLACK Example usage:|@ cap 20 4.5"; + + public static double cap = 0.0; + private static final double SUMMCGRADE = 20; + private static final double SUMMC = 4; + + + /** + * Constructor for CapCommand which checks if the totalMcTaken and currentCap is valid also. + * + * @param totalMcTaken + * users total module credit attained + * @param currentCap + * users current cap score + */ + public CapCommand(int totalMcTaken, double currentCap) { + this.totalMcTaken = totalMcTaken; + this.currentCap = currentCap; + setPromptType(PromptType.EDIT); + } + + /** + * Enum for the grading schematic of NUS. + */ + private enum GradeSchematic { + A_PLUS("A+", 5.0), + A("A", 5.0), + A_MINUS("A-", 4.5), + B_PLUS("B+", 4.0), + B("B", 3.5), + B_MINUS("B-", 3.0), + C_PLUS("C+", 2.5), + C("C", 2.0), + D_PLUS("D+", 1.5), + D("D", 1.0), + F("F", 0.0), + CS("CS", -2.0), + CU("CU", -3.0); + + private final String symbol; + private final double value; + + GradeSchematic(String symbol, double value) { + this.symbol = symbol; + this.value = value; + } + } + + /** + * Converts the grade assigned to a module the value by using the enum. + * + * @param grade + * grade assigned to module + * @return + * the value of the grade + */ + private double gradeConvert(String grade) { + double score = 0.0; + if (grade.equals("No grade yet")) { + score = -1.0; + return score; + } + for (GradeSchematic g : GradeSchematic.values()) { + if (grade.equals(g.symbol)) { + score = g.value; + } + } + return score; + } + + /** + * Calculates the cap of the user. + * + * @return + * cap of the user + * @throws InvalidCapCalculatedException + * When the attained cap is unimaginable + * @throws ModuleNotFoundException + * When the module called isn't found + */ + private double calculateCap() throws InvalidCapCalculatedException, ModuleNotFoundException { + String[] moduleList = ModuleManager.getModCodeList(); + double mcGrade = 0; + double sumMcGrade = 0; + double sumMc = 0; + double gradeValue; + int numberOfCsCuModules = 0; + int numberOfModules = 0; + for (String i : moduleList) { + numberOfModules++; + gradeValue = gradeConvert(ModuleManager.getModule(i).getModuleGrade()); + if (gradeValue == -1.0) { + throw new InvalidCapCalculatedException(); + } else if (gradeValue >= 0) { + sumMc += ModuleManager.getModule(i).getModuleCredit(); + mcGrade = ModuleManager.getModule(i).getModuleCredit() + * gradeValue; + sumMcGrade += mcGrade; + } else { + numberOfCsCuModules++; + } + } + if (numberOfCsCuModules == numberOfModules) { + sumMcGrade = SUMMCGRADE; + sumMc = SUMMC; + } + + cap = ((currentCap * totalMcTaken) + sumMcGrade) / (sumMc + totalMcTaken); + + if (cap < 0 || cap > 5.0 || isNan(cap)) { + throw new InvalidCapCalculatedException(); + } + return cap; + } + + private boolean isNan(double cap) { + return cap != cap; + } + + @Override + public CommandResult execute() { + try { + return new CommandResult(String.format("%s%.2f\n", MESSAGE_CAP_DISPLAY, calculateCap())); + } catch (InvalidCapCalculatedException e) { + return new CommandResult(MESSAGE_INVALID_CAP_ATTAINED, true); + } catch (ModuleNotFoundException e) { + return new CommandResult(MESSAGE_MODULE_NOT_FOUND, true); + } + } +} diff --git a/unused/CapCommandParser.java b/unused/CapCommandParser.java new file mode 100644 index 0000000000..a206fa187b --- /dev/null +++ b/unused/CapCommandParser.java @@ -0,0 +1,76 @@ +//@@author tobiasceg + +package seedu.ravi.parser; + +import seedu.ravi.command.Command; +import seedu.ravi.command.cap.CapCommand; +import seedu.ravi.exception.InvalidCapException; +import seedu.ravi.exception.InvalidMatchException; +import seedu.ravi.exception.InvalidModuleCreditException; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class CapCommandParser { + protected static final String TOTAL_MC_GROUP = "totalMc"; + protected static final String CAP_GROUP = "cap"; + protected static final Pattern CUMULATIVE_CAP_FORMAT = + Pattern.compile("(?\\d+)" + "(?\\s[0-9.]+)"); + + /** + * Takes the user's input and parses it into the respective arguments for CapCommand. + * + * @param parameters + * the user's input without the command word + * @return + * CapCommand with the relevant parameters + * @throws NumberFormatException + * When a string is parsed as an integer/double + * @throws NullPointerException + * referenced object is accessed by its a null + * @throws InvalidMatchException + * When the user input doesn't match the REGEX format for the Cap Command + */ + protected static Command prepareCapCommand(String parameters) + throws NumberFormatException, NullPointerException, + InvalidMatchException, InvalidCapException, InvalidModuleCreditException { + Matcher matcher = CUMULATIVE_CAP_FORMAT.matcher(parameters); + + Parser.matcherMatches(matcher, parameters, CapCommand.FORMAT, CapCommand.PROMPT_HELP); + + String mc = Parser.isMatcherNull(matcher.group(TOTAL_MC_GROUP)) + ? null : matcher.group(TOTAL_MC_GROUP).trim(); + String cap = Parser.isMatcherNull(matcher.group(CAP_GROUP)) + ? null : matcher.group(CAP_GROUP).trim(); + + int totalMcTaken = Integer.parseInt(mc); + double currentCap = Double.parseDouble(cap); + + isCapParametersValid(totalMcTaken, currentCap); + + return new CapCommand(totalMcTaken, currentCap); + } + + /** + * Checks if the user input for cap command is valid. + * + * @param totalMcTaken + * users total mc taken + * @param currentCap + * users current cap + * @throws InvalidModuleCreditException + * user input invalid mc + * @throws InvalidCapException + * user input invalid cap + */ + private static void isCapParametersValid(int totalMcTaken, double currentCap) + throws InvalidModuleCreditException, InvalidCapException { + if (totalMcTaken < 0 || totalMcTaken > 190) { + throw new InvalidModuleCreditException(); + } + + if (currentCap < 0 || currentCap > 5.0) { + throw new InvalidCapException(); + } + } +} diff --git a/unused/CapCommandTest.java b/unused/CapCommandTest.java new file mode 100644 index 0000000000..7e726af92a --- /dev/null +++ b/unused/CapCommandTest.java @@ -0,0 +1,37 @@ +//@@author tobiasceg + +package seedu.ravi.command.cap; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import seedu.ravi.command.CommandResult; +import seedu.ravi.command.add.AddCommand; +import seedu.ravi.command.add.AddModuleCommand; +import seedu.ravi.command.grade.GradeCommand; +import seedu.ravi.data.ModuleManager; +import seedu.ravi.exception.InvalidCapException; +import seedu.ravi.exception.InvalidModuleCreditException; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static seedu.ravi.util.Message.MESSAGE_CAP_DISPLAY; + +public class CapCommandTest { + static final String MODULE_CODE = "CS1231"; + static final double CAP = 4.37; + + @BeforeEach + void setupModManager() throws InvalidModuleCreditException { + ModuleManager.clearModules(); + AddCommand addModule = new AddModuleCommand(MODULE_CODE); + addModule.execute(); + GradeCommand gradeCommand = new GradeCommand(MODULE_CODE, 4, "A+"); + gradeCommand.execute(); + } + + @Test + void capCommand_MessageCapDisplayWithCap_isShown() throws InvalidCapException, InvalidModuleCreditException { + CapCommand capCommand = new CapCommand(20, 4.24); + CommandResult commandResult = capCommand.execute(); + assertEquals(String.format("%s%.2f\n", MESSAGE_CAP_DISPLAY, CAP), commandResult.feedbackToUser); + } +}