Generate https cert

sudo apt-get update
sudo apt-get install -y software-properties-common
sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install -y python-certbot-nginx
Then get a certificate `sudo certbot --nginx certonly`

Now edit the nginx config to add the fullchain.pem and privkey.pem paths.

sudo vim /etc/nginx/sites-enabled/default

Add lines 22-25.

server {
20 # SSL configuration
21 #
22 listen 443 ssl default_server;
23 listen [::]:443 ssl default_server;
24 ssl_certificate_key /etc/letsencrypt/live/;
25 ssl_certificate /etc/letsencrypt/live/;

Four coloring for large software

"In mathematics, the four colour theorem, or the four colour map theorem, states that, given any separation of a plane into contiguous regions, producing a figure called a map, no more than four colour are required to colour the regions of the map so that no two adjacent regions have the same colour." -- Wikipedia

"A codebase composed of small interconnected modules that communicate with each other in a well-defined way will have a lower complexity than one where the modules communicate with each other haphazardly." -

How to recover locked out AWS EC2 ssh machine

One time I accidentally messed with the `/etc/passwd` and locked myself out of being able to SSH into the machine. Since this is a remote machine in AWS I had no way of doing what I'd normally do. Which is attaching a keyboard and monitor and fixing this manually.

To fix, use the AWS EC2 Management page to:
- spin up a new instance of vanilla ubuntu EC2 (let's call it David)
- shutdown the locked machine (let's call it Goliath)
- unmount Goliath's volume
- attach the volume to David

Then follow this guide:

Summary of what I did from this guide:
sudo file -s /dev/xvdf # MBR (not data type)
sudo file -s /dev/xvdf1 # ext4
sudo mkdir mount_folder
sudo mount /dev/xvdf1 mount_folder # ext4 mounted
cd mount_folder
# undo crazy setting (see Note #1)
cd .. # to unmount
sudo umount /dev/xvdf1
# Note #2

Note #1: For me I tried to modify `/etc/ssh/sshd_config` to allow one more user to login. But this made me unable to login after. So I removed the offending line.

Note #2: now in the Volume webpage
- undo attach to David (Volumes tab)
- mount to Goliath (Volumes tab: attach as EBS path /dev/sda1)
- boot up Goliath (Instance tab)

Black Friday PC Building


TRUE,Cooler Master MasterLiquid Lite 240mm Liquid Cooling,$42.89
TRUE,Intel i7 7700 CPU,$269.36
TRUE,ASRock Z270 KILLER SLI/AC Z270 Motherboard,$128.69
FALSE,Mobo MIR,-$30.00
TRUE,"EVGA SuperNOVA 1000 G2, 80+ GOLD 1000W, Fully Modular",$118.51
TRUE,Thermaltake Core G21 Dual 4mm Tempered Two-Toned Glass Power Cover ATX Black Gaming Computer Case ,$64.34
FALSE,Case MIR,-$20.00
TRUE,Crucial Technology 32GB (2x 16GB),$259.99
TRUE,ZOTAC GeForce GTX 1060 6GB Mini,$267.89
TRUE,Toshiba Solid State Drive PCIe NVMe M.2 512GB,$247.90
TRUE,Windows 10 Home,$92.99
TRUE,Oculus Rift Headset,$679.99
TRUE,Oculus Touch Controller,$99.99


SLAM is simultaneous localization and mapping; the goal is to build/update a map while simultaneously keeping track of location within.

In other words, SLAM takes sensory data as input (such as camera, lidar, ultrasound) and outputs a partial map and location within.

A popular open source framework is called ORB SLAM. This is fast, robust, and efficient.


I'll summarize my findings here.

There are three papers you can read that describes how it works. You should read them in order, because the ideas build on each other (1-2) and (3) describe improvements made.

1. Bag of Binary Words
2. ORB-SLAM paper
3. ORB-SLAM2 paper

I'm not much of an expert in this field, so I'll try to explain in layman's terms of how I understand it. Here are essence of what you need to know.

  • Sensory data are a stream, but it can be discretized, such as a video stream.
    • Discrete means to represent a real space using a discrete quantities.
  • Videos are sequences of images.
  • In an image, there are points that can be easily identified and tracked across images.
  • These points can be identified by an algorithm called Bag of Words (read 1).
    • A picture is like a paragraph, it can be described by visual words.
    • Visual words are small images that represent like noses, eyes, mouth.
    • With enough words, you can guess what objects you're looking at, and from what angle.
    • For example, if you had two eyes and a nose, you would guess a face.
    • And if the two eyes are much bigger than the nose, you're likely looking downward angle to the face.
  • Bag of Binary Words improve performances of the Bag of Words (BoW) model.
  • The ORB-SLAM system uses the BoW model to build a database.
    • Database stores BoW features that represent an image.
      • Meaning the image was converted into BoW features.
    • These features are used as an index into a location map.
  • From an image and a location, a Key Frame can be created.
    • Key Frames are an association container, which can represent a mapping of BoW features into a frame in location space, and vice versa.
  • Using these BoW features, and sensor calibration data, a location is triangulated from mathematical calculation.
  • Many of these Key Frames are linked together.
    • You can think of Key Frames being a vertex in a graph, and an edge represent co-visibility.
      • That is, the BoW feature is visible from the other Key Frame as well.
    • This graph is called a covisibility graph.
    • Which represents a map.
  • Having this graph aids in knowing when to insert a new Key Frame into the database.
    • For example, when two Key Frames have less than 75% common BoW features.
  • When given an image, the database is asked to return a list of plausible locations.
    • The image is converted into BoW feature.
    • This feature is used to search the covisibility graph to find similar Key Frames.
    • Returns a list of Key Frames with statistical likelihood to represent which Key Frames contains the most matched BoW features.
    • The covisibility graph reduces search complexity, therefore speeding up search, and also reduces storage needs.
  • So now a map is being built at the same time it is localized.
    • SLAM.
  • In the future, we can come back with more data to:
    • Improve the map.
    • Ask the database for a localization result.

That's all folks. I'll add some pictures later.

Here's a video.


Tools I'm loving now

Clion (actually you do not need to purchase a license if you use the EAP (Early Access Program) license. Downside is you have to download a new one each month. But it'll be free to use for 1 month, and you don't have to pay $199 USD per year.

Slam mono
Fish Shell

Websocket Socketio Rant

Websocket Socketio Rant

I learned that websocket is not the same as While this may seem obvious in hindsight, I wasn't aware I was using until I spent a long time trying to figure out why I couldn't use websocket (ws://) protocol to connect to my (http://) server, which used to handle websocket connections. is built on top of the websocket protocol, but also supports old, non-websocket-supporting browsers. I was setting up a simple Python Flask webserver, and was using Flask Socketio. I thought they were one and the same.

Another thing I found is, as of now (Sept 2017), there are poor support for python clients. Of about the only two python packages I found to handle socketio, there seems to be many inconsistencies in the library function and I couldn't predict the behaviour of what it was supposed to do. After many hours of fussing about, I switched to C++ socketio library (sio_client.h). And it works very well, I got it to work quickly.

Swapping Macbook Pro SSD

Yes. You can upgrade to a newer MacBook Pro by just swapping the SSD. I looked around the webs and couldn't find whether it was feasible, so I just did it.

I had a Late-2013 MBP and a Mid-2015 MBP. Both are same in every aspect, except (1) GPU, (2) TrackPad, (3) Keyboard, (4) Battery.

  1. New AMD Radeon R9 M370X vs. older Nvidia GeForce GT 750M. Both discreet GPU performs well. Nvidia has a faster clock but AMD has slightly better benchmarks.
  2. New TrackPad had Force Touch. This means I didn't need to keep two fingers to press; one to aim, one to click the bottom.
  3. New Keyboard feels more responsive, more rubbery, less force needed to push. This slight difference can only be felt when gotten used to the older one.
  4. New Battery is a big issue for me. I had close to 500 cycles on the old laptop, and this new one has like 20.

I opened both and swapped their SSDs. To open Apple's proprietary screws require a Pentalobe P5 (1.2mm), and a Torx T5 (or was it T4?).

Both booted as normal. Not much difference in hardware. I did it for science and curiosity. Plus I could air blast the dust out of the vents.

I was signed out of iCloud and other email accounts. Safari and Chrome extensions were lost. Safari extension LastPass was already logged in when I reinstalled, and Chrome too.

Nginx hosting multiple domains with a single SSL certificate from Let's Encrypt


Multiple domains can be hosted with nginx server blocks. Below I give an example of how to generate a shared SSL certificate from Let's Encrypt, and how to setup two server blocks to use a shared SSL certificate.

Assuming you use Let's Encrypt as your CA authority, generate a SSL certificate for the domains:

sudo letsencrypt certonly -a webroot --webroot-path=/var/www/default/html/ -d -d

Alternatively, if your not using Let's Encrypt as your CA, read up the docs take a pause to note:

The SSL certificate needs to contain several names, in the SubjectAltName certificate field, for example, you might want to have and domains. Note the SubjectAltName field length is limited, to about 1000 characters IIRC.

Now I assume you have the SSL certificate generated.

Update the two server blocks /etc/nginx/sites-available/ and /etc/nginx/sites-available/ accordingly. A /etc/nginx/sites-available/default is not need. See the diff:

server {                                                        server {
  listen 80;                                                      listen 80;
  listen [::]:80;                                                 listen [::]:80;
  server_name;                                    |   server_name;
  return 301 https://$server_name$request_uri;                    return 301 https://$server_name$request_uri;
}                                                               }
server {                                                        server {
  server_name;                                    |   server_name;
  listen 443 ssl http2;                                           listen 443 ssl http2;
  listen [::]:443 ssl http2;                                      listen [::]:443 ssl http2;

  ssl_certificate /etc/letsencrypt/live/default/fullchain.pem     ssl_certificate /etc/letsencrypt/live/default/fullchain.pem
  ssl_certificate_key /etc/letsencrypt/live/default/privkey.p     ssl_certificate_key /etc/letsencrypt/live/default/privkey.p
  include snippets/ssl-params.conf;                               include snippets/ssl-params.conf;

  root /var/www/;                             |   root /var/www/;
  index index.php                                                 index index.php 
  location / {                                                    location / {
    try_files $uri $uri/ /index.html =404;                          try_files $uri $uri/ /index.html =404;
    autoindex on;                                                   autoindex on;
  }                                                               }
  location ~ /.well-known {                                       location ~ /.well-known {
    allow all;                                                      allow all;
  }                                                               }
  location ~ \.php$ {                                             location ~ \.php$ {
    include snippets/fastcgi-php.conf;                              include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/var/run/php5-fpm.sock;                       fastcgi_pass unix:/var/run/php5-fpm.sock;
  }                                                               }
}                                                               }

Note the folder that contains the SSL certificates /etc/letsencrypt/live/default/. You may need rename the folders that letsencrypt generated.

Additional references:


Lessons from Real-Time Programming class

Lessons from Real-Time Programming class

This post is about lessons I learnt in CS452 Real-Time Programming, a 4th year undergraduate class at the University of Waterloo. Better known as “trains” or “realtime” class.

“Easy stuff! You play with trains all day (literally, maybe even night). All you need to do is write one simple program to control multiple trains so they don’t crash!”

— chko on

The trains lab. Room 3018, 3rd floor Math & Computer building.

The class is a bit unconventional because it indirectly teaches other topics, like time management and teamwork, by providing a large amount of work — so that you have to learn these skills. I’ll talk about these lessons, hoping to address a more general audience.


This class has been around since at least the 80’s. Currently Bill Cowanteaches this class, and has been for over 20 years.

The equipment have evolved since then, but the underlying challenges have not.

For example, teamwork, setting priorities, and dealing with real (imperfect) systems.

Prof. Bill Cowan explains the why sensor pickup sometimes have trouble detecting slow moving trains. The gap between the contact points may cause the pickup switch to flip twice.

The early version of the QNX real-time operating system took off from a pair of students taking this class, Gordon Bell and Dan Dodge. They decided to expand the class project into a full-fledged commercial RTOS (real time operating system).

“You should try to find a partner for this class, it’ll be hard without one. Generally I’ve seen two outcomes:
(1) you become friends with your partner, or
(2) you stop being friends and hate each other.
I recommend not starting with a partner who is your friend, because you are already friends. Don’t risk it.”

— Prof. Bill Cowan


About 65% of the class involves building a small embedded kernel, with the other 35% working on the train management application.

You can choose to program in whatever language you want, because there aren’t any standard libraries provided. People generally program in C, because it’s known as a systems language, and the programming examples given in class. But there’s no reason why you can’t do it in Rust language, for example — although godspeed, you’re venturing into uncharted territory!

The kernel runs on a TS-7200 embedded system, and it talks to a Märklin Train System over RS232 type serial. The firmware is loaded on via RedBoot, a bootstrap environment for embedded systems.

The Märklin Train System. You can see the center console where the RS232 is attached. Off to the right is the grey box that houses the TS-7200.

The final exam is a take home 24 hour long exam, where you can use any resources you want, and you only need to do 3 of the 5 questions. The assignments and kernel make up 70% of the grade.

Optional Technical Info

The microkernel did very little; it

  • only kickstarts a couple of initial processes.
  • handled message passing between processes.
  • provided very basic interrupt handler and clock.
  • supports realtime operations; the scheduler is predictable (through priorities, and pre-emption).
  • avoided disk IO by loading kernel and programs into RAM directly.
  • needed to provide serial output to a PC terminal, to display graphics relating to the real-time actions being controlled, such as displaying position of trains on the track showing movement.

The realtime program is probably more work than the kernel. Because initially there were many constraints, but later on, assignments were of more guidelines than objectives.


I’ll talk about some of the lessons I learnt, and provide some reasoning or backstory to them.

Don’t trust anything. Don’t make any assumptions.

One assumption that was made was while building a acceleration and deceleration profile for the train — that the train would stop where we expected to. Calibration was done by running the train at full speed around the tracks, and when it hits a sensor, tell it to stop.

That assumption turned out false: at max speed, the train varies its stopping distance quite a bit, up to ±3 cm. Not only that, the train accelerates and decelerates non-linearly!

Real systems are often imprecise. For example, look at the stopping distance of a train. In our experiments, it never stops in the same place — for a variety of reasons: such as buffering, interrupt handling, incorrect system timing.

This meant that over the course of several start and stop move commands, there can accumulate quite a difference between where you think the train is, and where it actually is.

Consequently, our model couldn’t be trusted. We’d assume it was safe to perform a certain operation, and it of course, wouldn’t be. And that causes accidents like multi-track drifting to occur.

Multi-track drifting. Happens when a track switch flips direction while the train has yet to clear both axles.

Multi-track drifting is when you thought it was safe to flip a switch, and then it wasn’t. The poor train comes to a sudden stop because the front axles and rear axles are going to different directions.

When your model of the world and the real world itself are different, you get problems. We couldn’t trust our model. We’d assume it was safe to perform a certain operation, thinking we knew where the train was, and it wasn’t safe.

This explains the comic that is pasted on the walls beside the train set. Now I get it!

A printed out version of this comic was taped to the wall beside the train tracks. The original multi-track drifting.

If this was a real train, this would result it some serious accidents. A lesson we learnt after trying to figure out how this happened.

Assumptions are going to be wrong! So it’s important to build in error correction and recovery.

Often assumptions are wrong, or become wrong during the course of real life usage. Real systems don’t always run in your ideal situations. You can’t always think of all the edge-cases. Errors are going to happen. Your best chance is to try to realize the error as early as possible and correct for it.

Instead of eagerly switching tracks for the next train, we switched tracks only if the train had ownership of the track.

Map of the train switches and segments. We had two tracks, A and B, and they have different configurations. We hard coded the map to build the train track reservation system.

To solve this, we ended up building in margin of error around where we think the train is, assigned the train to have ownership to tracks, and made sure when trains approach tracks that they didn’t own, it would stop.

You are as only good as your tools.

Building the path/route finding portion of the project, we were manually reading a map and trying to reason about what the shortest ways were. This took a long time, and felt complicated.

Route a train from point A to point B was not difficult, but factoring in what paths are currently, or will be, blocked by other trains made it harder. We often stared at the layout map for a long time, trying to figure out whether this was the quickest path through this or not.

This is the track layout map. It’s easy to find the shortest path visually, for one train. Now try imagine putting more trains on here. After two trains, becomes pretty difficult. Trains probably need to negotiate with each other, and it’s not enough to try to all take the shortest path.

After staring at this for a long time, and it was clear that reading a map like felt a lot of work. Time to make our life easier.

This map contains the same information as the track layout map, but represented as a tree. This way, we can easily figure out what were shortest paths by counting the least number of moves. This tree factored in backwards movements as well. Because point A and point B may be most easily reached by reversing direction.

This tree map didn’t take much more effort, it was generated by GraphViz in the Dot language.

Tools empower you to be more productive. As a programmer, you’re always thinking about how to make things automated, and easier. A commonly seen trait that programmers have is to be lazy, a desire to automate things and make their own lives easier. Determine how much time you spent doing some work, and see if you can build a tool to make it easier.

Invest in building better tools when you find yourself repeating a task, as a rule of thumb, more than three times.

It’s ok to take on technical debt. Keep it simple, stupid.™

For example, having fancy colorful terminals. Ours was initially very pretty, but we noticed a lot of things had to be changed. Towards the end of the projects, we had avoided building fancy graphics because they took a lot of work and are likely to be changed later.

If you wanted to have pretty looking terminals, lot of time had to be dedicated for it. If you’re really bored, and have time to kill, I suppose it’s fine.

Our colorful terminal. It was all pretty, initially. Later on, we couldn’t afford much time to make things look good.

Later on, we took on more technical debts with screen drawing. It no longer looked as nice, but it worked.

If there are technical debts with higher priority, they should be addressed before diving into a lesser problem.

This sounds intuitive, but sometimes people become irrational and just spend time on low priority issues. Like making things look pretty.

Pair programming is effective teamworking.

Initially we dividing up projects, and mostly worked separately. This was okay for well-defined problems, as it was the case for initial kernel implementation. But later on, the problems we needed to solve became so inter-dependent that it was no longer feasible to build something in the dark.

Many quick idea iterations were needed, and we needed each other to bounce ideas around. Having a comfy couch is important!

And towards the end, we were doing pair programming out of despair; we had to write working code, and we had to write it fast.

Pair programming produces quality code that is better thought out, and a rate that is comparable, if not faster, to separating out tasks and doing code reviews.


I think taking this class was very valuable, and was a very nice way to wrap up my Computer Science undergrad.

These lessons are ingrained in my memories, and helped shape my behavior.

For example, after pair programming, I subconsciously debate about solutions to problems and bounce ideas around. To an outsider, it may seem argumentative, but it’s really an effective way to solve problems.

Thank you for reading.