What have you found for these years?

顯示具有 筆記 標籤的文章。 顯示所有文章
顯示具有 筆記 標籤的文章。 顯示所有文章

2008-06-25

ruby character encoding detection

最早是 mozilla 的程式:
Mozilla Charset Detectors
source code
相關文獻

有人移植到 Python 上:
http://chardet.feedparser.org/

非常好,再移植到 Ruby 上吧:
http://rubyforge.org/projects/chardet/

沒什麼文件的樣子,這邊寫個範例:

> sudo gem install chardet
Password:
Successfully installed chardet-0.9
1 gem installed

> irb
irb(main):001:0> require 'rubygems'; require 'UniversalDetector'
=> true
irb(main):002:0> require 'open-uri'
=> true
irb(main):003:0> UniversalDetector.encoding open('http://www.falcom.co.jp').read
=> "SHIFT_JIS"
irb(main):004:0> UniversalDetector.encoding open('http://godfat.org').read
=> "utf-8"
irb(main):005:0> UniversalDetector.encoding open('http://www.blizzard.com').read
=> "ascii"
irb(main):006:0> UniversalDetector.encoding open('http://sysoev.ru/nginx').read
=> "KOI8-R"
irb(main):007:0> UniversalDetector.encoding open('http://www.softstar.com.tw').read
=> "Big5"
irb(main):008:0> UniversalDetector.encoding open('http://www.baidu.com').read
=> "GB2312"
irb(main):009:0> UniversalDetector.encoding open('http://www.mozilla.org/projects/intl/UniversalCharsetDetection.html').read
=> "ISO-8859-2"

效能不清楚,大小寫不論,正確性應該還可以。

btw, 雖然我討厭 unicode 以外的編碼,
不過希望這些網站 encoding 不會改,不然就跟這裡的範例對不上了 XD
(其實我還以為要找到 big5 的網站很難了說...)

2008-06-09

這是接龍嗎?

http://www.ffsymphony.net/forums/viewtopic.php?p=85651#85651

裡面的這句話:

"Now, open you eyes and see, I am no mere Marduk,
my names are countless, my age beyond reckoning."

跟 Sacrifice(活祭)裡面 Marduk 所說的一字不差,
可是從來就不是第三人稱的描述。難道是同人嗎!?
懶得從頭看,就先 note 起來。

我真的曾經想把 Sacrifice 的劇本全部背起來過...
可惜 google 裡找不到,不然真的會考慮慢慢背。

*

updated:
嗯,還有其他的字句,不過好像不太一樣:

????: Greetings, old friend.
Pensuke: It cannot be! Marduk!
Marduk: Indeed, but in this world I will no longer have that name. Call me Ashur.
(沒記錯的話,後面應該是 They call me A???? here.)
Pensuke: Why have you come here?
Marduk: Our bargain is incomplete, your rivals have fallen, but our reckoning is not yet fulfilled.
Pensuke: My...my rivals?! You destroyed everything! The very earth was crumbling beneath my feet!
(我記得有 You destroyed everything 沒錯)
Marduk: Do not blame yourself overmuch, the doom of Alem was pre-ordained, content yourself that you were but a pawn, as you will be again.
Pensuke: Never!


*

updated2:
http://www.ffsymphony.net/forums/viewtopic.php?p=73329#73329
這一大段意思很接近,有些字句也一樣,例如:
「"Substance?" Arkamond asked. "What? Like a lord, or a king?"」
這段應該是 Mitharas 之類的拼法的人講的...
「"A tyrant." Pensuke replied. "Had you looked upon me then you would have thought me an evil man." He chuckled, bitterly. "Most people did. I had laboured all my life to build another man's empire, when he died too young...far too young, authority fell to me alone. But I was not as well loved as he had been. Despised is more like it."」
這段,意思非常接近,不過我不確定用字一不一樣。至少 tyrant,
died too young, far too young 有印象應該一樣。
還有這句
「"Aye, but the demon was too powerful, I could not control it."」

2008-06-04

request.query_parameters

updated:
原來 request.query_parameters 是 get variable,
而 request.request_parameters 才是 post variable...
兩個都要用,就要寫:request.request_parameters.merge(request.query_parameters)
這樣是優先 get 其次 post...

因為 rails 的 params 會對 input 做額外處理,
例如 user[account] 會變成 params[:user][:account],
還有 params 裡面被額外加入 params[:controller] 和 params[:action].
為了避免這個狀況,想要直接抓出最早 post 過來的資料,
在文件裡 AbstractRequest 中的 parameters 的 source 中看到:

     # File vendor/rails/actionpack/lib/action_controller/request.rb, line 286
286: def parameters
287: @parameters ||= request_parameters.merge(query_parameters).update(path_parameters).with_indifferent_access
288: end


發現在 ActionController::Base 中可以用 request.query_parameters
取得該我所要的資料。(i.e. no :controller and no :action)
不過相較於 params, 最主要的差異就是 params 用 symbol 當 key,
但 request.query_parameters 卻是用 string!

我想這是因為我從 request 中抓值的關係?一開始我想乾脆 map 一次,
不過 map 的結果會是 array, 可能只能 fold 如:

request.query_parameters.inject({}){|r,i|r[i.first.to_sym]=i.last; r}

只是忽然想到幾件事:

1. 本來 post 過來的就是 string, 最後也要轉成 string 輸出,
那需要多此一舉做轉換嗎?除非經常需要 lookup?

2. 之前想模擬 request, 直接複製 server log,
就會看到 "api_key"="abcdefg", "sig"="hijklmn", ...
這樣我要模擬,還要把 = 左邊的 string 改寫成 symbol,
如果我原本就是要 string, 不就不需要轉換了?

...firefox 3 rc1 顯示問題還是不少。這方面,最穩的還是 safari...
opera 有時候也會出這種問題... 字型亂跑。可惡的是我猜只有 mac 版
firefox 和 opera 有這些問題。

anyway, 總之,那我乾脆全面改成 string 當 key 算了。
初步測試結果,似乎沒問題!之前 test case 和獨立 server 都正常,
上線 server 卻總是怪掉的問題,看來永遠也不會有答案了.....

*

另一方面,這能算是 undocumented api 嗎?
我對於所謂如果沒用到 undocumented api, 表示程式沒什麼的這個說法,
實在有點不能接受。一來許多程式的價值完全不在使用 api 上,
最簡單的例子就是提供 api 本身的程式,東西當然要自己寫。

二來總覺得這是 document 撰寫失敗的問題,或是更嚴重的,
library 本身就設計失敗,使得 programmer 需要用到
本來就不是給 client 用的 function.

感覺,最容易碰到這種問題的是 end-user 用的 desktop application.
因為如果要做得很華麗,就必須大量使用 os dependent api,
如 win32 api, cocoa, 等等。而這種超級龐大的 api 架構,
因為過於複雜,本來文件就很難寫,而且設計本身也很容易不夠完美。
想要做一些比較特別的東西,例如入侵其他 desktop 上的 process,
像是 dr.eye 之類的東西... 應該有很多 dirty hack 在裡面?

再加上,這種程式的困難度往往都在 dependent on os api 的部份,
例如要怎麼 animate dock, 要怎麼修改 registry (windows),
等等,其實根本就不是難在程式本身上,全部是難在跟 os 溝通,也就是 api
有沒有查到、有沒有正確使用等等問題...
(還有,怎麼 workaround with the buggy/badly-designed api?)

我是覺得,其實絕大多數的程式,都跟以上無關就是了。
而且我真的覺得 api 的問題真的是很無趣,別人一改就 break 掉了,
還不如自己設計 api, 去 break 別人的程式 XD

2008-05-28

finder 大垃圾,爛爛爛

updated4:
試用了最有名氣的 Path Finder:
http://www.cocoatech.com/pf4/
果然比 Finder 好太多了... 也不會生出該死的 .DS_Store.
雖然還是有幾點我不滿意,例如字實在是太小了,
調整了「兩個地方」的字型,只有兩個地方放大,
還缺少 cmd + i 時的字型設定....
就不能 global 設字型嗎?我不能理解要四處用不同字型的道理。
就算要,也要每個地方都能設啊,缺一個實在是...
preference 分成兩邊也有點討厭,不過這設一次就好,比較無妨。
就試用一陣子看看吧... 不過正式版也不便宜...

接下來該跑 rm **/.DS_Store 跑一天試試嗎?
要全部移除 .DS_Store 也很費力啊...

updated3:
試用了一下 muCommander:
http://www.mucommander.com/
看起來功能比 Finder 強大多了,可是...

一樣會產生 .DS_Store =口=
救命啊...

updated2:
果然是密技:
$ defaults write com.apple.finder AppleShowAllFiles true
$ defaults write com.apple.desktopservices DSDontWriteNetworkStores true
寫在選項裡有這麼難嗎?嗯,我知道,要寫 UI 本來就比較麻煩,是吧?
還是 command line 最方便齁?所以都寫成密技最好了...

updated:
http://lists.apple.com/archives/applescript-users/2006/Jul/msg00404.html
怎麼設定看隱藏檔的啊?某個 script? finder 本身幾乎毫無設定可言。

Preventing writing of ".DS_Store" and "._filename" resource to network drives.

該死,那個奇怪的 _filename 果然是 mac 生出來的。
每次看到壓縮檔裡面一堆怪東西,我還以為是 tar 都會這樣...
原來是 mac 的 tar 才會。看來該全面改用 7za 了,反正他也會 tar.

*

第一個要解決的問題是,如何阻止 .DS_Store 產生

http://en.wikipedia.org/wiki/.DS_Store
http://kb.adobe.com/selfservice/viewContent.do?externalId=tn_16831

"To avoid creating .DS_Store files, do not to use the OS X Finder to view folders.
An alternative way to view folders is to use UNIX command line."

well, 檔案管理用 command line 真的是很痛苦的一件事。

$ sudo find / -name ".DS_Store" -depth -exec rm {} \;

這樣很吃系統資源的感覺,還設 cron 會不會太...

http://support.apple.com/kb/HT1629

懶得看,而且只有 network 的話也不夠啊。
最重要的是,不要入侵 flash disk 好嗎...

另外幾個問題是:

1. 無法顯示檔案大小,只有磁碟大小(這有時候很重要,
老實講,我根本就不 care 磁碟大小。)

2. 複製取代時幾乎毫無任何資訊,windows explorer
都會顯示雙方檔案大小!最好是還能跑 diff 或 md5 check ._.

3. 可不可以把 directory 固定放最上面啊!

4. 為什麼不能 sudo? 這樣我要怎麼用 finder 處理系統檔案?
只好切 root 或用 shell

5. 讓我看隱藏檔!windows explorer 都能顯示隱藏檔!

6. 垃圾桶,我不知道這算不算 finder 的一部份,清除部份檔案
不行嗎?為什麼一定要一次倒光光??simple workaround 是
進 shell 去 rm.... 或是先把垃圾收回去,把要清除的清掉,
再把其他垃圾放回去。

結論:
windows explorer 實在是太好用了!finder 實在太垃圾了。
(雖然 Thumbs.db 也非常非常討厭,不過產生率遠沒 .DS_Store 高)
(我自己沒開預覽就不會產生那鬼東西)
其實我還真的有在想是不是乾脆回去用 windows 算了...
反正 cygwin 也不是不能用...?
再加上 mac 根本就沒有一個堪用的 browser......
改用 opera 結果還會跟 open vanilla 打架 -_-b
firefox 又有其他不少問題... 而這些在 windows 上的 fx 都沒有 @@

除了寫程式方便、畫面美觀漂亮,其他幾乎都輸 windows 嘛 @@
10.5 穩定性又不足... 又沒有遊戲可以玩 XD

其他想抱怨的還很多... 像是內建的 tar 會生出奇怪的檔案??
du 沒有 -b option... 這也許是 linux 才有的?
順便抱怨 fish 只要進入含非 ascii 字元的目錄名稱,就會死在 sed...
這考慮下次投書給 fish 開發團隊,畢竟這問題他們可能永遠不會發現...
反之 bash 就跑得超快,utf-8 目錄名稱也都不會有問題
不過就預設的設定而言,fish 實在好用多了...

啊對了,windows 不分大小寫也很討厭...

還是乾脆來搞 linux 算了,不過這樣就不能開 audiofire 2 了
我記得 flash 也沒有 linux 版...

結論:linux 快統治世界,這樣其他軟體才有 linux 版

2008-05-10

svk => git 的麻煩...

我以為這是件很簡單的事,可惜試了幾個方式都失敗了 :(
問題是這樣,一開始我是希望能把 svk local branch 轉移到 git 上,
後來有點失敗,想說好吧那就轉移 svk mirror 就好了,這成功了。

現在我想把 svk 丟掉,所以想把 git svn 的 url 改成 remote svn server.
結果怎麼做都失敗 :(
難道不能這樣轉嗎?

錯誤是:

$ git svn rebase
Unable to determine upstream SVN information from working tree history

重新 build svn metadata 的錯誤是:

$ git svn fetch
[...]
Filesystem has no item: REPORT request failed on '/svn/!svn/vcc/default': No results returned from filesystem read operation. at /opt/local/bin/git-svn line 3833

不明白啊... orz

解決辦法大概就是:捨棄 svk mirror, 直接 clone remote svn repository :(
不想這樣做的原因是我不想要全部的 revision, 但也不想要只有 HEAD
我要 svk 上跳躍的 revision 啊... orz(因為有些時候我會 skip 掉不少 change)

本日昏昏沉沉

含淚送走 svk...

留言明天再回 ._. 我眼睛快張不開了,只是要做紀錄...
這有時效性,人類記憶有限,電腦記憶... 很大 XD

剛剛不想寫程式,所以就來試試 git
參考 google 肯定找得到的:(我亂查關鍵字他幾乎都是前幾筆...)
http://utsl.gen.nz/talks/git-svn/intro.html

不過他那些什麼 proplist, svm:source, svm:uuid,
這些我都不知道是什麼。svn:ignore 也不是很確定要怎麼用?
不去了解他的原因很簡單,我不喜歡在檔案上面貼標籤,
除了感覺非常不 portable 外,懶得學新把戲...

總之,反正我的東西都很單純,沒什麼大專案,簡單來就行:

(/home 打比較習慣,雖然我電腦不是這樣,還是照 /home 吧)
(我實在很討厭 apple 自己弄了一堆怪名字出來,尤其是那 Frameworks...)

$ git svn init file:///home/godfat/.svk/local/mirror/ludy
$ git svn fetch

這樣就行了,他那些 property 我不懂,也沒在用,不管他...
需要注意的是,因為我想放到同一個目錄下,所以我是 cd
到原本的 working copy 上。而上面其實也有不少沒放到 svk 上的東西,
git svn fetch 時如果沒把會重複的東西砍掉,會沒辦法 checkout?
總之就是 git status 會吐出一堆訊息... 手動處理這邊是稍微麻煩了點。
(不過也是因為 working copy 有很多額外的東西在裡面... 沒有的話就全砍就行)

一個個 fetch 完後(真的花了好長的時間........),先比比大小:

$ du -h ~/.svk
176M .svk

至於 git, 全部八個專案加起來,約 80M ~ 100M
果然是有比較小啊!取約略值的原因是,有些東西我沒轉到 git 上,
像是一些我確定不可能會再去看,或是有點重複累贅的東西,就沒弄了。

呃,怎麼說呢,其實我真的覺得這有一點不公平。可能是因為 Linus
號召力太大了?我不知道,我沒有去研究 git 的歷史。重點是,
感覺 git 的 support 一大堆,可是 svk 好像就沒這麼大的 community.

也許就真的如同上次在 rails community 上看到有人說的,
git 的 market 比 svk, mercurial, darcs 都好太多了。
嘛,其實 darcs 已經做得很好了吧?想想他還是 Haskell 寫的哩!

對我來說,最重要的是這兩點:

1. git support 真的很多,光看 git gui, 雖然不太好用,就覺得 svk 很可憐
居然到現在還沒有一個像樣的 gui 可以用...

2. git svn 看起沒問題,可以良好與 svn 合作

其他我不太喜歡 svk 的重點:

1. 可能是因為 svn 的包袱吧,在 svk 上改檔案名字實在是很討厭...
偏偏我又很愛改名字...

2. 沒辦法方便地攜帶整個 repository, 老實講,svk 有很多操作我還搞不太懂
總覺得應該有比較簡便的方式...
不過我覺得他中央管理所有專案的方式,也是有不少優點,
或許還需要一些改良吧?我猜?等 svk 3.0?

另一方面,捨棄 svk 對我來說還有個好處:

svk 的 dependency 真的很多,雖然說 port install svk 就搞定,
但是除了他以外,我真的沒有用到 perl 的東西了...
砍掉 svk 的話,perl 的一堆東西我也都能全砍掉了



那麼 git 有什麼缺點呢?老實講,還沒真的開始用,不知道,
也有點擔心最後還是會回去用 svk XD
不知道為什麼,對 svk 有某種好感 :p

第一次「使用」git 是為了抓 rubinius, 那時想說他怎麼用個
這麼少見的東西,找我麻煩。後來才發覺 git 現在真的很先進。
rubinius 也是少數用 rake 包裝包得不錯的專案,有機會想讀讀
他的原始碼,我覺得他自稱是「最先進」確實是有他的道理在。
可惜的是,在我的程式測試下,他真的跑得很慢...
而且相容性更是非常差,我沒一個程式真的能跑起來...
雖然 jruby 也一樣爛,不過 jruby 至少跑得很快...
(btw, 我對 jruby 很多執行檔不前綴 j 很感冒,他又強迫要設 PATH,
這樣我不去動手腳就一定會跟官方 ruby 衝突,很討厭)

另一個現在有印象用 rake 的專案是 IronRuby,
excellent, 我不改他 Rakefile 根本就不能 compile...
他路徑我記得設定很有問題,非常 windows style 之類的?
不知道現在有沒有改進,很久沒有在看進度了。

至於 parrot...
雖然我不是很喜歡把軟體跟建築拿來比較,
可是不得不說,有時候他們確實是很相像。
say, 比薩斜塔怎麼辦?拆掉嗎?
還是很期待他能跑起來就是了啦,萬能 vm 多好

不小心扯遠了,回主題。那時候在用 git 就對他印象很差:

1. 好慢
2. revision 為什麼要用 hash... 雖然這可能是概念完全不同之故

不過我現在自己測試才發現其實 git 真的很快,比 svk 快很多!
是因為 rubinius 本身太龐大,才會變得這麼慢吧?我猜。
只是這樣說來,svn 真的是個很... 殘廢的東西。
怪不得之前會看到有人像是一臉鄙視地說別人 svn 中毒。

雖然是這樣說,但好樣也有不少人連 svn 都不打算用...
只能說落差要大,要大到多恐怖都沒問題。

anyway, svk repository 應該會再留一陣子,看情況決定。
感覺 git 很多概念和 svk 還有段差距,所以在真的詳細用之前,
我想先讀讀其他文章看看。當初用 svk 也是四處看了不少東西
才漸漸習慣起來的 ˇ

而且看這些東西還蠻省腦力的,我喜歡...
真的比較技術或學術細節的東西,那真的是很傷神,不能當娛樂啊...

等 git 用得差不多後,就可以架 redmine 看看怎麼跟 git 整合了。
屆時我就不用四處亂貼奇怪的筆記了...

2008-05-09

module XhtmlFormatter

(updated: 也許可以試著加上 <code lang="ruby" style="twilight"> 或是
<code lang="c++"> 的 coderay support, 翻譯完就丟掉 code tag)

因應古怪需求,用 hpricot 硬幹一個 xhtml formatter...
輸入是文章,輸出是可以當作留言的 (x)html code

format_article '文章', :a, :img, :pre, :b, :em, :strong, :i
第一個參數是文章內容,後面的則是所有允許的 tag
不被允許的 tag 會被 escape 掉 <
目前只 escape < 成 &lt;, 原因是...
(updated: pre 內的 & 也會 escape 掉)
我忘了 @@ 總之剛剛測試是全部 escape 掉會有小麻煩...
所以有關於 & 之類的東西,可能會有點 bug, 這要再試試看
(其實是有點不爽,再加上今天整天注意力都很不集中...)
(換言之就是狀況差)

擇日再加到 ludy 中...

轉換的原則如下:
1. 除了 pre 包起來的區塊外,所有的 \n, \r\n, \r 全部換成 <br />
2. pre 包起來的區塊內,禁止使用 html, 全部一律 escape 掉 < 和 &
3. 因為上面的規則,加上 regexp 採用 greedy 原則,所以只有最外層 pre 有效
4. 忘記關閉 pre 的話,自動在文章最末端補上
5. 所有網址會轉換成有 a href 的連結,regexp 取自 drupal...
6. 網址包含各種通訊協定開頭的字串,還有 www. 開頭的網址,還有 email address.
7. pre 包起來的區塊內也有網址轉換成連結的效果

hpricot 效果蠻強的,還會自動修復一些 html,
不過介面敬謝不敏,細節不多說了(我現在只想筆記)

source code(正好試試效果如何!):


require 'set'
require 'rubygems'
require 'hpricot'

# 2008-05-09 godfat
module XhtmlFormatter
module_function
def format_article html, *allowed_tags
allowed_tags = Set.new allowed_tags
XhtmlFormatter.format_article_elems Hpricot.parse(
XhtmlFormatter.escape_all_inside_pre(html, allowed_tags)), allowed_tags
end

def format_autolink html
doc = Hpricot.parse html
doc.each_child{ |c|
next unless c.kind_of?(Hpricot::Text)
c.content = format_url c.content
}
doc.to_html
end

def format_url text
# translated from drupal-6.2/modules/filter/filter.module
# Match absolute URLs.
text.gsub(
%r{((http://|https://|ftp://|mailto:|smb://|afp://|file://|gopher://|news://|ssl://|sslv2://|sslv3://|tls://|tcp://|udp://|www\.)([a-zA-Z0-9@:%_+*~#?&=.,/;-]*[a-zA-Z0-9@:%_+*~#&=/;-]))([.,?!]*?)}i){ |match|
url = $1 # is there any other way to get this variable?
caption = XhtmlFormatter.trim url
if url =~ %r{^http://}
'<a href="'+url+'" title="'+url+'">'+caption+'</a>'
else # Match www domains/addresses.
'<a href="http://'+url+'" title="'+url+'">'+caption+'</a>'
end

# Match e-mail addresses.
}.gsub( %r{([A-Za-z0-9._-]+@[A-Za-z0-9._+-]+\.[A-Za-z]{2,4})([.,?!]*?)}i,
'<a href="mailto:\1">\1</a>')
end

def format_newline text
# windows: \r\n
# mac os 9: \r
text.gsub("\r\n", "\n").tr("\r", "\n").gsub("\n", '<br />')
end

private
def self.trim text, length = 50
# Use +3 for '...' string length.
if text.size <= 3
'...'
elsif text.size > length
"#{text[0...length-3]}..."
else
text
end
end
def self.escape_all_inside_pre html, allowed_tags
return html unless allowed_tags.member? :pre
# don't bother nested pre, because we escape all tags in pre
html = html + '</pre>' unless html =~ %r{</pre>}i
html.gsub(%r{<pre>(.*)</pre>}mi){
# stop escaping for '>' because drupal's url filter would make &gt; into url...
# is there any other way to get $1?
"<pre>#{XhtmlFormatter.escape_lt(XhtmlFormatter.escape_amp($1))}</pre>"
}
end
def self.format_article_elems elems, allowed_tags = Set.new, no_format_newline = false
elems.children.map{ |e|
if e.kind_of?(Hpricot::Text)
if no_format_newline
format_url(e.content)
else
format_newline format_url(e.content)
end
elsif e.kind_of?(Hpricot::Elem)
if allowed_tags.member? e.name.to_sym
if e.empty?
e.to_html
else
e.stag.inspect +
XhtmlFormatter.format_article_elems(e, allowed_tags, e.stag.name == 'pre') +
(e.etag || Hpricot::ETag.new(e.stag.name)).inspect
end
else
if e.empty?
XhtmlFormatter.escape_lt(e.stag.inspect)
else
XhtmlFormatter.escape_lt(e.stag.inspect) +
XhtmlFormatter.format_article_elems(e, allowed_tags) +
XhtmlFormatter.escape_lt((e.etag || Hpricot::ETag.new(e.stag.name)).inspect)
end
end
end
}.join
end
def self.escape_amp text
text.gsub('&', '&amp;')
end
def self.escape_lt text
text.gsub('<', '&lt;')
end
end

2008-05-07

Ruby 程式壓縮...

不要問我為什麼半夜心血來潮搞這個...
dependency 是 ruby2ruby,
ruby2ruby 的 dependency 是 ParseTree,
ParseTree 的 dependency 是 RubyInline
(其實還很蠢地 dependent on hoe, 不重要就不提了(雖然還是提了))

#!/usr/bin/env ruby

require 'zlib'
require 'rubygems'
require 'ruby2ruby'

class Ruby2Ruby
def indent s # 壓縮當然不要排版!
s.to_s
end
end

puts <<-END
require 'zlib'
eval(Zlib::Inflate.inflate('
#{[Zlib::Deflate.deflate(Ruby2Ruby.translate($stdin.read))].pack('m')}'.unpack('m')[0]))
END

隨便找了一個程式試,壓縮率約 51%

godfat ~/p/ludy> ruby rgz.rb < unit.rb > unit2.rb
godfat ~/p/ludy> ls -l
[...]
-rw-r--r--@ 1 godfat godfat 278 May 7 03:44 rgz.rb
-rw-r--r--@ 1 godfat godfat 1407 Apr 9 17:34 unit.rb
-rw-r--r--@ 1 godfat godfat 722 May 7 03:47 unit2.rb

試壓 ruby2ruby 更好,23172 壓到 6460, 約 27%

壓出來的程式就長這樣:

require 'zlib'
eval(Zlib::Inflate.inflate('
eJyNU81u3CAQvvMUyL3YSYOSSDl01Y3cW18gp9VqxeLxGokFCjhR0vTdM4Dt
dbxbtQcDnpnvm3+huPf0SctAeAhu54A34MqV5kf4Sld8L5UMEnyV1VwI8N6g
gTBGNeZFo1Fn8TjaijTQUolUkiv5BmXkqEgdL7qm8SL1RIiS35T+IfVIhIK6
s/E8xvOWgG4So9kHLvUuI1/L4caA8oMhFhwiPKh25mAz6qPjLeqH/8QbP5FS
/zFIF+kl0upiTQJ3Bwg7JX3IKWeBL6+yqJ4ZoNt4kRgbE8pomNLi1qpX8oU2
hmoTOqkPk6rXf1FaZwKIAM1/lPpzmj+BK/p9ynYBNzZgh31vMc2iQ9MCyaIQ
yeK1CDplkyrEsFc3a5oINisFz6C29IresYeKOdMjKtnOKsKAiw5b/x7eaWDY
8Otz+H2FgzFzMo3IdQ5nM03f9qxml2A357B/hnUhq2VYx4vBz3LPLZPPPMDn
Scr1juqDaVoexySuINPwUhZZhB3ID5aWYnin1bi7HVWL1YhNThw5Grp+RFuc
2NOKPdL7b1VFHPzqpYOysBb92B6Ht9hDaxzQofvWltlHVhMugjT6FMhpzfK8
bNm4BXNYWfA24HIOpJmE5UYtPWR7LJtZmI+dXQI+AE53nsY=
'.unpack('m')[0]))

基本上應該是可以直接跑,完全等價。不過我剛剛試了另一個會有路徑問題,
這點可能是 parse tree 搞的鬼... 要怎麼做才能完全正確我就懶得試了。
總之... zlib 不錯。

另外,ruby2ruby 有 bug...

Ruby2Ruby.translate '[1,2,3, *a]'
出來會是:
'1, 2, 3, *a'
外層的 [] 被吃掉了...
有空去 bug report 一下好了

2008-05-03

Chomsky hierarchy

我之前寫 regular expression 一直會碰上一個問題——
沒有遞迴。後來我一直在思索究竟 regular expression
可否寫成真正的 parser? 我覺得很難,不如直接用真正的
parser generator, 會比寫 regular expression 容易得多。

根據 Chomsky hierarchy,
基本上大部分的程式語言都是屬於 context-free grammar,
所以通常要寫 parser 也是針對 context-free grammar;
然而,regular expression 僅是屬於 regular grammar,
他的層級比 context-free grammar 低了一層,
也就是說,regular expression 確實不可能能夠 parse 出
所有 context-free grammar 的 language.

而這之間的差異,在於 context-free grammar 可以在
右側置放 nonterminal 和 terminal 的組合;
然而 regular grammar 只能放一個 nonterminal?

至於 context-sensitive grammar 更可以在左側置放
terminal 與 nonterminal 的組合。這邊先不管詳細的定義,
還在試圖理解中... 總之,我想大概這就是為什麼 regular expression
難以表達一些比較複雜的 pattern, 也說明出為什麼 regular expression
會讓我有沒有「遞迴」的感覺,他確實是缺少某種程度上的遞迴。

支援遞迴的話呢?那 regular expression 就不再是 regular expression,
他必然會升級到 context-free grammar...

所以我要求的東西大概是不存在吧 :D
因為那超出其定義的範圍內了,就像超人其實不是人這樣?

==

有時候會貪婪地想知道一切
這也是為什麼會有:The Problem with Wikipedia
吧?

學問的終點無止盡啊!偏偏你又能找到好多相似的道理,看得讓人心癢癢的

2008-02-19

Rice - Ruby Interface for C++ Extensions

Rice - Ruby Interface for C++ Extensions

一年半前(天啊,有這麼早嗎?)曾經介紹過 swig, 一個專門產生各種介於 C/C++
與其他語言 interface 的產生器。他是利用一個自訂的表示法,藉由讀取該表示法,
產生出各種不同真正的 binding 程式。其中也有內建不少 STL 的 binding,
所以想用 STL 的東西並不見得需要自己寫,只要叫他內部的東西出來即可。

swig 很厲害,不過他有個麻煩。雖然說 DSL 的威力強大,但是對於想要快速上手而言,
其實有時候反而會是種阻礙。另一方面,我 swig 手冊翻了翻,要把 C++ port 到
ruby 很容易,但反之不亦然,要在 C++ 中使用 ruby object, 就不是那麼方便。
(雖然也許這樣做是奇怪了點...)

所以後來我試了 Rice.
http://rice.rubyforge.org/
rice 的官方手冊也說了,rice 並不是要來取代 swig 的。swig 有他的不足,而 rice
大抵上又是模仿 boost.python 而作成的,所以兩者並不同。他自己也做過不少東西
是同時使用 swig 和 rice. 不過也不能說 rice 是 ruby 版的 boost.python.
因為他的目的也不是完全模仿 boost.python.

anyway, 之所以會想試用,是出自於找不太到良好的 C++ yaml parser. 我有看到兩個
C 版本的實作,但是真不好意思啊,個人實在不太喜歡純 C 的東西...。所以想說如果
可以把 ruby 的 yaml 搬過來就太好了。以下就是測試結果:

> sudo gem install rice

理論上這樣安裝是最方便的。要在 C++ 裡執行 ruby, 一樣會需要 ruby.h.
一般來說,他會在 lib/ruby/1.8/your_architecture/ 裡面。
在我的電腦上,他是:/opt/local/lib/ruby/1.8/i686-darwin9.1.0/

而 rice 呢,則是在 lib/ruby/gems/1.8/gems/rice-x.y.z/,
librice.a 則是在 lib/ruby/gems/1.8/gems/rice-x.y.z/rice/ 下。

所以在我的電腦裡,g++ options 是這樣下:

-I/opt/local/lib/ruby/1.8/i686-darwin9.1.0/ \
-I/opt/local/lib/ruby/gems/1.8/gems/rice-1.0.1/ \
-L/opt/local/lib/ruby/gems/1.8/gems/rice-1.0.1/rice/ \
-lrice -lruby -std=c++98 -Wall -w

主程式大概是長這樣:

int main(){
using Rice::Hash;
using Rice::protect;

ruby_init(); // 使用 ruby 前一定要呼叫
// 設定 load path, 否則 load path 會是 []
rb_eval_string("$LOAD_PATH << '/opt/local/lib/ruby/1.8'");
rb_eval_string("$LOAD_PATH << '/opt/local/lib/ruby/1.8/i686-darwin9.1.0'");

// require yaml 進來。當然也可以用上面的方式 require. 不過之所以會這樣寫,
// 是因為我不知道 load path 要怎麼直接從 rb_ function 中設定?
// 否則我是覺得能用 rb_ 去跑盡量用,evil eval 不是叫假的...
rb_require("yaml");

// protect 我猜是把所有的錯誤都轉成 rice 本身的 exception.
// Hash, 則是 ruby 的 hash 在 C++ 裡的 wrapper,
// 所以我是把 YAML 的讀取結果存入這份 C++ Hash 中。
Hash h(protect(rb_eval_string, "YAML.load(File.read('database.yml'))"));

// 這邊,我要做的事只是展現如何使用這份 hash.
Extractor e;
e.extract(h);
std::cout << std::endl;
}

雖然我覺得 doxygen 生出來的東西常常很難閱讀,不過 rice 的 doxygen 文件還算
不錯,有什麼東西都很清楚。就算不夠清楚,也能去直接看他的原始檔。他原始檔的東西
並不多,稍微翻一下,有什麼疑惑我想都可以解決。根據我 C++ 的經驗,rice 這份程式
也算是寫得非常漂亮的了,應該滿有參考價值。

我的 extractor 是把整個 hash 都走過一次,如果不需要這麼複雜的操作,其實也可以很
單純地這樣呼叫:

std::cout << static_cast<Hash>(h[String("development")])[String("adapter")];

這樣會輸出:

sqlite1

這樣實在是有點囉唆沒錯,不過我想這可以靠擴充 rice 解決。他有個 from_ruby 和
to_ruby 的 template, 擴充那個東西,好像就能把很多東西從 explicit 法轉成
implicit 法。不過我暫時懶得去做那麼多研究,這應該都是小問題。不過 down cast
就比較麻煩了。他有個 get method, 好像是能做一些 down cast, 但我測試都會有
runtime error, 大概是用法不對吧。有興趣的人歡迎去研究看看要怎麼做。

extractor 我想就不解釋了,就只是單純把抓出的 yaml 再輸出回 yaml.
其實那都已經差不多單純是 C++ 的問題了。僅列出程式碼與附註的一些註解:
(不過我沒測試過比較複雜的 yaml, 我想一定會有問題,當作業自己試著改好吧 :p)

#include <ruby.h>
#include <rice/Hash.hpp>
#include <rice/Array.hpp>
#include <iostream>

using Rice::Object;
using Rice::Class;
using Rice::Hash;
using Rice::Array;
using Rice::String;

// 排版算空格用的
std::string spacer(int depth){
std::string result;
for(int i=0; i<depth; ++i)
result += " ";
return result;
}

class Extractor{
public:
// 他 class 判斷法有點麻煩,所以我先把這三個 class instance cache 起來
Extractor(): hash_class_(Hash().class_of()),
array_class_(Array().class_of()),
string_class_(String().class_of())
{}
void extract(Object const& obj, int depth = 0) const{
if(obj.is_instance_of(hash_class_))
extract_hash(obj, depth);
else if(obj.is_instance_of(array_class_))
extract_array(obj, depth);
else if(obj.is_instance_of(string_class_))
std::cout << spacer(depth) << obj << "\n";
else // 這表示他是 Fixnum or Float?
std::cout << spacer(depth) << obj << "\n";
}
private:
void extract_array(Array const& obj, int depth) const{
for(Array::const_iterator i=obj.begin(), iend=obj.end(); i!=iend; ++i)
extract(*i, depth);
}
void extract_hash(Hash const& obj, int depth) const{
for(Hash::const_iterator i=obj.begin(), iend=obj.end(); i!=iend; ++i){
std::cout << spacer(depth) << i->key << ":";

// i->value 結果會是 ruby 上 C 的 VALUE, 所以要 cast 成 Rice::Object
if(static_cast<Object>(i->value).is_instance_of(hash_class_))
std::cout << "\n", extract(i->value, depth+1);
else // 單純的值
std::cout << " ", extract(i->value, 0);
}
}
private:
Class hash_class_, array_class_, string_class_;
};

2007-12-24

let's rake it!

in Rakefile:


inputs = Dir.glob('*.erb')
outputs = inputs.map{|o| o[0..-5]}

task :default => [:begin, outputs, :end].flatten
task :begin do; puts "processing templates: #{inputs.inspect}"; end
task :end do; puts "processed output: #{outputs.inspect}"; end

inputs.zip(outputs).each{ |input, output|
file output => input do
open output, 'w' do |o|
o << `erb #{input}`
end
end
}

把所有的 *.erb 轉出來,這樣就能輕鬆玩 meta-programming 了...
到時候可以寫一些 C++ getter/setter 的 generator,
或是 template parameter 吧..?

2007-09-07

魔王堡壘筆記

http://beast.godfat.org/forums/3/topics/24#posts-55

1.
敵人不做 collision, 考量如下:
collision detect 一向非常吃資源,就算是最單純的作法,
或是隔一段時間才 detect 一次,一樣非常吃資源。
在 flash 執行能力並不強,且單位量可能很多的時候,
做 collision detect 很可能會嚴重拖慢執行效能。

而更重要的是,enemy collision 對 tower defense 有什麼好處?
假使敵人會碰撞卡住,那麼使用 slow 甚至是 stun 的效果是否會太驚人?
除此之外,敵人會有停下來的時候嗎?答案當然是否,
所以 collision 對於 tower defense 其實是有點雞肋的。

所以不做。

2.
地圖上需要存哪些資料?敵人資料?塔的資料?
塔的資料是一定得存的,而且還需要反向查詢,
所以塔本身也要記錄自己的座標。
但是敵人呢?假設要存好了,那麼應該分開還是合併?
合併省記憶體,但我認為分開比較好。
一來這樣可以簡化流程,二來敵人是否需要記錄,
還需要再商榷。如果確定不要了,合併之下會不好移除。
而 flash 當然是 CPU 資源遠比 RAM 資源重要得多。

敵人其實應該是不用記錄的,因為需要查詢敵人的狀況並不多。
像是查詢敵人資料,這個可以做在敵人的 mouse click event 上,
沒有 collision detect, 記錄到地圖上的意義也沒有太多。
但還是有一個狀況需要查詢敵人位置,就是你的塔不能蓋在他身上。
這點可以在你按下去的那瞬間,直接用座標反查就好了。
畢竟玩家並不會瘋狂測試有敵人的地方能不能蓋塔,
省下所有一般情況下的運算能力比較重要。
畢竟,敵人記錄座標其實也是很費資源的,試想,進入和離開
區塊都是需要偵測的,那幾乎是無時無刻都要計算了。

3.
blocking algorithm 可以用 depth first search 就解決了,不是問題。
按下去的瞬間再做就好。

4.
敵人的 path finding alogrithm, 每一秒做一次即可。
也就是敵人每秒鐘做一次路徑修正。不過會不會因此撞上塔?
這點可能要再看看,是否要縮短路徑修正的時間,
或是撞上後立刻修正自己的位置,或是路徑修正和塔的碰撞分開做。
至於敵人的路徑搜尋,depth first search 不能找到最短路徑,
A* 怕太吃執行資源,這點要再看看。理想上當然是用 A*

5.
武器與敵人的碰撞?應該要用座標算,這部份還需要再考慮,
肯定也會是個效能瓶頸。複雜度似乎是 N*M, 如果效能太差
也許必須考慮讓計算變得粗糙或是直接減少敵人或子彈的數量。

2007-09-01

tower defense?

從 star craft 到 war craft 3, 甚至是現在一堆的 flash td,
我一直很喜歡這種型態的遊戲,也一直想要自己做一個,當然也一直都沒有
完成過。開始一點點這種事,倒是發生過很多次。稍微記錄一下需要哪些東西
好了﹍。

1. grid based, 不要類比地圖,安排位置時會覺得很麻煩。
2. wave control, 能狂按才會有爽度。
3. no air/ground difference, 敵人請一致。
4. 變賣打折嗎?可以移動嗎?
5. 可以跟敵人共享道路嗎?可以的話,需要 blocking algorithm.
6. 升級差異不要過大,讓群眾與精英都有一份空間。
7. 具有攻擊力的敵人(來自 war craft 3 tower war)

tower attribute:
hit points(HP)
damage
armor
range
fire rate(1/cool-down)
area of effect(AoE) e.g., circle, line, single, etc.
armor-piercing
cost(positive)

enemy attribute:
all above.
speed
size
cost(negative)

不知為何沒力起來,就寫到這﹍。

2007-08-22

Fedora Core 6 上安裝 beast (3)

覺得 pound + lighttpd 太麻煩嗎?又翻到一個應該不錯的選擇,
是一個俄國人寫的 http server, 也具有 reverse proxy 和
load balancing 的能力。

godfat ~ 3.2$ port info nginx
nginx 0.5.29, www/nginx (Variants: universal, dav, flv, mail, ssl)
http://nginx.net/

Nginx ("engine x") is a high-performance HTTP(S) server and reverse proxy,
as well as an IMAP/POP3 proxy server. Nginx was written by Igor Sysoev for
Rambler.ru, Russia's second-most visited website, where it has been running
in production for over two and a half years. Igor has released the source
code under a BSD-like license. Although still in beta, Nginx is known for
its stability, rich feature set, simple configuration, and low resource
consumption.

這個字實在是很難記…不過討論翻來翻去,他 serve static file 的效能和
lighttpd 在伯仲之間,而 load balancing 是正常可用的。所以與其使用
pound + lighttpd, 單用 nginx 可以簡化一些流程。我想缺點就是設定上
還是比 pound 複雜些,不過我個人是覺得比 lighttpd 簡單了。另外 nginx
好像沒有 windows 版,而 pound 和 lighttpd 都有 windows 版,
我想這對某些情況可能也是個考量吧?

雖然之前因為英文文件太少所以不太流行,但最近似乎還算有蠻多人推薦的,
而且這在俄國好像還蠻廣泛被使用的,試試應該無妨。

sudo yum install nginx

跟 lighttpd 一樣,一起丟到 beast 目錄下比較容易管理。
cp /etc/nginx/nginx.conf \
/home/YOUR_NAME/projects/beast/stable-1.0/config/nginx.conf
cp /etc/nginx/mime.types \
/home/YOUR_NAME/projects/beast/stable-1.0/config/mime.types
前者是 config 檔,後者是 mime-type 設定檔,會被 include 進去。

nano config/nginx.conf
=======================
user YOUR_NAME YOUR_NAME;
worker_processes 1;
pid /home/YOUR_NAME/projects/beast/stable-1.0/tmp/pids/nginx.pid;

error_log /home/YOUR_NAME/projects/beast/stable-1.0/log/nginx_error.log;

events {
  worker_connections 1024;
}

http {
  include /home/YOUR_NAME/projects/beast/stable-1.0/config/mime.types;
  default_type application/octet-stream;

  log_format main '$remote_addr - $remote_user [$time_local] $request '
                  '"$status" $body_bytes_sent "$http_referer" '
                  '"$http_user_agent" "$http_x_forwarded_for"';

  access_log /home/YOUR_NAME/projects/beast/stable-1.0/log/nginx_access.log main;

  sendfile on;
  keepalive_timeout 65;

  gzip on;
  gzip_min_length 1100;
  gzip_buffers 4 8k;
  gzip_types text/plain text/html text/xhtml text/css text/javascript;

  upstream mongrel {
    server 127.0.0.1:2000;
    server 127.0.0.1:2001;
    server 127.0.0.1:2002;
  }

  server {
    listen 80;
    server_name localhost;

    location ~ ^/(images|javascripts|stylesheets)/ {
      root /home/YOUR_NAME/projects/beast/stable-1.0/public
      expires 30d;
    }


    location / {
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $http_host;
      proxy_redirect off;
      proxy_pass http://mongrel;
    }
  }
}
=======================

其實還有一大堆設定我省略掉了,可以自己上官網或 google 找其他的設定。
啟動:
sudo nginx -c config/nginx.conf
關閉:
sudo kill `cat tmp/pids/nginx.pid`

我用這個去跑 YSlow, 應該是設定的關係,分數從 62 => 75...
但當然以我測試機的超低流量來看,就算直接用 mongrel 應該也是瞬間反應…

2007-08-15

Fedora Core 6 上安裝 beast (2)

不喜歡 apache 嗎?apache 沒辦法用 mod_proxy_balancer 嗎?
沒關係,我找到另外一個不錯的方式了,是 pound + lighttpd.
如果不想用 apache 的話,上一篇的 httpd 相關的東西都不要灌,
改灌:

sudo yum install Pound
sudo yum install lighttpd

我是覺得這邊分大小寫很沒意義,不過 yum 就是這樣﹍。

pound 是什麼?
The Pound program is a reverse proxy, load balancer and HTTPS front-end for
Web server(s). Pound was developed to enable distributing the load among
several Web-servers and to allow for a convenient SSL wrapper for those
Web servers that do not offer it natively.

lighttpd 我想大家都知道,一個非常快速的 http server, 只不過他的
mod_proxy 似乎有很多問題,以致於沒辦法用他。所以這部份用 pound 當
前端解決這個問題,流程變成:

http request => pound => lighttpd or mongrel cluster

安裝好後,先來設定 pound, 不過 https 就先暫時略過不管。
sudo nano /etc/pound.cfg
=========================
User "pound"
Group "pound"

ListenHTTP
    Address 0.0.0.0
    Port 80
End

Service
    URL "/(images|stylesheets|javascripts)/"
    BackEnd
        Address 127.0.0.1
        Port    1999
    End
    Session
        Type    BASIC
        TTL     300
    End
End

Service
    BackEnd
        Address 127.0.0.1
        Port    2000
    End
    BackEnd
        Address 127.0.0.1
        Port    2001
    End
    BackEnd
        Address 127.0.0.1
        Port    2002
    End
    Session
        Type    BASIC
        TTL     300
    End
End
=========================
前面的設定是把 host/images, host/stylesheets, host/javascripts
這三個 url 下的 request 都丟給 port 1999 處理,也就是等會 lighttpd
要使用的 port. 這邊使用 regex, 可以自由設定自己要的規則。假使未來 user
要使用 file_column, 可以再加個 user/avatar 之類的。

下面的則是全部丟給 mongrel_cluster 處理。設定上應該比 apache 簡單地多。
可以先測試看看,先把 lighttpd 的部份 comment 起來,啟動 pound 試試:
sudo pound

照理說這樣就能使用了。不行的話加個 config 檔路徑給他:
sudo pound -f /etc/pound.cfg

這邊我是在想要不要把 config 也放到 beast 裡面,不過 pound 應該只會
有一個,所以我想還是放到 /etc 下好了。停止 pound 的方式:
sudo kill `sudo cat /var/run/pound.pid`

製作 lighttpd 設定檔:
nano config/lighttpd.conf
==========================
server.modules = (
"mod_access",
"mod_accesslog"
)

server.port = 1999
server.bind = "127.0.0.1"
server.document-root = "/home/YOUR_NAME/projects/beast/stable-1.0/public"

server.username = "YOUR_NAME"
server.groupname = "YOUR_NAME"
server.pid-file = "/home/YOUR_NAME/projects/beast/stable-1.0/tmp/pids/lighttpd.pid"
server.errorlog = "/home/YOUR_NAME/projects/beast/stable-1.0/log/lighttpd_error.log"
index-file.names = ( "index.html", "default.html" )
accesslog.filename = "/home/YOUR_NAME/projects/beast/stable-1.0/log/lighttpd_access.log"

# mimetype mapping
mimetype.assign = (
".rpm" => "application/x-rpm",
".pdf" => "application/pdf",
".sig" => "application/pgp-signature",
".spl" => "application/futuresplash",
".class" => "application/octet-stream",
".ps" => "application/postscript",
".torrent" => "application/x-bittorrent",
".dvi" => "application/x-dvi",
".gz" => "application/x-gzip",
".pac" => "application/x-ns-proxy-autoconfig",
".swf" => "application/x-shockwave-flash",
".tar.gz" => "application/x-tgz",
".tgz" => "application/x-tgz",
".tar" => "application/x-tar",
".zip" => "application/zip",
".mp3" => "audio/mpeg",
".m3u" => "audio/x-mpegurl",
".wma" => "audio/x-ms-wma",
".wax" => "audio/x-ms-wax",
".ogg" => "application/ogg",
".wav" => "audio/x-wav",
".gif" => "image/gif",
".jpg" => "image/jpeg",
".jpeg" => "image/jpeg",
".png" => "image/png",
".xbm" => "image/x-xbitmap",
".xpm" => "image/x-xpixmap",
".xwd" => "image/x-xwindowdump",
".css" => "text/css",
".html" => "text/html",
".htm" => "text/html",
".js" => "text/javascript",
".asc" => "text/plain",
".c" => "text/plain",
".cpp" => "text/plain",
".log" => "text/plain",
".conf" => "text/plain",
".text" => "text/plain",
".txt" => "text/plain",
".dtd" => "text/xml",
".xml" => "text/xml",
".mpeg" => "video/mpeg",
".mpg" => "video/mpeg",
".mov" => "video/quicktime",
".qt" => "video/quicktime",
".avi" => "video/x-msvideo",
".asf" => "video/x-ms-asf",
".asx" => "video/x-ms-asf",
".wmv" => "video/x-ms-wmv",
".bz2" => "application/x-bzip",
".tbz" => "application/x-bzip-compressed-tar",
".tar.bz2" => "application/x-bzip-compressed-tar"
)
==========================
我很想省略 mime-type 設定,不過不設的話 firefox 好像會有問題。
safari 和 opera 是 ok 的,IE 我沒得測就沒測了。反正要設就是了,
有沒有問題不影響。只是希望 lighttpd 能內建這些設定﹍。

啟動 lighttpd
sudo lighttpd -f config/lighttpd.conf

這樣就算大功告成了!剛剛有測試 pound 的話記得改回原本設定並重新啟動。
比較詳細的介紹與說明可以參考這篇:
Configuring pound with lighttpd and mongrel.

*

summary:

用到的 server:

(1)
apache2.2 =>
reverse proxy + load balancer + serve static files

(2)
pound => reverse proxy + load balancer
lighttpd => serve static files

(3)
mongrel_cluster => setup mongrel cluster
mongrel => serve beast

結果就是 ((1) or (2)) + (3)

操作 apache:
啟動:sudo apachectl start
停止:sudo apachectl stop
重啟:sudo apachectl restart

操作 pound:
啟動:sudo pound -f /etc/pound.cfg
 或:sudo /etc/init.d/pound start

停止:sudo kill `sudo cat /var/run/pound.pid`
 或:sudo /etc/init.d/pound stop

重啟:sudo /etc/init.d/pound restart

操作 lighttpd:
啟動:sudo lighttpd -f config/lighttpd.conf
 或:sudo /etc/init.d/lighttpd start

停止:sudo kill `cat tmp/pids/lighttpd.pid`
 或:sudo /etc/init.d/lighttpd stop

重啟:sudo /etc/init.d/lighttpd restart

操作 mongrel_cluster:
啟動:sudo mongrel_rails cluster::start
停止:sudo mongrel_rails cluster::stop
重啟:sudo mongrel_rails cluster::restart

操作 postgresql:
啟動:sudo pg_ctl start
停止:sudo pg_ctl stop
重啟:sudo pg_ctl restart

2007-08-14

星之水餃安裝方式(Fedora Core 6 上安裝 beast (1))

Fedora Core 6 上安裝 beast

我選擇 apache2.2 + mongrel_cluster + postgresql

安裝 apache 和其他的東西。
sudo yum install httpd
sudo yum install httpd-devel
sudo yum install openssl
sudo yum install readline

安裝 ruby
sudo yum install ruby
sudo yum install ruby-devel
sudo yum install ruby-libs
sudo yum install rdoc
sudo yum install irb

安裝 postgresql
sudo yum install postgresql
sudo yum install postgresql-devel
sudo yum install postgresql-libs
sudo yum install postgresql-server

初始化 postgres
sudo mkdir -p /var/db/postgresql81/defaultdb
sudo chown postgres:postgres /var/db/postgresql81/defaultdb
sudo -u postgres initdb -D /var/db/postgresql81/defaultdb
sudo -u postgres pg_ctl -D /var/db/postgresql81/defaultdb \
-l /var/db/postgresql81/defaultdb/postgres.log start

拿來抓 beast... 捨 svn 取 svk 因為我討厭一堆 .svn
sudo yum install perl-SVK

sudo yum install rubygems

至少要用這些 gem
sudo gem install rails -y
sudo gem install mongrel_cluster -y
sudo gem install redcloth -y
sudo gem install ruby-openid -y
sudo gem install ruby-postgres -y

建立目錄。
mkdir -p ~/projects/beast
cd ~/projects/beast

用 svk 抓不會有一堆 .svn 礙眼。
svk mirror //mirror/beast \
http://svn.techno-weenie.net/projects/beast/branches/stable-1.0/
svk sync -s HEAD //mirror/beast
cd stable-1.0

產生讓 beast 用的資料庫。
sudo -u postgres createdb beast_prod

設定資料庫設定檔。
cp config/database.example.yml config/database.yml

nano config/database.yml
=========================
production:
  database: beast_prod
  adapter: postgresql
  host: localhost
  username: postgres
  password:
=========================

初始化 beast 資料庫。
rake db:schema:load RAILS_ENV=production

非常囉唆的 cluster 設定,user 可以開 mongrel,
不過因為我懶所以用自己的帳號跑。
sudo mongrel_rails cluster::configure -e production \
-p 2000 -N 3 -c /home/YOUR_NAME/projects/beast/stable-1.0 \
-a 127.0.0.1 --user YOUR_NAME --group YOUR_NAME

啟動 mongrel_cluster 吧。
sudo mongrel_rails cluster::start

接著是 apache2.2 的 mod_proxy_balancer 的設定,
如果 mod_proxy_balancer 沒有啟動記得把他打開。

建立 balancer 導向 port 2000~2002
sudo nano /etc/httpd/conf/httpd.conf
=====================================
<Proxy balancer://YOUR_BALANCER>
  BalancerMember http://YOUR_ADDRESS:2000
  BalancerMember http://YOUR_ADDRESS:2001
  BalancerMember http://YOUR_ADDRESS:2002
</Proxy>

Listen 80
<VirtualHost *:80>
  ServerAdmin YOUR_EMAIL
  ServerName YOUR_ADDRESS
  ProxyPass / balancer://YOUR_BALANCER/
  ProxyPassReverse / balancer://YOUR_BALANCER/
  ProxyPreserveHost on
  ErrorLog /home/YOUR_NAME/projects/beast/stable-1.0/log/apache_error.log
  CustomLog /home/YOUR_NAME/projects/beast/stable-1.0/log/apache_access.log combined

  ProxyPass /images !
  ProxyPass /stylesheets !
  ProxyPass /javascripts !
  Alias /images /home/YOUR_NAME/projects/beast/stable-1.0/public/images
  Alias /stylesheets /home/YOUR_NAME/projects/beast/stable-1.0/public/stylesheets
  Alias /javascripts /home/YOUR_NAME/projects/beast/stable-1.0/public/javascripts
</VirtualHost>
=====================================

接著啟動 apache 就 ok 了。
sudo apachectl start

最後來設定 beast 的 smtp, 如果想用 gmail 寄信的話,
我之前試過兩個方式,一個是使用 msmtp,
另一個是有人有寫一小段 ssl smtp 的 patch, 可以參考這裡:
http://www.stephenchu.com/2006/06/how-to-use-gmail-smtp-server-to-send.html

nano config/environment.rb
加入:
===========================
ActionMailer::Base.smtp_settings = {
  :address => "smtp.gmail.com",
  :port => 587,
  :domain => 'YOUR_DOMAIN',
  :user_name => "YOUR_GMAIL_ACCOUNT",
  :password => 'YOUR_GMAIL_PASSWORD',
  :authentication => :plain
}
===========================

nano app/models/user_mailer.rb
===============================
@from = 'YOUR_GMAIL_ACCOUNT@gmail.com'
===============================
我不是很確定這一步要不要做,我猜不做會被 gamil 擋掉。

接下來把那段程式碼 copy 到可以被 require 的地方,我是放在 lib 下:
nano lib/smtp_tls.rb
接著把他 require 進去:
nano config/environment.rb
===========================
require 'smtp_tls'
===========================

sudo mongrel_rails cluster::restart
註冊一下試試寄信吧!如果失敗的話,那篇連結裡有個 workaround:

nano lib/smtp_tls.rb
=====================
rescue EOFError
  ;
rescue OpenSSL::SSL::SSLError => e
  puts('Unexpected Exception: ' + e.message + ' : ' +
    e.backtrace.join("\n") )
end
=====================

我之前用是沒有這個問題,但在這台 fedora 上卻有這個問題,
也許是要更新 openssl 的版本?不管如何,加入上面那段暫時可用。

結論:
還是 macports 好用,速度快,更新快,只是 build 要很久就是了。

2007-08-08

總算弄起來 PostgreSQL 了

在 windows 上就白痴地安裝就能用了,甚至比 MySQL 還簡單。
mysql 實在是有太多怪怪的問題了,我個人實在不推薦,除非必要,
否則用 postgre-sql 應該是好得多。mysql 就我現在能想到的問題:
1. mysql socket, 真的是有夠煩的東西。
2. password algorithm changed, 那個 old_password 實在是﹍。

當然,我跟 database 不熟,其他的都只是隱隱約約聽過的說法,而上面那個
password 的問題,可能是 php 造成的,這不能怪 mysql 也說不定。
但反正用 postgre-sql 也沒什麼壞處吧?真不懂為什麼到處都在用 mysql.

用 macports 安裝:
sudo port install postgresql82
sudo port install postgresql82-server

接下來是 setup:
sudo mkdir -p /opt/local/var/db/postgresql82/defaultdb
sudo chown postgres:postgres /opt/local/var/db/postgresql82/defaultdb
sudo su postgres -c '/opt/local/lib/postgresql82/bin/initdb -D /opt/local/var/db/postgresql82/defaultdb'

這三行是 macports 指示的,初始化一個 database, 原因我不知道是什麼 XD
關於第三行,我昨天一直碰到一個問題,說什麼跟 KDC 有關的,我猜是
key distribution center, 我不知道要怎麼搞這個東西。
結果就是認證一直失敗,可以初始化 database, 但是

sudo -u postgres /opt/local/lib/postgresql82/bin/postgres -D /opt/local/var/db/postgresql82/defaultdb

不管怎麼樣都會失敗,一直在那邊 Sorry! Sorry! 的,有夠討厭。
然後我就試著改 postgres 的密碼,結果改到我的 mac os x login window
出現 postgres... 害我很不爽,google 半天好像沒有隱藏的好方法。
所以我就乾脆整個砍掉重練。

中間 google KDC 的錯誤,只能找到一筆日文的 blog, 看半天後我發現他有個
明確的指示,就是卸載 heimdal, 這真是個該死的東西啊!安裝 gnome 需要他,
但是我記得他已經好幾次讓我的安裝與配置的動作碰到很多次麻煩了。於是:

sudo port deactivate heimdal
(不能 uninstall, 因為 gnome 需要他﹍我有預感搞不好還是得弄 KDC)

接下來進行 su 時,就不會有那個 KDC 錯誤了。只是卻會出現另一個錯誤,什麼
cannot execute binary 什麼的,我忘記了,現在沒這個錯誤我沒辦法 copy XD
反正就是試了老半天都是不行,乾脆砍掉重練,這次不要啟動 heimdal 搞不好就行了。

不過在執行第三個指令:

sudo su postgres -c '/opt/local/lib/postgresql82/bin/initdb -D /opt/local/var/db/postgresql82/defaultdb'

又出現問題了。昨天明明就是很輕鬆地初始化 database, max_connections 是 30
但是今天 max_connections 只能有 10 ???
然後就噴 shared memory 不足的錯誤出來,叫我把 max_connections 降低。
看了半天,明明他的 request 才 1.6 MB 左右,這樣要降低會不會太扯了?
所以我不信他 XD

google 了半天,每個人都說要把:
kern.sysv.shmmax
調大一點。可是我不能接受,明明昨天就可以,哪有今天就不行的道理。
又試了半天,還有 google 了半天,還是找不到什麼有用的資訊,於是我決定﹍
還是把他調大好了,反正也沒差吧?我 real memory 可是有 3G 的(挺)

sudo nano /etc/rc
ctrl+w 找 kern.sysv.shmmax, 後看到:
kern.sysv.shmmax=4194304
好好,變大一倍吧!(十倍可能太誇張了)
kern.sysv.shmmax=8388608

據說這需要 reboot, 測試了一下還是不能初始化 database 後,我就 reboot 了。

sudo su postgres -c '/opt/local/lib/postgresql82/bin/initdb -D /opt/local/var/db/postgresql82/defaultdb'

過了!這次 max_connections 又回到 30 了。看來也許是我今天 shared
memory 用得比較兇的關係??天知道是什麼原因。

sudo -u postgres /opt/local/lib/postgresql82/bin/postgres -D /opt/local/var/db/postgresql82/defaultdb

成功啟動了!!雖然說他沒辦法背景執行,變成我 iTerm 要卡一個 tab 在那 XD
不過我想沒差,反正一定有辦法解決這個問題,也許就是 initdb 所說的第二行:

sudo -u postgres /opt/local/lib/postgresql82/bin/pg_ctl -D /opt/local/var/db/postgresql82/defaultdb -l logfile start 吧。

接著打開 pgAdmin3 看看,也成功連上 database 了!
http://www.pgadmin.org/
這個很好用啊,我覺得我還是需要 gui tool, cli 我不是很習慣。

還有 mysql gui tool
http://dev.mysql.com/downloads/gui-tools/5.0.html
我覺得用這個是比 phpMyAdmin 好啦﹍﹍。雖然說 phpMyAdmin 真的很好用,
但是總覺得很容易碰到問題,像是編碼問題,需要 hack 一下才能正常使用