Introduction
Hi! My name is Fong Zhi Zhong but you can call me Keith! I am currently a second year student at National University of Singapore studying Computer Science.
As a passionate programmer, I believe I can solve many problems through coding.
I am the team leader for Car Park Finder, a project for my CS2103T Software Engineering module, where I was in charge of UI (user interface), threading, scheduling and tracking.
1. Overview
Car park Finder is a CLI (command line interface) application to find HDB (Housing Development Board) car parks in Singapore.
It allows you to display a list of car parks with the convenience of typing. It provides crucial information like real time updates and cost of car parks.
If you use the computer frequently and commute by driving, you would find our application useful in your daily lives.
Interested? Head towards our releases page to download and try it out! No installation is required.
2. Summary of contributions
Given below are sections I contributed to the development of the application. They showcase my technical depth and ability. |
-
Major enhancement 1: Modified the find feature to search for partial words and ignore certain words.
-
What it does: Allows the user to search for partial instances of words without needed to type everything.
-
Justification: This feature improves the product significantly because a user can type lesser and the app should provide the same data still.
-
Highlights: This enhancement affects the existing commands and commands to be added in the future. I also wrote extra code which allowed us to re-use in the future.
-
-
Major enhancement 2: Integrated Google maps javascript api.
-
What it does: Every time the user sends a command, the display will be updated accordingly. E.g. Selecting a car park shows that one and only carpark.
-
Justification: This feature greatly improves the look and feel of the application. Plus it allows further more information to be displayed.
-
Highlights: This enhancement allows the user to see where the car park is in the entire map without needing to interact with the GUI itself.
-
-
Minor enhancements:
-
Pulled postal code information using coordinates data by querying an API to convert it to store in a file for quick loading.
-
Credits: [SVY21 to WGS84].
-
-
Code contributed: Click here to view my code on the CS2103T Project Code Dashboard.
-
Notable Contributions: [String Util], [Find Command], [Find Command Parser], [Gson test], [HTML, JS].
-
Other contributions:
-
Project management:
-
Enhancement of existing features:
-
Documentation:
-
Community:
-
Tools:
-
3. Contributions to the User Guide
Given below are sections I contributed to the User Guide. They showcase my ability to write documentation targeting end-users. |
3.1. Finding car parks : find
With a list of car parks, you can narrow down to just the car parks near your destination by either typing in the location or the specific car park number.
Format | Abbreviation | Example(s) |
---|---|---|
find KEYWORD |
fin |
find serangoon |
|
3.1.1. Example: How to find car parks by location
For this example, we will be looking at how to find all the car parks in Punggol.
53 car park(s) found! |
Type find punggol
into the Command Box. The message above should appear in the Message Box as confirmation that you
typed in correctly. Found car parks in Punggol shows how it would look like, with the Google Maps zoomed in.
3.1.2. Example: How to find car park by car park number
1 car park(s) found! |
Type find PP5
into the Command Box. The message above should appear in the Message Box as confirmation that you
typed in correctly. Found car parks in Punggol shows how it would look like, with the Google Maps zoomed in.
3.1.3. Example: Unable to find car park
If Car Park Finder is unable to find your location or car park number, it will display nothing.
0 car park(s) found! |
The message above will be shown, as well as an empty list in the Display Panel and no markers in the Google Maps.
3.2. Undoing commands: undo
Restores the list of car parks to the state before the previous undoable command was executed.
Format | Abbreviation |
---|---|
undo |
u / un / und |
|
3.2.1. Example: Successful undo
If you accidentally type an undoable command and wish to undo it, here is how.
Undo success! |
Type undo
into the Command Box. The message above should appear in the Message Box
as confirmation that you
typed in correctly.
3.2.2. Example: Unable to undo
Not all commands are undoable as there is a limit to the number of undo commands.
No more commands to undo! |
If you see the message above in the Command Box it means there are no more undoable commands. You can also check the history to view what commands you have typed in so far.
3.3. Redoing commands : redo
Reverse the most recent undo
command.
Format | Abbreviation |
---|---|
redo |
r / re / red |
|
3.3.1. Example: Successful redo
Redo success! |
Type redo
into the Command Box. The message above should appear in the Message Box as confirmation that you
typed in correctly.
3.3.2. Example: Unable to redo
You reach the end of how far you can redo. Take note that not all commands are undoable / redoable.
No more commands to redo! |
If you see the message above in the Command Box it means there are no more redoable commands. You can also check the history to view what commands you have typed in so far.
4. Contributions to the Developer Guide
Given below are sections I contributed to the Developer Guide. They showcase my ability to write technical documentation and the technical depth of my contributions to the project. |
4.1. Find feature
The find feature searches for a car park by keyword or location.
4.1.1. Overview
The find mechanism is facilitated by FindCommand
and FindCommandParser
. It extends Command
and implements the following operations:
-
FindCommand#execute()
— Executes the command by running a predicateCarparkContainsKeywordsPredicate
to update the car park list.
The find mechanism is supported by FindCommandParser
. It implements Parser
and contains the following operations:
-
FindCommandParser#parse()
— Checks the arguments for empty strings and throws aParseException
if empty string is found. It then splits it by one or more white spaces. It then removes any strings in the list of common words.
The predicate CarparkContainsKeywordsPredicate
takes in a list of strings and checks if any of the strings matches the name or address of a car park fully or partially.
The diagram above describes how the flow of a find command would execute. It rely on FindCommandParser
to ensure the variables are correct.
4.1.2. Example
Given below is an example usage scenario of how the find
mechanism behaves at each step.
Step 1. The user launches the application for the first time.
Step 2. The user executes find punggol
command to get all car parks in punggol.
The find
command calls FindCommandParser#parse()
.
If a command execution fails, it will not call FindCommand#execute() , and the car park finder state will not be saved.
|
Step 3. The entire list of car parks is filtered by the predicate CarparkContainsKeywordsPredicate
, which checks for the keyword punggol
.
Step 4. The filtered list of car parks is returned to the GUI.
The flow chart below describes the user interaction with the application and how it processes it.
4.1.3. Design Considerations
Aspect: How predicate works
-
Alternative 1 (Current choice): Predicate have additional filter with an ignore list.
Pros
Re-usable functions introduced for partial checking.
Cons
Reading the car park list while querying might cause unintended side effects if not handled properly.
-
Alternative 2: Filter the data when it is taken in.
Pros
Easy to maintain as predicate will have lesser conditions.
Cons
Breaks OOP style as the parser will modify the data.
4.2. UI
It is a combination of JavaFX, HTML and CSS. This section describes the challenges faced, how it was overcome and an example of how it works.
4.2.1. Overview
Initially, we wanted to showcase real time updates when the user issues a command. This would mean updating the HTML accordingly. However, we did not want to just update it, we wanted to showcase the selected car park or the filtered list accordingly.
4.2.2. Example
Step 1. The user launches the application and is greeted by this UI.
Step 2. The user selects a car park with a select
command. E.g. select 10
.
select 10
commandSelectCommand#Execute
is called. If the input is valid, it creates a JumpToListRequestEvent
event for BrowserPanel#handleCarparkPanelSelectionChangedEvent()
to catch.
Step 3. The user then list all the car park with a list
command.
A ListCarparkRequestEvent
is created and BrowserPanel
catches the event to call BrowserPanel#handleListCarparkRequestEvent()
list
commandThe HTML is refreshed to show all car parks.
4.2.3. Design Considerations
Aspect: HTML/CSS/JS design choices
-
Alternative 1 (Current choice): Have a callback function in javascript
Pros
Easy to implement google maps and stylesheet.
Cons
Hard to test. Different rendering between devices.
-
Alternative 2: Have a query in the url parameters to filter data and update iFrame
Pros
No rendering issue. Easy to test and debug.
Cons
Complex query and hard to understand again once working. Server must allow filtering by url paramters.
4.3. Postal Code
The postal code feature is built to allow easier finding of car park by knowing the postal code they are searching for.
As the car park data from data.gov.sg
does not have any postal code, we converted coordinates of each respective
car park to a postal code whenever possible.
4.3.1. Overview
Currently, postal code data are stored in a separate file. This is due to it being too slow and unreliable to convert coordinate to postal code in real time. However, in order to generate the file, we went through every car park and found their respective postal code.
4.3.2. Example
Step 1. The user launches the application.
Step 2. The system loads the file, postalcodeData.txt
into a Hashmap<Long,String>
using the GsonUtil#loadCarparkPostalCode()
where the key is a hash and the value is a postal code.
Step 3. The system goes through every car park’s coordinates and hashes them together with GsonUtil#fnvHash(x,y)
where x
is the x-coordinate of the carpark and y
is the y-coordinate of the carpark.
Step 4. If the key is found, it will return the value which is the postal code of the car park. If not, it will return the
default value 000000
.
As certain car park do not have postal code, 000000 is the default value and a flag to show that the car park does not have a postal code.
|
4.3.3. Design Considerations
Aspect: Source of postal code information
-
Alternative 1 (Current choice): Pull data from file
Pros
Fast and efficient. No need to change due to no postal code changes.
Cons
Unable to update for new car parks. Requires user to download updated jar file.
-
Alternative 2: Pull data from API
Pros
Easy to update and scalable to new car parks.
Cons
Too slow to do in real time. Takes roughly 20 minutes to update all car park postal code. Not realistic and efficient to do in real time.
4.4. [Proposed] Data Encryption
The car park data and user data will be encrypted to prevent users from editing and manipulating them.
4.4.1. Overview
The data encryption mechanism works by encrypting the information by a unique key generated by every users individual system. The key will stored in a secured location to prevent people from accessing it.
The two main files it will encrypt are:
-
Car park information
-
User’s favorites
4.4.2. Example
This feature is coming in v2.0.