My Projects

I’ve decided to make a summary of my past projects here. I have spent most of my free time on iOS development, and also explored some web development using PHP and JavaScript. In the past summer I used JavaScript to work on an educational software for a CS professor here at Duke.

I’ve ordered them according to my personal preference:)

  1. DukeCSA

DukeCSA (on GitHub) is the iOS app started by Jay Wang (currently a senior at Duke) to fit the needs of Duke Chinese Student Association. I joined the team around Christmas 2015. It combined many useful functionalities:

  • events post – users can view upcoming and past events hosted by DukeCSA. They can sign up or comment on the events in the app.
  • Q&A – students can ask their peers about life at Duke. This section is like Quora for Duke.
  • Class Database – users can view a massive (1000+) collection of comments on courses offered here at Duke to help them make choices.
  • Crush – users can express their secret admiration to others. If there is a match, both users will get notifications.
  • Web event poster – a web interface for the CSA committee to post a new event. The event will then be saved to our database and all users will be notified. The user does not need to write any code.

short demos:
notification indication

web interface

Read more about iOS projects


2. JFLAP web

JFLAP (Java Formal Language and Automata Package) is an educational software about finite state machines, Moore and Mealy machines, Turing machines etc. I worked on building the online version of JFLAP and integrating JFLAP into OpenDSA (Data Structures and Algorithms) project.

The job included designing and implementing the user interface, optimizing and implementing the algorithms and migrating Java version to JavaScript. I learned about formal languages and automata as well as software development.

short demo:

more about JFLAPmore about OpenDSAdevelopment blog, web demo


3. 3D iOS games

I also learned about 3D iOS game development. Below are demo videos of them:

Marble Maze – gravity-controlled



4. Tank Battle

This is a homework project in my software development class, but I treat it more than that. The game features elements such as stone, brick, grass and water. The player needs to protect the base and eliminate enemies. The game also uses permanent storage to present a leader board.


The design comes from the classic video game battle city.


5. Blog Post System

A blog post system written mainly with PHP. Responsive to both desktop and mobile devices. Users are able to view all posts without logging in and post articles or comments when logged in. Data is stored in MYSQL database. APIs are also built for possible iOS app development in the future.

demo: (It’ll probably be more fun if you could read Chinese)


6. Wheeshare

(my first iOS app!). This is an iOS app that promotes sharing among Duke students. I completed this project with grant from Duke CoLab, my current employer.
On the platform, students are able to post their belongings to lend, or to browse through the available items and request to borrow with one click. Students can also easily manage their posts.


Memo on C Language Programming

Starting yesterday I have been reading the official manual of C programming language from GNU. I have finished 17 chapters out of 20-something chapters of the whole manual. I realized that the best way to learn an open-source stuff is indeed to read the documentation/help manual.

Yesterday I covered basic knowledge of the programming language such as type, expression, function, and pointer. It didn’t take much time because I have read other materials on C before. I did spend some time understanding pointers since in Java there is no explicit definition of pointer.

Today’s new materials include IO, String operation and “making” a program with multiple C source code files. I’m going to write down here things new to me.


  1. File IO:
#include <stdio.h>
#include <stdlib.h>

int main() {
	FILE *stream;
	stream = fopen("shit.dat", "w");
	int my_array[2][2] =
	size_t object_size = sizeof(int);
	size_t object_count = 4;

	if (stream == NULL) {
		printf("shit.dat could not be created\n");
	printf("file opened for writing\n");
	fwrite(&my_array, object_size, object_count, stream);
	stream = fopen("shit.dat", "r");
	if (stream == NULL) {
		printf("shit.dat could not be read\n");
	printf("file opened for reading\n");
	fread(&my_array, object_size, object_count, stream);

	for (int i = 0; i < 2; i++) {
		for (int j = 0; j < 2; j++) {
			printf("%d ", my_array[i][j]);
	return 0;

Most important functions for input/output with files would be fopen, fclose, fread, fwrite, getline and fprintf. According to the manual, it is suggested to use fread, getline and fwrite since they are safer than the rest, some of which are already deprecated. It’s worth noting that the second and the third parameters of fwrite and fread are of type size_t. Other than this, this part is pretty easy.


2. Combination of getline and sscanf

getline is a safe method, if you pass in an uninitialized string pointer, the program will create a buffer of a proper size for you and populate the variable. However, if you use methods like scanf instead, you may encounter buffer overflow errors, which can be very common. getline returns a line of text before a linebreak from a stream, which can be either stdin or a file.

Then, sscanf is used to read stuff of a specific type or a format from the string. This combination, according to the manual, is much better than using scanf alone, since it avoids many errors.

Example code:

#include <stdlib.h>
#include <stdio.h>

int main()
	int args_assigned = 0;
	size_t nbytes = 2;
	char *my_string;
	int int1, int2, int3;

	while (args_assigned != 3)
		puts("Please enter three integers separated by whitespace.");
		my_string = (char *) malloc(nbytes + 1);
		getline(&my_string, &nbytes, stdin);
		args_assigned = sscanf(my_string, "%d %d %d", &int1, &int2, &int3);
		if (args_assigned != 3)
			puts("Invalid input!");
			printf("Three integers: %d %d %d\n", int1, int2, int3);
	return 0;

It doesn’t matter that my_string is initialized with a very small size: getline will take care of that.



ARGP is such a strong tool!! With this, it’s very easy to parse parameters passed to the program and provide the users with usage explanations and documentations interactively.

The boss function is argp_parse, which takes four parameters: 1. parameter options, in a struct type, 2. a function to handle the option and parameter fields, 3. a string describing the arguments format, 4. a string that documents the program.

There are so many options available for customization. Although it’s hard to remember all of the parameter types and requirements, in actual development process I can just copy the old example piece of code and continue happily from there.

Example code:

#include <stdio.h>
#include <argp.h>

const char *argp_program_version = "argex 1.0";
const char *argp_program_bug_address = "<>";

/* This structure is used by main to communicate with parse_opt. */
struct arguments
	char *args[2];
	int verbose;
	char *outfile;
	char *string1, *string2;

 * 	OPTIONS. Field 1 in ARGP.
 * 	Order of fields: {NAME, KEY, ARG, FLAGS, DOC}.
static struct argp_option options[] = 
	{"verbose", 'v', 0, 0, "Produce verbose output"},
	{"alpha", 'a', "STRING1", 0, "Do something with STRING1 related to the letter A"},
	{"bravo", 'b', "STRING2", 0, "Do something with STRING2 related to the letter B"},
	{"output", 'o', "OUTFILE", 0, "Output to OUTFILE instead of to standard output"},

 * PARSER. Field 2 in ARGP.
 * Order of parameters: KEY, ARG, STATE.
static error_t parse_opt (int key, char *arg, struct argp_state *state)
	struct arguments *arguments = state->input;
	switch (key)
		case 'v':
			arguments->verbose = 1;
		case 'a':
			arguments->string1 = arg;
		case 'b':
			arguments->string2 = arg;
		case 'o':
			arguments->outfile = arg;
		case ARGP_KEY_ARG:
			if (state->arg_num >= 2)
			arguments->args[state->arg_num] = arg;
		case ARGP_KEY_END:
			if (state->arg_num < 2)
	return 0;

 * ARGS_DOC. Field 3 in ARGP.
 * A description of the non-option command-line arguments that we accept.
static char args_doc[] = "ARG1 ARG2";

 * DOC. Field 4 in ARGP.
 * Program documentation.
static char doc[] = 
"argex -- A program to demonstrate how to code command-line options and arguments.\vFrom the GNU C Tutorial.";

 * The ARGP structure itself.
static struct argp argp = {options, parse_opt, args_doc, doc};

 * The main function.
 * Notic how now the only function call needed to process all command-line options and arguments nicely is argp_parse.
int main (int argc, char **argv)
	struct arguments arguments;
	FILE *outstream;
	char waters[] = "Some long sentence";

	/* Set argument defaults */
	arguments.outfile = NULL;
	arguments.string1 = "";
	arguments.string2 = "";
	arguments.verbose = 0;

	/* Where the magic happens */
	argp_parse(&argp, argc, argv, 0, 0, &arguments);

	/* Where do we send output? */
	if (arguments.outfile)
			outstream = fopen(arguments.outfile, "w");
		outstream = stdout;

	/* Print argument values */
	fprintf(outstream, "alpha = %s\nbravo = %s\n\n", arguments.string1, arguments.string2);
	fprintf(outstream, "ARG1 = %s\nARG2 = %s\n\n", arguments.args[0], arguments.args[1]);

	/* If in verbose mode, pring song stanza */
	if (arguments.verbose)
		fprintf(outstream, "%s", waters);

	return 0;

When it runs it really behaves like a “legit” GNU open source software!


I also read about makefiles: its rules, targets and variables that can simplify the code. I guess tomorrow I’ll read more about C. If I finish this manual I’ll take a look at the GNU Make manual.

Anyway, it’s cool that a book originally written 30 years ago is still not outdated at all.


First day on JFLAP project

Today is my first day working on JFLAP project! JFLAP is an educational software that teaches students about automata and turing machines etc. As instructed by my supervisor, I created a blog here. I’m just going to copy and paste what I write there to here daily.

Here’s my first day blog:

Today is my first day of working on JFLAP, and I actually did quite a lot. I got two books in the morning: Formal Languages and Automata by Linz and JFLAP by Rodger and Finley. I finished reading the first two chapters of Linz’s book. The first chapter introduces some basic concepts that include language, grammer and automaton, while the second teaches me about deterministic finite automata (DFA) and nondeterministic finate automata (NFA). I learned that these two automata may seem different, but they are able to transform to one another.

I then downloaded version 7 of JFLAP and tested the software following the JFLAP intro book. The software is very easy to use and since I read the chapters in Linz’s book, the graphs were familiar to me. I find that there are also many other features besides DFA and NFA. Hope that I can learn about them later in the summer.

In the afternoon I was given access to a server. To my frustration my account is not a sudoer, which means for now I can only build this blog with html and css. I will see if I can install wordpress later. That will make this website much prettier. In either case there will be many changes to this page for sure.

A lot left to learn, wish myself best of luck.

Blog Post System using PHP

Today I would like to talk in a little bit more detail about my blog post system written in PHP.

The main page looks like this:

Screen Shot 2016-05-08 at 5.08.49 PM

First, the database structure:

Screen Shot 2016-05-08 at 5.28.27 PM

The structure is actually pretty straightforward: one table for user authentication, one for posts and one for comments. For user authentication, password hashed with md5 is stored in the database. When the users attempt to log in, their hashed input and the one in the database is compared, a traditional approach. For each post, two main pieces of information are topic and content. They form the body of a post. Author is stored simply as the username. Date is stored as a formatted string instead of UNIX timestamp because somehow I could not get that to work :(. For comment, its associated post is stored as articleId. When I present the comments of each article, I query the database for this articleId. This might be slower than other methods such as keeping references, but since I’m not storing a million blog posts, this works just fine.

Recently I finished paging and comment system. For paging, I first query the post table and get the total number of posts. Then according to articles_per_page variable set in config.php I query the table for more times with a LIMIT to present posts only for a specific page. Page index is given with a GET request. If there is not such information in $_GET, the default value is set as 1, obviously.

For now, comments can only be viewed after you click on each single article to see the details. At the bottom of the article, I query the comment table to look for the articleId. A helper method does this and returns the comments as an array of objects. I then simply use a loop to traverse the array and echo them out on the page.

Posting comment is a little bit different: the post request is handled by another php file which does not present anything. After storing the comment into the database, the script routes back to the earlier article. In the POST request, only content is passed. articleId is passed with the super global variable $_SESSION. I’m not sure if this is the best way, but it is surely easier to write than the curl method that I found online.

Several problems I encountered:

  1. For creating the post, not only do I need to verify the user is logged in when the page is presented, I also need to verify when the post request is received. Because softwares such as Postman can easily create a post request and flood the database.
  2. For frontend, I find that the CSS argument clear: both is amazingly useful. I used float a lot for my page design, so a lot of times I want to keep divs stable.
  3. Typo is a bitch, especially those inside double quotes. When coding on a server there is no nice IDE that reminds me there is a grammar mistake or a typo, so I really need to be careful about these. Sometimes one typo took me twenty minutes to debug.
  4. Security. When I gave my address to my friend to test it. He hacked the site with simple javascripts easily, which forced me to filter any input that the users are giving to the site. Now I blocked the word script completely, so evil people cannot alert me every time I get on the blog.

Things that I will be working on:

  1. Keep user input in session. In my project, when the user hit “comment” or “post” but they are not logged in, they are directed to the log in page and directed back but the input is lost. I definitely don’t want them to type all over again, so caching inputs is a good idea.
  2. Move log in/out to the main page as a small popup. Right now when the users click on login, they are directed to another page to put in their username and password. However, keeping them in the same page will save users’ attention loss.
  3. Adding styled text and images in post. Maybe I could add some buttons so the users can upload images for posts. I have to be careful though because some users such as my friend could upload bad things to my beloved server.

That’s pretty much it. I am just done with my finals yesterday and good news is I got a perfect score on the algorithm final! Yayyy. For this summer I plan to learn more about iOS and building projects with PHP, Swift and maybe a little Javascript. My friend told me modern websites are mainly written with Javascript so I want to learn about that.

It’s been a while

Yes it has been a long time without a post on here. To be honest I spent most of my spare time on League of Legends. This evil game…

It’s almost the end of the semester and I still have three finals left. Other than school, I learned some php, some Node and also a little bit iOS and Watch OS. I built this blog post system using php and am still updating it. I plan to introduce following features: editing posts if logged in, adding timestamp and author info, and display posts in separate pages. These will take some time but it will also be fun along the way!

I also ordered an Apple watch a couple of days ago. Hope that I can build some interesting apps with it! Maybe I’ll build a watch version app for Duke CSA, but it will be hard for sure.

There’s always so much to learn and so little time.

Python server with Flask

With Flask and SQLAlchemy I talked about in the last post, I was able to implement a python server. It is able to show a list of restaurants in the main page. Clicking on restaurant names show their menu, and each menu item can be edited or deleted. Users can also create new menu items. The database uses SQLAlchemy, and url resolving and HTTP requests handling use Flask, a microframework that makes implementations of web servers very easy.

The link to the project on GitHub is here.

With flask, resolving url addresses is simply app.route('format'), and under this line declare the method for this address. Here is an example:

This means whenever the address fits the format host/restaurants/int, the method restaurantMenu will be executed. restaurant_id is a variable extracted from the url and passed in the method as a parameter. Whatever this method returns shows up on the webpage. In this case, the method is returning the result of render_templaterender_template is a method in Flask that looks for the template specified in the first parameter in /templates and pass in necessary variables. menu.html looks like this:Screen Shot 2016-01-13 at 9.40.55 AM

items is the variable passed in this template. Here html execution arguments are used.

url_for is another tool used in this project. It is also included in Flask. The first parameter is the handler method of the product url, and other parameters are variables passed.

The next step is for methods to handle both GET and POST HTTP methods. Here’s how to do it:

methods need to be put in @app.route. Of course, request class also needs to be imported from Flask. Handling different kinds of methods is virtually the same as handling one. It’s only one if statement away.

Finally, for the server to repond to requests with JSON object, objects in the database need to have a function that returns all of their information.

In object class of the database setup python file:

And then use jsonify class provided by Flask to return json:
return jsonify(MenuItem = menuItem.serialize)
The json can then be used by any kind of application!

As a next step of this project, I plan to implement a server that works with iOS applications. I may need to write a framework for Swift to talk with my server. This means a lot of work, but it has great potential!

I’ll just forget about the fact that I have a midterm 30 minutes later and one more tomorrow.

Progress of Wheeshare

Wheeshare has finally achieved all of its necessary functionalities. Before it could provide functions such as request, approve request and lend, but it was impossible for user to “step back” from the relationships with cancel request or re-lend item. Now users are able to cancel their requests and owners of items can re-lend their stuff once they have them back from the last borrowers. Besides this breaking relationship improvement, users can now view the status of their items in the main table view, such as “lended to Bill” or “requested by Jason”.

The logic of the relationship is pretty efficient. I used a little bit of binary spirit while designing it. Each item has three variables relevant to the borrow-lend relationship: giver, requester, and connected. Among these three, giver and requester are of type PFUser (user class written by Parse, which tragically is going to close in one year, fml), and connected is a Bool. Giver for an item is the owner and cannot be changed for the lifespan of the item. Whenever a user requests an item, the requester variable of the item will be given the value of this user. Connected means if the relationship is successfully built. If the owner presses “approve request”, connected will be changed to true.

Therefore, two free variables produce three possible outcomes:

  1. requester is not null and connected is false. The item is currently available and no one has requested.
  2. requester is someone and connected is false. The item is requested but not approved yet.
  3. requester is someone and connected is true. The item is in a borrow-lend relationship.

requester is null && connected is true cannot happen because that doesn’t make any sense.

As for deleting the items, owners are not allowed to delete their items on the platform if the items are requested or in a relationship. They are prompted to take care of the requests.

Things to do: improve UI HARD. If I knew I would be developing iOS apps, I would have gone to some art clubs back in high school. Switch to another online database or write one by myself with php and SQL. The latter would be challenging but also very rewarding.

The other day I discovered an app called PartiO, which aims at exactly the same thing as my app – let students share their stuff. The only difference is that they let people share with profits. I have already contacted them and wish to help them improve the product. Hopefully we will achieve something together.

OK these last two paragraphs just made me add “Babbles” to the category of this post.

Thoughts about building an SMS system

What a sunny day. Yesterday I decided to take one more class – Math221 to discover the possibility of math majoring. I don’t know if it’s possible for me to triple major in CS, ECE and math but we’ll see.

Recently I’ve been thinking how I can improve my Wheeshare app. I believe protecting user privacy should be of high priority, so the app could be better with a built-in SMS system like Taobao’s Aliwangwang or WeChat. However building such thing is no easy – from the data structure of chats to UI design to speed enhancement. No one wants a chat screen that lags. I have to think of an efficient architecture. If everything goes perfectly, I will upload the project to GitHub for others to use.

For the chat screen, I plan to use a UITableView to hold every chat message, with user thumbnail profile picture on each side. I will make a NIB file for the chat bubble and add a UILabel in it to display chat. One technical challenge would be how to update messages if the user received a new one. I will look into Parse API documentation to look for a notification API so that my app can observe the database on the user’s phone.

As for the general structure, I would like to create and store an object for each pair of users (if they started chatting, of course) and label it with two users’ IDs. When the app inits it tries to retrieve chats from online database with the current user ID. Inside each object I store an array of chat messages, each labeled with its sender.

Another technical challenge: how to cache all messages locally? For now, my tentative solution is to use CoreData so that I can directly push any updated chat object into the Core Data Stack. It sounds so simple right now but I am 100% sure it will give me a headache when I try to implement it.

One other problem to think about is whether to keep the connection between two users after they ended their relationship as borrower/lender. Again this is a privacy issue that I need to think about.

Other than this SMS system plan, I need to somehow restrict the app’s area. I probably need to get users’ locations and limit the access to Duke University for now to prevent possible malicious data attack. Thank you for watching, that’s it for today.

Paging view with control

Before talking about boring(no it’s absolutely not) programming, some babbles about my life. I’m going back to America tomorrow and will arrive at midnight. Let’s hope I won’t get much jet lag. As for the semester, I kind of need to learn to drive and get a license so life won’t suck. I’m taking a pretty hard algorithm class and at the same time having two jobs so wish me luck!

In the project StoreSearch, I used scroll view and UIPageControl to implement a paging view with control once, but what did I know I just mindlessly followed the detailed tutorial. Thankfully, I used the money granted by Duke CoLab to subscribe for online tutorials on Ray Wenderlich’s website and learned again about paging view there.

There are two ways to do this: one is using UIScrollView and set constraints on pages manually, the other is taking advantage of UIPageViewController and have things set up. I personally prefer the former because it’s more customizable, so selfishly I’ll write about that here.

First, we should have a view controller set up. This controller takes care of each page in our paging view. Then in the initial view controller put in a UIScrollViewController and set proper constraints.

Screen Shot 2016-01-09 at 8.20.46 PM

Next we accomplish paging through the following steps:

  1. set pagingEnabled to true:
    scrollView.pagingEnabled = true
  2. keep view controllers in a dictionary so that we can set constraints later:
    pages = [page1, page2, page3, page4, page5]
            let views = ["view": view, "page1": page1.view, "page2": page2.view, "page3": page3.view, "page4": page4.view, "page5": page5.view]
    /*"pageX" means the Xth view controller.*/
  3. set constraints on views:
    let metrics = ["edgeMargin": 10, "betweenMargin": 20]
    let verticalConstraints = NSLayoutConstraint.constraintsWithVisualFormat("V:|[page1(==view)]|", options: [], metrics: nil, views: views)
    let horizontalConstraints =
        NSLayoutConstraint.constraintsWithVisualFormat("H:|-edgeMargin-[page1(==view)]-betweenMargin-[page2(==view)]-betweenMargin-[page3(==view)]-betweenMargin-[page4(==view)]-betweenMargin-[page5(==view)]-edgeMargin-|", options: [.AlignAllTop, .AlignAllBottom], metrics: metrics, views: views)

Oh, before all these remember to set the view controllers for each page not to autoresize:

view.translatesAutoresizingMaskIntoConstraints = false

And voila we have a nice looking five pages view.

To add a page control, first add it in storyboard and set proper constraints and outlet:

Screen Shot 2016-01-09 at 8.21.30 PM

Then follow the steps below:

  1. set its number of pages:
    pageControl.numberOfPages = pages.count
  2. show the correct current page. We need to round the value of offset.x/width because we would like it to show the correct page when we are in between pages:
    extension TutorialViewController: UIScrollViewDelegate {
        func scrollViewDidScroll(scrollView: UIScrollView) {
            let pageWidth = CGRectGetWidth(scrollView.bounds)
            let pageFraction = scrollView.contentOffset.x / pageWidth
            pageControl.currentPage = Int(round(pageFraction))
  3. control the change of page with an action outlet:
    @IBAction func pageChanged(sender: AnyObject) {
            let currentPage = sender.currentPage
            let pageWidth = CGRectGetWidth(scrollView.bounds)
            let targetContentOffsetX = CGFloat(currentPage) * pageWidth
            UIView.animateWithDuration(0.33, delay: 0,
                options: .CurveEaseInOut, animations: { () -&gt; Void in
                    self.scrollView.contentOffset.x = targetContentOffsetX
                }, completion: nil)

    Here we’re using a cute little animation.

And there we go! Paging view with control. I uploaded the code to GitHub in case I need the template in future development. If one intends to use it be aware of its license.