程式碼高𠅙

2008/12/10

小朋友的邏輯測驗

小二的國語參考書上看到一個選擇題,題目是:
「媽媽說,哥哥和我是她的一對寶貝 (1) 兒女 (2) 女兒」
唸小二的大兒子,兒女、女兒亂猜一通…
再問念小一的小兒子,他也不能正確答題。
於是我問他們,說這話的是誰,大兒子就說是哥哥,小兒子也不能知道是誰說的。
這時候老婆很熱心的打 pass:題目都說是媽媽說,所以就是媽媽說的。
為了讓我自己不要昏死在旁邊,我只好給提示:
「哥哥、姐姐、弟弟、妹妹」其中一個說的,你們選誰。
這時候老婆知道我在問什麼了。
二個小朋友還是一臉茫然…
以前唸過皮亞傑談到識知發展的書,簡要的內容就是人的各種認知、邏輯能力,
是隨著年齡而成長的。所以一些成人們認為理所當然的事,
對小朋友而言,並不總是理所當然。
今天這道題目,總算讓我有了另一次體驗。

2008/11/11

Google Translate 非官方翻譯 API

之前為了將系統的多語化,其中一個議題就是要產生各種語系的訊息資源檔。繁簡中文的對譯,只要透過 Word 就行了,要是英日語,就得人工作業。靈機一動,想說何不借助既有的翻譯服務,為 resource 檔提供預設的簡中、英、日翻譯。

就這樣,找到了一些應用 Google Translate API 的討論。試用了之後,多少都有語系編碼的問題。我最後實作了一個版本,可以在輸入正體中文時,正常產出簡中、英、日語系的翻譯。

一開始我是採用 C# 語言測試,程式碼如下:

public static string TranslateText(string fromLang, string toLang, string msg)
{
  string target = "http://www.google.com/translate_t?ie=UTF-8&oe=UTF-8&text={2}&langpair={0}|{1}";
  string url = String.Format(target, fromLang, toLang, msg);
  WebClient webClient = new WebClient();
  webClient.Encoding = System.Text.Encoding.UTF8;
  string result = webClient.DownloadString(url);
  string sign = "<div id=result_box dir=\"ltr\">";
  result = result.Substring(result.IndexOf(sign) + sign.Length);
  result = result.Substring(0, result.IndexOf("</div"));
  return result.Replace("<br>", "\n");;
}

後來又做了一個 Java 的版本,程式碼如下:

public static String translateText(String fromLang, String toLang, String msg) throws IOException{
  String target = "http://www.google.com/translate_t?ie=UTF-8&oe=UTF-8&langpair=%s|%s&text=%s";
  String url = String.format(target, fromLang, toLang, URLEncoder.encode(msg, "utf-8"));
  String result = getUrlContent(url);
  String sign = "<div id=result_box dir=\"ltr\">";
  result = result.substring(result.indexOf(sign) + sign.length());
  result = result.substring(0, result.indexOf("</div"));
  return result.replaceAll("<br>", "\n");
}

public static String getUrlContent(String url) throws IOException {
  URL u = new URL(url);   
  HttpURLConnection conn = (HttpURLConnection)u.openConnection();   
  conn.setRequestProperty("User-agent","Mozilla/4.0");
  conn.setRequestProperty("Content-Language","UTF-8" );
  conn.connect();
  return slurp(conn.getInputStream());            
}

public static String slurp (InputStream in) throws IOException {
  StringBuffer out = new StringBuffer();
  byte[] b = new byte[4096];
  for (int n; (n = in.read(b)) != -1;) {
    out.append(new String(b, 0, n, "UTF-8"));
  }
  return out.toString();
}

測試程式長得像這樣:

public static void main(String []argv) throws IOException{
  System.out.println(GoogleTranslate.translateText("zh-TW", "zh-CN", "書不同文、車不同軌、世界不大同!"));
  System.out.println(GoogleTranslate.translateText("zh-TW", "en", "書不同文、車不同軌、世界不大同!"));
  System.out.println(GoogleTranslate.translateText("zh-TW", "ja", "書不同文、車不同軌、世界不大同!"));          
}

稍微說明一下我的測試心得。

首先,就是使用 Google Translate 時,最好是明確指定你所用的輸入編碼及輸出編碼,即上面 URL 連結中的 ie=UTF-8&oe=UTF-8。若不明確指定,Google 可是會依據你的輸入語言,而決定輸出編碼。例如,你輸入的語言是 "zh-CN",它預設會採用 gb2312 編碼回應。這會造成處理上的困擾。

其次,由於 .NET 與 Java 平台內建皆採用 UTF-8 編碼,因此在我們指定輸入編碼及輸出編碼時,當然是優先考量 UTF-8。

最後,如果你用 Eclipse 做測試,你可能會發現 console 裡有部分亂碼。請依照下圖,在 Run/Run Configurations... 裡面做設定,將 Console Encoding 指定為 UTF-8:

eclipse-console-utf8

最後就能產出正常的顯示了。

eclipse-console-utf8-2

2008/11/07

正妹牆螢幕保護程式

foxsaver-beauty1

辦公室前面擺了一個 40 幾吋的電漿螢幕,放置不用殊為可惜。與同事閒聊之際,突然靈機一動,何不拿來展示正妹牆,24 下時輪播,慰勞整天辛勞的宅男工程師。

有了這個想法,首先想到了就是要找個能播放 media rss 的螢幕保護程式。試了幾個,包括:

效果都出不來。決定拿 FoxSaver 一試 -- 嘿,別看太久,年輕人會流鼻血的。

FoxSaver 是 Firefox 的一個 Extension,可以把 Firefox 變成螢幕保護程式。從它的選項來看,圖片來源可以來自本機目錄,RSS 或一般網頁。由於這個 Extension 還在實驗中,在 addons.mozilla.org 網站上需要登入才能安裝。我在安裝之後,使用上是沒有大問題。重點來了,怎麼設定 FoxSaver 讀取正妹牆 RSS 呢。一圖勝千言,請見右圖 。

如此之後,在 Firefox 狀態列上的 FoxSaver 按鈕上點右鍵,選擇「FoxSaver 開始」就行了。

當然,也有人推薦用 PicLens/Cooliris 來觀正妹牆,除了可以自己操刀,將正妹們拉遠拉近觀看外(是不是第一次感受到那種呼之即來,揮之即去的操作感 >_<|||),要透過 Cooliris 來達到類似螢幕保護程式的效果,記得按一下三角型的播放鈕,這 -- 不就變成美女自動送上門的桌上版了嗎。

2008/10/15

glassfish-v2 JSP request 中文參數亂碼解法

最近幾天用 Microsoft Visual Web Developer 2008 Express Edition 練習 ASP.NET + ADO.NET,順便把 Java 陣營兩大 IDE Eclipse 及 NetBeans 拿來比較一下開發的易用性…

心得是,以 NetBeans 用 JSF + JPA 開發網站,開發的效率並不下於 ASP.NET + ADO.NET。而 Eclipse 的 JPA 工具(稱為 Dali Java Persistence Tool) 的功能其實也相當完善,例如,它可以讓你由 Java class 產生 db table,也可以讓你由 table 產生 entity class。唯一在使用性上不足之處,是 Eclipse 出廠設定較 NetBeans 薄弱。例如,為了使用 JPA,你必須自行下載一個 JPA 的一個實作,而為了使用 JSF,你也必須自行下載一個 JSF 的一個實作。下載後還要自行設定… 需要看一點功夫才設定的起來。而 NetBeans 如果下載的是 Web & Java EE 版,預設就能直接開發 JSF + JPA 程式,甚至連範例專案都含在裡面,deploy 一下,直接就能 run 了。

以上都是雜話,以下是正文,但正文不會很多。

在測試 NetBeans 開發 Web 網站時,遇到一件有趣的事。就是以 NetBeans JSP web application 的預設組態,deploy 到 glassfish-v2 上,輸入中文時,取得的資料會是亂碼。但若是以 JSF 來開發 web application 便不會有中文亂碼的問題。

glassfish 中文亂碼的問題,可參考 FaqHttpRequestParameterEncodingServlet Character Encoding,在 sun-web.xml 中加入 default-charset="UTF-8" 得到解決,如下所示:

   <sun-web-app>
     <locale-charset-info default-locale="">
       <locale-charset-map locale="" charset=""/>
       <parameter-encoding default-charset="UTF-8"/>
     </locale-charset-info>
   </sun-web-app>

(注意,在 NetBeans 裡面,預設將 JSP 及 Java 檔都以 UTF-8 存檔,且 JSP 皆加入 <%@page pageEncoding="UTF-8"%> 指示)。

但 JSF 沒有中文亂碼問題,雖然這是好事,但反道讓我有些不解。用 Google 查詢一下,原來在 JSF 規範裡面有特別提到要如何解析當前 request 參數的編碼,Tips for JSF character encoding 有精要的描述。有了這些資訊,便不需再透過撰寫 filter 來解決編碼問題了。

Technorati : , , , ,

2008/07/09

使用 Google Trends, 你有進行基值/基期校正嗎?

因為在 iThome 看到一位與我有一面之緣、熱衷 Flex 的高手,透過分析 Google Trends 資料,寫了一篇名為「RIA四雄群起:以Google Trends評析現有RIA四大技術(Flex、Silverlight、JavaFX、Curl)」的 blog。由於其中各種技術熱門程度的差異實在太大,激起了我進一步自行探索的動力。

第一件使我產生懷疑的是,文中指出 Flex 技術是 2004 年發行 1.0 版,我到 Wikipedia 查了一下資料,是 2004 年 3 月。那時候 Flex 還是 Macromedia 所提出的一個 Server 端方案,需配合貴死人的 Server 端執行。而由圖一可以明顯看出,Flex 的趨勢線在 2004 年初就一直處於高檔,直覺跟…好吧--年紀--告訴我這不合理。

ria-3

圖一:未經校正的 Google Trends 查詢:Flex, Silverlight, JavaFX, Curl

而第二件讓我覺得更不合理的是,如果你直接透過 Google 查詢 Curl,可以發現十之八九都與 RIA 無關。這樣的查詢流量怎能將它全部歸到 Curl for RIA 這一塊呢。

我相信 Flex 這將近 0.9 的 Search Volumn Index,並非指 Macromedia/Adobe 的 Flex 技術;同樣的,Curl 大多的查詢流量也與 RIA 無關。為了進行檢驗,我將查詢語句作了一些修正,以期找出較具代表性的指標。新的查詢為:Macromedia Flex, Microsoft Silverlight, Sun JavaFX, Adobe Flex。

ria-4

圖二:經過校正的 Google Trends 查詢:Macromedia Flex, Microsoft Silverlight, Sun JavaFX, Adobe Flex

這個查詢中,Flex 的熱門程度可用 Macromedia Flex + Adobe Flex 來代表。基本上可看出,在 2004 年 3 月以前,少有人關注 Flex。而 Microsoft Silverlight 的聲勢,"有段時間" 其實並不小於 Macromedia/Adobe Flex,那 Sun 的 JavaFX,就趴在地上了。

不過,究竟一般網民在查詢時,並不會特別以 Adobe Flex、Microsoft Silverlight 這樣的組字方式去下。以上,我所要說明的是,在以 Google Trends 進行分析時,得對基期或基值進行校正。透過第二個查詢我們已經證明 2004 年 3 月前的 Flex 流量,不能算是 Flex for RIA 這一塊的流量。如果將圖一 Flex 的流量值向下平移 0.9 單位,可以看出 Flex 對 Silverlight 的比值將接近圖二所示。

行文至此,是不是可以建議 Google Trends 提供類似基期/基值校正的功能。不然,就趕快把 Google Treands 的 API 給 release 出來吧!

相關連結:

Technorati : , , , ,

2008/05/08

PMOG 簡易練功外掛

(2009/04/02)警告--本文一開始只是作為概念性驗證, 現在 PMOG 已針對這裡所提供的方法作出防範,勿再使用本文所提供之方法,以免告成帳號被刪 :(

前一陣子收到了 PMOG 的啟用信,便依照「電腦玩物」的說明,趁著工作空檔試玩了一下。突然想到,在一般的 game 系統,都有一些超級玩家或高手,懂得利用外掛程式來練功,那這個 client 端基於 Firefox 的遊戲平台,要寫一個練功的外掛應該也不是難事吧!

PMOG 平台裡面,透過 Datapoint 來代表玩家的經驗值。增加 Datapoint 最簡單的方式,就是瀏覽不同網域的網頁。如果我們要透過這樣的規則來練功,代表我們每天要想辦法去到不同的網域。而哪來那麼多不同的網域呢來瀏覽呢?

透過 Google 查詢,我找到一個 "Random Link" 連結,每當你瀏覽這個連結時,它會將你導到不同的網址。因此,你可以把這個連結放到 Firefox 的書籤工具列,每次按一下,就會連到不同的網頁。

接下來,就是想辦法讓上面的程序自動化。有時間、有時間精神的高手可以寫個 Firefox Extension。比較偷懶一點,就可以透過 Greasemonkey script 來達到這個功能。以下是我所使用的 user script:

// ==UserScript==
// @name           automatic random link
// @namespace      http://isong.blogspot.com/
// @description    visit random web pages automatically
// @include        *
// ==/UserScript==

setTimeout(function() {
  location.href = "http://random.yahoo.com/bin/ryl?"  + new Date().getTime();
}, 5000);                                

只要在 Greasemonkey 中增加此用戶腳本,然後在想練功時啟用此腳本,就可以看到你的 Datapoint 值不斷增加囉!

相關連結:

Technorati : , , , ,

2008/04/21

用 JavaScript 來修飾你的超連結

網頁之間的互相引用、評論,是當代網誌的形式之一,而造就的結果就是正文之中充斥著超連結。

這樣的書寫風格本身並沒有所謂的好或不好。在我的日誌中,也存在不少此類用法。問題是,如果同一篇日誌中,重複提及一個特定的網頁,而該網頁又值得透過超連結參引,那麼重複編製超連結的動作,也會令人覺得繁瑣。

為此,我想到設定一種 "形式",再加上 JavaScript,來為正文中的特定字眼加上連結。

構想是,在每篇網誌的最後,加上一段 "相關連結" 或 "參考資料",段落名稱是什麼不重要,重點是:

  1. 將連結以無序清單的形式標明,每一清單項目以連結開頭
  2. 以冒號+空白 (": ") 來區分連結及解說文字,例如:
    • 愛頌過生活: 就是過日子,人生不需太多大道理!
    • DOM: Document Object Model (DOM); W3C 的官方說明

上例中的 "愛頌過生活" 及 "DOM" 字串,會被當作匹配條件,在正文的段落 (<p>...</p> 包起來的部分) 中,比對相符的字眼。若出現相符的字串,將被 JavaScript 套上超連結。

用來轉換文字成超連結的 JavaScript 程式碼如下:

<script type="text/javascript">
var init = {
  cmds: [],
  run: function(){
    for(i = 0; i < this.cmds.length; i++)
      this.cmds[i]();
  }
}

function getText(anchor){
   return anchor.text ? anchor.text : anchor.innerText;
}

function fixPostElements(){
   var uls = document.getElementsByTagName("ul");
   for(var i = 0; i < uls.length; i++)
      insertResourceLink(uls[i].parentNode)
}
function insertResourceLink(element) {
  var links= {};
  var lis = element.getElementsByTagName("li");
  for (var i = 0; i < lis.length; i++){
    if(lis[i].innerHTML.indexOf(": ") != 0){
      as = lis[i].getElementsByTagName("a");
      for(j = 0; j < as.length; j++)
        links[getText(as[j])] = as[j].href;
    }
  }
  var ps = element.getElementsByTagName("p");
  for(key in links) {
    var regKey = new RegExp(key, "g");
    for(var i = 0; i < ps.length; i++) {
      ps[i].innerHTML = ps[i].innerHTML.replace(regKey,
         "<a href="+ links[key] +">" + key +"</a>");
    }
  }
}
init.cmds.push(fixPostElements);
</script>

將上面的程式碼置於 HTML 的 head 區塊,在 body tag 中加上 onload="init.run()",於撰寫網誌時採用本文規範的形式,即可達所述的效果。

一篇符合本文形式規範的網誌文章,可參考 "PRISM for Firefox 3 beta 5 url link opening issue"。事實上,筆者正是在撰寫該文時,因對重複的超連結編製深感不耐,才產生此構想的。

附帶一提,如果讀者採用 Google Reader 或其他 RSS 閱讀軟體,那麼你將無法看到此 JavaScript 的效果,因為 RSS feed 中並不含 JavaScript 轉譯碼… 這樣的設計,或許可以解釋為:「為親自造訪本站的讀者,所提供的一點加值服務 ^__^」。

2008/04/18

Prism for Firefox 3 beta 5 url link opening issue

今天將自用的電腦換成還在 beta 中的 Firefox 3,順手就裝了可以「將網頁變成桌面程式」的擴充套件 Prism。它的功能一如產品網頁描述,可以在桌面產生一個 URL 連結,也可以顯示 tray icon。

我首先轉換的應用網站便是 Gmail,轉換成完後,點選桌面 Gmail 捷徑,帶出一個沒有任何修飾 (不會讓你分心) 的 Gmail 應用程式視窗。怪的是,在我的環境 Windows XP + 這樣的組合下,在 Prism 的 Gmail 網頁中開啟 URL 連結時,它開啟的外部瀏覽器竟是 IE,而不是我所期望的 Firefox。在 Firefox 「工具/選項/進階」中將 firefox 設定成系統預設瀏覽器也沒有用。

本想試試 Linky 這個專門用來改進連結開啟方式的擴充套件,但在 Prism 中卻無法安裝。我沒去細究那是 Prism 本身,還是 Linky 或 Firefox bata 3 的版本關係,總之就是不能用。

查了一下 firefox command line arguments, 看到了 -setDefaultBrowser 這個選項,可以將 firefox 設定成系統預設瀏覽器。於是我試著在 DOS 指令視窗中輸入以下指令:

C:\>cd "\Program Files\Mozilla Firefox 3 Beta 5"
C:\Program Files\Mozilla Firefox 3 Beta 5>firefox -setDefaultBrowser

沒想到這麼一來,當我再次於 Prism 的 Gmail 網頁中開啟連結時,竟然就能將連結開啟於 Firefox 中了。

相關連結:

Technorati : , , , ,

2008/04/12

Miro 1.2.* 無法啟動的 Bug 及 Quick Dirty Fix

Miro 這套以 XUL Runtime 為基礎的網路影片撥放軟體,有著優良的使用介面及易用豐富的影片搜尋功能,在網路上已經有不少 blogger 介紹過,我就不再贅言。

如果你也是 Miro 的愛好者,或是看過介紹後躍躍欲試,卻同我一樣遭遇以下畫面:

Miro StartUp Error

除了程式視窗外框、骨架外,所有內容都沒有顯示出來。那麼底下提供一個 quick dirty fix,或許可以解你想看影片的燃眉之急。

首先,找到 C:\Program Files\Participatory Culture Foundation\Miro\components\pybridge.py 這個檔案。找到其中一段程式碼:

   keyElement.setAttribute('keytext', _('Spacebar'))

由於這行程式中的 _(Spacebar) 在執行期會運算成 "空白鍵" 這個中文字串,進一步造成 UnicodeDecodeError: 'ascii' codec can't decode byte 0xe7 in position 0: ordinal not in range(128) 的錯誤。因為並未深入了解 Miro 完整的 localization 架構,這是一個目前看來我無法完整解決的問題。因此我採用一個 quick dirty fix,將上面那行改成如下:

   keyElement.setAttribute('keytext', 'Spacebar')

注意,由於程式是 python 語言,因此請不要改變以上程式碼的縮排。儲存檔案,重新開啟 Miro,那麼你應該可以重新找尋、欣賞喜好的影片了。

Miro OK Now

Note: 本方法僅在 Window Miro 1.2, 1.2.2 版上試驗過。

Technorati : , , , ,