第一次機車被拖吊

出門正要騎車載老婆去上班時,卻發現機車不見蹤影。
心想,該不會被拖走了吧。果不其然,老婆發現地上有寫下拖吊場的聯絡電話,於是…
計程車到拖吊場:NTD$180
拖吊場領車:移置費NTD$200、保管費NTD$300、在禁止臨時停車處所停車罰款NTD$600
機車平安無事…無價…

電影流水帳(2007/12/25~2007/12/31)

很拼命地看了三部片子,看到不錯的演員張靜初跟久違的桂倫鎂…

  • Bee Movie(IMDB),蜜蜂在人類法庭控訴人類盜取蜂蜜的官司故事,一開始起頭不俗,可惜後來還是脫離不了人類的思維。如果只是拿來跟小朋友介紹關於蜜蜂的一些事情還不錯。
  • 不能說的·秘密(IMDB),周杰倫自導自演的第一部電影,我自己覺得他拍的不錯,劇情流暢,氣氛也不錯,值得看看的電影。
  • 門徒(Wikipedia)。嚴格來說,並沒有真正全部都看完,從前面的三、四十分鐘切入,後面則脫漏了一些細節。描述警察為了查出整個毒網,派出臥底Nick,潛伏長達數年以查出所有細節,潛伏到最後甚至變成接班人。看得出來,導演與編劇有認真作過功課,所以對於吸毒、賣毒者的描寫非常真實。值得一看的電影。裡面張靜初與古天樂先後都提到一段屬於自己的故事:

    當初我認識他(她)的時候,他(她)就在吸毒了,後來在一起以後想勸他(她)戒掉,可是他(她)卻說不可能戒掉,於是我就陪他(她)吸,想證明可以戒掉,那知真的很難戒掉….

    ,再對照後面林昆(劉德華)講的一句話:

    那些癮君子最會裝,吊起癮來。有什麼做不出?有什麼說不出?千萬別招上這些人,不然你還以為自己做錯了。

    ,真的是很令人唏噓,毒,不能碰啊…

如何在 CentOS 安裝 Ruby on Rails

如果你照著這篇:在 CentOS 安裝 Ruby on Rails,卻怎麼樣也裝不起來的話,我想你碰到跟我一樣的問題了。錯誤訊息可能會是這樣子的:

ERROR: While executing gem … (Gem::GemNotFoundException)
Could not find rails (> 0) in any repository

研究了一下,發現應該是因為 RubyWorks 所提供的Source 沒有 rails gem 的關係,這也跟 RubyWorks 定位為 Production server 有關係。
總之如果你想把 CentOS 當作開發環境的話,不妨用

$sudo gem sources -a http://gems.rubyforge.org

把官方的 gem source 加進去,然後再輸入

$sudo gem install rails -y

即可。

點給老張的歌

今天騎車上班的時候,不知不覺哼到這兩首歌,發現跟好友老張的心境相符~
一首是野百合的春天

仿佛如同一場夢
我們如此短暫的相逢
你像一陣春風輕輕柔柔吹入我心中
而今何處是你往日的笑容
記憶中那樣熟悉的笑容
你可知道我愛你想你念你怨你深情永不變
難道你不曾回頭想想昨日的誓言
就算你留戀開放在水中嬌艷的水仙
別忘了寂寞的山谷的角落裡野百合也有春天

另一首是張震嶽作詞作曲的自由

我沒有關係 你可以假裝沒事離開這裡
一切好安靜 我只是想把情緒好好壓抑
到底誰會先說再見 我知道我一定哭泣
走的時候記得說愛我 愛我
說愛我 說愛我 難道你不再愛我
我的淚 滴下來 你從來不曾看過
為什麼 為什麼 愛情讓人變沈重
沒有人 告訴我 原來不是我想像
不要回來 你已經自由了 我也已經自由了

希望是不會走到這個地步:不要回來,你已經自由了,我也已經自由了。

How to monorail by Generator tool(4)

在研究過之後,我決定在 ScaffoldHelper.cs 裡面添加 GetText 這個函數,用來取得字串。

#region Localization helpers
public string GetText( IResource resource, string str )
{
if( resource==null )
return str;
object resStr = resource[ str ];
if( resStr==null )
return str;
return resStr.ToString();
}
#endregion

這樣在 .vm (template)檔案裡面,就可以這麼使用,以取得本地化後的字串:

$ScaffoldHelper.GetText($textres, "Name" )

當然你還是可以用原先的方法:

$textres.Name

所以 PageBrowser() 也可以跟著修正為:

#region Pagination helpers
public string PageBrowser( Page page )
{
return PageBrowser( page, null );
}
public string PageBrowser( Page page, IResource resource )
{
StringWriter output = new StringWriter();
PaginationHelper helper = new PaginationHelper();
helper.SetController(this.Controller);
string firstText = GetText( resource, "First" );
string prevText = GetText( resource, "Previous" );
string nextText = GetText( resource, "Next" );
string lastText = GetText( resource, "Last" );
if (page.HasFirst)
output.Write(helper.CreatePageLink(1, firstText ));
else
output.Write( firstText );
output.Write(" | ");
if (page.HasPrevious)
output.Write(helper.CreatePageLink(page.PreviousIndex, prevText ));
else
output.Write(prevText);
output.Write(" | ");
if (page.HasNext)
output.Write(helper.CreatePageLink(page.NextIndex, nextText ));
else
output.Write( nextText );
output.Write(" | ");
if (page.HasLast)
output.Write(helper.CreatePageLink(page.LastIndex, lastText ));
else
output.Write( lastText );
return output.ToString();
}
#endregion

最後在資源檔裡面加上必要的字串並且修改 .vm (template)以後,就可以得到本土化後的結果。

How to monorail by Generator tool(3)

這一次要講的是 Localization,不幸的是 Generator 沒有考慮到 Localization 問題,所以由 Generator 產生出來的代碼,並不包含這部份,但這卻是一個很好的機會讓我去了解 Generator 與 monorail 底下的機制。

Castle官方網站上已經有介紹該怎麼 Localization:Resources and Localization,但不幸的是,他使用 Visual Studio.Net 作為範例,Visual Studio.Net 已經掩蓋了所有細節。
在研究官方文件與相關文件之後,以下是我的步驟。

首先,你要先在 app/controllers 加上:

[Resource("textres", "ToDo.categories")]

這表示在 view(template) 那兒使用 $textres 就可以存取資源檔的內容。

所以在 app/views/categories/list.vm 裡,就可以把必要的字串改用$textres.字串名稱替代掉,這裡我就不列出整個 list.vm 了,只列出幾行:

<!--略-->
$HtmlHelper.LinkTo( $textres.AddNewCategory, "categories", "new")
<!--略-->
$HtmlHelper.LinkTo( $textres.View, "categories", "view", $category.Id)
<!--略-->
$HtmlHelper.LinkTo( $textres.Edit, "categories", "edit", $category.Id)
<!--略-->
$AjaxHelper.LinkToRemote( $textres.Delete, "delete.aspx", $DictHelper.CreateDict("with='id=$category.Id'", "condition=confirm('Delete?')", "onsuccess=new Effect.Fade('category$category.Id')"))
<!--略-->

然後我選擇在 app/ 下建立一個 resources 目錄,用來放置資源檔:

;Filename: categories.txt
;Language: en-US
View=View
Edit=Edit
Delete=Delete
AddNewCategory=Add a new Category
;Filename: categories.zh-tw.txt
;Language: zh-tw
View=檢視
Edit=編輯
Delete=刪除
AddNewCategory=加新類別

這裡要特別注意,把文字檔的編碼存為 unicode 或是 utf-8,否則會有亂碼出現。

最後修改 default.build,以便把資源檔編譯進去,這裡我也只列出關鍵的幾行:

<!--略-->
<target name="build" description="Compile all source files">
<mkdir dir="${dir.bin}" />
<copy flatten="true" todir="${dir.bin}">
<fileset>
<include name="${dir.lib.castle}/**" />
<include name="${dir.lib.npgsql}/**" />
<include name="${dir.lib.mysql}/**" />
<include name="${dir.lib.migrator}/**" />
<include name="${dir.lib.nunit}/nunit.framework.dll" />
</fileset>
</copy>
<resgen todir="${dir.src.app}/resources/">
<resources>
<include name="${dir.src.app}/resources/*.txt" />
</resources>
</resgen>
<csc target="library" output="${dir.bin}/${project::get-name()}.dll">
<sources>
<include name="${dir.config}/Boot.cs" />
<include name="${dir.src.app}/**/*.cs" />
<include name="${dir.src.test}/**/*.cs" />
<include name="${dir.migrations}/**/*.cs" />
</sources>
<resources basedir="." prefix="ToDo">
<include name="${dir.src.app}/resources/*.resources"/>
</resources>
<references basedir="${dir.bin}">
<include name="System.Web.dll" />
<!--略-->

最重要的就是 resgen 這個區塊與 csc 裡面的 resources 區塊,resgen 是把文字檔轉換為 .resources 資源檔,而 csc 裡面的 resources 則是表示要把產生出來的 .resources 編譯進去。

好了,該修改的都修改了,接下來就是重新建立,輸入 nant 就會自動重新編譯。
有點美中不足的是,下面顯示頁次的部份仍然是英文,這是因為這些字串被寫死在 ScaffoldHelper.cs 裡面,我想下次再來修改這部份。

後記:

  • csc resources 所指定的 prefix 與 [Resource(“textres”, “ToDo.categories”)] 的第二個參數息息相關,不妨修改來試試看。
  • 網站文件有提到 LocalizationFilter 的部份,但是用了卻不行,有待繼續研究。

電影流水帳(2007/12/14~2007/12/24)

  • 博物館驚魂夜Night at the Museum(IMDBWikipedia),就是很適合小朋友看的電影,整個重點還是在於博物館晚上所發生的怪事。
  • 3:10 to Yuma(IMDBWikipedia),中譯:決戰310。在台灣好像不賣座?Yahoo!電影居然查不到,或許根本沒上片也不一定。不過這部西部片很好看,由一個江洋大盜與一個瘸腿父親所交織出來的故事,最後的轉折出人意表之外。

How to monorail by Generator tool(2)

接下來,就參考這篇有名的 Four Days on Rails 來試試看吧~
首先呢,由於隔了這麼久才寫這篇,所以 Generator 改位置了,你得從這裡:http://svn.castleproject.org:8080/svn/castle/trunk/Experiments/Generator/ Checkout,其他大致都跟上篇一樣。

  1. 先利用 monorail ToDo,建立專案,接著依照上篇文章作必要的設定,同時我們使用 rc2,不使用最新的版本(也就是你不用更動 default.build),設定的部份就不再贅述。
  2. 建立資料庫,這邊我是用MySQL,建立的資料庫名稱是 ToDoDev,不過這只有跟修改連線字串有關係。
  3. 修改資料庫的連線字串,連線字串是放在 config/databases/ 下的 ActiveRecord 設定檔裡面,你可以看到這邊有兩個設定檔,他很貼心的把開發用與測試用的資料庫分開:development.xml、test.xml,事實上,你還可以增加一個 Production (或是其他名字)的 ActiveRecord 設定檔,表示這是正式上線用的資料庫。切換的時候,可以更動 config/boot.cs 以決定使用哪個 ActiveRecord 設定檔,預設是 development。
  4. 建立 Model,首先先產生”Category”,Category 的欄位如下:

    id int autoincrement
    name varchar(255)
    created_on datetime
    updated_on datetime

    ,在專案的目錄下輸入:script\generate model Categories name created_on updated_on,這邊要注意的是,不需要特別寫 id,因為慣例至上,Generator會自動幫你增加 Id 這個欄位。Generator 會幫你作三件事情:產生 Category 這個類別、產生測試 Category 的 Unit test 類別以及建立資料表格的程式,你可以從指令的輸出結果很清楚的看到。

    exists app\models
    create app\models\Categories.cs
    exists test\models
    create test\models\CategoriesTest.cs
    create db\migrations
    create db\migrations01_AddCategoriesTable.cs

  5. 接下來,要去修改 Categories 類別的屬性型態,Generator 預設都是把型態設為字串,db\migrations 那邊則都是建立 varchar(50)。所以除了 app\models\Categories.cs 要修改型態之外,db\migrations01_AddCategoriesTable.cs 下也要改!這邊把 Name 改為 255 個字元,created_on與updated_on 則改為 DateTime。
  6. 都修改完畢之後,就可以執行 nant migrate,這個步驟會幫你去實體資料庫作必要的事情。為甚麼要這樣子作?我想是因為一般資料庫的 script 是沒有作管理的,因此,才刻意把這些要去資料庫建立表格、修改欄位等的動作都放到 db\migrations 下,以便把這些程式也都納入版本控制。
  7. 執行 script\generate scaffold Category,這個步驟會一口氣幫你把 CRUD 的頁面都弄出來。
  8. 那麼,就編譯吧,直接執行 nant,只是卻出現了…

    [csc] app\controllers\CategoriesController.cs(36,72): error CS0246: 找不到型別或命名空間名稱 ‘Category’ (您是否遺漏 using 指示詞或組件參考?)
    [csc] app\controllers\CategoriesController.cs(56,45): error CS0246: 找不到型別或命名空間名稱 ‘Category’ (您是否遺漏 using 指示詞或組件參考?)

    這個,得去修改 CategoriesController.cs,把 Category 都改為 Categories,這看來是 Generator 的問題。接著又再出現

    error CS1501: 方法 ‘CreatePagination’ 沒有任何多載使用 ‘2’ 個引數

    ,唉~這個錯誤訊息實在是太黯然又太銷魂…你必須再次修改 CategoriesController.cs,添加這兩行:

    using System.Collections;
    using System.Collections.Generic;
    

    然後把

    PropertyBag["categories"] = PaginationHelper.CreatePagination( Categories.FindAll(), 10);

    改為

    PropertyBag["categories"] = PaginationHelper.CreatePagination( (IList)Categories.FindAll(), 10);

    ,接下來應該就沒問題了。

  9. 先試試看到目前為止的成果吧,輸入script\server,然後打開你的瀏覽器,在位址列輸入:http://localhost:8080/categories/list.aspx,就能看到結果了。

執行結果:
categories_list_aspx

plugin_syntaxhighlighter

blogger 使用 dp.syntaxhighlighter 的話,你會發現根本無法生效,主要是因為 blogger 把換行符號都替換成 <br/> 了,而且還沒有設定可以決定是否要替換。
很幸運地,有人已經提出解決方法:yehyeh: Blogger dp.SyntaxHighlighter斷行問題解決方法

只是,我已經套用blogger-ext2了,於是想說,是不是可以寫一個blogger-ext2的 plugin 來解決這個問題。
非常感謝jQuery的強大功能,不到半天就完成了,最重要的是,不用像上面解決方法一樣,寫了一堆 code。

// Register dp.SyntaxHighLighter
// Dependency:
//   jQuery-1.2.1
//   blogger-ext2-core (最新版,0.7.x 的樣子)
//   dp.syntaxhighlighter-1.5.1
BloggerExt.SH = function() {
// Plugin 會由此開始
if( dp!='undefined' ) {
// 找到 pre, textarea 下所有 br,然後替換成換行符號,收工。
jQuery("pre > br").each( function() { jQuery(this).replaceWith( "\n" ); } );
jQuery("textarea > br").each( function() { jQuery(this).replaceWith( "\n" ); } );
dp.SyntaxHighlighter.ClipboardSwf = 'http://syntaxhighlighter.googlecode.com/svn/tags/1.5.1/Scripts/clipboard.swf';
dp.SyntaxHighlighter.HighlightAll('code');
}
};
BloggerExt.SH.user_pref = function() {
var prefs = [];
return prefs;
};
BloggerExt.SH.update_pref = function(prefs) {
};
BloggerExt.register('SH', { SH: true} );

使用範例:

<script type="text/javascript" src="jquery-1.2.1.pack.js"></script>
<script src="blogger_ext2.js" type="text/javascript"></script>
<script type="text/javascript" src='http://syntaxhighlighter.googlecode.com/svn/tags/1.5.1/Scripts/shCore.js'></script>
<script type="text/javascript" src='http://syntaxhighlighter.googlecode.com/svn/tags/1.5.1/Scripts/shBrushCSharp.js'></script>
<script type="text/javascript" src='http://syntaxhighlighter.googlecode.com/svn/tags/1.5.1/Scripts/shBrushVb.js'></script>
<script type="text/javascript" src='http://syntaxhighlighter.googlecode.com/svn/tags/1.5.1/Scripts/shBrushPhp.js'></script>
<script type="text/javascript" src='http://syntaxhighlighter.googlecode.com/svn/tags/1.5.1/Scripts/shBrushJScript.js'></script>
<script type="text/javascript" src='http://syntaxhighlighter.googlecode.com/svn/tags/1.5.1/Scripts/shBrushSql.js'></script>
<script type="text/javascript" src='http://syntaxhighlighter.googlecode.com/svn/tags/1.5.1/Scripts/shBrushXml.js'></script>
<script type="text/javascript" src='http://syntaxhighlighter.googlecode.com/svn/tags/1.5.1/Scripts/shBrushPython.js'></script>
<script type="text/javascript" src='http://syntaxhighlighter.googlecode.com/svn/tags/1.5.1/Scripts/shBrushCss.js'></script>
<script type="text/javascript" src='http://syntaxhighlighter.googlecode.com/svn/tags/1.5.1/Scripts/shBrushCpp.js'></script>
<!--假設你已經把上面代碼存為 plugin_syntaxhighlighter.js 了 -->
<script type="text/javascript" src='plugin_syntaxhighlighter.js'></script>