Raspberry Pi as a toy web server

1. Tell my router to route certain traffic to the Raspberry Pi. For example, I route HTTP and SSH traffic to one of my Pi’s. I disabled password login for  SSH, using public key authentication instead: in /etc/ssh/sshd_config, use the following setting and restart SSH service using `sudo service ssh restart’.

2. Getting my IP address of the Raspberry Pi. I firstly created a PHP script on my domain to record the IP address in a text file.

Then tell the Raspberry Pi to report its IP address every 5 minutes, using crontab:

After a while the IP address is recorded in the text file and updated every 5 minutes.

3. Optionally create a DNS record for the Pi. I use Cloudflare to manage DNS settings by myself, so just add/update an entry in Cloudflare’s settings. I point pi.daoyuan.li to the IP address of one Pi. This can be done automatically in the future.

4. Install Flask on the Pi.

5. Install nginx and uwsgi on the Pi.

6. Set up nginx along with uwsgi and Flask.

Edit nginx config:

Edit uwsgi config:

Create a simple Flask app:

Start up uwsgi:

7. Done! http://pi.daoyuan.li:5000/

 Update on June 24, 2014:

Getting the external address in step 2 can be done by running this command in Raspberry Pi:

See: http://www.commandlinefu.com/commands/view/5427/get-your-external-ip-address

NumPy’s ndarray indexing

In NumPy a new kind of array is provided: n-dimensional array or ndarray. It’s usually fixed-sized and accepts items of the same type and size. For example, to define a 2×3 matrix:

When indexing ndarray, it supports “array indexing” other than single element indexing.  (See http://docs.scipy.org/doc/numpy/user/basics.indexing.html)

It is possible to index arrays with other arrays for the purposes of selecting lists of values out of arrays into new arrays. There are two different ways of accomplishing this. One uses one or more arrays of index values. The other involves giving a boolean array of the proper shape to indicate the values to be selected. Index arrays are a very powerful tool that allow one to avoid looping over individual elements in arrays and thus greatly improve performance.

So you basically can do the following:

Besides, when you do equals operation on ndarrays, another ndarray is returned by comparing each element:

mod_wsgi and mod_xsendfile on OS X 10.9 Mavericks

Updated on Nov 4, 2013: The following tricks may still work, however I have found a much easier solution. Simply install Xcode command line developer tools and you should be able to compile source code without issues:

After upgrading my Mac from 10.8 to 10.9 Mavericks my apache stopped working, so I have to reinstall mod_wsgi and mod_xsendfile. However, tricks are needed to compile and install these mods successfully.

Upgrade Xcode

Upgrade Xcode in App Store. As mentioned by Valerie:

I had to manually upgrade Xcode (after Mavericks upgrade) from the App Store & agree to its license because ./configure hung forever until I did that.


For mod_wsgi installation, create a soft link to OSX10.9.xctoolchain:

Then run configure under mod_wsgi source code directory:

It will generate a Makefile similar as follows:

However, this Makefile is not correct and running ‘make’ the compiler will complain something like:

Prepend the following line to CPPFLAGS value:

Save the Makefile and it will look something like:

Then make && install:

Modify /etc/apache2/httpd.conf to enable mod_wsgi:


Use the following command to compile and install mod_xsendfile:

Enabling HTTPS/SSL

After upgrading OS X the apache configuration was reset, but your original config is save to /etc/apache2/httpd.conf.pre-update. I need to enable SSL in httpd.conf again by uncommenting the following line:

Restart Apache and everything should work fine

Upgrading Tastypie from v0.9.11 to v0.9.12 and above

Here are my notes on how to upgrade Tastypie from version 0.9.11 to 0.9.12, as there’re no release notes for v0.9.12. Release notes for 0.9.13 and above are available here: http://django-tastypie.readthedocs.org/en/latest/release_notes/index.html.

1. override_urls() becomes prepend_urls(), the new name makes more sense since what the function does is to insert customized urls instead of replacing the default urls with your customized urls.

2. obj_* methods accepts different parameters. Before:

Now obj_get, obj_create, etc. accepts bundle as the parameter apart from keyword arguments. You can get request object from the bundle:

3. apply_authorization_limits is no longer in use and it’s replace with a finer grained authorization mechanism. For example:

Please note that *_list methods should return a list or raise exceptions; whereas *_detail methods should return boolean values or raise exceptions. For more information, see: http://django-tastypie.readthedocs.org/en/v0.9.12/authorization.html

Hi, the company I’m working for (yabroad.com) is hiring Website Backend and Frontend Developers to our platform team. We are building an open platform for youngsters to travel beyond boarders and we offer youngsters internship, language study, travel and volunteer opportunities. Please contact me if you are interested.

Installing mod_xsendfile on OS X Lion

First download mod_xsendfile.c from https://tn123.org/mod_xsendfile/

Then compile and install it:

Add the following line to /etc/apache2/httpd.conf at the end of the first block of “Load” statements:

At last, restart the apache server

Hi, the company I’m working for (yabroad.com) is hiring Website Backend and Frontend Developers to our platform team. We are building an open platform for youngsters to travel beyond boarders and we offer youngsters internship, language study, travel and volunteer opportunities. Please contact me if you are interested.

Giving name to a Finnish baby

Today was a good day, thanks to the following things:

  1. It was nice to talk with a colleague from Ericsson Beijing. I got to know what’s going on in China through someone else’s eyes. Also I know how it looks to work in Beijing and how a different job may feel like. She said working in Operations is quite stressful and may require a lot of night shifts, which is not good for anyone’s health. One of her colleagues in Japan had worked night shifts continuously for 90 days… I feel lucky to work in a job that is less likely to cause health problems, although sometimes I do want a bit more pressure.
  2. During lunch we were chatting and one topic came out when discussing giving names to babies. It turns out that Finns give names to their babies secretly for the first three month after the baby is born. That’s probably due to religious reasons, i.e., the devils can not claim the baby if it doesn’t bear a name. It’s also funny that Finns wait until the baby is born to give it a name, simply because they want to make sure the baby’s image matches the name. Hmm, how can you possibly do that? How do you know how “Jussi” should look like? Well, Finns simply do.
  3. I succeeded to revert my Galaxy Tab back to stock version, there wasn’t any noticeable damage to it. It’s nice to have a working tablet that a brick.
  4. I got a clearer view of the short-term goal of the project I’m currently working on.
  5. There are a lot of spam comments in my website, luckily the Akismet plugin successfully blocked all of them. Akismet is free of charge and it works like magic.
  6. Yesterday I managed to update my WordPress Responsive Theme to the latest version, and managed to fix the “number of comments title wrongly aligned” issue.

Migrating JComments to WordPress

I switched back to WordPress from Joomla! after I registered this new domain. After migrated all the posts to WordPress using FG Joomla to WordPress, I noticed the comments have not been transferred. After some digging I didn’t find satisfactory plugin to do that, so I wrote my own PHP script to fulfill this task. The code is also available from GitHub.






Multiple Sessions

A linked list of all RUDP sockets is maintained. When rudp_socket() is called, an RUDP socket is created and added to the linked list. An RUDP socket keeps a record of the pees/sessions it talks with. When RUDP receives a packet from an unknown socket address, or when RUDP receives a send packet request to an unknown socket address, a new session is created. And for each session, a linked list of all buffered packets is kept.

Session Establishment and Tearing Down

When rudp_sendto() is called, the protocol first check if there exists a session between the sender and receiver. If not, the protocol will try to setup a session by sending RUDP_SYN messages. And the packet the application wants to send will be buffered in the created session. After an RUDP_ACK message is received, the server side socket start sending out packets. Go back N protocol is used to control the sending process. After the protocol receives a rudp_close() signal, it will first check whether there are still active sessions and packets in the sending buffer. If not, the protocol will send out RUDP_FIN messages and after receiving RUDP_ACKs, the session is torn down.

CrazyBus Launch Script


Collage is a little game that let users to rearrange pictures according to the given order. The main logic is as follows:


Oracle VPD策略实现行级安全性

VPD 即Virtual Private Databases,提供了对数据库的精密访问控制 (graind access control (FGAC) ),使用VPD,可以在数据记录集定义用户的访问权限。

通过VPD 策略,相当于用户操作数据库中的数据时隐式添加一些条件。比如我们要实现特定角色只能操作数据库表中的特定行的数据,这就可以用 VPD 策略实现。现在以车队长只能操作员工表中的属于他的车队的员工的数据信息为例具体说明:

1. 构造策略函数:

2. 授予执行策略函数的权限:

3. 向数据库表添加策略:


现在,如果你以admin身份登录执行 ‘SELECT * FROM EMP’ , 则实际执行的是 ‘SELECT * FROM EMP WHERE 1 = 1’ , 其中 ‘1 = 1’ 这个条件是策略函数的返回值;如果你以其他身份登录执行 ‘SELECT * FROM EMP’ , 则实际执行的是 ‘SELECT * FROM EMP WHERE 1 = 2’ 。