Skip to content →

Author: Daoyuan Li

The plethora of opportunities

For most of us, we live in a society with abundant resources: delicious food to taste, delicate clothes to put on, various activities to attend to, wonderful places to visit and numerous things to do. Yet, all these abundance are not necessarily good for us: we’re getting distracted to the extend that we don’t know what exactly we’re chasing for.

Some people say we are getting superficial — that we are trying endlessly from one thing to another and shortly getting tired of each of them. But this superficialness doesn’t come from nothing. We’re superficial not because there exist many temptations, instead, we’re not able to resist these temptations that trick us into thinking about illusions and trajectories of ourselves. We try to find life meanings by doing things but often end up in vain, maybe the right way to go is not finding meanings: maybe it’s the other way round. How we do things and live our lives is simply the meaning.

The meaning of a nomad’s life is traveling and not settling anywhere. The life meaning of a adventurer is adventure. A person focusing constantly on something becomes an expert.

Opportunities are always there, but we are not. It’s not an opportunity without the capability of taking advantage of it, be it the accumulation of prior experiences or fast learning and adapting abilities.

Indeed there are too many opportunities, however, one does not need thousands of opportunities to succeed. One is enough. Prepare for it, focus on it, reach for it before it comes to you and let it work for you.

Leave a Comment

Migrating/Installing Prestashop to Amazon AWS EC2

Recently I migrated a Prestashop website to AWS/EC2 and the process is quite smooth. Here’s how to do it.

1. Get your Website data: including Prestashop website files and a latest database dump. Remove all the files except index.php in /cache/smarty/compile and /cache/smarty/cache. (See here.)

2. Launch your EC2 instance. But before doing that, check first if a pre-configured or managed Prestashop is available in your preferred region (more info here). If not, choose the appropriate instance type and get it running. In my case I chose Ubuntu Linux.

3. Install the AMP (Apache, MySQL and PHP). On Ubuntu you can simply do it with a few simple commands:

sudo apt-get update
sudo apt-get upgrade
sudo tasksel install lamp-server
sudo apt-get install phpmyadmin

Make sure that you remember your password for MySQL root user and phpmyadmin user.

4. Copy your database dump and website files to your EC2 instance using scp, for instance:

scp -i you-key.pem files.tar.gz ubuntu@your-ec2-instance.compute.amazonaws.com

5. Create a MySQL user for Prestashop, you don’t want to use the root user for this purpose. You can do this using phpmyadmin or a command line. Also, create a database for Prestashop and grant the user you’ve created just now all privileges on this database.

6. Import your database from the dump:

mysql -u root -p ps < db_dump.sql

7. Extract your website files on your EC2 instance. In my case, inside /var/www/html/. If there is an index.html file inside this directory, remove it first. Make sure you set the correct user and group to all the website files:

sudo chown -R www-data:www-data *
sudo chmod -R 755 *

Note that if don’t set the correct permissions, you may get complaints from Apache, like the following:

PHP Fatal error:  Uncaught exception ‘SmartyException’ with message ‘unable to write file /var/www/html/cache/smarty/compile/46/d9/69/wrt54ecd6c1856a72.61943173’ in /var/www/html/tools/smarty/sysplugins/smarty_internal_write_file.php:44

Stack trace:

#0 /var/www/html/tools/smarty/sysplugins/smarty_internal_template.php(201): Smarty_Internal_Write_File::writeFile(‘/var/www/html/c…’, ‘<?php /* Smarty…’, Object(Smarty))

#1 /var/www/html/tools/smarty/sysplugins/smarty_internal_templatebase.php(155): Smarty_Internal_Template->compileTemplateSource()

#2 /var/www/html/classes/controller/AdminController.php(1936): Smarty_Internal_TemplateBase->fetch(‘controllers/mod…’)

#3 /var/www/html/classes/controller/AdminController.php(2337): AdminControllerCore->initModal()

#4 /var/www/html/classes/controller/Controller.php(163): AdminControllerCore->init()

#5 /var/www/html/classes/Dispatcher.php(373): ControllerCore->run()

#6 /var/www/html/admin123/index.php(54): DispatcherCore->dispatch()

#7 {main}\n  thrown in /var/www/html/tools/smarty/sysplugins/smarty_internal_write_file.php on line 44

8. Enable mcrypt for PHP:

sudo updatedb
locate mcrypt.ini
> /etc/php5/mods-available/mcrypt.ini
locate mcrypt.so
> /usr/lib/libmcrypt.so.4
> /usr/lib/libmcrypt.so.4.4.8
> /usr/lib/php5/20121212/mcrypt.so
sudo vi /etc/php5/mods-available/mcrypt.ini
sudo php5enmod mcrypt
ls -al /etc/php5/cli/conf.d/20-mcrypt.ini
> lrwxrwxrwx 1 root root 31 Feb 24 19:32 /etc/php5/cli/conf.d/20-mcrypt.ini -> ../../mods-available/mcrypt.ini
ls -al /etc/php5/apache2/conf.d/20-mcrypt.ini
> lrwxrwxrwx 1 root root 31 Feb 24 19:32 /etc/php5/apache2/conf.d/20-mcrypt.ini -> ../../mods-available/mcrypt.ini
service apache2 restart

9. Update your Prestashop settings in the config/settings.inc.php file. Set the correct database information.

10. Enable mod_rewrite:

sudo a2enmod rewrite
sudo service apache2 restart

Also, make sure to add something like the following in your apache site configuration file:

        <Directory />
                Options FollowSymLinks
                AllowOverride all
        </Directory>
        <Directory /var/www/html/>
                Options Indexes FollowSymLinks MultiViews
                AllowOverride all
                Order allow,deny
                allow from all
        </Directory>

And then remember to restart your apache server.

11. Install sendmail:

sudo apt-get install sendmail

12. Go to your Prestashop back office and reconfigure your domain. Go to Preferences -> SEO & URLs and scroll down to Set shop URL section.

Now everything should be OK, your new Prestashop website is available on your new domain!

If you have any issues, just drop a line here or email me.

4 Comments

Luxembourg at first glance

Now it’s been two weeks since I arrived at Luxembourg. In general the experience has been positive, except that it’s been raining for a consecutive of ten days and snowing for the rest days. It’s a bit humid, but not to the extend that I should complain. At least the air is free of smoke and particles.

It’s quite where I live, although it’s just fifteen minutes walk to the old town as well as the railway station. Almost everything is in walking distance, supermarkets, banks, hospitals, schools, government offices,Asian markets. There’s also a police school just 200 meters away. I suppose it’s a safe neighborhood.

Work is also nice, though one has to be self-motivated. Coworkers are extremely nice, but many of them prefer speaking French, which I believe is good for me since I’d like to pick up the language. I already applied for a university language course. There’s also opportunities to meet great minds. This morning there was a distinguished lecture, where one professor talked about privacy in internet using big data.

The startup business is going slowly but according to the plan. Office isn’t too far away and fits our purpose. Orders for office computers are placed this evening and we can start the real work shortly. It’s good to have someone supporting the business, with both funding and experience.

One thing brothers me is that the washing machine is broken and it’s talking forever to fix it. The agent promises anything but I’ve now learned to be wiser and not to believe her words.

Life is much easier when you have someone helping you out. For that I’m extremely grateful for the help I received from my friend.

And I miss my girlfriend. It’s a journey we’ve chosen together, and there has to be temporary sacrifices for a better tomorrow. So for now just follow what we’ve planned. I believe we’re heading for the better.

Leave a Comment

OSX Yosemite cannot boot when TRIM is enabled on third-party SSD

After upgrading my MBP to OSX Yosemite and enabling TRIM, the computer cannot boot into the system after restart. It stuck with a no-entry sign.

You can solve this issue by following instructions from http://www.cindori.org/trim-in-os-x-yosemite/

Boot your Mac in Recovery Mode by holding Cmd-R during boot

Open the Terminal from the menu bar

Run these commands, replacing YourDisk with the name of your Mac disk

rm -rf /Volumes/YourDisk/System/Library/Extensions/IOAHCIFamily.kext
cp -r /System/Library/Extensions/IOAHCIFamily.kext /Volumes/YourDisk/System/Library/Extensions/IOAHCIFamily.kext
touch /Volumes/YourDisk/System/Library/Extensions
kextcache -u /Volumes/YourDisk

For me, I have to first use the disk utility to unlock my SSD first since I have Filevault enabled, otherwise the first command above will complain about “readonly” files.

Since TRIM is very helpful for SSDs, it’s encouraged to have it enabled for better performance. You can use Trim Enabler v3.2.5 and above without issues. But note that it disables kext signing on your mac, “it still leaves you with the same amount of security as in OS X Mavericks, where the kext signing requirement didn’t exist”. (http://www.cindori.org/update-on-trim-in-yosemite/)

4 Comments

WordPress pages load very slowly after Google is blocked

After Google is completely blocked in China since May 31, I’ve had problems loading my website. After some investigation I found out the problem lies in loading failure of Google Fonts. Since it takes a long time to fail, the page waits before it fails and display with the fallback styles.

To solve the problem, I crawled the font styles from Google and put it up on my server. Then I changed the WordPress theme to use the font style on the server. Everything seems to work perfectly after that.

Another option would be completely disable Google Font Styles. This can be easily done using the WP plugin “Disable Google Fonts”, if you’re using WP’s default twenty-* themes. In my case, I would have to comment out two lines in Mog Theem Functions file (functions.php). Since my theme relies on Google Fonts, instead of commenting out the lines, I changed these to lines to use the localized style file:

	//wp_enqueue_style( 'opensans', 'http://fonts.googleapis.com/css?family=Open+Sans');
	//wp_enqueue_style( 'josefinslab', 'http://fonts.googleapis.com/css?family=Josefin+Slab:600');
	wp_enqueue_style( 'opensans', '/gfonts.css');
	wp_enqueue_style( 'josefinslab', '/gfonts.css');

 

Leave a Comment

Fear makes one only weaker

Yesterday morning I received a call from one business partner complaining about two german students not satisfied with the internship position at another business partner in Changzhou. So we decided to drive to Changzhou in order to get a subjective grasp over the issue. And the issue was more serious than we have expected: neither of the two interns are satisfied with the placement, and one was in a very bad physical situation. Plus, he had lymphoma — a type of cancer — a few years ago and is still recovering from the treatment.

Strange thing was that he felt quite in Germany, but since he was pale and didn’t feel very well, we took him to the hospital for a check. We we arrived at the hospital, he couldn’t even stand up and we had to use a wheel chair to escort hime to the emergency treatment department, where the doctor checked his heart rate, body temperature, oxygen level, and a comprehensive blood test.

We looked very serious about his situation, but the doctor said everything was OK with him. She smiled and said to us in Chinese, “I believe he has hysteria”. I’ve heard about hysteria before but never really met someone with such symptoms. So I observed him carefully as the doctor give him a saline. One of my colleagues sat next to him and chatted with him. He seems extremely normal to me when he is not discussing about his illness or cancer. They constantly bursted into laughters when they talked about funny experiences, which is a bit weird since patients next to him are really seriously ill.

After confirming with the doctor again and again, we decided to go for dinner before the saline was finished and he seemed much better. We went to a german restaurant and had a really nice dinner. Over the dinner no one mentioned about his illness nor cancer. And he seemed totally fine.

This is really the first time I see how one’s mind may affect his physical state — in such a drastic way. That’s why when one is afraid of bad things, bad things always happen. Because fear of something makes one weaker, so that one does not have enough energy to defend oneself. This is another ‘scarcity’ problem: when you focus too much on something, you’re using too much bandwidth and leaving too little bandwidth for other things. And you’re trapped deeper and deeper until you are completed depleted of bandwidth or energy — that’s when you collapse.

The best way to fight this problem is to lose some focus on the fears. Then you’ll have more bandwidth to cope with other more important stuff. Just step back, ignore the fears for some time, and find out the long-term plans or goals. After all, not all in life are important, at least some are not any important as we’ve thought.

Leave a Comment

The lean method

I knew there was something wrong with the management and how we do things at Yabroad, but it was difficult for me to convince other people what we were doing and how we do things are not the best way to run a startup business. When I talk about pragmatism, people talk about visions and having a long-term goal; when I talk about experiments, people talk about previous experience; when I talk about planning and specific goals, people talk about execution. After reading “The lean startup” and “Running lean”, I’m more convinced about how a business should really operate.

The lean method is really about how to get things done efficiently, be it running a small project, or managing a international corporation. It’s about down-to-earth planning and taking advantage of resources efficiently. It’s a call for doing things that really matters. When proposing a new project, ask not if we think it’s cool, ask how we’re going to satisfy the end users. And the first step to go is really getting to know the actual users, what are the problems they find painful and how other products are approaching the problems, and why our proposal is better than the existing solutions.

We made a mistake at Yabroad that we think people are willing to come to China if we don’t charge them much. While our competitors are charging thousands of euros per application, we charge only a few hundred. But we didn’t see an exponential growth, the increase of applications was only negligible. We talked too much about disruptive innovation and thought lowering the price will piss out all our competitors and help us gain a portion of the market share rapidly. We were wrong.

The decision was made without much evidence to prove our assumption. Price is indeed an important factor when people want to visit a different country, but it’s not the deciding factor. Given the opportunity to visit North Korea or Iran, does it still matter if you want to pay thousands of euros or hundreds of euros? Our customers want security and reliability, lowering the price simply does not help, and let’s hope it doesn’t jeopardize customers’ trust in us.

We were not utilizing validated learning. In fact few of our decisions were made based on solid facts and validated results. Arrogant people often think they are the best in this world and they usually piss of everyone else and complain about “why everyone is against me?” Arrogant companies don’t get customers. What they do is not to satisfy customers, they just want to prove themselves correct.

The build-measure-learn loop should be continuous and iterate in fast pace. Build a minimum viable product and measure how successful it is and learn where it could be improved and improve the MVP and enter the next build-measure-learn loop. Validate minimal concepts at a time. Get the whole project running and receiving income before burning out what you have.

It’s true that starting up is really management — if you know where to put resources and man power, and keep track of the direction the business is running towards, you won’t be too wrong.

Leave a Comment

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’.

RSAAuthentication yes
PubkeyAuthentication yes

# To disable password authentication:
ChallengeResponseAuthentication no
PasswordAuthentication no
UsePAM no

# To disable root login:
PermitRootLogin no

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.

<?php                                                                            
                                                                                 
$token = 'secret';                   
                                                                                 
if ($_GET['token'] == $token) {                                                  
    if (!empty($_SERVER['HTTP_CLIENT_IP'])) {                                    
        $ip = $_SERVER['HTTP_CLIENT_IP'];                                        
    } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {                        
        $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];                                  
    } else {                                                                     
        $ip = $_SERVER['REMOTE_ADDR'];                                           
    }                                                                            
    $fp = fopen('home_ip.txt', 'w');                                             
    fwrite($fp, $ip);                                                            
}                                                                                
                                                                                 
?>

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

pi@alice ~ $ crontab -l
*/5 * * * * curl daoyuan.li/home_ip.php?token=secret

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.

sudo apt-get update
sudo apt-get install python-pip
sudo pip install Flask

5. Install nginx and uwsgi on the Pi.

sudo apt-get install nginx
sudo apt-get install build-essential python python-dev
sudo apt-get install python-virtualenv
sudo pip install uwsgi

6. Set up nginx along with uwsgi and Flask.

mkdir flask && cd $_
virtualenv env
. env/bin/activate
pip install Flask

Edit nginx config:

~/flask $ cat flask_nginx.conf 
server {
    listen      5000;
    server_name localhost;
    charset     utf-8;
    client_max_body_size 75M;

    location / { try_files $uri @flask; }
    location @flask{
        include uwsgi_params;
        uwsgi_pass unix:/home/pi/flask/uwsgi.sock;
    }
}
sudo rm /etc/nginx/sites-enabled/default
sudo ln -s flask_nginx.conf /etc/nginx/sites-enabled/default 
sudo service nginx restart

Edit uwsgi config:

~/flask $ cat flask_uwsgi.ini 
[uwsgi]
#application's base folder
base = /home/pi/flask

#python module to import
app = hello
module = %(app)

home = %(base)/env
pythonpath = %(base)

#socket file's location
socket = /home/pi/flask/uwsgi.sock

#permissions for the socket file
chmod-socket    = 666

#the variable that holds a flask application inside the module imported at line #6
callable = app

#location of log files
logto = /home/pi/flask/uwsgi.log

Create a simple Flask app:

~/flask $ cat hello.py
from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"

if __name__ == "__main__":
    app.run()

Start up uwsgi:

uwsgi --ini flask_uwsgi.ini &

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:

curl ifconfig.me

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

Leave a Comment

What’s important for a start-up

A friend of mine is considering to set up a startup company , here are the things I think are important for startup. Usually when people think of a startup they think of new ideas. However I don’t think good ideas are so important. It’s not difficult to come across a good idea, but it is extremely difficult to get one idea realized. People usually don’t buy ideas, they pay for products and services. Besides, ideas can be easily copied, while its more difficult to copy the implementation of the idea. Furthermore, one can easily judge if one idea is novel or not, by comparing with current solutions; while it’s not so straight to claim one idea to be better than others. Ideas  solve problems and good ideas solve problems in a better way. However, before a problem is actually solved (that is when an idea is realized), ideas are nothing but plain wishful thinking.

I think the most valuable and important  thing for a startup company is the team. The team decides where the company is going towards, what the company is going to do, how they are going to do it and whom they are going to do business with and sell the product to. The team determines how fast company will move and turn and act. Since the only advantage of a startup company has over a large corporation is its fast decision making process and execution, the team is the deciding factor of a startup’s survival or death.

It doesn’t matter really if you have a good idea or not, as long as you have a good team and given some time, you definitely will come up with a fantastic idea. An ideal team for me would be something like this: everyone has his/her domain of expertise and others can completely rely on his/her capability of getting things done in his/her domain. Members in the team has slightly intersecting capabilities and as a team form the whole capability map. Someone brings everyone else together and keep everyone motivated and moving; someone is a technical guru and has the insight of solving problems efficiently; someone knows customers and is able to sell them everything he/she has in hand; someone is keen to budget control and at the same time knows where exactly to spend money; someone has extremely good relationships with the rest of the world. Members in the team does not have to agree with each other and they should be able to discuss or argue and reach a decision in a timely manner. They should have the insight into problems and the analytic skills to identify and prioritize tasks.

And still among the team the founders are even more important. They are really what the startup is. They give the startup a life if done correctly; or else the bad genes will follow the company forever. They are the startup’s creators, parents and baby-sitters. They should have the courage to risk everything they already possess for a glimmer hope of success. They believe and love what they are doing not because they don’t have other choices, but rather choose to not to have a choice. They believe they are doing the right thing and are willing to take responsibilities for what they are doing.

When people think of startups, people immediately think the ultimate goal for a company is to go public and get listed in major exchanges. That’s not startups’ goal. Companies need to make money. And founders need to consider this task from day one, if not day zero. Making money is not the same as getting funded by angel investors or venture capitalists. Getting funded is one way out of many to get the ideas recognized but not the ultimate goal. People fund startups because they think the companies are going to make a huge amount of profit. Making profits is about proving to the world that what the startup does is meaningful. What’s the point of keeping burning cash anyway?

When big companies like Google and Facebook purchase small or startup companies, what they’re really buying is the customers, the technologies, and the talents. And among these three, talents are the most important to me, since without the talents the customers and technologies will be found nowhere. In short, you’re destined to success or failure the day you choose the team members for your startup.

Leave a Comment

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:

import numpy as np
a = np.array([[1,2,3,], [4,5,6]], np.int32)

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:

a = np.array([1, 2, 3], np.int32)
a[np.array([0, 2])) # Fetch the first the third elements, returns np.array([1, 3])
a[np.array([True, False, True])] # Same as the line above

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

a = np.array([1, 2, 3], np.int32)
a == 2 # Returns array([False,  True, False], dtype=bool)
a != 2 # Returns array([ True, False,  True], dtype=bool)
a[a != 2] # Returns a sub array that excludes elements with a value 2, in this case array([1, 3], dtype=int32)
Leave a Comment

Statistics of insurance sold on Taobao.com on Valentine’s Day

On Feb. 14th Taobao launched a campaign to sell insurance products, which promises 7% yearly interest rate. The sales data is public, so I wrote a script to crawl them down and did a brief study on this data. Here’re the results.

On that day (actually sold out in less than two hours in total) more than 40,000 people participated, resulting a total sales of almost one billion CNY (the exact number: 980,270,000 CNY). Two companies participated in this sales campaign: Zhujiang and Tian’an. The sales statistics are:

ZhujiangTian’anTotal
# of Customers138312909242923
Sales mean (k CNY)24.92205921.84700322.837872
Sales min (k CNY)111
Sales 25% (k CNY)122
Sales 50% (k CNY)101010
Sales 75% (k CNY)202522
Sales max (k CNY)10009001000
Sales total (k CNY)344697635573980270

The histograms of how many people pay for each amount.

le100kgt100kle100k

Zhujiang was extremely popular: in 2 minutes and 56 seconds it reached a sales of 200,212,000 CNY, that’s more than 1 million CNY sales PER SECOND! Indeed Chinese are crazy about online shopping. 😀

Leave a Comment

MapReduce in MongoDB

http://docs.mongodb.org/manual/core/map-reduce/

http://docs.mongodb.org/manual/reference/command/mapReduce/

> db.lattern_money_record.mapReduce( function() { emit(this.quantity, 1) }, function(key, values) { return Array.sum(values) }, {   query: {'quantity': {$gt: 500}}, out: {inline: 1} } )
{
	"results" : [
		{
			"_id" : 550,
			"value" : 3
		},
		{
			"_id" : 570,
			"value" : 1
		},
		{
			"_id" : 580,
			"value" : 1
		},
		{
			"_id" : 583,
			"value" : 1
		},
		{
			"_id" : 587,
			"value" : 1
		},
		{
			"_id" : 600,
			"value" : 2
		},
		{
			"_id" : 660,
			"value" : 1
		},
		{
			"_id" : 700,
			"value" : 2
		},
		{
			"_id" : 800,
			"value" : 5
		},
		{
			"_id" : 900,
			"value" : 2
		},
		{
			"_id" : 924,
			"value" : 1
		},
		{
			"_id" : 949,
			"value" : 1
		},
		{
			"_id" : 980,
			"value" : 1
		},
		{
			"_id" : 990,
			"value" : 1
		},
		{
			"_id" : 1000,
			"value" : 12
		}
	],
	"timeMillis" : 36,
	"counts" : {
		"input" : 35,
		"emit" : 35,
		"reduce" : 6,
		"output" : 15
	},
	"ok" : 1,
}

The MapReduce code I used to analyze the 20 million hotel reservation records:

def get_aggregation(collection):
    '''
    1. Get unique set of people
    2. Get most frequent users
    3. Get aggregation by location of birth, age, month and day of birth
    '''
    # Emit multiple times in mapper function:
    # http://docs.mongodb.org/manual/reference/command/mapReduce/
    mapper = Code('''
                  function() {
                    function validate_rid(id) {
                        // From: https://gist.github.com/foxwoods/1817822
                        // 18位身份证号
                        // 国家标准《GB 11643-1999》
                        function rid18(id) {
                            if(! /\d{17}[\dxX]/.test(id)) {
                                return false;
                            }
                            var modcmpl = function(m, i, n) { return (i + n - m % i) % i; },
                                f = function(v, i) { return v * (Math.pow(2, i-1) % 11); },
                                s = 0;
                            for(var i=0; i<17; i++) {
                                s += f(+id.charAt(i), 18-i);
                            }
                            var c0 = id.charAt(17),
                                c1 = modcmpl(s, 11, 1);
                            return c0-c1===0 || (c0.toLowerCase()==='x' && c1===10);
                        }

                        // 15位身份证号
                        // 2013年1月1日起将停止使用
                        // http://www.gov.cn/flfg/2011-10/29/content_1981408.htm
                        function rid15(id) {
                            var pattern = /[1-9]\d{5}(\d{2})(\d{2})(\d{2})\d{3}/,
                                matches, y, m, d, date;
                            matches = id.match(pattern);
                            y = +('19' + matches[1]);
                            m = +matches[2];
                            d = +matches[3];
                            date = new Date(y, m-1, d);
                            return (date.getFullYear()===y && date.getMonth()===m-1 && date.getDate()===d);
                        }

                        // return rid18(id) || rid15(id);
                        try {
                            ret = rid18(id) || rid15(id);
                            return ret;
                        } catch (err) {
                            return false;
                        }
                    }

                    function validateEmail(email) {
                        // http://stackoverflow.com/questions/46155/validate-email-address-in-javascript
                        var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
                        return re.test(email);
                    }

                    var str = this.CtfId;
                    if (str && validate_rid(str)) {
                        var prov = parseInt(str.slice(0, 2));
                        var year, month, day, sex;
                        if (str.length == 15) {
                            year = parseInt('19' + str.slice(6, 8));
                            month = parseInt(str.slice(8, 10));
                            day = parseInt(str.slice(10, 12));
                            sex = parseInt(str.slice(14, 15)) % 2 ? 'M' : 'F';
                        } else {
                            year = parseInt(str.slice(6, 10));
                            month = parseInt(str.slice(10, 12));
                            day = parseInt(str.slice(12, 14));
                            sex = parseInt(str.slice(16, 17)) % 2 ? 'M' : 'F';
                        }
                        var age = 2013 - year;
                        var valid_provs = [11, 12, 13, 14, 15,
                            21, 22, 23, 31, 32, 33, 34, 35, 36, 37,
                            41, 42, 43, 44, 45, 46,
                            50, 51, 52, 53, 54,
                            61, 62, 63, 64, 65,
                            71, 81, 82, 91];
                        if (age <= 0 || age > 100 ||
                            month <=0 || month > 12 ||
                            day <= 0 || day > 31 ||
                            valid_provs.indexOf(prov) == -1) {
                            emit('Corrupted', 1);
                        } else {
                            // emit('Province ' + prov, 1);
                            // emit('Age ' + age, 1);
                            // emit('Month ' + month, 1);
                            // emit('Day ' + day, 1);
                            // emit('Sex ' + sex, 1);
                            // emit('Prov ' + prov + ' Sex ' + sex, 1);
                            // if (this.Address && this.Address.length > 3) {
                            //     var cur_prov = this.Address.slice(0, 3);
                            //     emit('From ' + prov + ' to ' + cur_prov, 1);
                            // }

                            // var email = this.EMail;
                            // if (email && validateEmail(email)) {
                            //     var idx = email.lastIndexOf('@');
                            //     var domain = email.slice(idx + 1);
                            //     emit(domain.toLowerCase(), 1);
                            // }

                            if (prov == 32 && sex == 'M') {
                                emit(str, 1);
                            }
                            // if (prov == 32 && sex == 'F') {
                            //     emit(str, 1);
                            // }
                        }
                    } else {
                        emit('Corrupted', 1);
                    }
                  }''')
    reducer = Code('''
                   function(key, values) {
                    return Array.sum(values);
                   }''')
    result = collection.map_reduce(
        mapper, reducer, 'aggregation', query={'CtfTp': 'ID'}
    )
    return result

 

Leave a Comment

The Last Battle: Long-term vs. Short-term Gains

During yesterday’s meeting the boss mentioned that our unpaid salary and bonus will be paid, when we have enough money, maybe in April when we receive the other half of high interest loan. Personally I don’t think paying the money will do any good to the company, and eventually it may harm ourselves, since if the company can not move on, everyone, including me, will be disappointed. However, as I’m involved in this, I’m not willing to give up the money I’m supposed to receive. And asking for the money will make me look like as if I don’t care about the company and everyone else’s future, especially when I’m the one speaking out for a few of us. So now I’m caught in a dilemma: I’m not willing to give up the potential short term benefits, which in turn may jeopardize my long term gains.

And the reason for this is that I’m different from others; I care about short-term gains while others can afford not to. And that’s why I feel helpless. I can not expect anyone to help me get things done; I’m on my own. And even if I stand up for myself and gain some short-term benefits for others, they will accept them without appreciating my efforts.

I’m completely trapped, by myself, with my colleagues’ help of standing away from me — neither stopping nor encouraging me and neither refusing nor appreciating my favor — and I didn’t even know how I entered the trap in the first place.

Leave a Comment

The Last Battle: My Fear

The day we reach an agreement to cut off employees was not a difficult day for me, as I always knew there would be a day like that coming; I was prepared. In the evening when I was talking with Xin, he said he feared not being able to reach the goal when planned during the day, which I fear not. What I fear was returning to the old pattern again, the patten that make the boss keep trying to find funding for us without actually focusing on how to achieve our established goals. I was afraid that he keeps borrowing money to pay off previous debts, while we struggle to reach our goals. I was worried that the boss prioritize fund raising over proving our values.

Yesterday came a challenge: the local government finally seemed to approve one of our projects: letting us operating a part of one restaurant building inside our community, which means we can again get loans from banks with relatively low interest rate. The boss hesitated. According to Xin, the boss wondered if it’s still necessary to lay off people.

Now it looks like the boss has overcome his reluctancy. He finally sent out an email telling everyone about our plan. What remains to be seen, though, is how the restaurant operates in the future and whether it could bring us profit. And even if it does, does it help us?

The boss has one thing I could learn from: he sure knows how to connect with people and never gives up unless he reaches his goals. As for the many things that I contempt about, there’re many.

He never listens to anyone. He is so dedicated to his own thoughts that nobody seems to be able to change his mind. Talking with him is of no use; he likes reading from elsewhere. Yesterday I was irritated by him when he shared something he read about and it was about things we already mentioned to him earlier for several times. A man who trust his eyes more than his ears, I’d say.

He is over-confident about almost everything. He always overcommit. I don’t know a single occasion when he reach his goals or fulfilled his commitments.

He has many things I couldn’t bear with, but what the heck I’m doing with him?

Leave a Comment