记一次email code question

Amazon.com在中国招人,如果简历pass了,最开始会有一次email code question,就是约定好时间,通过email把一个问题发过来,然后在一定的时间之内把东西实现好发回给amazon。

第一次做这个code question,感觉比在电话/skype里直接写code要好很多,至少完全是自己在写code,没有外界的干扰。

我收到的问题是,amazon定义了一个类以及它的接口和说明,要在一个小时之内实现这个类。主要是要定义好数据结构,其中大多数方法很简单,只有两个接口需要涉及到算法,也不算太难。最难的是需要在一个小时之内实现。。。

我的情况是:
一个小时的时候写好了除最后一个接口外的实现,最后一个函数已经想好怎么写了,但还没写完;
先发了个邮件把当前的工作发了过去,估计要被刷;不过既然已经写了,索性多花点时间把它做好——
一个小时10分钟的时候,最后那个函数也写完了,但是完全没有测过; 那就继续写UT吧——
一个小时40分钟的时候,写了几个基本的UT,至少能测到所有的函数,其间发现两个code的bug,修掉了。

也就是说,我花了100分钟的时间完成了amazon要求在60分钟之内实现好的东西。
p.s. amazon还要求在每个接口上document它的时间/空间复杂度,这个也没时间写,但是这个倒是不难。

总之,说明写code的速度还不够快;
但是,总觉得要在60分钟之内搞定它,也没太大意义,真的实现好一个类/接口,一般应该这么做吧:
实现功能;
写UT测试功能,保证功能正常(或者UT先写);
优化实现(比如说时间/空间复杂度)。
还是蛮花时间的。

Anyway,只是记录一下这次code question。

Share

临时解决Firefox扩展autoproxy的“可代理资源列表”不能用的问题

在天朝,用Firefox又翻墙的基本上都知道autoproxy(“福”)这么一个神器,用它配合各种翻墙软件(比如说GoAgent),可以做到对于国内的网站直连,对于需翻墙的网页用代理,效率很高。

更方便的是它是根据URL的规则来代理,所以一个网页里的其它资源(比如JPG,js,css等)都可以通过这个规则来决定是否被代理,效率更高。

不过这也带来一个问题,如果把一个被墙的网站加入代理列表,然后打开这个网站,这个时候往往出现这种情况:浏览器能打开一部分网页(比如header)但是接下来就不停地loading中,打不开完整的网页,比如stackoverflow,在load的过程中会调用 https://cdn.sstatic.net/Js/full-anon.en.js,这个被墙了,于是整个stackoverflow还是几乎打不开。
autoproxy issue on stackoverflow

于是autoproxy提供了一个“可代理资源列表” (Proxyable items),网页里的所有元素都可以设置是否使用代理(当然也是根据URL)。很实用的功能。
然而不知道从哪个版本的Firefox开始这个功能就坏了,打开来永远显示”No proxyable items”。如上图。
在忍了一段时间之后,决定自己看一下。

以前从来没搞过FF的扩展,只能试着看看了。
1) 从github上clone了一份源码,“编译”(其实是打包),生成了xpi;
2) 用 `firefox -ProfileManager` 启动FF,新建一个debug的profile(以防影响平时的使用),添加扩展,然后打开console log;
3) 发现在request.js的184行出了null exception:

getAllLocations: function(results, hadOutdated)
{
  let now = Date.now();

  // Accessing wnd.frames will flush outstanding content policy requests in Gecko 1.9.0/1.9.1.
  // Access it now to make sure we return the correct result even if more nodes are added here.
  let wnd = getReferencee(this.window);
  let frames = wnd.frames;
  ...
}

很明显是getReferencee()返回了null导致的。再看这个函数

function getReferencee(/**nsIWeakReference*/ weakRef) /**nsISupports*/
{
  try {
    return weakRef.QueryReferent(Ci.nsISupports);
  } catch (e) {
    return null;
  }
}

没太看明白,但估计是FF升级到某个版本之后就不能用这样的函数了。

尝试野蛮一点,让它直接return 原来的object:

function getReferencee(/**nsIWeakReference*/ weakRef) /**nsISupports*/
{
  return weakRef;
}

再测试,居然就好了!
autoproxy issue fixed on stackoverflow

为了能用这个功能,临时就改成这样吧,可能会有crash或者memory leak,但是至少目前work正常,呵呵。有空的时候再研究到底怎么回事。

p.s. 如果有懂FF的extension的童鞋,请告知原因或者直接fix~
p.p.s. 在github上Fork了一份,建了个branch issue_proxyableitems在上面改了。生成的xpi放在了这儿,对此功能有无比需求的童鞋可以直接下载了用 🙂

Share

用homeshick管理dotfiles

无论是Ubuntu还是Fedora还是其它Linux发行版,用户的配置文件尤其是.bashrc总是一件很重要的事情,这关乎到“用户体验”。为了在不同的电脑上有相同一致的“体验”,比如说公司和家里的电脑,伟大的程序猿们想出了不少解决方案,其中homeshick是个不错的东东。用了一阵感觉良好,总结一下。

原理
homeshick把配置文件集中放在一起(~/.homesick/repos/<repos>),并用git来管理/同步/更新。
在$HOME目录下用symbol link把实际的配置文件link过来,比如说像这样:

.bashrc -> /home/<user>/.homesick/repos/dotfiles/home/.bashrc
.gitconfig -> /home/<user>/.homesick/repos/dotfiles/home/.gitconfig

安装
首先,你得有git, 最好还有github帐号,这样方便维护你自己的dotfiles。
然后:

git clone git://github.com/andsens/homeshick.git $HOME/.homesick/repos/homeshick
printf '\nsource "$HOME/.homesick/repos/homeshick/homeshick.sh"' >> $HOME/.bashrc
. ~/.bashrc

安装完毕

使用
如果想从头开始用自己的配置文件,可以生成一份自己的repo,见下面的命令和注释

homeshick generate <dotfiles>  # 生成一个repository
homeshick track <dotfiles> .bashrc  # 生成一个symlink,并把.bashrc添加到repo里
homeshick track <dotfiles> .xxx  # 其它你想添加的dotfile
homeshick cd <dotfiles> # cd到repo的文件夹
git add home # 添加到git
git commit -m "Initial commit, add .bashrc" # commit
git remote add origin [email protected]/<gitname>/<dotfiles> # 添加到github
git push -u origin master   # Push到github
cd - # 返回

如果在另外一台机器上想使用刚才添加过的dotfile,(比如说家里的机器,或者新安装了系统)
首先,按上面的步骤安装homeshick
然后:

homeshick clone <gituser>/<dotfiles> # clone github上的repo, 并自动生成symlink

搞定!

其它
Check dotfiles有没有更新

homeshick refresh

在文件夹里的dotfiles,比如说vim vundle,一般在 .vim/bundle/vundle

homeshick cd <dotfiles>
git submodule add https://github.com/gmarik/vundle.git home/.vim/bundle/vundle
homeshick link

Q.E.D.

Notes
1) Homeshick github: https://github.com/andsens/homeshick
2) 小心不要commit敏感信息,比如密码/API key,等等。要是真不小心commit到github了,参考这篇文章: https://help.github.com/articles/remove-sensitive-data

Share

2013国庆@嘉茂国际花鸟园

    这次国庆*又*很忙,几乎每天都是吃来吃去的,不过总算有那么一天,一大家子人去嘉茂国际花鸟园玩了。

    这个花鸟园位于江阴和无锡的中间,离家很近,开车过去也就20分钟的路程,比起无锡市的景点来要近多了,这点很不错~

    一近门是个大花圃,顶部透明的建筑,地上摆满了各种花花草草,连头顶上也垂着各种植物(抱歉我都不认得。。。);一些休闲的桌椅坐落其中,绝对是个环境优美的和朋友小聚的好去处!于是,我妈和我LP都很兴奋地拍了不少照片~
    tips: 门票50,老人小孩半价;网上订票40;但是如果去里面用餐就可以免费入园。如果真想省这个钱,可以找一帮散客假装一起去吃饭,入口处就让进了Open-mouthed smile

LP_1LP&ViewLP_2妈

    连着花圃的是三个园子。

    鸟园有着不少各类的观赏鸟,颜色鲜艳的金刚鹦鹉,高贵但是不开屏的孔雀,还有一些不记得名字的没见过的鸟类,也就瞎看看。不过其中有一个鹦鹉还真会吃瓜子,是真的剥开来吃瓜子肉的那种,厉害!
孔雀鹦鹉

    有着假山、池塘的是中间的园子,锦鲤,鸳鸯,黑天鹅,主要就是这些了吧。只有这个园子是露天的,在亭子里看看鱼,打打牌,这里最休闲了~
假山流水

    最后一个是莲花池,中间是有着很多五颜六色的莲花的池子,周围长着奇异的像是巨型牵花一样的树,感觉也不错的。池子里还有很大的叫不出名字的叶子,比较少见,不过在中国的池子里有这样造型的东西,就会有人扔硬币,即使是这样的叶子也不例外。。。
莲花叶子

    说实话,这个花鸟园花钱去有所不值,但是去吃个饭,看看园艺,打打牌,一家人休闲地小聚,倒是很不错的。
全家福

Share

Nginx https load-balance on Raspberry Pi

我的Raspberry Pi工作了大约半年之后,文件系统开始出现莫名其妙的问题,各种文件都出现乱码,以至于某系统命令一执行就segment fault。到重新“安装”系统的时候了。

之前主要跑的服务是我的博客,nginx + wordpress搭的,在RPi上因为CPU的问题(php-fpm执行时几乎占满cpu),响应比较慢。既然重新弄了,考虑把某些请求交给家里的其它机器来处理。
家里还有一台跑Ubuntu的笔记本,希望满足如下要求:
1) 如果笔记本开机着,http请求(几乎)都交给笔记本处理;
2) 如果笔记本关机,http请求都由RPi来处理;
这些应该是完全自动实现的。

在Stackoverflow上问了这个问题,有人提示说可以通过nginx的load-balance功能来实现我的需求。于是开始google一番,找到了解决方案。
基本的思想是,把nginx配置成反向代理,笔记本和RPi都作为upstream来处理http请求;通过nfs共享同一个wordpress目录;配置mysql让wordpress访问同一个数据库。
一步一步来配置这些。
其中Raspberry Pi的地址固定为192.168.1.100,笔记本的地址固定为192.168.1.101,数据库名为minewpdb,数据库用户名为minedb

1. 配置Mysql
mysql仍然放在RPi上,让mysql接受网络的请求,这样不同的机器可以用同一个mysql数据库。

sudo vim /etc/mysql/my.cnf
==> 把 bind-address 改成RPi的ip地址
bind-address            = 192.168.1.100

mysql -u root -p #登录mysql控制台
mysql> grant all on minewpdb.* to 'mineblog'@'192.168.1.100' identified by 'xxx'; # 本地RPi的wordpress访问
mysql> grant all on minewpdb.* to 'mineblog'@'192.168.1.101' identified by 'xxx'; # 笔记本的wordpress访问
mysql> quit;
sudo service mysql restart # 重启mysql服务

# 在RPi和笔记本上分别测试一下
mysql -u mineblog -h 192.168.1.100 -p # 如果能登录成功,就ok了

2. 配置wordpress
Wordpress仍然在RPi上,只要修改wordpress的config文件,把数据库的host,用户名和密码都设对就行了。

sudo vim /path/to/wordpress/wp-config.php
==> 修改DB_HOST等参数
define('DB_NAME', 'minewpdb');
define('DB_USER', 'mineblog');
define('DB_PASSWORD', 'xxx');
define('DB_HOST', '192.168.1.100');

3. 配置nfs
在RPi上设置nfs export,让笔记本mount它,这样可以保证跑的wordpress是同一份。


sudo vim /etc/exports
==> 添加wordpress目录到exports
/path/to/wordpress 192.168.1.101(rw,no_root_squash,insecure,sync,no_subtree_check)
sudo service rpcbind start  # RPi的nfs依赖于rpcbind
sudo update-rc.d rpcbind enable  # 设置rpcbind自动启动
sudo service nfs-kernel-server start  # 重启nfs

在笔记本上,mount这个目录:

sudo mount -t nfs 192.168.1.100:/path/to/wordpress /path/to/wordpress

4. 配置nginx
在RPi上要把nginx配置成反向代理,upstream是RPi和笔记本,端口号都是8000,真正的wordpress运行在8000端口上。
添加新的配置文件 /etc/nginx/sites-available/wordpress-load-balance,注意我把http的访问全部重定向到https,以防GFW

# Upstream to abstract backend connection(s) for php
upstream php {
server unix:/var/run/php5-fpm.sock;
}

upstream mineservers {
# 设置两个upstream, 其中笔记本优先,同时设置5s的fail_timout
# 因为局域网很稳定,所以max_fails设成1就行了,
# 如果fail就说明笔记本关机中,让RPi自己来处理
server 192.168.1.101:8000   weight=999 fail_timeout=5s max_fails=1;
server 192.168.1.100:8000;
}

server {
listen 80;
server_name mine260309.me;
rewrite     ^ https://$server_name$request_uri? permanent;
}

server {
listen          443 ssl;
server_name     mine260309.me;

ssl_certificate     /path/to/cert/mine260309.me.2014.chain.crt;
ssl_certificate_key /path/to/cert/mine260309.me.2014.key;
ssl_protocols       SSLv3 TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers         HIGH:!aNULL:!MD5;
access_log         /path/to/wordpress/logs/proxy.log;
error_log            /path/to/wordpress/logs/proxy_error.log;

location / {
# 代理到upstream
proxy_pass  http://mineservers;

### force timeouts if one of backend is died ##
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;

### Set headers ####
proxy_set_header        Accept-Encoding   "";
proxy_set_header        Host            $host;
proxy_set_header        X-Real-IP       $remote_addr;
proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;

### Most PHP, Python, Rails, Java App can use this header ###
#proxy_set_header X-Forwarded-Proto https;##
#This is better##
proxy_set_header        X-Forwarded-Proto $scheme;
add_header              Front-End-Https   on;

### By default we don't want to redirect it ####
proxy_redirect     off;
}
}

server {
root /path/to/wordpress;
# 在8000端口监听
listen          8000;
server_name     mine260309.me;
... # normal wordpress configurations
}

在笔记本上用同样的配置就可以了。

这样,任何一个请求到RPi,它会让nginx优先反向代理到笔记本的nginx的8000端口,由笔记本来处理;
如果笔记本关机,在5秒钟之后它会fail,于是再由RPi自己的8000端口处理。

Q.E.D.

Share