程式碼高𠅙
2012/09/14
你所想像不到的 Javascript
一則關於思考的小故事--心裡掛鳥籠
偉大發明家兼德科公司創辦人凱特林,擁有 140 多項專利,及近 30 多所大學的榮譽博士頭銜,我曾經聽他談起專門闢室思考的事情,他比喻那是在心裡掛鳥籠。這則故事也讓我回想起個人兒時的生活經歷:小學一二年級前,我並不是特別喜歡讀書。有一天父親竟然買了一架簡易式的折疊式書桌,說是給我當禮物。當時我對那書桌的設計感到好奇,也覺得它的樣式精巧。每天吃完晚飯後,非得「享受」一下坐在它上面的「樂趣」不可。就這樣,也養成我至今為止尚稱喜歡閱讀的習慣。
這種說法似乎很怪異,然而當你聽過他以 100 美元跟人打睹的事,就會比較有概念了。
有一回凱特林向朋友說,他有辦法讓對方在來年買一隻鳥當寵物。那位朋友心想,誰也無法「逼」他做這種事,就和他打賭了。
不久之後,凱特林送了一個瑞士手工精製的昂貴鳥龍給這位朋友。朋友把鳥籠帶回家,覺得鳥籠實在美極了,於是掛在飯廰裡。可是他發現每當客人來訪時,總有人問:「你的鳥什麼時候死的?」
「我從沒養過鳥。」他會這麼說,然後把整件事解釋一遍。重複幾次之後,他終於去買了一隻鸚哥,再把輸掉的 100 美元付給凱特林。凱特林後來說:「如果你把鳥籠掛在心裡,終究會放點什麼東西進去的。」
正如凱特林的鳥籠能引來一隻鳥,特定的思考地點也能引來好的想法。如果你來到思考的地點希望能產生好的想法,那麼終究會想出一些好點子。
如果這樣的人也能成功的扭轉她的生命
萊恩於 1900 年代中期住在俄亥俄州的迪凡斯。她一直沒有學開車,自從有了孩子以後,也從沒出外工作過。在她那個年代,身為母親就必需留在家裡。這本來也沒有什麼問題,只不過她家裡很缺錢,而且她有 10 個小孩!這則故事給了我很深的感觸。如果在那樣環境下的女人都能因為策略思考而成功,那麼我相信大都數人成功的條件都比她優越的多。我把這樣的故事告訴一個酒鬼朋友,想聽聽看他有何看法。
她的丈夫凱利在一家機械廠工作,收入十分微薄。更糟的是,凱利是個酒鬼,每星期拿回家的錢,1/3 都被他喝掉了。
任何人在街上遇見萊恩,恐怕都看不出她會運用策略思考,但她的確是。她必需撫養 10 個小孩,打理家務,還要另外賺到足夠的錢養活全家。
在那個時間,製造廠商經常贊助徵稿競賽…〈略過部分〉
萊恩的文字能力不錯,婚前在地方報社工作又鍛鍊了不少,因此她想了一個順理成章的計劃。既然她不能外出賺錢 (即使有人願意照顧 10 個小孩,你能想像這筆褓姆費有多可觀嗎?) 那就參加競賽來賺取金錢與家用品。
想要照顧一家 12 口,洗這麼多人的衣服,還要同時寫數百首詩。廣告歌曲和宣傳短文,需要高度的策略。萊恩做到了。
首先,她苦心建立了一些關係網,用來蒐集參賽表格和購物證明,諸如盒蓋、罐頭標籤等等。其次,她必須在做家事的時候寫東西。每年她都買一本活頁筆記薄,把點子記錄下來,並追蹤一切參賽後的相關資訊。
接下來的挑戰,是找出時間寫作。她處理家務時,總是會把筆記本翻開就近放著,但是她發現燙衣服是最佳時機。
萊恩的策略思考並不限於書寫的準備工作,她也運用策略挑選書寫內容。每一次徵文比賽,她都慎選字眼。她的女兒泰莉回想萊恩準備競賽的情形,說道:
「她 總是會說競賽不只是收集盒蓋和表現聰明才智,還要考慮格式 (有些競賽會要求使用特定字眼,有時若是使用產品想關字眼可以加分)、產品對象 (針對家庭、年輕人或小孩) 和評審。比起贊助商和產品,參賽者更應該重視作為評審的廣告代理商。每個廣告商都有他們的偏好,可能是韻文或散文,可能是幽默或中規中矩的文章。」
萊恩打聽出每家廣告商的喜好,這個策略幫了大忙。在幾年當中,她為這個大家庭贏了幾台洗衣機和烘乾機,數十件大大小小的電器用品、兩輛新車 (車子賣了)、數面筆小額獎金,和兩筆大額獎金,分別是 5000 元與 3400 元。
她把第一筆大額獎金做為頭期款,買下一棟房子,一家 12 口終於搬出 2 房的出租屋。第二筆獎金則用來償還丈夫偷偷申請的二胎房貸 (她一直到償還日前一個月才發現)。
當情況不允許失敗,策略思考就是你最好的選擇。萊恩本來可以偶爾寫首詩,投稿到地方報社去,但她需要做點事來幫忙家人的生計。「像我爸爸這樣的丈夫和父親,永遠不可能改變,」她的女兒說:「我們家唯一的希望就是看媽媽怎麼改變,怎麼撫養一群快樂健康的孩子。」
萊恩成功了。她不僅讓家人活下來,還幫助他們成功。她擁有 7 個小孩大學畢業,1 個拿到博士學位,還有 1 個法學院畢業。
他說:嗯!能討到這樣的老婆就好了。
嗯,這……也算是策略思考的第一步吧。
2011/10/14
Google+ Bookmarklet
Google+ <== 這是 Bookmarklet 連結
使用方式:
- 將上面這個 Bookmarklet 連結,拉到瀏覽器的網址列,或加入書籤。
- 在 網址列 或 書籤 中點選剛加入的 Google+ Bookmarklet,就能將目前瀏覽的網頁,分享到 Google+ 上,以下是分享頁面抓圖。
- 按下 Share 鈕即可分享。
2011/09/06
用 Java Annotation 簡化命令列參數處理
其實在 Web 上,同樣的問題也存在,就是怎麼把 URL 對應到特定的 servlet, action 或 controller 的方法上。這不管是在 Spring Framework 3 Web MVC, Servlet 3 或是 Jessey 中,都有一套近似的解法,就是使用 @Annotation。
OK, 那我們何不如法泡製,也用 @Annotation 來處理命令列參數呢? 我設計的命令列規範如下:
- 將命令列參數區分成「選項」及「選項參數」。選項如 -start, -stop;選項參數如 -start localhost 18080 中,未加 dash 符號的字串,即紅字部分。
- 一個命令列可以接受多個選項及多個選項參數。
- 支援將選項綁定到主程式裡面的方法,以下我稱之為「選項常式」。
- 支援將選項參數綁定到選項常式的參數上。
- 支援自動列出所有選項及其說明。
- 自動檢查選項參數是否正確。
- 支選整數型態的選項參數。
package com.isong.cmdexe;
/**
* Usage example:<pre>
* java -jar ds.jar -start localhost 2011
* java -jar ds.jar -start localhost 2011 -sm
* java -jar ds.jar -stop
* </pre>
* @author edwardsayer
*/
public class DummyServer {
/**
* @param args
*/
public static void main(String[] argv) {
new CmdExecutor(new DummyServer()).exec(argv);
}
// execute: java -jar ds.jar -start localhost 2011
@CommandArg(value = "-start ip port", desc = "start the server instance.")
public void doStart(String ip, int port){
System.out.println("Starting server at " + ip + ":" + port + "...");
}
// execute: java -jar ds.jar -sm
@CommandArg(value = "-sm", desc = "start session monitor.")
public void startSessionMonitor(){
System.out.println("Starting session service...");
}
// execute: java -jar ds.jar -stop
@CommandArg(value = "-stop", desc = "stop the server instance.")
public void doStop(){
System.out.println("Stoping...");
}
}
從以上的程式碼片段,可以知道這組 Command line API 提供了一個 CmdExecutor 類別, 以及一個 @CommandArg annotation。
@CommandArg 會在主程式的選項常式上,加上標注訊息,包括選項名稱,以及選項描述。
而CmdExecutor 類別則依據 @CommandArg 所提供的資訊,綁定使用者輸入的參數。另外,若使用者未輸入任何參數,CmdExecutor 則顯示參數提示訊息,這些訊息,其實是我們透過 @CommandArg 加諸在每個選項常式上的訊息。範例如下:
Available options: -start ip port start the server instance. -sm start session monitor. -stop stop the server instance.
接下來,就來了解 CmdExecutor 及 @CommandArg 的實作方式。先看看 @CommandArg 的程式碼:
@Retention(RetentionPolicy.RUNTIME)
public @interface CommandArg {
String value();
String desc() default "";
}
可以看到 @CommandArg 包含兩個屬性。value 用來設定選項名稱,而 desc 用來設定選項描述。
CmdExecutor 較為冗長,程式碼如下:
public class CmdExecutor {
private Map cmdMap;
private StringBuffer cmdDocs;
private Object target;
public CmdExecutor(Object target){
this.target = target;
}
public int exec(String[] args){
System.out.println("args = " + Arrays.asList(args));
initCommands();
if (args.length == 0) {
showCommands();
return 0;
}
for (int i = 0; i < args.length; i++) {
if (args[i].startsWith("-")) {
String option = args[i];
Method method = cmdMap.get(option);
if (method == null) {
System.out.println("Unknown options: " + option);
showCommands();
return 1;
}
try {
Class[] types = method.getParameterTypes();
Object[] paras = new Object[types.length];
for (int j = 0; j < types.length; j++) {
if ( ++i >= args.length || args[i].startsWith("-")) {
System.out.println("Invalid option parameter count: " + option);
showCommands();
return 1;
}
if(types[j].isAssignableFrom(String.class))
paras[j] = args[i];
else if(types[j].isAssignableFrom(int.class)
|| types[j].isAssignableFrom(Integer.class))
paras[j] = Integer.valueOf(args[i]);
else
throw new IllegalArgumentException("Invalid command parameter type: " + method.getName());
}
method.invoke(target, paras);
} catch (Exception e) {
e.printStackTrace();
}
}
}
return 0;
}
private void initCommands(){
if (cmdDocs != null)
return;
cmdDocs = new StringBuffer("Available options:\n");
cmdMap = new HashMap();
Method[] methods = target.getClass().getMethods();
for (Method method: methods) {
CommandArg argCmd = method.getAnnotation(CommandArg.class);
if (argCmd != null) {
cmdDocs.append(argCmd.value() + "\n " + argCmd.desc() + "\n");
cmdMap.put(argCmd.value().split(" ")[0], method);
}
}
}
private void showCommands(){
System.out.println(cmdDocs);
}
}
以上主要程式邏輯放在 exec 這個方法上,它會透過呼叫 initCommands 方法,建立所有選項常式之描述 (cmdDocs) 及對應 (cmdMap)。完成後,就是實際去解析命令列參數。如果沒有任何參數,就透過 showCommands 顯示說明。如果有,就進行選項與主程式方法的對應。
2010/02/28
用 AutoHotkey 啟用雲端字典及翻譯
Google 字典一直是我相當喜愛使用的網路服務,簡潔的版面及清晰的解釋及例句,都是我喜歡它的原因…硬要說它有什麼缺點的話,就是沒有看到日文的支援。固然透過 Firefox 或 Chrome,我們可以很容易的瀏覽器中啟用翻譯服務,但若是想要在其他應用程式中也使用到 Google 字典,就必須借助其他方法了。
AutoHotKey 是一個 Windows 下的桌面工具,可以讓我們透過自訂的快速鍵,啟動特定的應用程式、開啟文件、或指定的 URL 等。我們可以利用 AutoHotKey 的功能,在桌面上一鍵啟動 Google 字典及翻譯。
- 下載 AutoHotKey
- 執行安裝
- 安裝完成後,執行 AutoHotKey
- 在 Windows 的 System Tray 中,在 AutoHotKey 的 [H] 按鈕上按右鍵,帶出右鍵功能表,選擇「Edit This Script」
- 此時 AutoHotKey 預設會以 Windows 內建的「記事本」(Notepad) 開啟 AutoHotKey.ahk,供我們編輯
- 接下來就得編輯 AutoHotKey 的指定碼了,所幸相當簡單。其 Help 中有詳細的說明,我把常用的網頁服務設定如下的代碼區塊。
- 網友們可複製以下程式碼,貼到 AutoHotKey.ahk 檔案最後,然後存檔,關閉記事本。
- 使用 AutoHotKey 的右鍵功能表,執行「Reload This Script」。
至此大功告成,以後在任何應用程式中,只要先選定 (反白) 要查詢的文字,然後按下 Win + X 組合鍵,就可將選定文字帶至 Google 字典中查詢;此外,你也可以使用 Win + S 啟用 Google 搜尋,或使用 Win + Z 啟用 Google 翻譯。
另外,如果你想要讓 Windows 啟動時就自動執行 AutoHotKey.ahk,可以為 AutoHotKey.ahk 建立一個捷徑,並將捷徑放置在開始功能表裡面的「啟動」目錄即可。
Ahk 代碼:
;; 定義按 Win + S 鍵,啟用 Google 搜尋 #s:: clipboard = ; Empty the clipboard Send, ^c ClipWait, 2 Run http://www.google.com.tw/search?hl=zh-TW&q=%clipboard% return ;; 定義按 Win + X 鍵,啟用 Google 字典 #x:: clipboard = ; Empty the clipboard Send, ^c ClipWait, 2 Run http://www.google.com.tw/dictionary?aq=f&oq=breed&langpair=en|zh-TW&hl=zh-TW&q=%clipboard% return ;; 定義按 Win + Z 鍵,啟用 Google 翻譯 #z:: clipboard = ; Empty the clipboard Send, ^c ClipWait, 2 Run http://translate.google.com.tw/translate_t#auto|zh-TW|%clipboard% return
Technorati : AutoHotKey, dictionary, goodiesh, google, translation
2009/09/15
WinForm: 如何判斷表單是否開啟在 Visual Studio 的 Designer 中
最近工作上用到比較多微軟的開發工具,像是 Visual Studio, Reporting Servoces, ASP.NET 等。
我們採用了一套 UI Framework,可以在 ASP.NET 上,以 WinForm 的程式設計模式來開發 Web 表單。在表單開發上,可完全免除自行撰寫 Client 端 JavaScript 的需要。簡言之,這種開發模式具有 WinForm 的優點,相對的,開發 WinForm 時所需要面對的問題,這裡同樣要面對。
例如,在開發 WinForm 表單時,我們常會在元件的 Load 事件載入資料來源,進行資料綁定。在執行環境這樣的邏輯沒有問題,但在開發環境,以 Visual Studio 的 Designer 開啟元件時,就可能會遇到無法讀取設定檔、資料連結錯誤等等問題,而造成 Designer 無法順利開啟表單。
我查詢了一下,在 MSDN Windows Developer Center 上也有人詢問這個問題,其中有個開發者已經給了一個可用的 solution,但因為他的描述過於複雜,且要求改寫基底類別,所以我擷取了他的解法,加以簡化。
首先,我們撰寫一個 GuiUtil 類別,其中包括下列方法:
public static bool InDesignMode()
{
try
{
return System.Diagnostics.Process.GetCurrentProcess().ProcessName == "devenv";
}
catch
{
return false;
}
}
如此一來,我們就可以採用以下的程式碼,在 Client 端程式的 Load 事件中進行呼叫,而不會產生設計畫面出不來的狀況了。
if (!GuiUtil.InDesignMode())
{
InitDataBinding();
}
-- 完 --
