2007年11月24日 星期六

iGoogle BossKey 暗黑老板鍵小工具

由於 iGoogle 提供的小工具已經非常非常的多元化.. 舉凡股市投資組合, 打電動, 看新聞, 聊天, 看美女圖, 都可以在 iGoogle 中全部搞定... 嘿嘿..
頁面停留在 iGoogle 中, 已不見得是用功好學在努力找資料了... 這時就需要 iGoogle 老板鍵 功能.

這是在 GTDD2007 當天下午分組程式設計時寫的小工具(編號 30), 可能太害羞還是氣氛的關係, 很少人在各組間走動觀摩討論... 所以得票數一票 :( (還是同桌投的..呵呵)
阿土伯把它補完整一點並加上設定、多國語.. 放出來和大家分享..

功能:
  • 隱藏 iGoogle 的畫面
  • 帶入 傳統 Google 搜尋頁面
  • 自動在搜尋欄位中填入設定關鍵字

##CONTINUE##
說明:

暗黑老板鍵小工具說明, 要用情境模式來示範解說.. 大家就了解了.

話說阿土伯上班正努力的用功........... 看盤/看圖/打電動..


這時老板突然走了過來, 看的正精彩,關掉瀏覽器實在太可惜了(等會要重執行).
趕快使用暗黑老板鍵...(F10). 畫面馬上變成:


老板問: 阿土伯你在做什麼...
阿土伯: 報告老板, 我正準備要在 Google 搜尋上查詢有關 google 的相關新聞, 研究 google 的成功模式能不能應用在公司上面.... (呼~~ 要臉不紅氣不喘的回答, 小朋友不要學, 大哥哥是練過的)

OK~~ 大致上軟體就是這麼用的....

設定畫面:



加入您的 iGoogle:
請點取 Add to Google 直接加入您的 iGoogle 中.



原始程式及小工具 URL:
http://racklin.googlepages.com/bosskey.xml

PS.
像這樣的暗黑小工具投到目錄中不知道能不能審核通過..
對不起 kevin, 不小心又弄了一支 html-inline gadget, gtdd2007 當日苦口婆心希望大家寫 html type gadget...

2007年11月23日 星期五

gtdd2007 感想

昨天參加了 Google Taipei Developer Day 2007 收獲很多..
最大的收獲就是阿土伯有榮幸能和眾多網路名人一聚, 如 qing , tempo,
xdite, Bawbaw.hu, 以及一群年輕、專業又有活力的 funp 團隊.

也非常感謝 Google 評審團對阿土伯設計的小工具支持及肯定, 讓我有幸獲得 "工程師特別獎" 的殊榮...
,對我而言,無疑是最大的鼓勵,更加深我在開發以及程式開放分享上熱忱。

也希望未來能開發/開放更多的小程式小工具和大家分享..
以及和各位網路高手交流, 教學相長...

2007年11月13日 星期二

GRE 開發備註二

阿土伯手上專案終於完工了, 並 Release 給客戶以及交付生產線試用了.

看看最後一篇文章, 足足隔了一個多月(手腳變慢了 = =), 各位朋友, 久違了..

近期會整理一下及發表阿土伯在開發 Gecko / XULRunner Application 時, 所開發的一些 Utilities Libraries.

這篇主要介紹及回答為什麼當時阿土伯要用 GRE 而不是 Java RCP(eclipse RCP / netbeans RCP...etc,)

##CONTINUE##

GRE/XULRunner 特色

* Cross Platform -
只要是有 mozilla or firefox 都可以執行您的 Application. 這部份的特色和阿土伯喜愛的 Java 一樣可愛.

* Gecko Rendering Engine -
有了 Gecko Rendering Engine, 可以用大家最熟悉的 HTML 技術來開發富豐的 GUI.
更可以內崁 Flash Object 來開發更炫麗 GUI.
當然, 你要內崁 Java Applet 來開發 GUI 也可以.

* Javascript
使用 Javascript 來開發 Application. 任何您原來在 Web 上開發的技巧都可以直接使用.
再加上豐富大量的 3rd-party Libraries (jQuery / Dojo / YUI) + Firebug 開發效率及入門門檻低.

* XUL / XML / XBL / SOAP
做為 Rich Client Platform , XUL+XBL 配合的讓人讚賞.. 而 XBL 讓您利用 CSS Selector 的方式, 讓 XUL / HTML 可以
binding 到 Content / Properties / Methods / Events / Style .
這部份讓您對於開發 XUL 有很大的彈性.
在部份的應用下, 可以開發類似於 jsp / jsf 的 custom tag .

* XPCOM
透過 XPCOM, 可以讓 javascript 使用原生的方法.
利用 XPCOM 開檔 , 網路連線 , 資料庫操作等.
亦可以自行利用 C++ 或 javascript 實作自己的 XPCOM , 有點像 JNI.


心得
對於一個中/大型的 Application 專案, 建議採用 Java RCP.
對於一個小型的 Application 專案或設計專案 Prototype 時, 這時利用 GRE/XULRunner 是在適合不過的了..
(大專案也行啦.... firefox/thunderbird 就是, 它們可不是小專案呀...)

而且...... 還有一個當初我採用的最大原因....... ....
若是利用 Java RCP, 每次換個客戶,換個 UI , 或是加點小功能..工作就會再回到我們手上來...
用了 Gecko.. 現在變成美術設計的事了, 除非 XPCOM / XBL 有問題, 才需要 debug 及維護.
這下子, 原來 "軟體部門" 的專案變成了 "設計部門" 的專案... 這才是太極最高奧義呀~

歡迎大家來信或留言討論...

2007年9月28日 星期五

ifunP 推推王點播台 問題修正

由於 funp.com 改版, 在 RSS 上做了部份修改.
link tag 的 URL 變更, 所以造成 ifunP 無屁可 fun 的情況發生. 目前已修正完成並上傳.

您無需重新安裝, 在幾小時後 Google Cache 重整後您即可使用到新版的 ifunP.

當然, 您急著用可以利用以 URL 新增的方式, 在 URL 中加個亂數.
如 http://racklin.googlepages.com/ifunp.xml?200709271100 這樣也可以跳過 Google Cache 用到即時更新的版本...

由於目前閉關趕專案中, 未能即時發現問題並改正, 造成不便在此請大家見諒...
感謝 mark 的強勢提醒告知(利用 IM 的匿稱讓我看到.... )

2007年9月17日 星期一

GRE 開發備註一

整整花了一個星期閉關搞 GRE . 這裡的 GRE 不是指英文的 GRE普通測驗. 而是 Gecko Runtime Environment.

源起:
由於手上一個 CASE 的需求是需要為公司的硬體週邊做一個檢測程式, 而這些週邊含 Serial Port(RS232) / Parallel Port(IEEE 1284) / USB 裝置 / 以及部份數位 TTL信號.
而這些裝置希要提供 Win32 / Linux(趨勢) 上測試通過.
且這支測試程式還有另一個任務, 就是 Open Source C++ 部份的 API 給買裝置回去整合的廠商參考實作.
本來想用 Java + JNI 把它解決掉, 因為要 Release 的廠商多, 每一家要有自己的版本及 Logo, 所以要一家一家改 JForm 有點麻煩, 本來試試 JavaFX 來動態搞, 不熟再加上第二個原因.
廠商的工程師都是使用 C++ , 用 Java+JNI 等於我還是要再寫一份 C++ 的 Sample 給廠商.

最主要的是.....想玩玩 GRE , 於是... 整個架構如下..

XUL/XHTML -> Javascript -> XPConnect -> XPCOM(C++ or Javascript)

##CONTINUE##
所以, 除了最底層的裝置操作用 C++ 實作, 且這部份的 Code 剛好就是要給廠商的 Sample Code.
其它的 GUI 部份及全部的程式流程, 只要在 XUL/XHTML 中寫寫 Javascript , 而 jQuery 部份修改也能操作 XUL ...
所以每個客戶的程式界面要多炫就能有多炫,還可以給個 Flash 單介面和動畫 Splash 呢。

卻被 Win32 平台搞死:
在 Linux 下開發很順利, 整個實作過程和原始概念差不多, 也開發的很愉快..
沒想到原本以為最容易的 Win32 平台, 由於開始想用 GRE 前沒做太多功課, 卻是惡夢的開始.

阿土伯是打算使用 VC++ 2005 express edition 來 make , 怎麼搞就是一堆 error.
後來看到 Windows Build Prerequisites 差點昏倒, 原來 Gecko 1.8 在 VC++ 2005 express 是 NO .. 問題剩下最後一哩路了, 總不改用 "原版A拷 VC6 / VC7.1" 呀~~
查了很多, 日本人寫的這篇還算詳細, 雖然整個 mozilla 還是無法 build 出來, 但 extensions 及 sdk 都還沒問題. 給使用 VC++ 2005 express 的大家參考.


建議參考資料:
XULRunner - 一個可以單獨運作的 gecko 開發包, 如果沒有一定要 embed gecko , 由這個開始會很舒服.
XPCOMViewer - 一個用來 Browse XPCOM 的工具, 您可以看到 Gecko 中一大堆實用的 XPCOM Interface.
XPCOM Strings / XPCOM Array / XPCOM Hashtable - 這也是讓阿土伯最無力的文件之一, 資料有點老舊, 如果你是直接使用 Gecko-SDK 而不是由 seamonkey-src 來 build 你的專案, 你會發現文件中說的 class 在 SDK 中都不存在, 因為 frozen / unfrozen API 的關係. 建議直接花時間看看 SDK 中的 .h 看看有什麼 Class 比較快.
這部份等結案後再來整理...

總之... 忙到爆... 但希望這個工做完.. 以後就能涼到爆....
因為, 不管什麼程式, 都只剩下 XUL/XHTML + Javascript 了.. 這部份要怎麼改都行.

2007年8月27日 星期一

AOP for jQuery

就在寫 jQuery 1.1.4 那篇介紹文的同時, 逛了一下 jQuery plugins , 看到了一個很有意思的專案.
jQuery AOP , 看起來是一個新的專案,作者於 2007/08/17 上傳第一個 release 檔案.

aspect-oriented programming (AOP) 在 Java 中有幾個流行的 AOP 實作, AspectJ , AspectWerkz JBossAOP, 所以有關 AOP 的介紹, 請看上面四個 Link, 不在此重覆說明.

而 jQuery AOP 則是實作了 before / after / around 三個 advice, 雖然名為 jQuery AOP, 其實並未使用到 jQuery 的任何特性及功能, 所以即使您沒有使用 jQuery , 依然可以小改一下 code 來使用哦, 所以一定要堆的啦.

##CONTINUE##
我們可以很容易的利用 javascript 的 Function.apply() 來 hook function 或 object(Blogger Hack Tip#1) , 所以實作起來相當的輕巧, 只有 943 bytes.

舉一個實例:
任何程式語言, 在程式寫作過程中, 我們少不了要 Log , 然而 Log 的動作和程式本身實際的業務邏輯無關, 若是為每一個業務操作的 function / method 前後都加上 Logger.log('message'), 對於程式本身而言.. 太過於難看(bad smell).
所以這時我們可以藉由 Dynamic proxy 或 AOP framework 來改善這個 bad smell.

使用 jQuery AOP 在 javascript 中使用 after / before / around advices 變的很簡單:

例1 對 native object 切入:

jQuery.aop.before( {target: String, method: 'replace'},
function(regex, newString) {
alert("About to replace string '" + this + "' with '" + newString + "' using regEx '" + regex + "'");
}
);
"Hello World".replace("Hello", "Hello jQuery");


例2 對 global function 切入:

function testEcho ( arg) {
alert('testEcho: ' + arg);
}
jQuery.aop.before( {target: window, method: 'testEcho'},
function(arg) {
alert("About to testEcho arguments is " + arg);
}
);


例3 對 instance object 切入:

var TestObj = function (name) {
this.name = name;
};
TestObj.prototype.hello = function (arg) {
alert(this.name + ':' + arg);
};
var rack = new TestObj('rack');
jQuery.aop.before( {target: rack, method: 'hello'},
function(arg) {
alert("before "+ this.name +" say " + arg);
}
);
rack.hello('hello');


其它各位依此類堆.... 有了 jQuery AOP , javascript 也能寫的很優雅嘍.
(都已經 Hook Blogger了, 之前怎麼沒想到順便弄一個 plugin , 唉~~ sense 不足.. 被搶頭香了 :D )

jQuery 1.1.4 Release

jQuery 1.1.4 出來了 , 這將會是 1.1 系列的最後一版, 下一版本會跳到 1.2 了.
雖然被 jaceju 的 [JavaScript] jQuery 推出 1.1.4 版 搶了頭香 :D ,
阿土伯還是介紹一下, 並以一些比較技術部份簡介一下.
##CONTINUE##

Speed Improvements


在三個基本常用的操作上, ID selectors, tag name selectors, 和 each() 迴圈處理上, 速度有大幅的提昇.

Any Name jQuery


jQuery 在前面的版本, 只使用了二個 global variables , 就是 $ 和 jQuery, 現在 1.1.4 後, 您可以將這二個變數也換掉, 並和其它 3rd party 的 Library 整合,果如他在 Google 的演說一樣, (阿土伯這篇有介紹), 這版就加入了, 它帶來了二個好處:

1. 你可以在同一網頁使用不同版本的 jQuery:
這個功能, 或許猛一看, 你會認為為什麼有這樣的需求??
然而, 如果您的 Library 是運用在其它大量 3rd party library 的場合, 這個功能將會是很大的相容性保證.
如:
1. 阿土伯的 Blogger-Ext 它會運用在 blogspot.com 上的, 然而很多網誌作者已自行擴充了很多功能, 也可能使用其它版本的 jQuery, 這時這個功能將能保證不會有相容性問題.

2. 使用 Firefox 的使用者一定知道 Firefox 有很多的 extensions 可以使用, 包含 Greasemonkey 等, extensions 作者可能用到了 jQuery 來設計 js , 如果這時網頁也使用 jQuery, 這時這個功能將保證不會和網頁有相容問題.
2. 您可以將 jQuery 整合進其它 Namespace 中:
同上, 你更能將 jQuery 整進你 Library 的一部份, 一同發表, 這時, 您可以維護一份您自己使用的版本, 即使網頁作者換了別的版本 jQuery, 你的程式也不會發生相容性的問題.

也就是未來版本的 BloggerExt , 阿土伯可以將它整進 BloggerExt.jQueryBloggerExt.$ , 這樣 BloggerExt 將對任何網誌有最大的相容性以及最低的侵入性.

jQuery 在設計之初, 就有良好的設計模式以及未擴充任何 Native Objects , 這時就派上很大的用途.

// With the Dojo Toolkit
dojo.jquery = jQuery.noConflict(true);
dojo.jquery("#elem div").slideDown("slow");
// or with Yahoo UI
YAHOO.query = jQuery.noConflict(true);
YAHOO.query("span.hidden").removeClass("hidden");


.slice()


對於 jQuery 的 objects , 我們可以使用如同標準 Javascript arrays slice() function.
這個 Function 太優了, 它讓 jQuery 操作和 Javascript Array 有一致的操作介面.
所以, 理所當然的 .eq() , .lt() , .gt() 就被捨棄掉了. 因為可以用 .slice() 取代它.

Bug Fixes


53 個 1.1.3.1 版本的問題修正, 詳見 the bug tracker , 相當多的修正, 希望不會太快出現 1.1.4.1 :q

Local Variables:

一樣同他在 Google Tech Talk 上建議的良好習慣, 這版 1.1.4 便是將自己放在

(function(){
// your code
})();

中.

Blogger-ext2 使用方式


所以有使用 Blogger-ext2 的朋友, 只要將

<script type="text/javascript" src="http://blogger-ext2.googlecode.com/files/jquery-1.1.4.pack.js"></script>

即可完成 jQuery 的昇級動作..

2007年8月24日 星期五

John Resig 談 Building a JavaScript Library

( 的發起人) 在 Google Tech Talk 談如何建立一個 JavaScript Library:Building a JavaScript Library,包含影片及投影片。

對於每一位有心學好 Javascript 的 Programmer 都該花點時間看一下, 除了介紹 jQuery 外,包含很多設計 Javascript Library 的實用技巧及觀念, 即使您不是使用 jQuery 也該看一看.
##CONTINUE##
阿土伯對於實作(Implementaion)上的實務技巧簡單筆記:

  • 使用 Local variables / 盡可能使用最少的 Global Variables
    這部份是所有語言都共通的良好習慣, 讓您的程式碼及變數, 作用在最小的 Scope 中.
    或盡可能宣告最少的 Global Variables.
    在 Javascipt 中這個 Wrapper 寫法, 應當成基本程式習慣, 尤其是如果您的 javascript 會和其它大量的 javascript 一起運作時, (如阿土伯寫在 iGoogle 的 html-inline gadget ):

    (function(){
    // your code
    })();



    (function(){
    // your code
    }).call(this);


    (參考: Blogger Hack Tip #2 - Javascript Code Style)
  • Namespacing
    如果一定要讓自己的 Library 使用到 Global Variables 時, 請使用 Namespace.
    如:(Dojo, Yahoo UI, jQuery, BloggerExt)
  • 利用 Namespace 和其它 Library 相容並存或合作.
    這是 Namespacing 的擴展應用, 當您的 Library 僅作用在單一 Namespace 時, 您可以將自己的 Library 掛在別的 Library 下. 如 BloggerExt.proccess(); YamUtils.BloggerExt.proccess();
  • Don't Extend Native Objects
    其中, 這點和阿土伯的理念一拍即合, 也是我在 2007/02 之後的所有專案換到 jQuery 的原因. ( 參考: jQuery: 又一個非常優秀的 JavaScript Framework. )
上述 John Resig 所說的技巧, 也都全部應用在新版本的 jQuery 1.1.4, 請參考這篇 中, 有興趣的朋友可以看看 jQuery source code.

2007年8月23日 星期四

ifunP 推推王點播台 / 推文貼紙 支援 funP.com alpha4 嘍

就在 funP 展開了 alpha4 改版的夏日傳說 , 在 2007.08.22 上線嘍!!
由於 Alpha4 的改版, 阿土伯愛放屁(ifunP)放不出來了..
以及推推王 堆文貼紙加強版 變的不好看(高度不夠, 原 55 現在 69)..
所以都一併更版, 讓阿土伯的小工具也有個美好的夏日傳說...

##CONTINUE##
ifunP 點播台更新版本:
您不需要重新安裝, 由於 iGoogle 會 cache , 應該在 1 - 2 天或更短的時間內即可使用到最新的版本.
當然, 若您等不及, 請先將小工具移除, reload Browser , 再加入一次小工具應該就能直接用到更新的版本.

ifunP 點播台 功能介紹及說明

funP 推文貼紙:
您不需要改版任何語法, 已利用原檔案覆蓋更新..
若您是自行下載至其它位置, 請您再下載回去.
推推王 推文按鈕貼紙 加強版介紹及說明

2007年8月21日 星期二

+1 for Closures

Java7 即將導入 closure 語法, 這個在 Ruby 中非常精巧方便的特性, 即將導入 Java 中, 在許多論壇上造成很大的激辯.

對於 Java 是一個成長中的語言. 它會一直的進步以及導入新的語法及特性. 然而, 其中平衡點的拿捏真的就很重要了.

Java6 中的 Scripting Language 介面, 以及 JRuby 的成熟, 已經可以讓您在 JVM 中使用 javascript / python / ruby , 其實我們有很多方式可以混合開發應用在我們的專案中.

Java7 中導入了 closure 雖可以讓程式語法精簡且較為優雅, 然而, 它變的太 Ruby.
阿土伯我不想喝著一杯 "走味的咖啡" 呀~ 即始它鑲上了紅寶石~
不過..............
##CONTINUE##
如果有辣妹站台, 那阿土伯也要加入支持 closure 進入 java7 嘍.







無關人身攻擊... 不過這位太重量級了, 會讓 java7 的包袱更沈重, 那就免了唄....


原文: Closures Are Hot
原文: +1 for Closures

2007年8月14日 星期二

blogger_ext2.js 0.6.3 / 0.7.2 修正版發表


0.6.3 / 0.7.2 修正版本發表:
主要是阿土伯將大家列給我的已知問題修正, 沒有新的功能加入:

changelog:
* 較新/舊的文章 換頁到第三次後, 表情符號及繼續閱讀功能失效. (fixed)
* 表情符號效能修正, 若該內容無符號則不處理. (fixed)
* registerHook API 修正 (fixed)
- 使用 Hook API 的 plugin 發生換頁問題, 將一併獲得解決.

##CONTINUE##
0.6.3 版 all-in-one script

<script src='http://blogger-ext2.googlecode.com/files/blogger_ext2-0.6.3.pack.js' type='text/javascript'></script>


0.6.3 版 核心 script

<script src='http://blogger-ext2.googlecode.com/files/blogger_ext2-core-0.6.3.pack.js' type='text/javascript'></script>


0.7.2 版 目前在 svn 中, 所以不用改變. 隨時會引用到最新版本.


表情符號修正版

<script src='http://blogger-ext2.googlecode.com/files/plugin_replace_smiley-0.2.pack.js' type='text/javascript'></script>


詳細使用說明:
0.6 版
0.7 版

讓大家久侯了, Sorry and Thanks.

Technorati Tags: , ,

2007年8月13日 星期一

黑米小按鈕 加強版

利用 HEMiDEMi 官方 javascript 改良了一下, 提供一個以 DOM 操作為主的版本.歡迎官方直接引用.

加強了以下三點:
1. 解決在各 Blog 平台上部份網誌會造成畫面一片白的問題.
2. 一顆/多顆 按鈕語法統一.
3. 支援 Blogger-ext2, 在 Blogger 系統中換頁, 小按鈕依然能生效.
##CONTINUE##
解決畫面一片白:
其實這個問題同 "推推王 推文按鈕貼紙" , 加了 黑米小按鈕 貼紙後, 有時畫面會一片白. [出現空白頁]
這在 Blogger 系統最為明顯, 因為 Blogger 系統的 Sidebar, 換頁都是使用 javascript 動態 產生, 所以只要在 onload 前, 黑米小按鈕的 javascript 執行到, 而黑米小按鈕的 javascript 僅利用 document.write 產生一個 iframe.這時的 document 就僅剩下一個 iframe , 所以您會得到一片白.
請大家忘了 document.write 這個 n 年前的遺產吧.. 以 DOM 來提供小工具.

按鈕語法統一:
使用此一加強版, 不再分一個按鈕或多個按鈕, 您只要使用單一的語法即可. 而語法中也看不到 javascript , 只是一個 div 的語法, 您可以輕輕鬆鬆放入 黑米小按鈕.

使用方式:
放在網頁 <head> 位置加入 或 加入 html/javascript 網頁元素:
程式碼:

<script src='http://blogger-ext2.googlecode.com/svn/trunk/3rd/hemidemi_bookmark_button2.js' ></script>


放在按鈕位置的
程式碼:

<div class="hemi_button" style="font-size:0px;">網址</div>

如果不打就直接用貼紙所在頁面的網址.

就是這麼容易, 不管幾顆都是一樣.


如何在 Blogger 系統中使用:
1.範本 => 版面配置 => 修改 HTML => 勾選「展開小裝置範本」 => 在 </head> 前加入

<script src='http://blogger-ext2.googlecode.com/svn/trunk/3rd/hemidemi_bookmark_button2.js' ></script>

2. 找到 <p><data:post.body/><p> 在 <p><data:post.body/><p> 前加入按鈕語法

<div style='float:right; margin-left:10px; font-size:0px;' class="hemi_button"><data:post.url/></div>


如何在天空(yam) 系統中使用:
1.管理者後台 => 功能設定 => 個人資料 => 部落格描述: 中填入

<script src='http://blogger-ext2.googlecode.com/svn/trunk/3rd/hemidemi_bookmark_button2.js' ></script>

2. 在發表網址時, 在 "追加內容" 加入按鈕語法

<div style='float:right; margin-left:10px; font-size:0px;' class="hemi_button"></div>

3. sample.

詳細參數及使用說明可參考 [功能] 黑米小按鈕

PS. 推推王推文按鈕也是存在相同的問題. 請看這裡.

ifunP 推推王點播台 可直接推文嘍

在修改 推推王 推文按鈕貼紙 加強版 之餘, 順便把阿土伯考慮很久的 ifunP 點播台 加上了直接推文功能. 現在大家可以直接在 iGoogle 中利用 ifunP 點播台小工具直接推文嘍.

ifunP 點播台 功能介紹及說明.

希望大家會喜歡.
##CONTINUE##
有圖有真相:



PS. 考慮原因我在 這裡 有 唸到, 我是覺得大家還是要連回 funP 原始網站, 支持原網站才對.
怕加了直接推文會影響 funP 的流量.. 那就不是阿土伯的本意了..
後來想想, 應該影響不大, 大部份的人不會看到 "標題" 就 "推" 下去的, 還是會連回去看才對.

推推王 推文按鈕貼紙 加強版

利用推推王官方 javascript 改良了一下, 提供一個以 DOM 操作為主的版本.歡迎官方直接引用.

加強了以下二點:
1. 解決在各 Blog 平台上部份網誌會造成畫面一片白的問題.
2. 一顆/多顆 按鈕語法統一.
3. 支援 Blogger-ext2, 在 Blogger 系統中換頁, 小按鈕依然能生效.

##CONTINUE##
解決畫面一片白:
由於已有許多網友反應, 加了 推推王 推文按鈕貼紙 後, 有時畫面會一片白.
在Blogger加入推推王按鈕導致不明反白的解法 , 問題2, 問題3
這在 Blogger 系統最為明顯, 因為 Blogger 系統的 Sidebar, 換頁都是使用 javascript 動態 產生, 所以只要在 onload 前, 推推王的 javascript 執行到, 而推推王的 javascript 僅有三行, 也就是利用 document.write 產生一個 iframe.這時的 document 就僅剩下一個 iframe , 所以您會得到一片白.
請大家忘了 document.write 這個 n 年前的遺產吧.. 以 DOM 來提供小工具.

按鈕語法統一:
使用此一加強版, 不再分一個按鈕或多個按鈕, 您只要使用單一的語法即可. 而語法中也看不到 javascript , 只是一個 div 的語法, 您可以輕輕鬆鬆放入 推推王推文按鈕.

使用方式:
放在網頁 <head> 位置加入 或 加入 html/javascript 網頁元素:
程式碼:

<script src='http://blogger-ext2.googlecode.com/svn/trunk/3rd/funp_button2.js' ></script>


放在按鈕位置的
程式碼:

<div class="funp_button" style="font-size:0px;">網址</div>

如果不打就直接用貼紙所在頁面的網址.

就是這麼容易, 不管幾顆都是一樣.


如何在 Blogger 系統中使用:
1.範本 => 版面配置 => 修改 HTML => 勾選「展開小裝置範本」 => 在 </head> 前加入

<script src='http://blogger-ext2.googlecode.com/svn/trunk/3rd/funp_button2.js' ></script>

2. 找到 <p><data:post.body/><p> 在 <p><data:post.body/><p> 前加入按鈕語法

<div style='float:right; margin-left:10px; font-size:0px;' class="funp_button"><data:post.url/></div>

style 說明可參考 funP Button On Blogger

如何在天空(yam) 系統中使用:
1.管理者後台 => 功能設定 => 個人資料 => 部落格描述: 中填入

<script src='http://blogger-ext2.googlecode.com/svn/trunk/3rd/funp_button2.js' ></script>

2. 在發表網址時, 在 "追加內容" 加入按鈕語法

<div style='float:right; margin-left:10px; font-size:0px;' class="funp_button"></div>

3. sample.


PS. 黑米小按鈕也是存在相同的問題. 請看這篇留.

2007年8月10日 星期五

iGoogle 自動翻譯小工具真有趣

剛才在使用 iGoogle 自動翻譯 小工具, 試著想把一篇英文技術文件轉成中文, 看看會不會看的快一點, 發現翻出來好有趣.. 真是讓阿土伯充滿驚奇呀~~

惡搞玩玩看, 輸入 Rack Lin, Rack = 機架(電腦述語), Lin = 林
##CONTINUE##
所以 Rack Lin = 機架林 嘍.. 嘿嘿.... 這麼容易讓你猜中, 就不是 Google 了.

答案是: 林齒條 , 齒條咧... 讓阿土伯好想哭....

輸入: I am Rack Lin 應該是我是林齒條嘍, 嘿嘿.... 就說這麼容易讓你猜中, 就不是 Google 了嘛.

答案是: 我機架林.... 又正常了?聽起來舒服點...

來惡搞一下小土仔的名子吧: Shine Lin 是 發光林, 陽光林, 或閃耀林 嗎???

答案是: 林光輝 ... 好個菜市場名呀~~~

輸入: I am Shine Lin 應該是我是林光輝嘍...

答案是: 我照林... 哇咧... 這是啥....

Google 自動翻譯小工具, 我真是猜不透您呀~~~ :)

2007年8月8日 星期三

iGoogle Easy Layout 更新~

由於 iGoogle Render Html 於 2007/08/08 做小改版, 導致原 EasyLayout 無法作用, 阿土伯已於第一時間配合改版, 已能相容目前的 iGoogle 了.

阿土伯已上傳更新版本, 所以您無需重裝小工具, 然而由於 iGoogle 會 Cache 小工具, 所以請您耐心等侯, 小工具會於 Cache 失效時, 自動套用新版本.

使用說明, 請見 EasyLayout 簡介.

PS. iGoogle 會對此一部份改版, 是否意味著, 未來 iGoogle 將內建調整欄位的功能.. 樂見其成 :D
PS2. 出現了 c_4 又意味著有四欄的配置?
##CONTINUE##
技術部份:
原 iGoogle Render Html Layout: 所以 EasyLayout 僅需覆寫 CSS Style 重定義 c_1, c_2, c_3 即可.

<div id="c_1" class="yui-u" style="display: block;">
<div id="c_2" class="yui-u" style="display: block;">
<div id="c_3" class="yui-u" style="display: block;">

新 iGoogle Render Html Layout: c_1,c_2,c_3 width 強制出現在 HTML 中, 又取代了 EasyLayout CSS Style , 所以輔以 DOM 方式設定屬性.

<div id="c_1" class="yui-u" style="width: 32%; display: block;">
<div id="c_2" class="yui-u" style="width: 32%; display: block;">
<div id="c_3" class="yui-u" style="width: 32%; display: block;">

2007年7月27日 星期五

iGoogle funP 推推王點播台 小工具

親愛的, 我把 iGoogle 變成 funP 推推王了, 是瘋狂還是有趣....

寫了一個 iGoogle 的 funP 推推王小工具.
小工具的名稱就叫 ifunP 吧... (愛放屁?) :D
它提供了類似 funPaper 點播台的功能, 您可以利用 ifunP 快速的瀏覽推推王上的資訊, 以及被推的次數.
除此之外, 由於我是使用 TabRSS 為核心, 所以, 您可以自行新增訂閱 RSS 到 ifunP.
這下真的和 funP 點播台有點異曲同工之妙了.... :)

當然, 請搭配 EasyLayout 使用, 然後加上天氣, Flickr 相簿小工具, 讓您的版面配置和 funP 推推王很相似唷.

功能:
  • 提供 funP 點播台功能.
  • 可自行新增項目.
  • 可以直接於 iGoogle 中推文. (new)

讓您用 iGoogle 更方便更好用...
##CONTINUE##
小工具畫面:


很像 funP ? 有圖有真相:


原始 funP:


加入您的 iGoogle:
請點取 Add to Google 直接加入您的 iGoogle 中.





原始程式:
http://racklin.googlepages.com/ifunp.xml

L10n:
http://racklin.googlepages.com/ifunp_tw.xml

Technorati Tags: , , ,

2007年7月17日 星期二

建立您專屬的 iGoogle 個人首頁 補完計劃

Google 個人首頁 正名為 "iGoogle" 了, 網路上也有很多詳細的介紹, 還沒使用的讀者, 您一定要試試看...

iGoogle 提供了大量的 Gadget 應用程式, 並且支援分頁管理多個 Gadget, 而每個 Gadget 又能任意以滑鼠左鍵拖曳, 使用起來非常迅速方便...
最重要的特點就是承襲了 Google 的優良傳統, 整個 iGoogle 在反應速度上很快速. 使用起來給人的感覺很順暢.

目前阿土伯將 iGoogle 當成一個資訊綜整及閱讀的平台, 將 project status, machine status 都弄成小 Gadget 以及 Email / RSS Reader 已經將公事/私事都在 iGoogle 監看, 再一一連回原系統中簽核回覆.

本文會簡單介紹 iGoogle 的基本特點以及加上一些 Gadget 讓您的 iGoogle 更好用.

還在等什麼了: 快連上
iGoogle台灣:http://www.google.com.tw/ig?hl=zh-TW

##CONTINUE##
iGoogle 基本功能快速簡介:
  • 新增小工具 »

    點選網頁右上角的「新增小工具」,會出現首頁內容目錄,點選您要的小工具下方的圖示[立即新增] 將其加入你的 iGoogle 個人首頁.
    由於小工具眾多, 您亦可以用搜尋的方式找尋小工具來新增.

  • 按照 URL 新增:

    若您要的小工具沒有在首頁內容目錄中, 或您要新增的是 RSS 內容, 可點選[搜尋首頁內容]右邊的 "按照 URL 新增" 連結, 然後填入小工具的網址或 RSS 網址, 亦可以將小工具加入您的 iGoogle 個人首頁中.

  • 設定版面:

    iGoogle目前包含動態佈景,每個佈景的背景圖會隨著一日作息時間而動態改變. 阿土伯的版面是 "茶坊" , 因為喜歡看那隻小狐每天都很忙碌.

  • 分頁功能:

    當您小工具越放越多時, 就是該使用分頁的功能, 依功能將它們分類到適當的分類中, 讓您的個人首頁更清楚.

iGoogle 進階功能補完:

  • 工具箱:
    http://www.google.com/ig/modules/compound.xml
    工具箱可以將頁面上的小工具收藏為分頁,讓你的頁面更整潔、更好用!


  • 設定欄位:
    http://racklin.googlepages.com/easylayout.xml

    iGoogle 的版面配置只能三欄模式(1/3, 1/3, 1/3), 在有些情況下很不方便,而利用 EasyLayout, 它會整合進 iGoogle 的 設定版面旁邊新增一個選項 "設定欄位", 讓您可以為分頁設定成 三欄模式, 二欄模式( 2/3 1/3 , 1/3 2/3, 1/2 1/2) , 或 一欄模式.

    [詳細介紹]

  • Tab RSS:
    http://racklin.googlepages.com/tabrss.xml

    Tab RSS 小工具. 讓您整合訂閱多個 RSS Feed 並且可直接預覽 Feed 內容, 可以同時訂閱不限個 Feed, 並以標籤方式整合管理.並且可以設定每個 Feed 下載的則數以及可設定是否下載內容.

    [詳細介紹]
  • Flickr 相簿小工具:
    http://racklin.googlepages.com/flickr_igoogle.xml

    Flickr 相簿小工具, 可依 username 或 tags 列出的公開相片.提供小圖及中圖模式,提供中圖顯示 "標題" / "註解" .

    [詳細介紹]


iGoogle 其它:
範例: (首頁, 標準三欄模式)


範例: (新聞, 二欄模式)


寫 gadget 時: (Google Gadget Editor 一欄模式)


歡迎大家一起討論或補完, 讓 iGoogle 更實用方便更貼近您的生活.
當然, 阿土伯邊用邊看看還有什麼功能及建議, 繼續補完下去...

iGoogle 介紹相關網站: [打造你的iGoogle個人化首頁全功略]

Technorati Tags: , ,

2007年7月16日 星期一

iGoogle Easy Layout 小工具

寫了一個 iGoogle 的 Easy Layout 小工具.
由於目前 iGoogle 的版面配置只能三欄模式(1/3, 1/3, 1/3), 在有些情況下很不方便(如看新聞或寫 Gadget Debug).
所以寫了 Easy Layout , 它會整合進 iGoogle 的 設定版面旁邊新增一個選項 "設定欄位", 讓您可以為分頁設定成 三欄模式, 二欄模式( 2/3 1/3 , 1/3 2/3, 1/2 1/2) , 或 一欄模式.
由於已整進選項中, 所以本身不會佔一個小工具的空間, 且在您變更欄位數後, 會自動把小工具移至正確的欄位上, 如: 原本在三欄模式下的第三欄小工具, 在改成二欄模式後, 會自動移到第二欄中.

更新資訊:
  • 2007/08/08 發現 iGoogle Render Html 的語法有做了改變, 導致原 EasyLayout 無法作用, 已配合改版.

功能:
  • 整合進選項中, 不佔一個小工具位置.
  • 提供 三欄/二欄/一欄 模式.
  • 自動將小工具移至合理欄位中.
讓您用 iGoogle 更方便更好用...
##CONTINUE##

中文 ScreenShot:


英文 ScreenShot:


二欄效果:



加入您的 iGoogle:
請點取 Add to Google 直接加入您的 iGoogle 中.




原始程式:
http://racklin.googlepages.com/easylayout.xml

L10n:
http://racklin.googlepages.com/easylayout_tw.xml
http://racklin.googlepages.com/easylayout_en.xml


Technorati Tags: , ,

2007年7月15日 星期日

iGoogle Tab RSS 小工具

寫了一個 iGoogle 的 Tab RSS 小工具. 讓您整合訂閱多個 RSS Feed 並且可直接預覽 Feed 內容
提供中文/英文二個語系.

功能:
  • 可以同時訂閱不限個 Feed, 並以標籤方式整合管理.
  • 可以設定每個 Feed 下載的則數.
  • 可設定是否下載內容.
  • 可以預覽 "標題" / "日期" / "內容" .
  • 提供 lightbox 視窗效果" 或 列表展開內容.
  • 點標題連結回原 Feed URL.

讓您在 iGoogle 看 RSS 更加方便好用...
(可以不用再透過 "工具箱" 管理多個 Rss gadgets 嘍. 高效又省資源唷)

##CONTINUE##

中文 ScreenShot:


英文 ScreenShot:


視窗 LightBox 效果:



加入您的 iGoogle:
請點取 Add to Google 直接加入您的 iGoogle 中.




原始程式:
http://racklin.googlepages.com/tabrss.xml

L10n:
http://racklin.googlepages.com/tabrss_tw.xml
http://racklin.googlepages.com/tabrss_en.xml


Technorati Tags: , ,

2007年7月12日 星期四

iGoogle Flickr 相簿小工具 更新~

有使用阿土伯的 iGoogle Flickr 相簿小工具的朋友, 如果您發現突然看不到照片了..
請您先移除阿土伯的小工具, 然後
請清除您瀏覽器 的 cookie 和 cached 即可更新.
Internet Explorer: 工具->網際網路選項->刪除 cookie, 刪除檔案
Firefox: 工具->選項->個人隱私->顯示cookies->清除全部 Cookies.
然後關閉瀏覽器, 重開瀏覽器.
再重新安裝一次即可.
##CONTINUE##
原因是 iGoogle 的 script 有改版, 原先阿土伯用來 parse JSON 是利用 Google 現有的 Script.
也就是 ig_C.parse 那個 C 我以為是 Core 的意思, 所以就安心給它用下去..
今天 Google 改版, parse 變成在 ig_D.parse ... 所以..... orz...
原來那個 C 是 javascript obfuscate 弄出來的~~
所以現在改成阿土伯自己 parse ... 唉~~ 踩到一個地雷....

安裝方式及介紹: http://racklin.blogspot.com/2007/07/igoogle-flickr.html

2007年7月10日 星期二

iGoogle Gadget 蘋果攝影隊 今天我最美

台客必備 iGoogle Gadget 蘋果攝影隊 今天我最美 , 請有需要者服用.

說到要用 Flickr Photos Gadget 在 Flickr 中以 beauty 想看到好圖, 那可能只會想要飛踼而已..
而說到 beauty , 除了有名大站和 Diggirl 外, 讓阿土伯想到的就是 http://blog.1-apple.com.tw/beauty/ .
這才是也是 素人自拍 美女外拍的代表呀~~

##CONTINUE##





加入您的 iGoogle:
請點取 Add to Google 直接加入您的 iGoogle 中.




請一邊唱 Mc Hotdog 的 "我愛台妹" 一邊安裝使用...
謝謝.


原始程式:
http://racklin.googlepages.com/beauty_1apple_igoogle.xml


Technorati Tags: , ,

2007年7月9日 星期一

iGoogle Flickr 相簿小工具

為 Flickr 相簿寫了一個 iGoogle 的小工具. 提供中文/英文二個語系.

由於 iGoogle 會 cached , 所以請清除您瀏覽器 的 cookie 和 cached 即可更新.
Internet Explorer: 工具->網際網路選項->刪除 cookie, 刪除檔案
Firefox: 工具->選項->個人隱私->顯示cookies->清除全部 Cookies.
然後關閉瀏覽器, 重開瀏覽器.


功能:
  • 可依 username 或 tags 列出的公開相片.
  • 提供小圖及中圖模式.
  • 提供自動更新功能.
  • 提供中圖顯示 "標題" / "註解" .
  • 點圖自動載入大圖提供 lightbox 效果 並顯示 "標題"/"註解"/"拍照日期"
  • 點大圖連回 Flickr.
fixed:
  • 修正 IE 顯示大圖會不正確的問題.
  • 可以看任何 Tag 的公開相片.


讓您在 iGoogle 看相片更加方便好用...
##CONTINUE##

中文 ScreenShot:


英文 ScreenShot:



加入您的 iGoogle:
請點取 Add to Google 直接加入您的 iGoogle 中.



Spec:
  • Use Flickr REST Services with JSON Response.
  • Use HTML-inline in gadget.xml. NO iframe.
  • Use Javascript Timer. NO URL Reload.

原始程式:
http://racklin.googlepages.com/flickr_igoogle.xml

L10n:
http://racklin.googlepages.com/flickr_igoogle_tw.xml
http://racklin.googlepages.com/flickr_igoogle_en.xml


軟體背後:
exifphotostamper , 我那寶貝老婆找不到合用的 iGoogle Flickr Gadget 可以同時顯示 "標題/註解/日期" 且不用點回 Flickr 中看大圖. 只好生一個給她嘍 :)



Technorati Tags: , , ,

2007年7月5日 星期四

jQuery 1.1.3.1 Release.

jQuery 1.1.3 才 Release 三天, 緊急修正的 1.1.3.1 版本就發佈了...
這個快速的修正版本主要修正了六個主要的問題,可以在 on the bug tracker 看到修正的問題!
而 Blogger-ext2 剛好就會遇到 #1342 的問題. Fade Navbar 在 IE6 無作用.
請昇級到 jQuery 1.1.3 的朋友再昇級到 1.1.3.1 一下 orz...
##CONTINUE##

所以有使用 Blogger-ext2 的朋友, 只要將

<script type="text/javascript" src="http://blogger-ext2.googlecode.com/files/jquery-1.1.3.1.pack.js"></script>

即可完成 jQuery 的昇級動作..

Technorati Tags: , ,

2007年7月4日 星期三

blogger_ext2.js 0.7.0 分支全新功能 beta 版發表

0.7.0 分支 beta 版本計劃:
由於 jQuery 1.1.3 在 DOM Selector 上大幅的進步, 所以阿土伯的 blogger-ext2 也改寫了, 把 DOM Traversing 上依 id 來直接找物件(這樣最快, 但需要動態新增的 element 都配上 id) 拿掉了, 因為二者在速度上已沒什麼差別了. 但程式碼看起來比較單純簡短.

使用者偏好設定:
0.7 上最大的功能, 就是加入了使用者偏好設定的機制, 也就是除了網誌作者利用 Blogger-ext2 來擴充您的 Blogger 之外, 您的讀者更可以依個人喜好調整這些設定, 達到個人最佳的閱讀感受.
##CONTINUE##
舉個例來說好了:
像是 LabelCloud 這個 Web2.0 最酷必備的功能, 就被我老婆嫌棄: "我才不管什麼 Cloud, 字大大小小的不好看@@"
再者社群書籤也是, "那麼多國外的, 可不可以只留 hemi, yahoo, funp @@".

也就是說網誌作者的喜好不一定是最貼近您的讀者, 現在, 利用 Blogger-ext2 的新功能 ,您除了提供最酷的功能之外, 更能提供最合乎使用者閱讀習慣的網誌環境.
由於這是全新實作的介面, 所以才將原 0.6.x 分支成 0.7 , 0.6.x 的 bug 阿土伯依然會處理.
但較新的功能會在 0.7.x 上實作.


偏好設定本身亦提供 API 給 plugins 的開發者, 您不用處理設定畫面, 只需要將您的設值名稱及呈現方式列出, Blogger-ext2 會自行將 Form 畫出, 並處理使用者設定的細節.
0.7 本身亦向下相容 0.6 的 plugins, 所以比較複雜, 大部份阿土伯都測過了, 但為求穩定, 會於更努力測試完整後, 正式發表 0.7.0 的版本.

changelog:
* 使用者偏好設定.
* 社群書籤按鈕新增 funp

當然, 阿土伯需要大家幫忙測試, 以下為 0.7.0b 的使用方式.請大家幫忙測試並告知阿土伯您的意見.

0.7.0b 版 script,目前在 svn 中.
All-in-one:

<script src='http://blogger-ext2.googlecode.com/svn/trunk/src/blogger_ext2.js' type='text/javascript'></script>

只有核心:

<script src='http://blogger-ext2.googlecode.com/svn/trunk/src/blogger_ext2-core.js' type='text/javascript'></script>


如何出現使用者偏好設定的區塊:
只要您在您的部落格任何想要提供設定區塊的地方, 加上

<div id="user_pref_container"></div>

即可, 就是這麼容易.
更方便的方式就是像阿土伯一樣, 直接利用 "網頁元素"->"HTML/JavaScript", 在內容中打入您想要的訊息及

<div id="user_pref_container"></div>

即可嘍 .

美化偏好設定:
偏好設定可以利用 CSS 設定風格, 以下為阿土伯目前的 CSS:

<style type='text/css'>
#user_pref_container ul {
padding-left: 10px;
}
#user_pref_container li{
margin: 0 2px;
padding: 0 2px;
display: inline;
background-color: black;
border-bottom: 1px solid white;
}
#user_pref_container li a{
color: white;
text-decoration: none;
}
#user_pref_container li.tabs-selected {
background-color: #D25A0B; /*Brown color theme*/
border-color: #D25A0B; /*Brown color theme*/
}
#user_pref_container div.menuline {
clear: both;
width: 100%;
height: 5px;
background: #D25A0B; /*Brown color theme*/
}
</style>


plugin 實作偏好設定的範例:
只要為您原先開發的 plugin 新增二個 function 即可.

user_pref:
如果您有實作 user_pref function , 您的 plugins 設定便會出現在偏好設定中.
您無需處理偏好設定表單細節, 您只要回傳一個陣列, 包含您所有設定的欄位即可.
格式:
{tab_name: 'sample', name: 'sample', display_name: 'Sample Enable', data_type:'bool', default_value: BloggerExtOptions['sample'] }

tab_name: 您的 plugin 所要產生的 page control tab.
name: 設定參數名稱
display_name: 設定參數功能說明
data_type:
目前的 datatype 有 string , bool, enum 分別為 input[@type=text], input[@type=checkbox], 以及 select 的下拉選單.
其中如果您的 data_type: enum, 您必需再提供一個選項的陣列
options: [{display: 'Full Mode', value: 'full'},{display: 'Summary', value: 'summary'}, {display: 'Title', value: 'title'}]
default_value:

update_pref:
使用者設定完成, blogger-ext2 呼叫 update_pref 並傳給您使用者的設定, 供您做相關設定處理. 基本上, 您只要將設定值, 設定至 BloggerExtUserPrefs 即可.


以 hide_navbar 為例, 只比原先 0.6.x 多實作二個 function , 沒有實作亦可以, 只是不提供使用者設定而已, 並不會影響運作.

// Register Sample
BloggerExt.sample = function() {
// Plugin 會由此開始, 此 Sample 無功能.
};
BloggerExt.sample.user_pref = function() {
var prefs = [];
prefs.push({tab_name: 'sample', name: 'sample', display_name: 'Sample Enable', data_type:'bool', default_value: BloggerExtOptions['sample'] });
prefs.push({tab_name: 'sample', name: 'sample_input', display_name:'Sample Text', data_type:'string', 'default_value': BloggerExtOptions['sample_input'] });
prefs.push({tab_name: 'sample', name: 'sample_opt', display_name:'Sample Option', data_type:'enum', 'default_value': BloggerExtOptions['sample_opt'],
'options': [{display: 'Full Mode', value: 'full'},{display: 'Summary', value: 'summary'}, {display: 'Title', value: 'title'}]});
return prefs;
};
BloggerExt.sample.update_pref = function(prefs) {
BloggerExtUserPrefs['sample'] = (typeof prefs['sample'] != 'undefined') ? true : false ;
BloggerExtUserPrefs['sample_input'] = (typeof prefs['sample_input'] != 'undefined') ? prefs['sample_input'] : 'default_input' ;
BloggerExtUserPrefs['sample_opt'] = (typeof prefs['sample_opt'] != 'undefined') ? prefs['sample_opt'] : 'full';
};
BloggerExt.register('sample', { sample: true} );


Technorati Tags: , ,

2007年7月2日 星期一

jQuery 1.1.3 Release~ Blogger-ext2 請使用新版.

jQuery 經過漫長的等待, 終於出新版了, 這一版本 1.1.3 最大的特色, 就是速度,速度,速度~~

##CONTINUE##

在先前 http://mootools.net/slickspeed/ 的測試報告中.
相信有很多朋友和阿土伯一樣, 對於 jQuery CSS Selector 速度有些小小的驚訝和失落.
現在 slickspeed 的數字要改觀了, jQuery 1.1.3 和 jQuery 1.1.2 差了 8 倍的效率.
http://dev.jquery.com/~john/slickjq/ 看起來相當的另人興奮~~

由於 jQuery 目前也 hosting 在 Google Code 下, 且和阿土伯一樣利用 Google Code 的 files 做為 Release 的方式(為了不影響原 jQuery 的計次統計),所以有使用 Blogger-ext2 的朋友, 只要將


<script src='http://blogger-ext2.googlecode.com/files/jquery.pack.js' type='text/javascript'></script>

改成:

<script src='http://blogger-ext2.googlecode.com/files/jquery-1.1.3.pack.js' type='text/javascript'></script>

即可完成 jQuery 的昇級動作..


另 jQuery 1.1.3 功能及原文Link:
jQuery 1.1.3: 800%+ Faster, still 20KB

Technorati Tags: , ,

2007年6月28日 星期四

Get class name in static method ( Java and PHP )

在撰寫 Iterators in PHP5 這篇文章時, 逛了一下 TWPUG 看看大家對於 PHP5 或相關的討論,
無意中看到了這個有趣的主題《取得 static method 實際上的 caller class type.
雖不知為何有這樣的需求(是希望藉於 parent class 提供 static factory methods, 然後子類別呼叫 parent class's static factory methods ?? ), 這有個觀念上需要釐清, 但就結果論, 要得到這個結果的確是一個有趣的嘗試..
##CONTINUE##

Java static method 觀念:
static method(靜態方法) 不屬於物件實體,而是由類別名稱直接被存取的,所以它們不像實體方法一樣是在執行時選取的,也因此 static method 會被稱為「靜態」的原因,因為它們總是在編譯時就連結好了。
父類別中的 static method 可以被子類別中其它的 static method 所 shadow,但不能被 override。
但要是父類別的 method 被宣告成 final 的話,就代表它既無法被 shadow 也無法被 override。

一段關於 shadow 的名詞解釋 [1]:「使用和父類別中之變數相同的名稱來宣告變數,我們便可稱此一變數 shadow(遮蔽) 了父類別的變數。使用關鍵字 super 可以指向被遮蔽的父類別變數,或藉由將此物件轉型成父類別的型態來指向它」。
[1] Niemeyer & Knudsen,2001,Java 學習手冊,O'REILLY,第 6 章、附錄C。

相信在 PHP5 中的 static method 應該也是和 java 相同的定義.

所以這個問題的關鍵變成不在 this / self (php) / __CLASS__ (php) 在執行時期是誰.
是實作 static method class 本身, 所以我們得到的都會是 Parent 這個輸出. 換言中, 我們需要的是 呼叫的順序是什麼, 誰是第一個呼叫我? 就能可能嘗試推出想要的結果.

Java Way:
在 Java 中, 我們可以透過 Class.getName() 是取得 class name 的方式.
然而, 要使用 Class.getName() , 有幾個方式
  1. 物件實體(instance object).getClass().getName() 前題是要有物件的實體.
  2. Dog.class.getName() 然而, 您都寫 Dog.class 就表示你知道 Class Name = Dog .. orz.
  3. Class.forName("Dog").getName() 同上.
同上觀念部分, 我們無法利用 Class.getName() 得到想要的結果(同上,即使我還是不知道為什麼要這麼做).

利用 Exception
還記每個 java programmer 的好朋友, 每每發生 Exception , 呼叫 e.printStackTrace() 時那 Dump 出來的資訊.
它記錄了所有 call stack trace. 所以利用 StackTrace 剛好可以得到這個問題的解決方式(算是偏門).


public class Parent {

public static void test() {
StackTraceElement[] stackTraceElement = new Throwable().getStackTrace();
System.out.println(stackTraceElement[stackTraceElement.length-1].getClassName());

}

public static void main(String[] args) {
Parent.test();
}

}


public class Child extends Parent {
public static void main(String[] args) {
Child.test();
}
}


public class AnotherChild extends Parent {
public static void main(String[] args) {
Child.test();
}
}


PHP Way:
PHP 中也可以呼叫 get_call_stack() 得到 call stack trace.
然而, 很不幸的 get_call_stack() 無法為 php 解決這個結果.
於是轉向 Hook static method 它. 利用 runkit 可以做到. (同 java: 算是偏門).
runkit 可於 PECL 下載 http://pecl.php.net/package/runkit , http://pecl4win.php.net/list_dlls.php
下面例子,我在 windows (只要丟個 php_runkit.dll , php.ini 加一加很快)測試通過.. 其它平台沒有測試.


<?php
class Father {
public static function getInstance($class=null) {
if ($class == null) $class = get_class();
echo "className = " . $class . "\n";
}
}

class Child extends Father{
}

class AnotherChild extends Father {
}


// Before runkit hook
echo Child::getInstance();
echo AnotherChild::getInstance();


class StaticMethodHelper {
public static function fixStaticMethod($parentClass) {
foreach (get_declared_classes() as $class) {
if (is_subclass_of($class, $parentClass)) {
$rc = new ReflectionClass($class);
foreach ($rc->getMethods() as $m) {
if ($m->isStatic() && $m->isPublic() && ($m->getDeclaringClass()->getName()!=$class) ) {
$body='$args = func_get_args(); array_unshift($args, "'.$class.'"); return call_user_func_array(array("parent","'.$m->getName().'"),$args);';
runkit_method_redefine($class, $m->getName(),'',$body, RUNKIT_ACC_PUBLIC);
}
}
}
}
}
}

// Runkit redefine static method.
StaticMethodHelper::fixStaticMethod('Father');

echo Child::getInstance();
echo AnotherChild::getInstance();

?>


Output:

C:\dev\php\php-5.2.3-Win32>php c:\tmp\test.php
className = Father
className = Father
className = Child
className = AnotherChild


以上僅就結果而言達到 "想要的效果結果", 但在 Java/PHP 實務上建議應該避免這樣的嘗試.

2007年6月27日 星期三

Observer Pattern in PHP5

PHP5.1 後, 新增了 Observer Pattern 的支援.
這個能改變物件依存關係,讓物件狀態一有變動,就自動通知其他相依物件做該做的更新動作, 由程式需要主動呼叫, 改為物件觀察的角色. 這依然是 java 中最常見的特性 awt 以及 MVC 的基楚.
但依然很少人利用.
##CONTINUE##

這篇著重在 PHP5 的 Observer 這個觀念上.
並應用了 SplObjectStorage 這個方便的 Class , 它可以讓您將任何 object 放入其中, 並 iterator 它.

這個不倫不類的例中, 用來承現 PHP 常處理的資料物件上, (因為 PHP 目前尚未有 App Container , 所以暫時 (不會?)用來處理 event 或 listener 上).
我們假設 Teacher / Student / School 都是 DB 上的物件的 ORM , 在以往, 我們需要在 Controller 中處理它的相關性,
並各自呼叫變動的狀態.. 利用 Observer Pattern, 我們能寫出更抽象的 OR 物件, 它僅關心在本身發生了什麼事,
而不需由呼叫端依 Student 或 Teacher 各別處理狀態改變.


<?php

class Teacher implements SplObserver {
private $name;

public function __construct($name) {
$this->name=$name;
}

public function update(SplSubject $subject) {
echo $this->name . " Teacher Says: Hello~~~ \n";
}

}

class Student implements SplObserver {
private $name;

public function __construct($name) {
$this->name=$name;
}

public function update(SplSubject $subject) {
echo $this->name . " Student Says: Hello~~~ \n";
}
}

class School implements SplSubject {

private $name;
private $people ;
private $state;

public function __construct($name) {
$this->people = new SplObjectStorage();
$this->name = $name;
}

public function getName(){
return $this->name;
}
public function attach(SplObserver $observer) {
$this->people->attach($observer);
}

public function detach (SplObserver $observer) {
$this->people->detach($observer);
}

public function notify() {
foreach($this->people as $person) {
$person->update($this);
}
}

public function getState() {
return $this->state;
}

public function setState($state) {
$this->state = $state;
}

}

$school = new School('Rack Lin junior school');

$rack = new Student('rack');
$rack2 = new Student('rack2');
$lily = new Teacher('Lily');
$school->attach($rack);
$school->attach($rack2);
$school->attach($lily);
$school->notify();
?>

Output:

rack Says: Hello~~~
rack Says: Hello~~~
rack2 Says: Hello~~~
rack Says: Hello~~~
rack2 Says: Hello~~~
Lily Says: Hello~~~




Technorati Tags: , ,

2007年6月26日 星期二

Iterators in PHP5

讀了石頭成的《為什麼還不升級PHP5》 以及 jaceju 於《PHP5 將滿 4 歲》.
一轉眼, PHP5 發表已經四個年頭了呀~真快.

個人覺得 PHP5(Zend Engine 2) 最大的演進, 在於 Exceptions / SPL / OO 的導入.
還記得四年前在 Zend 剛看到 PHP5 Exceptions/SPL/OO 的功能介紹, 內心的震撼很大.
因為它承襲了 java 的許多特性, 而這也意味著 PHP5 由 PHP3/PHP4 給人的 Scripting Language 印象,
成為一個更為強固的語言(那是什麼??? 還是 Scripting Language .. 來亂的).
##CONTINUE##

而 Exception Handle 的導入, 我們不再是利用 @function_name 或 set error_reporting 的方式來 "隱藏" 或"吃掉" 問題, 而是主動把可能發生例外的地方 try catch 起來, 這讓用 php5 開發的 web site 更加強固及可預測性.

而 SPL 則提供了類 Java 的 collections 架構. iterator interface, 這個在 Java 中是大量被使用的方法.
然而, 利用 Google 查詢一下, 可以發現討論和使用 SPL 及 Iterator 特點的 php 討論並不多..果然是會令 Zend 及 PHP5 開發團隊有些失落.
PHP5 擁有了類似 java 的優點及特性, 卻保有了 PHP 的精巧及簡便的思維來實作.. 這在當時, 讓阿土伯流了很多口水.

這篇著重在 PHP5 的 Iterator 這個觀念上.

Loop 迴圈

<?php

/* Looping over an array */
foreach ( $array as $item ) {
// Do something with $item
}

/* Looping over a MySQL result set */
while ( $row = mysql_fetch_array($result) ) {
// Do something with $row
}

/* Looping over files in a directory */
while ( false !== ($file = readdir($dir)) ) {
// Do something with $file
}
?>

上面是 php 中常見的 collections 或 datas 利用迴圈走訪每一筆資料的作法.. 它們看起來類似, 但是對於不同的資源(array, files, database) 又有些許的差異.

對於不同的物件及程式實作品, 你便需要知道每一個差異及輪巡的方式, 才能夠利用迴圈一一輪巡他們.

我們能夠提供一個標準的方式, 不論我們面對的是什麼資源(array, files, database, xml, ldap), 都只要使用相同且最直覺的方式輪巡嗎?

是的, 這就是 SPL 的 Iterator 的目的, 它不是解決您迴圈輪巡的效率問題, 它提供標準介面解決單一操作方式.


foreach($iterator as $obj){/* ...... */ }


Iterator of Array

<?php

$colors = array ('red','green','blue');
$iterator = new ArrayObject($colors);

foreach($iterator as $color) {
echo "color is: " . $color . "\n";
}
?>


OKOK!! 我知道大部份人會說, 不透過 ArrayObject 這個 Wrapper , 直接 foreach ($colors as $color) 也是可以.

沒錯, 同上所述, 在 array 的 iterator 上, 和傳統寫法是一致且類似的, 因為"單一操作"的解決 solution.

但在後面進階應用中 Iterator Iterator, 您會發現取得物件的 iterator 帶來的額外好處. 包含您對 ArrayIterator 加上 FilterIterator 或 LimitIterator.

順便說一下 java 的方式. 在 java 1.4 以前, 對於 collections 的 iterator 必需要


while(iterator.hasNext()) {
Object obj = iterator.next();
}

並加上 class cast 等.. 十分不方便, java 1.5 tiger 提供了類似 PHP5 SPL 的作法

for(Object obj : collection ) {
}

相信 php5 / java 1.5 和 ruby 的 collect.each 已經提供了相對優雅簡便的操作方式.


Turn Object to Iterator

前面提到的, 有時侯我們希望對物件輪巡多筆資料也變的很容易且直覺, 我們不再需要暴露出一個內部 properties array 讓使用者輪巡, 有時也可能內部資料不是個simple array(也許是properties, 也許是 data), 利用 SPL 實作的 Bookmark.php 範例


<?php

class Bookmark implements IteratorAggregate {
/* 使用 array 示範資料, 在 real case 中, 資料不一定是個 simple array */
private $links = array('阿土伯程式大觀園', 'google', 'delicious');

/* 部份原 Object 實作的專屬功能, 和 iterator 無關.... */
public function getResponseHtml() { /* ....... */ }
public function imRobot() { /* ....... */ }

/* 僅實作 getIterator 即可 */
public function getIterator() {
return new ArrayObject($this->links);
}
}

?>

<?php
$bookmark = new Bookmark();
foreach ($bookmark as $link) {
echo "link is: $link \n";
}
?>


而我們一樣只要使用標準的 foreach 語法, 即可對我們 Bookmark 物件輪巡資料, 而不再只是對 array foreach.
透過實作 IteratorAggregate 介面, 我們能為任何 Class 提供 getIterator 的功能並實現了此介面的功能.

註: 本文假設您已了解 Java/PHP5 Interface 的定義, 這裡的任何類別實作了 XXXX 介面, 即可提供 XXXX 功能.
實作 - 除了 keyword 的 implements 外, 您必須要在您的程式內"實作(現)" 介面中所定義抽象方法.
所有範例中, 都有實作所有定義的抽象方法, 而不僅於 class A implements IteratorAggregate {} 就存檔執行.


Iterator Iterator

在說明 Iterator Iterator 部份, 我以寫作一個類似 Unix 下的 find 指令為範例, 並示範了幾個 SPL 已經實作的幾個有用的 Iterator.

和 Java collections framework 相同, 您在使用 SPL 預設實作品時, 應保握一個原則, "優先考慮復合(composition), 然後才是繼承(inheritance)" ( Effective Java Programming Language Guide , item 14).

也就是優先考慮 has a , 然後才是 is a 的關係.

也就是說對於 ArrayObject / ArrayIterator / DirectoryIterator /RecursiveDirectoryIterator .... 等實作品, 在大部份情況下, 請不要繼承它, 而是復合它.


第一版的 RackFind, 我們先把目錄下的檔案全部列出來, DirectoryIterator 和 RecursiveDirectoryIterator 是 SPL 提供的目錄操作的方便 class , 差別在於後者會一併例出子目錄下的檔案.


<?php

class RackFind implements IteratorAggregate {

private $path = "";
private $file = "";

public function __construct($path, $file="") {
$this->path = $path;
$this->file = $file;
}

public function getIterator() {
return new RecursiveDirectoryIterator($this->path);
}
}

$find = new RackFind("c:/tmp", "test");
foreach($find as $f) {
echo $f->getFileName() . "\n";
}
?>


上面程式已能將 tmp 目錄下的所以檔案列出來了, 那 find 功能在哪呢??
我們需要為 RecursiveDirectoryIterator 提供一個 Filename FilterIterator. 完整範例二如下:

<?php

class RackFind implements IteratorAggregate {
private $path = "";
private $file = "";

public function __construct($path, $file="") {
$this->path = $path;
$this->file = $file;
}

public function getIterator() {
return new FilenameFilter(new RecursiveDirectoryIterator($this->path), $this->file);
}
}

class FilenameFilter extends FilterIterator {

private $file = "";

public function __construct($it, $file="") {
parent::__construct($it);
$this->file = $file;
}

public function accept(){
if (strlen($this->file) ==0) return true;
return ereg($this->file, $this->current()->getFileName());
}
}

$find = new RackFind("c:/tmp", "test");
foreach($find as $f) {
echo $f->getFileName() . "\n";
}
?>


OK~~ 現在只有檔名中包含 test 的會被 iterator 出來...

最後, 老板永遠是機車的, 一個 find 決對沒那麼容易, 假設老板說, 檔案太多, 可不可以分頁, 每頁只列出 5 個檔案...
這時, 我們讓我們的 Iterator 再經過 LimitIterator 的簡單實作.


<?php
class RackFind implements IteratorAggregate {

private $path = "";
private $file = "";
private $size =0;

public function __construct($path, $file="", $size=0) {
$this->path = $path;
$this->file = $file;
$this->size = $size;
}

public function getIterator() {
if ($this->size >0) {
return new LimitIterator(new FilenameFilter(new RecursiveDirectoryIterator($this->path), $this->file), 0, $this->size);
}else {
return new FilenameFilter(new RecursiveDirectoryIterator($this->path), $this->file);
}
}
}

class FilenameFilter extends FilterIterator {
private $file = "";

public function __construct($it, $file="") {
parent::__construct($it);
$this->file = $file;
}

public function accept(){
if (strlen($this->file) ==0) return true;
return ereg($this->file, $this->current()->getFileName());
}
}

$find = new RackFind("c:/tmp", "test", 5);
foreach($find as $f) {
echo $f->getFileName() . "\n";
}

?>



Iterator useful classes
最後, 你可以透過 spl_classes() 來得到 SPL 的實作 classes , 它提供了您很多的預設實作品, 大部份情況下都夠用的.

如 5.2.3 提供了:


Array
(
[AppendIterator] => AppendIterator
[ArrayIterator] => ArrayIterator
[ArrayObject] => ArrayObject
[CachingIterator] => CachingIterator
[DirectoryIterator] => DirectoryIterator
[EmptyIterator] => EmptyIterator
[FilterIterator] => FilterIterator
[InfiniteIterator] => InfiniteIterator
[IteratorIterator] => IteratorIterator
[LimitIterator] => LimitIterator
[NoRewindIterator] => NoRewindIterator
[OuterIterator] => OuterIterator
[ParentIterator] => ParentIterator
[RecursiveArrayIterator] => RecursiveArrayIterator
[RecursiveCachingIterator] => RecursiveCachingIterator
[RecursiveDirectoryIterator] => RecursiveDirectoryIterator
[RecursiveFilterIterator] => RecursiveFilterIterator
[RecursiveIterator] => RecursiveIterator
[RecursiveIteratorIterator] => RecursiveIteratorIterator
[RecursiveRegexIterator] => RecursiveRegexIterator
[RegexIterator] => RegexIterator
[SeekableIterator] => SeekableIterator
[SimpleXMLIterator] => SimpleXMLIterator
[SplFileInfo] => SplFileInfo
[SplFileObject] => SplFileObject
[SplObjectStorage] => SplObjectStorage
[SplObserver] => SplObserver
[SplSubject] => SplSubject
[SplTempFileObject] => SplTempFileObject
)


且 Adodb 最新的版本, 對於 ResultSet 也都支援 SPL 的 Iterator , 所以, 您都可以利用本篇的技巧處理它們.

$rs = $db->Execute($sql);
foreach($rs as $row) {
echo "r1=".$row[0]." r2=".$row[1]."
";
}

來取代傳統的.

while (!$recordSet->EOF) {
print $recordSet->fields[0].' '.$recordSet->fields[1].'
';
$recordSet->MoveNext();
}


透過 SPL Iterator , 不論您對到的是任何資料, 處理的方式都是相同, 這對於您將資料處理程式包成 DAO
來說, 不管您是後端是利用 XML, Array, Database , LDAP , 利用 iterator , 所有的呼叫方式及使用方式是相同的.

附錄 Adodb Iterator 實作, 也是相當直覺優雅
http://api.lifetype.org.tw/d5/ddf/adodb-iterator_8inc_8php-source.html

2007年6月24日 星期日

ExifPhotoStamper 1.0.3 - 更新版推出

每天一新版, 這大概是阿土伯的 opensource/freeware 中更版最快的了..
因為它有個惡勢力使用者(老婆大人), 他的需求會立即新增上去 :D

##CONTINUE##
因為 google code 限制單一檔案 20mb, 請下載分割檔案以下面指令合併或用 7-zip 合併解壓即可.


copy /b exifphotostamper-1.0.3-win32.zip.001+exifphotostamper-1.0.3-win32.zip.002 exifphotostamper-1.0.3-win32.zip

1.0.3 版:

  • 目的檔案 變更檔名 功能.
  • 執行結果 debug.log , 有使用上的問題, 請將 log 寄給阿土伯.

詳情請見:

http://racklin.blogspot.com/2007/06/exifphotostamper.html

2007年6月21日 星期四

ExifPhotoStamper 1.0.2 - 更新版推出

部份網友反應的問題及想法, 阿土伯將它做了修正, 並加上了新的功能.. 謝謝大家的建議..
因為, 阿土伯的小土仔只有一位, 沒有太多 Sample Case 可以測, 還望大家繼續試用嘍 :D

##CONTINUE##
1.0.2 版:
  • 修正部份年齡日推算得到大於 1000 的 bug (阿土伯沒注意到 java 回傳的是 微秒, 不是秒 Orz....)
  • 新增字體外框可設定顏色.
  • 字體下方畫陰影.

詳情請見:

http://racklin.blogspot.com/2007/06/exifphotostamper.html

2007年6月20日 星期三

ExifPhotoStamper 1.0.3 - 批次為照片加上日期+


簡介:
ExifPhotoStamper 是一個精巧的 Java 應用程式 For JavaSE 5.0 或 以上.
它提供您批次處理 Exif 中的拍照日期加入到您的照片的四個角落其中一個.
然而, 除此之外, 它提供了一個特殊的功能: "開始日期" 功能.

##CONTINUE##
什麼是"開始日期", 利用"開始日期"功能, 您可以為您的照片設定一個起始的日期, 如您寶寶的出生日期, 男女朋友開始交往日期, 阿土伯的生日等, 利用 ExifPhotoStamper , 它除了將您相片 Exif 中的拍照日期加在相片中外, 還會加上由開始日期到拍照日期經過的時間.
所以, 你可以很輕鬆知道這是寶寶幾個月大的相片, 男女雙方交往多久後的相片, 或阿土伯混吃等死多少年了等, 方便為您的寶寶及親人做相片日記.

當然, 利用 format syntax 功能, 您可以自定壓上去的日期格式或乎略開始時間功能, 將 ExifPhotoStamper 當成標準的 批次壓日期小工具.

最後, ExifPhotoStamper 產生的圖檔, 依然會保留著原始檔案中的 Exif 資訊, 所以您上傳到 flickr 或支援 exif 的網路相簿或管理軟體, 依然可以正確的排序/統計及管理.


支援功能:
  • Exif Date/Time support.
  • Target File will exist Source File 's Exif Infomation metadata.
  • Font/Size/Color Setup.
  • Corner / Margin Setup.
  • Stamp Format Syntax support.
  • Font Border Color Setup.
  • Drop Shadow .
  • Target File Rename.
  • Debug Log.

ScreenShot:




小土仔的 Sample:

Sample (客制化格式, 中文 format)




Sample (Stamp)



Large-dl:http://exifphotostamper.googlecode.com/svn/trunk/sample/DSCN2007-out.JPG

Sample (Orig)

Large-dl:http://exifphotostamper.googlecode.com/svn/trunk/sample/DSCN2007.JPG


使用中文格式:

1. 請在字形名稱中選擇一個中文字體.
2. 格式: (%Y歲%M個月%D日) %y/%m/%d

其中 % 後面緊跟一個英文字母表示指令, 其它隨您填寫, 您也可填

格式: 我的小寶貝 - (%Y歲%M個月%D日) 於 %y年.%m月.%d日.

它等於是幫您浮水印字在上面唷..

指令有:
%Y - 經過(年) %M - 經過(月) %D - 經過(日)
%y - 拍照(年) %m - 拍照(月) %d - 拍照(日)
%H - 拍照(時) %i - 拍照(分) %s - 拍照(秒)


Featured Download:
所有作業系統: without-jvm
http://exifphotostamper.googlecode.com/files/exifphotostamper-1.0.3-bin.zip (340 KB)

Windows: with-jvm (請下載二個檔後一起解壓縮, 因為 google code 有單一檔案 20mb 的限制)

http://exifphotostamper.googlecode.com/files/exifphotostamper-1.0.3-win32.zip.001
http://exifphotostamper.googlecode.com/files/exifphotostamper-1.0.3-win32.zip.002
(29.5 MB)

copy /b exifphotostamper-1.0.3-win32.zip.001+exifphotostamper-1.0.3-win32.zip.002 exifphotostamper-1.0.3-win32.zip



Open Source:

http://code.google.com/p/exifphotostamper/


Require JavaSE5 以上:
ExifPhotoStamper 需要 JavaSE5 或以上的環境, 若您不是下載 Windows 版, 或您的電腦尚未安裝 JavaSE , 請到下列網址先下載安裝.
http://java.sun.com/javase/downloads/index.jsp
點選 Java Runtime Environment (JRE) 6u1 旁的 Download.


軟體背後:
每一個軟體背後, 都有一個心酸的故事~~~ :D
才瘋狂的結束了前一陣子的專案, 本以為可以利用端午連假休息在家躺四天, 沒想到老婆大人一個命令下, 傕生出了這個軟體.
"把小土仔的相片整理一下, 去采風輸出一本相簿給他的爺爺看吧..." 這個.. 我能躺的時間少了一天 ....
"對了... 送去沖印的相片能不能加上當時拍照的日期"... 這... 容易, 網路上一堆 Free Software 能做吧..
"呀~~ 那日期前面能不能加上小土仔目前 幾個月大又幾天 "... 這... 沒有這樣的軟體吧........
"不管~~ 沒有你就一張一張用 gimp 打字把幾個月大又幾天打上去" ...... orz....

相信一定有很多爸爸/媽媽需要這個軟件... 希望對大家有幫助....