快速使用uwsgi部署

之前尝试在阿里云部署一个bottle.py写的web服务,选择了unbuntu12.04,一穷二白的ubuntu上用uwsgi部署还挺简单的。这里简单记录一下。

先要改一改程序代码,声明一个application

1
application = bottle.app()

然后安装uwsgi,demo.py就是修改过的bottle的代码。

这里我遇到了— unavailable modifier requested: 0 --,要安装uwsgi-plugin-python,并且uwsgi启动时候添加--plugin python

一些uwsgi的操作看这里

1
2
apt-get install uwsgi uwsgi-plugin-python
uwsgi --socket :8000 --plugin python --file demo.py --processes 4 --pidfile /tmp/demo.pid --touch-reload=/tmp/restart -d uwsgi.log

安装nginx

1
2
3
4
5
6
7
apt-get install libpcre3 libpcre3-dbg libpcre3-dev
apt-get install zlib1g zlib1g-dbg zlib1g-dev
apt-get install make
cd /path/to/nginx
./configure
make
make install

最后配置nginx。默认安装路径在/usr/local/nginx/conf/nginx.conf

1
2
3
4
5
6
7
8
9
10
11
server {
    listen       80;
    server_name  demo.artori.us;

    location /static/ { alias /home/root/demo/static/; }

    location / {
        uwsgi_pass      127.0.0.1:8000;
        include         uwsgi_params;
    }
}

自此搞定

via:

UIWebView加载本地资源

作为一个不会javascript只会jQuery的程序员,我在做Objective-c和HTML5页面交互的demo的时候需要HTML至少依赖一个jQuery,放在本地咋整?

创建UIWebView的时候

1
2
3
4
5
6
7
8
9
10
11
_webView = [[UIWebView alloc] initWithFrame:CGRectMake(0,0,self.view.bounds.size.width,self.view.bounds.size.height)];
NSString *htmlFile = [[NSBundle mainBundle] pathForResource:@"index" ofType:@"html"];
NSString* htmlString = [NSString stringWithContentsOfFile:htmlFile encoding:NSUTF8StringEncoding error:nil];

NSString *path = [[NSBundle mainBundle] bundlePath];
NSURL *baseURL = [NSURL fileURLWithPath:path];

[_webView loadHTMLString:htmlString baseURL:baseURL];
// 把baseURL知道bundle的Url,就能调用bundle里的其他文件了,图片音乐什么的
[self.view addSubview:_webView];
[_webView release];

添加.js文件的时候

添加js文件有点特殊,xcode会以为js是可以编译的代码。要在Xcode的target里,把.js文件从 “Compile Sources” 移到 “Copy Bundle Resources” .

写HTML的时候

可以直接写相对路径了。<script src="jquery.min.js"></script>

题外话1: 有个基友要做一个HTML5播放视频的东东,想把视频缓存到本地,但是UIWebView无视HTML5 mainifest里指定的音频视频文件,还有5M的限制。其实也可以存下来本地加载撒。

题外话2: objc可以用stringByEvaluatingJavaScriptFromString:在webview里执行脚本。js要调用objective-c就比较麻烦。iOS可行的办法是利用custom URL scheme,跳转到应用之后应用或从path或从querystring来判断js要调用什么类什么方法,比较蛋疼。最理想的方式应该是safari插件支持的方式,可惜iOS没有。

via:

Arthur的2012总结

我觉得这篇2012年总结如果今天不写估计我这辈子都不会写了。2012的末日没有如期而至,以至于写2012年末总结的计划不得不又被提上日程了。

2012年总的来说发生的事情不算多,但是心态变了很多。

博客几乎没怎么折腾,偶尔写了几篇文章。换了octopress。换完博客系统的时候倒是热情高涨把evernote里攒下的素材写了一堆。不过现在又瞬间消极怠工了。

dev

今年主要是iOS开发结结实实的盖了几层楼,从之前搭搭积木的阶段,终于到了可以自己造轮子的程度了。完成了几个公司里的产品、项目。现在正在给自己做一个简单的app,买了idp,打算最后把这个应用弄到appstore上,虽然很多人不看好,不过我的初衷也只是做着玩,才没有改变世界的伟大志向呢。

另外因为参与了一个微博应用开发,所以对python、bottle.py、uwsgi都熟悉了不少,之前提到的那个app,以及接下来要说的小玩具的服务端,也都是用bottle和mongodb架起来的,不过VPS能力有限部署的时候还是用了passenger wsgi。

说的小玩具是一个arduino做的小东西,其实就是按一下按钮发一条微博,把它当作门铃来用的话就可以知道家里有没有人按门铃了,虽然知道了也没办法进一步才去什么错失。。。 关于这个东西欢迎关注微博@阳哥的门铃

life

依然在魔都打拼,因为之前公司搬到杨浦,所以也住到杨浦来了,和好基友@lionelzhang 好基友@luosky 同居了,住在复旦大学附近,欢迎来做客,做客前记得联系,我好搞下卫生。

10月份的时候正式跳槽了,离开之前的人间网、爱折客,从创业公司来到了一家金融企业。新的工作新的环境,包括换工作这件事情本身,在我内心起了不少化学变化。说实话这个决定让我失去了不少珍惜的甚至引以为傲的东西,当然也感受到了很多期待之内期待之外的新东西。

要说今年印象深刻的好玩经历。十一的时候租了一辆车一路疾行500公里路去参加一个同事的婚礼,吃过晚饭出发,到了那里的时候已经是后半夜了。作为一个今年换了10年期驾照的「老司机」来说,第一次开这样的远门是不是太水了一点。在台州的时候还出了第一次车祸哦。。。

另一个大事就是欧洲杯,不被看好的意大利居然一路杀进决赛。决赛是转成跑到宁波去看的,不过输的也太难看了一点吧。

diagram

好吧最后是去过的地方、看过的书、看过的电影。

2013加油。

Bottle直接返回pymongo查询结果

以前提到过bottle,也写过在django里使用pymongo,这次是在bottle里用pymongo。

bottle有类似ROR的一些特性,比如处理请求的时候直接return一个字典,框架会自动把它parse成json(autojson)。

我是想偷个懒来着,把代码写成了下面这样。

1
2
3
4
@get('/api/today')
def api_today():
    udid = request.GET.get('udid')
    return self.coll.find_one({'udid':udid, 'date':today})

这会有问题,因为find_one返回的bson没办法直接parse。伟大的发明都是在偷懒的时候诞生的,看起来我要做的事情也很简单,只要能让我改一改parser就行了。

  1. 写一个dump方法替换原来JSONPlugin里的
  2. 设置Bottle app的autojson为False。Bottle(autojson=False)
  3. 把有自己dump方法的JSONPlugin给install到app里
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class MongoEncoder(JSONEncoder):
    def mongo_dumps(obj):
        # convert all iterables to lists
        if hasattr(obj, '__iter__'):
            return list(obj)
        # convert cursors to lists
        elif isinstance(obj, pymongo.cursor.Cursor):
            return list(obj)
        # convert ObjectId to string
        elif isinstance(obj, bson.objectid.ObjectId):
            return unicode(obj)
        # dereference DBRef
        elif isinstance(obj, bson.dbref.DBRef):
            return db.dereference(obj) # db is the incetance database
        # convert dates to strings
        elif isinstance(obj, datetime.datetime) or isinstance(obj, datetime.date) or isinstance(obj, datetime.time):
            return unicode(obj)
        return json.JSONEncoder.default(self, obj)

app = app()
app.autojson = False
m_encoder = MongoEncoder()
app.install(JSONPlugin(json_dumps=lambda s: dumps(s, default=m_encoder.mongo_dumps)))

via:

异或

不介绍什么是异或了,有人叫半加、数学系的叫按位模2加

下文用得到的一些简单的性质

  • x^0 = xx^x = 0

  • 交换律:x^y = y^x

  • 结合律:(x^y)^z = x^(y^z)

  • 自反性:x^y^y = x

下面是几个小题目,可以用异或解决,挺有技巧性

交换两个数ab

1
2
3
a = a^b
b = a^b
a = a^b

有意思的是搜索其他异或例子的时候,发现了这篇文章,文章里实现了一个异或交换的算法,和本文主题无关,不过很有意思,函数更多的时候应该只操作值而不是变量。

UPDATE_2013-05-06: 这个,看到云风写了一个利用这个特性做的双向链表,挺好玩,忍不住写过来。

A集合里拿掉数x得到B集合,求x

XOR(X)表示将X集合内所有的数做异或

XOR(B)^XOR(A) = XOR(B)^XOR(B)^x = 0^x = x

1
2
3
4
A = (1..10000).to_a
B = A - [1234]
x = (A + B).reduce(&:^)
puts x #1234

via: http://www.javaeye.com/topic/420487

A集合里拿掉数x、y得到B集合,求x和y

首先按上一个的办法可以推导出xor(A)^xor(B) = xor(B)^xor(B)^x^y = 0^x^y = x^y

x^y的二进制结果,第n位为1,说明x和y的第n位不相同

根据第n位是否为0把A里所有的数分成A1和A0两个数组(A1里的数的二进制第n位都是1,A0都是0)

A1和A0应该各包含了a或者b(这样第n位才能异或出1)

同理可以把B分成B1和B0两个数组

可以得到第一个数 x = A1^B1

第二个数可以y = A0^B0,当然也可以用x^y^x求得

另外如果x^y为0,即x == y,令SUM(X)为X集合内所有数求和

(SUM(A) - SUM(B)) / 2 = x

via: http://blog.chinaunix.net/uid-12453618-id-2935334.html

集合A里只有数x出现1次,其余数全都重复出现2次,求x

xor(A) = x^y^y^…^z^z = x^(y^y^…^z^z) = x^0 = x

1
x = A.reduce(&:^)

集合A里只有数x出现1次,其余数全都重复出现3次,求x

xor的本质相当于“按位模2加”(adding modulo 2),令p1,p2…pn为布尔值,true为1、false为0,(+)表示异或操作。

p1 (+) p2 (+) ... (+) pn == ( p1 + p2 + ... + pn ) % 2

所以只需要实现按位模3加

( p1 + p2 + ... + pn ) % 3

将集合中所有数二进制表示的同一位的0或1相加,最终的和对3去摸,得到的数即是x

A = {5, 7, 7, 7},二进制表示两个数

1
2
3
4
5
6
7
8
9
  101
  111
  111
+ 111
------
  434
%   3
------
  101

但愿这坨东西能让人看懂

via: http://www.cs.umd.edu/class/sum2003/cmsc311/Notes/BitOp/xor.html

没有^操作时候实现异或,只用&|~

这里的转换有很多,比如下面这个

x ^ y == (~x & y) | (x & ~y)

具体查看维基百科 《Equivalencies, elimination, and introduction》部分,各种公式

Xcode优化过的PNG

开始做iOS应用就有一个“公理”,图片素材要使用png格式,至于公理是怎么形成的完全不知道,只是听说在官方文档里提到过一句:苹果会对png进行优化。

为什么优化?谁优化的?什么时候优化的?怎么优化的?

和所有的魔术一样,说穿了就不好玩了。一切的根源是iPhone的显存。iPhone的vRAM在存放单个像素的颜色的时候,并不是按照传统的“红-绿-蓝”这样的顺序排列的,而是“蓝-绿-红”,即我们常说的RGB,在iPhone的显存里是BGR。并且,没有alpha通道。

另一边,png格式按照“红-绿-蓝”的顺序描述颜色,并且支持alpha通道的半透明,RGBA四个通道各占1个字节。

  • 为什么优化? 因为一边RGB一边BGR,一边有alpha一边没有alpha。
  • 谁优化的? 文章标题已经剧透了,Xcode优化的。
  • 什么时候优化的? Xcode在编译时,会对png资源进行优化。
  • 怎么优化的? 优化做了两件事:
    1. 把png里所有的RGB颜色转成BGR顺序
    2. 把png里所有的alpha通道先和RGB三通道先乘好(比如R:1 G:1 B:1 A:0.5的颜色直接转成 R:0.5 G:0.5 B:0.5)

这样最终设备在运行时渲染这些颜色的时候,不需要任何处理,一个汇编语句就把数据丢尽显存里了。

PS: 这里还有一个手动转换,和还原的办法

via: http://iphonedevelopment.blogspot.jp/2008/10/iphone-optimized-pngs.html

从wordpress搬到octopress

断断续续把wordpress转换到octopress上了。这是z-blog转到wordpress之后第二次更换博客系统了,octopress很酷,markdown的数据复用、搬家、存档都比lamp的wordpress轻便的多。

从导出wordpress数据库,转换为markdown,部署到github,搬图片文件,转换评论,磨磨蹭蹭的前前后后大约拖延了有两周,到今天终于把域名解析给换到这里来了。

最头疼的是转换文章的脚本不见得可靠,老文章的格式乱七八糟需要一篇一篇手动去修正,我现在做了一半,至少保证最新的大约3/5的文章是修改过的友好的格式。

很久没有更新博客,evernote的博客素材已经攒了一大堆,有空一篇一篇写出来吧。

2012欧洲杯Google,iCal,Outlook日历

今晚欧洲杯就开打了。在Live Calendar里导入了这个日历之后,同步到Windows Phone上很爽。

  1. 在Google Calendar订阅好友的日历:euro2012calendar@gmail.com

  2. 直接访问这个地址,在最下面添加到Google Calendar

  3. 下载这个ics文件导入到outlook, live calendar或iCal、iPhone等

原文地址:http://www.eurojoe.com/2012/06/01/euro-2012-google-calendar/

Git修剪分支

项目运转的久了,很多个人的战略的bugfix的feature的分支一堆一堆,今天忍不住想清理一些已经被合并的分支。这里用到了几个相关的git命令。

  • git branch 可以查看本地有的分支,当前分支之前有个*。

  • git branch -r 查看所有远程的分支(不代表远程还有的分支)

  • git branch -a --color 查看所有分支(--color加颜色,绿色是tracking的)

  • git branch -d TAG 删除本地分支,如果这个分支有没有合并的提交,git会提示你改用 -D 强制删除(或干脆别删除!)

  • git push REMOTE :TAG 删除远程REMOTE(比如一般叫origin)分支,注意分支名前加冒号

  • git remote prune REMOTE 这个指令比较特殊,如果你在A仓库上git fetch过,在B仓库用上一条命令删除了远程分支,那么A仓库里 git branch -r 还是可以看到已经删掉的分支。这个时候可以用这个命令修剪这些分支。

  • git prune 在本地也可以使用,不过作用我还真不清楚,官方用推荐用 git gc

记录下,git真的很萌的你们不要黑他。

以上。

Mac OS 10.7.3用xcode提交二进制文件验证失败

近日在提交一个app的时候发生了奇怪的错误。错误如下:

iPhone/iPod Touch: Icon.png: icon dimensions (0 x 0) don’t meet the size requirements. The icon file must be 57x57 pixels, in .png format

我使用的Xcode版本是4.2.1,其实一下子也懵了完全没头绪。我第一时间当然是以为我的Icon.png真的出问题了,因为偶尔我会自己用一个叫做prepo的app来把512的图标转成57像素的,所以我第一时间以为是它的问题。(因为它之前也把比如10k的blabla@2x.png转成了20k的blabla.png)。于是我用Photoshop重新转换了一个图标来试图解决这个错误,结果当然是失败了。

各种Google之后,问题被锁定到了Mac OS 10.7.3这个升级包上,升级了之后是第一次提交二进制文件。这个讨论都已经说明了病灶在哪里。

Xcode提交当然还是存在问题,无法通过验证,而且暂时没法解决。但是办法还是有,使用更加原始的Application Loader来上传。于是我打开Application Loader并登陆之后问题又出现了。

嗯,自带的版本看来太老了。于是各种Google之后新的版本终于还是找到了。使用方法很简单,跟着向导一步一步做(前提是itunes connect上的应用已经waiting for upload状态)直到需要在硬盘选择文件。首先在Xcode里Product -> Build for -> Building for archiving。然后Xcode工程下Products目录,有个 工程名.app,右键Show in finder,在它的上一级目录里找到release版本的app。当然上传前要把它打包成zip文件,application loader不能指定.app。最后完成向导,文件终于上传成功鸟 -。- 然后可以等着review了。

更新:好吧看到了新说法是只要装好Application Loader 2.5.1,重启xcode,clean工程,重新archive,然后就能通过验证了,不需要真的使用Application Loader上传。 没试过,不一定管用,可以试试看。

以上。