星期三, 2月 25, 2009

我看"草泥馬"現象





最近對岸突然多出了一個新用語, "草泥馬" ,
原本也以為只是低俗的搞笑罷了,
但稍微了解一下, 事實上其實整個事件還滿悲哀的,
大底上就是中共在2009年初開始部署的一項淨化網路文化環境的行動"整治網際網路低俗之風專項行動"所引發的一系列集體創作的事件, 這個所謂的"反低俗" ,把中國有名的網站包括谷歌(即google) 百度 新浪 搜狐 豆瓣 MSN中國 也都列在整肅名單之列.

略通歷史的人應該要知道, 群眾很難學會包容, 事實上低俗跟藝術的差異, 在群眾的眼裡往往只在一線之隔, "草泥馬"一系列的改編, 雖說也許是一種反動, 對於廣大的群眾而言, 不正是低俗的一種表現而已嗎? 對於這樣的低俗難道該容忍嗎? 然而我們該知道, 一直以來所謂的異端思想, 也不過就是對主政者不利的想法罷了. 不少文學作品在古代不是被禁就是被焚毀, 不只因為不容於當時的風俗, 而也對掌權者不利, 又或只是殺雞儆猴, 道德在掌權者的眼中不過就是一把名正言順的大旗, 端看何時要拿有利 而要揮向的又是誰而已. "包法利夫人"正是著名的一個例子, 今天隨手拿起一本皇冠出版社的經典文學譯本, 大概在那個時代都會被列為禁書吧.

反低俗不僅是一面大旗, 握在主政者的手中, 更是一手好棋, 因為對掌權者不利的, 自然是再低俗不過了...
一座低俗無法通過的偉大之牆已經建立了, 而低俗正在掃蕩了, 下一步呢? 或許身為當代的一份子, 在反政治文, 一切看經濟的媚俗潮流中, 也只能唱唱草泥馬之歌, 萌一下草泥馬的愛情, 淡淡的說一句, "認真你就輸了"...

星期一, 1月 19, 2009

超偶2總冠軍賽心得

雖然自己愛聽女聲, 不過我其實是滿少看台灣歌唱比賽的節目,
平常聽的如果不是西洋金曲類的大概就是公信榜武道館還是些OP/ED之類的歌,
不過星期日凌晨聽符瓊音在超級偶像2總冠軍戰第三輪唱的Listen還是特別的受到感動,

"某"評審說符瓊音這首的缺點是還在Beyoncé的陰影下,
"仍"沒辦法超越Beyoncé,
我實在是覺得有點吹毛求疵,
撇開大家都知道的感冒及破音不談,
我覺得Beyoncé這首歌的靈魂其實還是被展現了,
我想符瓊音肯定是看過電影Dreamgirls的,
她自己大概也知道自己所伴演的角色是Effie White這個唱功一流卻因外型所困的歌手而非Beyoncé所演的那個美麗的Deena Jones,
像Beyoncé這樣子外貌與音藝兩者俱全應該是她一生都想企求的目標. 或許她正是害怕從Jennifer_Hudson所演的Effie White看到自己的影子
才唱了Beyoncé這首可以代表自己心聲的曲子. 不論如何我覺得這首歌仍然是整個總冠軍賽最好聽的一首, 沒有因為這首而大翻盤實在也是太殘念了...

這次因為感冒(跟魔咒?)只得到第二名只能說是相當可惜
因為雖然其他人唱的也不錯
不過老實講只有符瓊音的歌才真的讓我的耳朵有滿足感.
超偶2第一名是誰其實也不重要了 因為也已經都過去了,
符瓊音麻煩你趕快找個好製作人出張好專輯吧...

星期四, 12月 11, 2008

[tips] 針對特定model改變django ORM預設delete()行為的方法

Django ORM裡的預設delete行為是去模擬ON DELETE CASCADE, 主要是為了保證資料的一致性, 但是雖然在自帶的admin介面裡會提示是否要刪除其他相關聯的資料, 不過仍然可能會對某些需求帶來一些困擾, 而且到目前為止並沒有一個標準的方法來更改這個機制, 這邊我提供一個簡單的方法將model的ON DELETE CASCADE行為改為RESTRICT, 就是在需要不同機制的model裡去override orm原本的delete行為 :

 
def delete(self):
s = CollectedObjects()
self._collect_sub_objects(s)
if len(s.items()) == 1:
super(self.__class__, self).delete()
else:
pass



這可確保當沒有任何關聯物件時才會刪除, 否則只會安靜的pass,
this hack probably need django 1.0+.

星期一, 9月 29, 2008

[link] django-mako

mako template是我除了django預設的template之外,
唯一真的有在product上使用過的template,
mako對於我來說的優點是其簡單非XML的語法,
此外mako無需任何C/pyrex extension,屬於純python的實作,
非常適合在無需django及host上沒有C compiler時單獨安裝。

現在有網友替mako template做了一個django-mako的plugin,
使用mako跟django整合又更容易了。

連結:
mako:
http://www.makotemplates.org/ (LICENSE: MIT)

django-mako:
http://code.google.com/p/django-mako/ (LICENSE: apache 2.0)

星期四, 9月 25, 2008

挺不錯的pyinstall

distutils跟setuptools有些什麼什麼好又有些什麼什麼不好,
其實不少python使用者是心知肚明的,
不過一般來說python programmer除了喜歡pythonic之外,
發佈套件也通常都會遵守發佈python package的標準格式,
發佈setuptools的eggs跟distutils的source tarball
雖然每個python user遵循標準程序的原因未必相同,
不過這似乎已是一種不得不的慣例.

最近在distutils跟setuptools之外出現了新選擇:
Tarek Ziadé的distributeIan Bicking的pyinstall

比較完整也比較吸引我眼球的是Ian Bicking的pyinstall,
一來Ian Bicking的東西向來簡單好用,
二來pyinstall的確解決了一些煩雜的問題,
三來Ian Bicking的社群影響力較大,成為新標準的可能性極高.

pyinstall大致相容於setuptools的easy_install並且提供了一些新的功能跟補強,
我自己認為pyinstall最重要的東西,
是在unix上提供了一個足以取代egg格式的新格式: bundle,
bundle格式有兩個我認為很重要的特點:
第一個就是dependencies include,所有相依的套件全都被放在同一個bundle檔案裡.
第二個是source based.
bundle有點像是一整個相依的freebsd ports或gentoo
ebuild加上其distfiles集合在一起的source整合格式,
所有的source跟編譯及安裝規則都放在同一個檔案裏面,在安裝的同時才進行編譯(.pyc and .so)
所以不像binary格式的eggs需要依版本分2.4的eggs跟2.5的eggs,只要下載同一個檔案就可以安裝了.
當然source based distro/package system的好壞見仁見智, 也會有些限制.
不過至少編譯時間過久這個缺點對於python來講應該是不存在的.
因為大部分的python packages依靠c的部份不多, 另外產生.pyc檔也並不會太慢.

此外pyinstall除了支援同一作者的virtualenv外,
對於整個python環境也有提出了一個解決方法 -- Requirements
事實上對於easy_install base安裝的工具最害怕的就是: 下一次裝不知道其相依的套件還會不會是相同版本.
因為安裝最新版未必是我們最希望的事情, 因為很有可能最新版將我們需要的功能給改變了,我會比較希望能夠有一個版本的控制
Requirements不僅可以由撰寫Requirements file來限制整個相依性的版本,
還可以用pyinstall.py --freeze=require.txt的方法,將整個開發環境的所有python版本套件版號都紀錄下來
方便你移到所以需要新安裝的機器上. 如果再結合上bundle, 幾乎就是非常完美的佈署方案.

pyinstall目前只有0.1.1版, 而且似乎還會有更多加強, 不過我認為這個工具的方便性跟應用的潛力非常大, 值得作個推荐.

更詳細的資訊請參考:

pyinstall:
http://www.openplans.org/projects/topp-engineering/blog/2008/09/24/pyinstall-a-new-hope/
http://pypi.python.org/pypi/pyinstall

distribute:
http://tarekziade.wordpress.com/2008/09/24/distribute-a-setuptools-fork/
http://mail.python.org/pipermail/distutils-sig/2008-September/010031.html
http://bazaar.launchpad.net/~tziade/distribute/trunk/files

星期一, 9月 15, 2008

Django有吉祥物囉!

今年9月6-7日的Django Conf 第一天的最後一個議程是Cal Henderson的Keynote: Why I Hate Django,其中提到很重要的一點: Django沒有吉祥物,Django需要一個具有"Awesome"跟"Magical Powers"特性的吉祥物來作代表。於是在全球Django愛好者的腦力激盪下,屬於Django自己的吉祥物出現囉! 就是avalonstar的Bryan Veloso所設計的這隻可愛的pony喔!






ponybadge

更多django pony的有趣資訊請參考:
http://avalonstar.com/blog/2008/sep/9/web-framework-ponies/

http://code.google.com/p/django-pony/


http://www.djangopony.com/



http://twitter.com/djangopony/

星期四, 9月 04, 2008

Django 1.0 released !!

http://www.djangoproject.com/weblog/2008/sep/03/1/

Django 1.0 released!

1.0是Django project一個很重要的里程碑,因為一直以來官方對於Django 1.0有個很重要的承諾,就是在1.0之後的所有版本都將維持向前相容性,就是不論是到1.x多少版,都將維持對1.0版本程式的相容性而不會再作任何會打破相容性的重大變動。這也是為什麼1.0版本會遲遲不推出的原因。

不過1.0 release的這一天終於來了,
根據Django官方網頁的說法,自從上一個穩定版Django 0.96.2以來,到這次的1.0版本發佈,已經有超過三十五萬行的Django程式碼被修正或改變,足見改變之大。(改動350000行的python, orz)

這次總算是讓我可以使用Django的新版本了,畢竟用了0.95.x跟0.96.x實在是很久了,而Django的SVN trunk對於真的要上線的系統畢竟還是個比較危險的使用方式。不過美中不足的是debian lenny似乎還是會來不及將Django 1.0包進debian linux系統,看來以後安裝上線系統又要多費一番功夫。

想知道更詳細的改變內容跟新增功能請看Django 1.0 release notes

星期一, 8月 25, 2008

coscup 2008遊記

時間過的飛快, 其實感覺去年的coscup 2007似乎才剛結束而已. coscup 2008又開始了,
這次kalug的朋友去了好多, 平常會掛在irc頻道上的至少就有去了一半以上,
一些平常少出現的朋友也都遇到了, 還遇到了一些原本只在irc或網路上看過的前輩跟朋友.

星期六早上雖然有點睡過頭,
不過還是跟lloyd大大坐著高鐵順利的來到了台大應力所的會場,
(走好久啊,難怪有人迷路), 這次小弟我也有準備了兩個20分鐘左右的session要介紹,
主要是簡短的講了一下django跟py3k這兩個有關python的議題,
第一天下午講django時由於臨時因為筆記型電腦接上投影機後畫面出不來,
倉促的商借了yurenju(小朱)的筆電 但是似乎因為是沒有字型的關係,
替代字型其實有點不好看 有些字重疊在一起 不過還是硬著頭皮把他講完了
另外20分鐘其實很短, 所以講的好像有點倉促 主要還是講一些觀念上的個人看法
希望能引起一些朋友對django的興趣.
這場講完後見到了非常客氣謙虛的WilliamYeh葉秉哲大大,跟他作了一些心得交流,
其實我有好幾本他的翻譯書 應該要拿來給他簽名才是.
另外感謝這場大家對我的笑話還挺捧場的,
似乎沒有人睡著,不然講下午第一場實在是有點辛苦,
連我自己都會覺得昏昏欲睡.
下午也有跟freenode irc上#python.tw我們python幫的gasolin, keitheis碰到,
上次coscup 2007跟gasolin聊比較久,
這次gasolin好像比較忙 聊了一下就不見人了
第二天下午我要跟keitheis找gasolin的時候, 就發現人海茫茫 真是難找
這次第二天結束吃飯的時候其實在跟thinker聊台灣pycon下次會不會辦的時候
lloyd有跟thinker提到說, 台灣的pycon其實也可以借coscup BOF的時間來辦,
我也覺得實在應該要排一場BOF讓#python.tw的人互相認親聊天才對.

今天晚上的晚餐是像海浪一樣的pizza海, 兩百五十人份的pizza果然是壯觀,
BOF我是參加我們自己kalug主辦的OpenStreetMap, 拿了一些pizza跟雞翅飲料進場地, 邊吃邊聊.
人比我原先預期的多,陸陸續續大概有三十到四十個左右的朋友來,
BOF內容主要是這次OpenStreetMap的講者louis來講一些josm跟openstreetmap的一些情形.
Arne講到了一些tag標示的東西及提到一些路名中文拼音上的混淆,
lloyd大大講了一些gsm logger支援的狀況. 大家有得吃又有得聊 實在滿不錯的.
不過下次應該要在場地準備一些面紙之類的 不然大家吃東西吃的油油的
又要跑廁所洗手 這樣歡樂的BOF就被打斷了.

晚上跟keitheis,還有我們kalug的lloyd大大,凍翔,
study area的billy回到住宿的飯店, 聽說凍翔跟billy聊到很晚,
keitheis從台南坐夜車上來之後還跑到誠品 另外我跟lloyd大大也很累 所以也就先睡了.

第二天一大早爬起來其實還是有點累 不過早上我有py3k的簡報要報
這次一樣借了yurenju的筆電, yurenju有幫我修改了字型 字型效果就好了不少.
真是非常感謝小朱大力幫忙. Ping長輩一開始介紹我的時候提到提姆之禪,
我自己一時還會意不過來 只有python之禪 我哪來的提姆之禪,
原來他所說的提姆是指曾在python mailing list上有tim bot之稱,
撰寫The Zen of Python (Python之禪) 的Tim Peters, 不是在說我有什麼禪,
Tim Peters其實是python界的傳奇人物之一, 我取ID時的確是沾了他的一點光,
希望我寫的程式也能得到他的庇蔭. (笑)

其實py3k這場講起來感覺時間更短, 有點意猶未盡, 才一下子就被後面的舉牌美眉舉牌了,
不過為了怕影響到後面的講者更精彩的議題, 就講的稍微快了點,
雖然原本就只打算講一些py3k的重要觀念跟想法,
但是還是覺得好像有點倉促, 可能下次繼續在kalug講一場好了, (有人想聽的話 orz)
順便恢復一下據lloyd大大說我老是把20分鐘的投影片講成3個小時的功力 XD

第二天下午的場次時跟以前高中的優秀學弟, Mozilla TW的Bobchao小聊了一陣,
我跟他都覺得雖然很多網友其實平常網路上有所聯絡,
但是辦個實體的聚會其實還是有他的效果, 所謂見面三分情嘛!
irc跟網路上的朋友通常是分散四處的關係 其實平常也很難見到,
人生相逢便是有緣, 珍惜緣份就是一種福氣 不是吗?

晚上跟著一群coscup的大大們,還有kalug在台北的朋友們去吃飯聊天,
不過我因為要趕著搭高鐵回家, 另外chihchunhychen也要先走,
就請shawn順便先送我去車站, 結束了短短兩天的coscup 2008之旅.

我這次的投影片都會放在kalug的這邊,
另外coscup 2008的官方網站之後可能也會有錄影跟投影片的下載,
還請各位前輩朋友多多指教囉.

星期三, 7月 16, 2008

[tips] 淺嘗 lift

lift是個由Scala語言所開發的web framework,由於想試玩一下據說連James Gosling都玩的Scala,索性就試著裝裝看lift,看看有沒有機會在上面開發Web APP。據說Scala在.NET及java平台下都可以執行,不過我試的平台是sun jdk 1.5。

首先先安裝好jdk跟maven2,再來打入這一大串,


mvn archetype:create -U \
-DarchetypeGroupId=net.liftweb \
-DarchetypeArtifactId=lift-archetype-basic \
-DarchetypeVersion=0.9 \
-DremoteRepositories=http://scala-tools.org/repo-releases \
-DgroupId=mytestorm.group -DartifactId=mytestorm.app


這會自動建立一個可連結derby database ,有models的ORM骨架的web application. 最厲害的是maven這個工具連scala,jetty這些你缺的dependency都能幫你裝到好。

接下來可以修改mytestorm.app/src/main/scala/bootstrap/liftweb/Boot.scala將db的connection string改成:"jdbc:derby:mytest;create=true" 這等一下會在我的專案目錄mytestorm.app裡建立一個名為mytest的derby db,再打入mvn jetty:run 就可以啟動webserver了(這裡打入mvn tomcat:run的話會幫你裝好tomcat). 因為lift已經事先幫你建好了model,所以現在連到server的8080 port或http://127.0.0.1:8080,就可以看到一個可以登入的歡迎畫面:





到這邊其實就已經有一點django admin模組的味道了,可以註冊帳號跟login什麼的,
如果用django的術語來講,整個lift的架構也不難解釋,django的urlconf跟settings被放在bootstrap/Boot.scala,
model.py被放到scala/your-proj's-group/model這個目錄裡,template是在webapp裡,template tag在scala/your-proj's-group/snippet裡,view在scala/your-proj's-group/view/,
說來說去,實在也是換湯不換藥,大底上目前的web開發就是如此。

如果你還有興趣的話,可以到抓下lift 0.9的release tarball, 然後解開之後到lift-0.9/sites/example裡,用mvn jetty:run 將example都跑起來玩一玩。裏面有幾個sample還滿有趣的,還包括一個comet的聊天室實作。

稍微玩了一下其實沒啥大感覺,主要覺得lift用的maven工具太複雜了,讓整個開發像在變魔術一樣,老是要找東西被裝到那,反而覺得scala沒什麼玩到,主要都在搞設定,另外mavan在裝dependency的時候整個download的過程都要連到國外總站,要裝的package又不少,導致安裝速度變得有點慢,如果能有台灣mirror應該會好一點。

星期一, 7月 14, 2008

[tips] rewrite debian/ubuntu 's lighttpd conf script from perl to python

Today I want to port lighttpd on another platform which basically a debian sarge system but without perl and dpkg package system on it. Since it's a debian based platform so I start from porting debian's binary lighttpd package, however I've found there're some perl script lays in /usr/share/lighttpd which are used when lighttpd startup.

While I can easily dump the result of perl script into a textfile,
and then startup my lighttpd correctly, I thought "maybe port it to python is not a bad idea." (since my target platform has python!), so here is the effort:
create-mime.assign.py

#!/usr/bin/python
#
# This script directly translate from debian's lighttpd perl script:
# create-mime.assign.pl
#
# Author: timchen119.at.nospam.gmail.com
# License: Public Domain
#
import sys

try:
f = open("/etc/mime.types",'r')
extensions = {}
print "mimetype.assign = ("
for line in f:
line = line.strip()
if line.startswith('#'): continue
if line != "":
splitlist = line.split()
if len(splitlist) < 2: continue
mime = splitlist[0]
for ext in splitlist[1:]:
if ext in extensions.keys(): continue
extensions[ext] = 1
print '".%s" => "%s",' % (ext,mime)
f.close()
print ")"
except Exception,e:
print e
sys.exit(1)


include-conf-enabled.py
#!/usr/bin/python
#
# This script directly translate from debian's lighttpd perl script:
# include-conf-enabled.pl
#
# Author: timchen119.at.nospam.gmail.com
# License: Public Domain
#

import os,glob

confdir = "/etc/lighttpd/"
enabled = "conf-enabled/*.conf"

os.chdir(confdir)

for file in sorted(glob.glob(enabled)):
print 'include "%s"' % file

use-ipv6.py
#!/usr/bin/python
#
# This script directly translate from ubuntu's lighttpd perl script:
# use-ipv6.pl
#
# Author: timchen119.at.nospam.gmail.com
# License: Public Domain
#

import socket

##this sometimes not accurate. (like in vserver mode)
#if socket.has_ipv6:
#

try:
if socket.socket(socket.AF_INET6,socket.SOCK_STREAM,0):
print 'server.use-ipv6 = "enable"'
except:
pass

All of these files can be found in http://kalug.linux.org.tw/~tim/lighttpd-debian-python-script/
Well something quite interesting happened when I port the debian's create-mime.assign.pl into python, It's that my python script's final result is not equivalent to perl one and has more mime types than its :
--- perlmime.txt    2008-07-14 15:29:23.000000000 +0800
+++ pymime.txt 2008-07-14 15:29:33.000000000 +0800
@@ -114,6 +114,11 @@
".dvi" => "application/x-dvi",
".rhtml" => "application/x-httpd-eruby",
".flac" => "application/x-flac",
+".pfa" => "application/x-font",
+".pfb" => "application/x-font",
+".gsf" => "application/x-font",
+".pcf" => "application/x-font",
+".pcf.Z" => "application/x-font",
".mm" => "application/x-freemind",
".gnumeric" => "application/x-gnumeric",
".sgf" => "application/x-go-sgf",
@@ -193,6 +198,11 @@
".pk" => "application/x-tex-pk",
".texinfo" => "application/x-texinfo",
".texi" => "application/x-texinfo",
+".~" => "application/x-trash",
+".%" => "application/x-trash",
+".bak" => "application/x-trash",
+".old" => "application/x-trash",
+".sik" => "application/x-trash",
".t" => "application/x-troff",
".tr" => "application/x-troff",
".roff" => "application/x-troff",
@@ -282,6 +292,7 @@
".tgf" => "chemical/x-mdl-tgf",
".mcif" => "chemical/x-mmcif",
".mol2" => "chemical/x-mol2",
+".b" => "chemical/x-molconn-Z",
".gpt" => "chemical/x-mopac-graph",
".mop" => "chemical/x-mopac-input",
".mopcrt" => "chemical/x-mopac-input",

So I start to dig why this happened, and I've found a strange perl regex filter all these mimetypes out, I believe it's a minor bug in original perl program. (or it does implicitly doing something meaningful? well I can't figure it out.)
--- create-mime.assign.pl    2008-07-14 15:35:58.000000000 +0800
+++ create-mime.assign.pl.new 2008-07-14 15:36:07.000000000 +0800
@@ -7,7 +7,7 @@
chomp;
s/\#.*//;
next if /^\w*$/;
- if(/^([a-z0-9\/+-.]+)\s+((?:[a-z0-9.+-]+[ ]?)+)$/) {
+ if(/^([A-Za-z0-9\/+-.~%]+)\s+((?:[A-Za-z0-9.+-~%]+[ ]?)+)$/) {
foreach(split / /, $2) {
# mime.types can have same extension for different
# mime types

replace this line and this will produce same results as mine.

usage:
just copy these py scripts to /usr/share/lighttpd
and change these lines if you're using debian based system
#### external configuration files
## mimetype mapping
#include_shell "/usr/share/lighttpd/create-mime.assign.pl"
include_shell "/usr/share/lighttpd/create-mime.assign.py"

## load enabled configuration files,
## read /etc/lighttpd/conf-available/README first
#include_shell "/usr/share/lighttpd/include-conf-enabled.pl"
include_shell "/usr/share/lighttpd/include-conf-enabled.py"