2010年9月23日

WAPP = Windows + Apache + PostgreSQL + PHP5

BitNami WAPPStack greatly simplifies the development and deployment of PHP applications. It includes ready-to-run versions of Apache, PostgreSQL, PHP and phpPgAdmin and required dependencies. It can be deployed using a native installer. BitNami WAPPStack is distributed for free under the Apache 2.0 license.

Windows環境開發PHP5網頁應用,若資料庫搭配MySQL,則有許多All-in-one的整合安裝程式可用,例如XAMPPAppServ等。開發階段需要的Apache+PHP5+MySQL+phpMyAdmin等,都可以一次搞定,省去個別下載、安裝及設定的困擾。

但如果選用PostgreSQL資料庫,是否也有這樣方便的整合安裝程式呢?

當然也可以拿XAMPP、AppServ來加裝PostgreSQL,但BitNami WAPPStack已經幫我們把一切搞定了,它整合以下開發PHP5+PostgreSQL的基本需求軟體。
  • Apache 2.2.14
  • PostgreSQL 8.4.4
  • PHP 5.2.14
  • PHPPgAdmin 4.2.2
下載WAPPStack: http://bitnami.org/stack/wappstack

雖然只要一個安裝程式就能搞定,但我們如果希望它能更方便一點,其實可以自己打包成可攜式的綠色軟體。我們只要將它安裝至特定的路徑,例如 C:\WAPP ,再把整個資料夾打包,就可以放在隨身碟帶著走,需要用它的時候再解到相同位置。

但是少了安裝程式的執行過程,有些動作就必須自己寫批次檔代替,WAPPStack自動設定的服務名稱有wappstackApache、wappstackPostgreSQL兩個。以下的批次檔需要放在WAPP資料夾下,可以幫我們處理掉安裝、移除、啟動及停止服務。

install services
serviceinstall.bat INSTALL

uninstall services
serviceinstall.bat REMOVE

startup services
net start wappstackApache
net start wappstackPostgreSQL


shutdown services
net stop wappstackApache
net stop wappstackPostgreSQL

2010年9月21日

[Lighter Java] Select Java Client / Server VM

最近發現一些啟動java vm的參數,會影響到伺服器運作的效能。若執行的程式很小,不太需要調校,但是對Tomcat、JBoss等J2EE container來說,一些參數的設定就會有比較明顯的影響。

JVM在啟動時,會依據作業系統及處理器核心數量、記憶體容量判別 Client 或 Server 兩種機器類型。

從Oracle提供的「Server-Class Machine Detection」文件來看,Java SE6對伺服器等級機器(server-class machine)的定義為:「至少擁有2個核心以上的處理器、2個Gigabyte以上的實體記憶體。」

實際啟動JVM時,也會根據作業系統的不同而有預設的差異。
  1. 在AMD64平台上,不管Solaris/Windows/Linux預設都是server vm,並且不提供client vm。
  2. 在x86(i586)平台,除Windows是預設client vm,其他Solaris/Linux則是依照伺服器等級,若條件符合就預設server vm,否則還是會使用client vm。
所以需要調整的情況,就是當作業系統為32位元的Windows,擁有足夠的記憶體容量及多核心處理器,而java卻選擇client vm,我們需要手動指定server vm。另一種情況則是32位元的Linux伺服器,雖然未達到Java SE6定義的伺服器等級,但那部伺服器專跑J2EE應用,可以佔用大部分系統資源,仍可指定為server vm。

並非每一種情況用server vm執行都會比較好,依照Oracle提供的文件所述,server vm在啟動時可能會比較慢,但長時間運作來看則會較好的效能。

要判別java預設用哪一種vm,可以用 java -version 查詢。

例如這是一個server vm的輸出。
java version "1.6.0_21"
Java(TM) SE Runtime Environment (build 1.6.0_21-b06)
Java HotSpot(TM) 64-Bit Server VM (build 17.0-b16, mixed mode)

以下則是client vm的輸出。
java version "1.6.0_21"
Java(TM) SE Runtime Environment (build 1.6.0_21-b07)
Java HotSpot(TM) Client VM (build 17.0-b17, mixed mode, sharing)

在java後面添加 -server 或 -client 參數,可以建議java使用指定的 client或server vm。
  1. java -server
  2. java -client
要測試java是否依照參數啟動,同樣用-version指令。
  1. java -server -version
  2. java -client -version
有些情況下, java -server 會跑出以下的錯誤訊息。
Error: no `server' JVM at `C:\Program Files\Java\jre6\bin\server\jvm.dll'.

這種情況是因為安裝的Java Runtime並未包含server vm需要的支援,我們需要將環境變數的PATH設定,重新指定為JDK的bin路徑,例如「c:\Program Files\Java\jdk1.6.0_21」。

"c:\Program Files\Java\jdk1.6.0_21\bin\java.exe" -server -version

要設置 -server 最好不要直接寫在 JAVA_OPTS ,因為對於一些GUI應用程式或Applet來說,用server vm執行並不見得比較好;因此設定在 CATALINA_OPTS (tomcat) 或 JBOSS_OPTS (jboss) 是比較好的選擇。

圖片來源:The Java HotSpot Performance Engine Architecture
根據Java HotSpot白皮書的說明,Client VM的編譯器不像Server  VM執行很多的最佳化,所以花比較少時間分析和編譯代碼,因此Client VM啟動速度較快。


The Client VM compiler does not try to execute many of the more complex optimizations performed by the compiler in the Server VM, but in exchange, it requires less time to analyze and compile a piece of code. This means the Client VM can start up faster and requires a smaller memory footprint.

延伸閱讀:

2010年9月12日

話說退伍後找工作這回事

退伍後最常被問到的問題,就是「在哪裡工作」。

認識的人大多退伍、畢業,準備開始就業,都好關心「工作」這件事,好像沒有工作整個人就會枯萎似的。這種焦急程度和以前在學校時判若兩人,以前那些面對未來的現實還能放慢腳步、神態自若的學子,一夕之間都融入現實社會了。許多人關心在「哪裡」工作,許多人在意是不是一份「好工作」。

我這才察覺到自己似乎也要對「工作」這件事情,抱著嚴肅一點的態度去面對。

有不少人問我幹嘛不去業界找間科技公司待?!這實在很難簡短回答。

只能說,心裡最後的決定都是經過無數次的反覆掙扎,才痛下決心。

在當兵入伍前,我就已經不打算退伍後要急著去找工作,如果按照原訂計畫,我是想先出國一陣子再說,只是計畫趕不上變化,沒辦法按部就班地執行。

大概從七年前開始算起,我雖然一直都是念日校的學生,但其實我花在工作的時間一直遠遠大於課業的時間。有很多時候,我沒去上課,是為了趕案子,報告、考試沒準備就上陣,是因為前天案子做不完,爆肝熬夜到天亮。

為什麼不好好當個學生就好呢?!這也很難回答。

早在我還年幼不懂事的時候,我就已經深刻感覺到自己對念書沒啥興趣,只想把時間揮霍在可以獲得樂趣的東西。所以國中畢業後,我心裡早就沒有要去升學的準備;繼續待在學校當個學生,一來是父母希望我這樣做,二來是出去外面也不知道要幹嘛,第三則是抱持著到學校或許可以遇到相同興趣的人,所以最後隨便就去念了五專。

專四、專五我花大部分的時間在工作、網咖、圖書館,很多時候我並不知道學校老師教過什麼。

五專快畢業的時候,原本已經準備好先當兵找工作的,但莫名其妙居然還考得到一間學校,我從沒想過花兩三個星期看題庫會有什麼效果。這一次是我爺爺希望我繼續念,二來是我覺得最後一張畢業證書能印個國立似乎好看些,第三則是繼續念書我仍可以維持工作及收入。

繼續念二技的選擇,後來我覺得是對的。因為在那段時間,我得到和更多公司合作的機會,不乏能給更好條件的公司,學校給的工讀金拿來付學費也綽綽有餘,多餘收入足夠我繼續在興趣上揮霍。而覺得自己念書不如人,也讓我在這段時間多少知道學校老師教過什麼。

後來繼續念研究所,其實已經完全在意料之外,我並沒太大的興趣做學術研究,但暫緩兵役讓我有時間繼續完成手邊的工作。那兩年我花在學校的時間不多,而在學校大多時間也是幫老師工作。大多數的時間我除了工作,也增加其他不少休閒玩樂,但這並沒有讓我荒廢論文研究的課業,只是爆肝的時間又多了點,白天上課要硬撐著眼皮。這兩年的收入明顯多了些,讓我可以揮霍在更多的興趣上,時間過得很充實,接觸更多東西讓我覺得這段時間值得。直到畢業後才發現,研究所兩年期間的收入加總有超過一百萬。

一直有好長一段時間,每天除了白天上課還要完成好幾件工作,我覺得好累,很不想再工作了。如果有機會真想逃出國去走走,呼吸新鮮空氣。山裡騎單車讓我能短暫滿足幻想,所以我騎車。

作為一個不務正業的學生,我遇到的大多問題都不是來自課業,而是來自工作。

當工作把自己逼到一個懸崖上,就會開始重新思考為什麼工作。

我曾經告訴我的指導教授,以後我不想做軟體設計的工作,他很訝異、覺得可惜。但其實是我已經把職業和志業給混淆了,所以無法分辨什麼才是自己想要的價值所在。

入伍讓我有機會告別手邊所有工作,無事一身輕地放長假去。當兵的日子雖然苦悶又無聊,但卻是我這幾年來,少有的心理休息時間,每天就是慵懶地去完成一連串不需動腦的雜事,無時無刻都有人可以聊天打屁,沒什麼壓力。

在每次夜深人靜站哨時,我經常思考「志業」與「職業」的問題。

退伍後要急著找好工作?!我找不到這麼做的理由為何,與其著急還不如好好休息,思考一下如何發展志業,而不是急促開始一生的職業。

職業是個枷鎖,而志業讓你得以自由。

有了好幾年累積的辛酸路程,在退伍後重構「生活」時,我對於工作更小心謹慎地設下自己的規則,以免落入充滿職業的人生。

找一個在別人眼中似乎還不錯的大公司的工作,然後開始把「job description」的內容上手,凡是要看好的那一面,培養對工作的熱忱及興趣,把被交付的工作做得盡善盡美,努力求表現好取得升遷加薪機會,在這家公司看不到希望就換一家試試,再怎樣都要努力得到退休的機會。

以上,我並不希望發生在自己身上,因為那是我眼中的職業。

我相信每個人都有天賦,但是要讓天賦自由,並不是單單選擇一個好的職業就能辦到。並非每個人都適合到一家大企業任職,有些人天生很適合,有些人則不,沒有好與不好的問題。

發展一條最適合自己的路,並不容易,有時候甚至動輒創業才能找到這條路。這條路不見得是最舒適,它可能滿佈荊棘與泥沼。但只要走上最適合自己的路,很容易就會發現心情是隨時保持愉悅的,每跨出一步都是充滿動力,因為心裡早已清楚自己的目標就在前方。

我知道「設計能幫助別人的好軟體」是我這輩子的理想,我希望自己的志業是成為能對世界作出那麼一點貢獻的軟體設計師,我只是個平凡人,所以只要有一丁點貢獻就心滿意足。軟體設計讓我很容易找到樂趣,但也很容易迷失、迷惘。這把兩面刀刃劃傷自己的時候,就是當我察覺自己正在做軟體設計,但不是為了理想,而只是為了自己的飯碗、為五斗米折腰的時候,那種時候,一點一滴流失的生命,換來的只有錢而沒有快樂。

因此,我對工作仍抱有不少想像。
  • 要有足夠的時間陪家人或自己獨處
  • 興趣即工作,隨時都能得到樂趣,不需要培養就能熱血沸騰
  • 工作會上癮,能沉浸在其中無法自拔,就像打一款經典PC GAME那樣
  • 工作與理想有相同的目標,要對社會有貢獻
  • 能真的發揮所長,心裡很明確知道這是天賦,而不必欺騙自己
  • 每天早上都能興奮地醒來、期待著趕快開始工作
  • 希望時間腳步放慢點,可以繼續沉浸在工作的愉悅中
  • 週末度假時,能抱著期待挑戰下週工作任務的心情 
  • 五個工作天結束時,能驚覺自己完成大量的任務
  • 能夠不斷追求更好的效率,完成更困難的挑戰,而不必計較是否值得
  • 需要休息的時候,隨時能夠放下,不用勉強自己的身心
  • 即使在工作中,仍隨時能感覺到時間屬於自己
  • 收入不必太多,但是和努力、專業程度成正比,能滿足生活所需和合理物質慾望即可
  • 不要把獲利擺第一,至少心裡確實這樣想,雖然實際上還是要賺錢才能活
  • 工作和生活沒有清楚的界線,工作完全是自己生活的一部分
  • 能不斷充實新知、專業,除工作技能,還能不斷學習跨領域知識
  • 一天比一天更專業,有足夠的時間研究、創造新的東西
  • 能夠全力以赴去做自己認為對的事,而不必浪費時間獲得每個人的支持
  • 每天都能有正常的作息、用餐及運動時間
  • 可以得到自己渴望的東西,至少未來有機會
  • 當想法改變時,可以不用因此換工作,就能實現新的想法
  • 理想總有一天會實現
既然志業不是一蹴可藉,那用一輩子時間來換總行吧?

或許,找個工作,有份收入,對初入社會口袋空空的我們來說很重要。但對我來說,我寧願多花點時間讓自己有機會做志業、而非職業。

在決定自己要做什麼工作時,我不在乎自己薪水跟別人比起來是多是少,工作能讓自己得到多少真正想要的價值才是重點。我知道收入是要靠自己努力而不是等公司決定,我也從來不期望一家公司會給工程師「遠高於工程師」的薪水,換句話說也不必期望一家公司會給經理「遠高於經理」的報酬。相較之下,一家出發點良好的微型新創公司,比起金字招牌的大大大公司更吸引我,一個能幫助我完成階段目標的任務,也遠比一個讓別人覺得好聽的職稱更有趣,我只在意自己的能力能成長多少%並發揮多少%。不在一家公司上班的時候,自己還有多少價值才是我所關心。

很多事情都不是在人力銀行急急忙忙找份工作,就可以看得見、想得清楚。比起「在做什麼工作」,「最近玩什麼」、「在研究什麼」、「發現些什麼」,或許更能夠讓你我交流。

找工作這回事,對我來說,慢慢來,比較快!

2010年9月11日

Blogger加掛SyntaxHighlighter,顯示漂亮的彩色程式碼

Syntax Highlighting是一種讓程式碼更容易閱讀的方法,透過不同色彩及字體的標示,讓閱讀者更容易分辨變數、保留字、函式等關鍵字。

以PHP來說,最常用的Syntax Highlighting工具就是老牌的GeSHi,它支援的程式語言種類之多,讓人冒出驚嘆號!而且直到最近它一直都有在維護、改良,我在一個星期前發現它新版不能正確解析Scheme程式語言的程式碼,把bug提交給GeSHi開發者的Issue Tracker,結果很快就釋出改正的新版本。

然而GeSHi需要在伺服器端做處理,如果是自己架設的部落格,要整合GeSHi並不難,而且通常都有現成的外掛可用。

但是以Blogger這種放別人家的網誌服務,就沒辦法用簡單的方法整合GeSHi。

幸好有syntaxhighlighter的出現,僅靠瀏覽器端執行的JavaScript就可以達到相同效果。

最新的syntaxhighlighter版本已經移到這裡「SyntaxHighlighter  3.0.83」,目前仍有在持續維護。雖然支援的程式語言種類沒有GeSHi那樣包山包海,但對於常見的程式語言來說(如下列表),已經相當夠用了。
AS3, Bash, ColdFusion, CSharp, Cpp, Css, Delphi, Diff, Erlang, Groovy, JScript, Java, JavaFX, Perl, Php, Plain, PowerShell, Python, Ruby, Scala, Sql, Vb, Xml

使用SyntaxHighlighter對網頁的SEO也是有幫助的,因為程式碼在HTML原始碼中是完整的呈現,像Pastebin.com用JavaScript的方式內嵌,實際網頁原始碼根本沒有包含程式碼;同時,在最後輸出給瀏覽器的HTML中,<pre>...</pre>之間是原始的程式碼文字,並不會被加入額外的HTML標籤。所以瀏覽者在搜尋時,關鍵字若出現在網誌提供的程式碼中,文章就會更有機會被找到。

讓人興奮的是,SyntaxHighlighter有提供公開的Hosted Version,這意味著純粹使用Blogger寫網誌,而沒有申請其他檔案寄存服務的使用者,並不用再麻煩地去註冊一個空間來放所需的檔案,也不必偷偷使用別人的連結。設定的步驟相當簡單,請參考以下設定步驟。

SyntaxHighlighter預設已有不錯的行號顯示:

在Blogger的後台,打開「設計」、「修改HTML」。

先找到<b:skin>標籤,在此標籤前加入以下代碼。
<!-- SyntaxHighlighter  3.0.83-->
<link href='http://alexgorbatchev.com/pub/sh/current/styles/shCore.css' rel='stylesheet' type='text/css'/>
<link href='http://alexgorbatchev.com/pub/sh/current/styles/shThemeDefault.css' rel='stylesheet' type='text/css'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shCore.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shAutoloader.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushAS3.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushBash.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushColdFusion.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCSharp.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCpp.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCss.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushDelphi.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushDiff.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushErlang.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushGroovy.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJScript.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJava.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJavaFX.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushPerl.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushPhp.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushPlain.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushPowerShell.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushPython.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushRuby.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushScala.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushSql.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushVb.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushXml.js' type='text/javascript'/>

再找到</body>標籤,在標籤前加入以下代碼。
<!-- SyntaxHighlighter  3.0.83-->
<script type='text/javascript'>
     SyntaxHighlighter.all()
</script>

完成修改後,儲存。

接著在編輯網誌文章時,使用「修改HTML」模式,使用<pre>標籤來呈現程式碼,而class屬性則設為「brush: 程式語言代碼」,程式語言代碼請參考在文章開頭的SyntaxHighlighter已支援程式語言列表。
<pre class="brush: groovy">
println 'Hello World'
println 1 + 2 + 3
</pre>

另一個議題是,當我們要放的程式碼文字,包含了HTML的特殊字元,例如大於>、小於<等,這時候就需要用HTML編碼工具先轉換好,否則Blogger會認為文章包含不合法的HTML標籤。

如果您使用的瀏覽器剛好是先進的Firefox,可以參考我們先前發表過的Blogger HTML Encode文章,使用我們開發的Greasemonkey Script即可以輕鬆解決這個問題。

使用Groovy與OpenCSV,動態Class Library加載

由於Java程式依賴CLASSPATH設定,如果將需要的JAR檔都丟到CLASSPATH指定的lib路徑,很一定會造成資料夾內容凌亂不堪;但每次要執行Java程式都要以-cp指定自定CLASSPATH的話,又會是個麻煩事。
對於可以很方便寫小程式的Groovy來說,我喜歡使用懶人做法,把「開始資料夾\Groovy\Start GroovyConsole」打開就開始寫程式,特別是拋棄式的小程式,寫完執行目的達到就可以丟掉的那種,我可不想又為它建一個資料夾、存檔,而且還要跟需要的JAR檔放在一起。
在Groovy程式裡我們可以用this.class.classLoader.rootLoader.addURL()加載需要的JAR檔,而不需要去修改系統變數或是執行參數,JAR檔喜歡放在哪邊都沒關係。
以下的Sample程式碼,展示Groovy如何使用OpenCSV提供的CSVWriter建立一個CSV檔。
jar_file = new File("D:\\javalib\\opencsv-2.2\\deploy\\opencsv-2.2.jar")
csv_file = new File("D:\\yourfile.csv")

this.class.classLoader.rootLoader.addURL(jar_file.toURL())
import au.com.bytecode.opencsv.CSVWriter

String[] row = "one,two,three".split(',')

writer = new CSVWriter(new FileWriter(csv_file), (char)'\t')
writer.writeNext(row)
writer.close()

2010年9月10日

Java / Groovy 的 HTML Encoding

開發網頁應用時,有些情況我們需要將資料庫讀取的文字,先經過編碼後再輸出,因為直接輸出原始文字,有些文字會被當作HTML的標籤或特殊字元處理。

例如程式碼中的 大於"<" 、 小於">" 等符號。

PHP程式可以用:
  • htmlspecialchars
  • htmlentities
在Java及Groovy程式我一直沒認真去找最佳答案,JSTL有escapeXml屬性,EL有 ${fn:escapeXml(problem)} 有些情況用string replace,有些情況用XML generator提供的function,總之,解決方法很多但就是不知道哪個比較好。

今天又遇到需要輸出大量程式碼的問題,再度認真google一下,發現Apache Commons Lang有提供StringEscapeUtils

下載 Apache Commons Lang

直接呼叫static method即可,用起來算是方便。
org.apache.commons.lang.StringEscapeUtils.escapeHtml(source_text)

這是目前我覺得滿意的解決方式,因為 Apache Commons 出品可以信賴,另外它也提供很豐富的功能(參考文末提供function list)。要說有什麼缺點,我想應該就是殺雞用牛刀的問題吧,為了一個小功能又要放進新的library,而且只用到其中一個class的一個method。不過在開發J2EE應用時,我已經不太在乎殺雞是不是用牛刀,目前手邊的專案規模還很小,但 WEB-INF/lib 資料夾就已有36個JAR檔,God bless my java。

CSV、HTML、Java、JavaScript、SQL、XML一包搞定。

static String     escapeCsv(String str)
static void     escapeCsv(Writer out, String str)
static String     escapeHtml(String str)
static void     escapeHtml(Writer writer, String string)
static String     escapeJava(String str)
static void     escapeJava(Writer out, String str)
static String     escapeJavaScript(String str)
static void     escapeJavaScript(Writer out, String str)
static String     escapeSql(String str)
static String     escapeXml(String str)
static void     escapeXml(Writer writer, String str)
static String     unescapeCsv(String str)
static void     unescapeCsv(Writer out, String str)
static String     unescapeHtml(String str)
static void     unescapeHtml(Writer writer, String string)
static String     unescapeJava(String str)
static void     unescapeJava(Writer out, String str)
static String     unescapeJavaScript(String str)
static void     unescapeJavaScript(Writer out, String str)
static String     unescapeXml(String str)
static void     unescapeXml(Writer writer, String str)

Ajaxload 免費提供開發Ajax應用時所需的Loading圖示

開發AJAX應用時,如果在背景更新某個區塊的HTML代碼,會比起重新載入頁面流暢許多,但是在等待網頁伺服器回應的這段時間,使用者會不知道自己剛剛按下去的動作,到底是執行了沒。

這時候可以放一個Loading的圖示,讓使用者知道目前是在等待回應的狀態。

在找合適的Loading圖示時,剛好發現這個 Ajaxload 網站,免費提供多款樣式的圖案,有自訂前景背景及透明背景等選項,很容易就能夠挑到一個滿意的樣式。

2010年9月7日

早該知道的程式設計兩三事

今天一早打開Desire的RSS Reader,就點進這篇文章《Programming Things I Wish I Knew Earlier》,作者Ted Dziuba以linux geek的觀點談論程式設計這件事。

以下引述自原文內容。

會有這些想法,是因為在新創公司工作,軟體開發人員同時必須身兼系統管理員。

兩條簡單的規則,避免過度的複雜化

  1. 避免寫一支程式同時取用兩個以上的資料來源
    最佳情況就是讓程式跟大多數Unix指令工具一樣,一個程式負責一個input產生一個output。
  2. Linux可以做的事,就不要傻傻地自己去做
    除非xargs指令解決不了問題,否則就不要去用Hadoop MapReduce (一種新興雲端概念的框架)
    不要實作自己的鎖定服務,除非Linux的檔案鎖定沒有作用
    盡量用ImageMagick處理影像檔,除非必要否則別去用PIL之類的影像處理函式庫
    現代的Linux發行版已經解決大量的問題,你需要做的只是去找方法
(譯註:如果能解決問題的工具不是OpenSource軟體,身為台灣人,你可以選擇用盜版、也可以自己重新實作,在良心及肝功能之間作抉擇。所幸大部分我所需的功能都有OpenSource替代方案。拿xargs跟Hadoop MapReduce相比有些誇張,換個方式說,能用SQLite/MySQL滿足的需求,就不要傻傻地用SQL Server或Oracle Database搞死公司自己。ImageMagick是很方便的命令列影像處理軟體,最常用的是它的convert轉檔指令,做個縮圖轉格式啥的靠它就能搞定,通常沒必要去用緩慢又要自己handle錯誤的函式庫,但使用ImageMagick要注意安全性問題)

當你真的需要時才去做平行處理,而不是光想要就去做
一台機器處理得不夠快,無法滿足需要時,應該去分析為什麼跑得這麼慢,而不是急著去做更複雜的平行處理。

如何照料一個行程
在一個行程掛點(crash)時,要讓它可以自動重新執行,有Upstart工具可以用,設定檔的範例如下。
respawn
respawn limit 10 600
exec python /path/to/my/program.py

NoSQL is NotWorthIt
Ted嘗試將Redis用在非主要任務的系統,那些應用程式的資料如果流失並不是什麼大不了的事。大多時候可以運作,但問題發生時,Redis伺服器hang住,socket連線接通後卻沒有回應,重新啟動伺服器花了45分鐘才恢復。也許其他NoSQL資料庫情況會好一些,但是問題點還是一樣,為什麼好端端的PostgreSQL同樣可以完成工作不用,而非要去玩新奇卻必須冒險的東西。

Event Loops are Just Okay
Wikipedia上提供的一段Event Loops程式碼示範。

function main
    initialize()
    while message != quit
        message := get_next_message()
        process_message(message)
    end while
end function

簡單說,就是每次收到任務時才開始做事,而且必須做完一件才接受下一個任務。
最危險的是程式設計師搞不清楚自己做了什麼事。在event-loops及thread之間抉擇最佳的方式,必須視I/O bound等軟硬體的特性,有時也可以混著用。

Hardware Matters
雲端運算的強大似乎很有吸引力,當它變得高效能又可靠時,世界各地的不同電腦將成為你程式執行的實體機器。這裡不是在談論Extra Large EC2的容量超大,而是一個系統效能特徵為何。
舉例來說,對輸出資料量龐大的應用程式,你會希望呼叫 fsync (通常是用在實際將資料寫入磁碟) 時盡可能早點結束,fsync是作業系統提供的函式,它你的程式無法控制的黑盒子。當這是一個瓶頸時,必須靠的是硬體升級,裝一個內建電池的RAID控制器,這樣 fsync 呼叫幾乎可以立即完成,因為RAID控制器的記憶體可以先保存資料,即使遇到電源失效,它也能保證資料最後會被寫入。
對於必須讀取大量資料的應用程式,當對檔案的隨機存取動作頻繁時,花多點錢裝上效能不可思議的固態硬碟(SSD),就能夠解決磁碟讀取效能的問題(但是對循序讀取的程式來說差異就沒那麼大)。
硬體開銷是資金的好去處之一。要解決效能的問題,花錢升級硬體比起重寫程式有效率多了。當你用普通的機器執行程式,就不該期望它能跑出不普通的效能。

2010年9月6日

網頁內嵌PDF文件閱讀器使用Google Docs Viewer

Google Docs Viewer  目前支援DOC、PDF、PPT、TIFF三種檔案格式。

這個服務有開放給End User,只要連到下面這個網址,填入檔案位址「必須符合上述幾種有支援的檔案格式」,就可以產生線上閱讀器的連結位址。
http://docs.google.com/viewer


要使用這個閱讀器,檔案必須已經上傳到某網站,且必須是公開可讀取。Google Docs Viewer服務並不提供上傳檔案,因為Google Docs、Google Sites等服務都可以寄存文件檔案。

以下是一份PDF格式的投影片網址,以及產生的線上閱讀器位址。
http://www.ubuntu.com/system/files/u35/Centrify-Final.pdf
http://docs.google.com/viewer?url=www.ubuntu.com%2Fsystem%2Ffiles%2Fu35%2FCentrify-Final.pdf

Google提供Docs Viewer服務,對很多網路應用應該能提供不少幫助。

還記得以前念的學校導入一套網路學習平台(LMS),老師們可以將PDF、PPT、DOC的教學文件丟到線上課程中。但如果沒有另外製作HTML版本的教材,那用起來就挺麻煩,學生的電腦必須裝有PDF Reader、Office Word/PowerPoint等軟體。

這樣子操作起來,線上學習平台變得很像FTP伺服器,只要閱讀軟體跟瀏覽器的整合不是很理想,就必須先下載到自己的電腦才能打開。而且現在的閱讀裝置愈來愈多,小筆電、手機、平板電腦、電子書,只為了看文件而在這些裝置加入肥大的軟體,即使使用者願意裝,也不見得裝置跑的作業系統能允許,即使真能裝上相容的軟體,還不見得能跟學習平台良好整合。

Google Docs Viewer似乎幫我們解決這問題了!(雖然Term of Service內容還看不到@@)

網頁內嵌Docs Viewer簡單到不行,只要幫文件所在網路位址產生一串<iframe>。
<iframe height="780" src="http://docs.google.com/viewer?url=www.ubuntu.com%2Fsystem%2Ffiles%2Fu35%2FCentrify-Final.pdf&amp;embedded=true" style="border: medium none;" width="600"></iframe>

J2EE Servlet request.getParameter() UTF-8 encoding issue

在J2EE平台開發Web Application,編碼是一個要小心處理的問題。儘管我們選擇整個系統採用一致的UTF-8編碼,卻有以下一堆設定要注意:
  1. JSP pageEncoding
  2. contentType in http header and html
  3. response.setCharacterEncoding
  4. request.setCharacterEncoding
  5. useBodyEncodingForURI
  6. URIEncoding
再搭配Groovy或Quercus(php)使用,除了file.encoding問題,還有GET/POST資料處理的編碼問題。

為了做最後一到防線,讓以後碰到編碼問題不必東改西改,我設計一個fetch method來解決GET/POST編碼問題。

pseduo code

class ServletHelper {
  method fetch ( name, defaultValue ) {
    if request.getParameter( name ) not exists {
        return defaultValue
    }
    if request.characterEncoding is UTF-8 {
      return request.getParameter( name ) as UTF-8
    }
    else {
      return request.getParameter( name )
    }
  }
}

2010年9月4日

jQuery Sandbox

週末用了幾個小時打造這個新站「jQuery Sandbox」。以DokuWiki為基礎,提供使用WIKI語法的內容編輯。

這個網站提供一個簡單的服務:快速地測試、展示一段簡單的jQuery程式碼。

將文字介紹、HTML及JavaScript程式碼,以WIKI語法完成編輯後,就會產生一個具有demo及download按鈕的畫面。

使用者按下demo,可以立即看到測試網頁執行結果;按下download即可把原始碼下載到自己的電腦。



對於開發者來說,在測試新語法的過程中,可以方便地在線上測試一段code,看看是否能正常運作,並且在完成後,就立即成為可作展示或教學的網頁,展示的程式碼經過著色(syntax highlighting),用WIKI語法要加上一些說明文字也很容易。當然,還可以將連結放在自己的部落格。

其實,jQuery Sandbox的功能並不限於jQuery的程式碼,只要是網頁HTML代碼都可以當作內容,不過我暫時只想將它當作展示jQuery語法使用方式的WIKI網站。

在開發這個網站的過程中,發現DokuWiki蠻容易開發這類的應用,以這些功能來說,僅加入及修改不到20行程式碼就完成了。

連結

2010年9月1日

清除Windows的DNS快取

在修改DNS伺服器的A/CNAME紀錄後,瀏覽器或網路程式仍然讀取快取的舊紀錄。

如果不想等待快取更新,可以用幾個指令可以解決這個困擾:
  1. 清除DNS快取可以用“ipconfig /flushdns”指令。
  2. 測試快取中的DNS紀錄用“ping aaa.bbb.ccc”指令。
  3. 由ISP提供的DNS伺服器查詢用“nslookup aaa.bbb.ccc”指令。


若要關閉Windows快取機制:
  1. 執行“regedit”,找到 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\ Dnscache\Parameters 
  2. 編輯或新增一個DWORD數值,命名為 NegativeCacheTime 並將其值設為
lyhcode by lyhcode
歡迎轉載,請務必註明出處!