2008年9月1日 星期一

李斯諫逐客書

學生時唸到的古文, 沒想到在現在會這麼有感覺.
本土/外來/挺誰/嗆誰/反誰/護誰 一再操作這樣議題昇高人民對立是否得宜...
政治也是一種專業, 程式設計亦然.
當批評別人的設計有問題時, 能謙虛的自省自己的專業, 是否也出現了相同的問題, 並容納多元的意見以及不同團隊間的合作...
共勉之~

##CONTINUE##

李斯諫逐客書    李 斯
  秦宗室大臣皆言秦王曰:「諸侯人來事秦者,祇為其主遊間秦耳,請一切逐客。」李斯
議亦在逐中。斯乃上書曰:「臣聞吏議逐客,竊以為過矣。」
  「昔穆公求士,西取由余於戎,東得百里奚於宛,迎蹇叔於宋,求丕豹,公孫支於晉。
此五子者,不產於秦,而穆公用之,井國二十,遂霸西戎。孝公用商鞅之法,移風易俗,民
以殷盛,國以富彊,百姓樂用,諸侯親服獲楚,魏之師,舉地千里,至今治強。惠王用張儀
之計,拔三川之地,西井巴蜀,北收上郡,南取漢中。包九夷,制鄢郢,東據成皋之險,割
膏腴之壤,遂散六國之從,使之西面事秦,功施到今。昭王得范雎,廢穰侯,逐華陽,強公
室,杜私門,蠶食諸侯,使秦成帝業。此四君者,皆以客之功。由此觀之,客何負於秦哉!
向使四君卻客而不內,疏士而不與,是使國無富利之實,而秦無強大之名也。」
  「今陛下致昆山之玉,有隨和之寶,垂明月之珠,服太阿之劍,乘纖離之馬,建翠鳳之
旗,樹靈鼉之鼓:此數寶者,秦不生一焉,而陛下說之,何也?必秦國之所生然後可,則是
夜光之璧,不飾朝廷;犀象之器,不為玩好;鄭衛之女,不充後官;而駿馬駃騠,不實外廄
;江南金錫不為用;西蜀丹青不為采。所以飾後官,充下陳,娛心意,說耳目者,必出於秦
然後可,則是宛珠之簪,傅璣之珥,阿縞之衣?錦繡之飾,不進於前;而隨俗雅化,佳冶窈
窕,趙女不立於側也。夫擊甕叩缶,彈箏搏髀,而歌呼嗚嗚快耳者,真秦之聲也;鄭衛桑間
,韶虞武象者,異國之樂也。今棄擊甕而就鄭衛,退彈箏而取韶虞,若是者何也?快意當前
,適觀而已矣。今取人則不然,不問可否,不論曲直,非秦者去,為客者逐,然則是所重者
在乎笆樂珠玉,而所輕者在乎人民也。此非所以跨海內,致諸侯之術也。」
  「臣聞地廣者粟多,國大者人眾,兵強者士勇。是以泰山不讓士壤,故能成其大;河海
不擇細流,故能就其深;王者不卻眾庶,故能明其德。是以地無四,方民無異國,四時充美
,鬼神降福
。此五帝,三王之所以無敵也。今乃棄黔首以資敵國,卻賓客以業諸侯,使天下
之士退而不敢西向,裹足不入秦,此所謂『藉寇兵而齎盜糧』者也。」
  「夫物不產於秦,可寶者多;士不產於秦,而願忠者眾。今逐客以資敵國,損民以益讎
,內自虛而外樹怨於諸侯,求國無危,不可得也
。」
  秦王乃除逐客之令,復李斯官。
大意:
   (一)自「秦宗室大臣皆言秦王曰」至「竊以為過矣」
     說明逐客為過。
   (二)自「昔穆公求士」至「而秦無強大之名也」
     (舉繆公、孝公、惠王、昭王例)說明客有功於秦(暗示逐客為不智)。
   (三)自「今陛下致昆山之玉」至「致諸侯之術也」
     說明逐其民人而取其色樂珠玉,非王霸者之所為(以色樂珠玉之取襯客之去為不
     合理)。
   (四)自「臣聞地廣者粟多」至「此所謂藉寇兵而齎盜糧者也」
     說明卻客而為他國所用,非秦之福(以逐客資敵業諸侯說明爭取人才的重要性)
     。
   (五)自「夫物不產於秦」至「不可得也」
     說明逐客則國危。
   (六)自「秦王乃除逐客之令」至「復李斯官」
     記敘李斯復官。

2008年8月18日 星期一

GREUtils 1.1 in trunk

GREUtils 1.1 已經 update 到 http://greutils.googlecode.com/svn/trunk 中, 有興趣參考 Source Code 或使用, 請利用 svn checkout .

GREUtils 是一個 XULRunner / Firefox extensions Javascript Utilities Libraries.
1.0 到 1.1 基本上是全面改寫, GREUtils 1.1 提供以下功能:
  • Object extend function
  • include / include_once specified URL script.
  • XPCOM utilities
  • Charset Convert
  • Preferences Services
  • File IO
  • Dialog utilities (all XPCOM implemented, can use in javascript code modules)
  • Controller and CommandDispatcher? Helper
  • Cryphto Hash Utilities – md5 / sha1 /sha256
  • JSON encode / decode use XPCOM implemented (VERY FASTer then json.org's javascript version)
  • Threading – Native Multi-Threading support
  • JavaScript code modules support

其它改變:
  • GREUtils 1.1 全部改寫了 1.0 的 inline document , 由 ScriptDoc 改成了 jsdoc 格式, 以方便產生出 API Reference.
  • Makefile for linux user , 以方便產生 minified / packed / jsmodues / jsdoc 等 distribution files.
  • singleton support
  • inherits / namespace support (many idea and source from goog javascript libraries).
Project URL: http://code.google.com/p/greutils/

API References: http://greutils.googlecode.com/svn/trunk/jsdoc/index.html

2008年7月4日 星期五

Threading in Firefox 3

Firefox 3 (Gecko 1.9) 新增了許多特色 (詳見 ), 其中一項重要的特色, 便是導入了 Thread Manager 機制.

##CONTINUE##

在 Firefox 3 以前, 我們要讓 Javascript 程式在背景執行, 最簡單的方式便是利用 setTimeout / setInterval 方式:


function backgroundTask() {
// Perform a small amount of work

window.setTimeout(arguments.callee, 100);
}

window.setTimeout(backgroundTask, 100);

以上的方式雖然可以把程式丟到背景執行, 然而, 它依然只是在主執行緒(mainThread)中, 以非同步的方式執行.

Firefox 3 後, 導入了 Thread Manager , 讓我們可以撰寫平台相關的真正多執行緒程式.

要實作多執行緒 Javascript 程式,本身必須是 XPCOM Object, 且實作 nsIRunnable 介面(和 Java Thread 很像不是嗎?).
詳細範例可參考 Thread Manager nsIThreadManager .

Thread Utils:
雖然 Firefox 3 已經大大簡化了多執行緒程式的寫作方式(且很有 Java 風格), 但就 Javascript 來說, 就顯的有些麻煩, 我們要為每一個要執行的程式, 一一實作成 XPCOM Object 也是一件很煩人的事..
阿土伯在 GREUtils Rewriting 計劃中, 為 Threading 做了一些封裝, 讓您可以比較容易且直覺的使用 Firefox 3 所帶來的 Multi-Threading 這份大禮.

有關 Thread 部份的 Code 如下, 已修改過可以獨立運作於 GREUtils 整個專案之外:

/**
* Thread - is simple and easy use Thread Manager APIs libraries for GRE (Gecko Runtime Environment).
* ONLY Work with Firefox 3 or XULRunner 1.9
*
* @public
* @name GREUtils.Thread
* @namespace GREUtils.Thread
*/
var GREUtils = GREUtils || {};

GREUtils.Thread = {

_threadManager: Components.classes["@mozilla.org/thread-manager;1"]
.getService(Components.interfaces.nsIThreadManager),

_mainThread: null,

_workerThread: null,

reportError: function(err){
Components.utils.reportError(err);
}
};


/**
* getThreadManager
*
* @public
* @static
* @function
* @return {Object} nsIThreadManager
*/
GREUtils.Thread.getThreadManager = function(){
return this._threadManager;
};


/**
* getMainThread
*
* @public
* @static
* @function
* @return {Object} nsIThread main thread
*/
GREUtils.Thread.getMainThread = function(){
if (this._mainThread == null) {
this._mainThread = GREUtils.Thread.getThreadManager().mainThread;

// extends magical method to worker thread
// this._workerThread.dispatchMainThread = GREUtils.Thread.dispatchMainThread;
}
return this._mainThread;
};


/**
* dispatchMainThread
*
* @public
* @static
* @function
* @return {Object} nsIThreadManager
* @param {Object} aRunnable
* @param {Object} aType
*/
GREUtils.Thread.dispatchMainThread = function(aRunnable, aType) {
var mainThread = GREUtils.Thread.getMainThread();
var aType = aType || mainThread.DISPATCH_NORMAL;
try {
mainThread.dispatch(aRunnable, aType);
}catch (err) {
GREUtils.Thread.reportError(err);
}
};


/**
* dispatchWorkerThread
*
* @public
* @static
* @function
* @return {Object} nsIThreadManager
* @param {Object} workerThread
* @param {Object} aRunnable
* @param {Object} aType
*/
GREUtils.Thread.dispatchWorkerThread = function(workerThread, aRunnable, aType) {
var aType = aType || workerThread.DISPATCH_NORMAL;
try {
workerThread.dispatch(aRunnable, aType);
}catch (err) {
GREUtils.Thread.reportError(err);
}
};

/**
* getWorkerThread in pool
*
* @public
* @static
* @function
* @return {Object} nsIThread worker thread
*/
GREUtils.Thread.getWorkerThread = function(){
// get presist work thread
// will not create new worker thread
if (this._workerThread == null) {
this._workerThread = GREUtils.Thread.getThreadManager().newThread(0);

// extends magical method to worker thread
// this._workerThread.dispatchMainThread = GREUtils.Thread.dispatchMainThread;
}
return this._workerThread;
};


/**
* createWorkerThread - create new worker thread.
*
* @public
* @static
* @function
* @return {Object} nsIThread worker thread
*/
GREUtils.Thread.createWorkerThread = function(){
// create new worker thread
var worker = GREUtils.Thread.getThreadManager().newThread(0);

// extends magical method to worker thread
//worker.dispatchMainThread = GREUtils.Thread.dispatchMainThread;

return worker;
};


/**
* CallbackRunnableAdapter
*
* @public
* @class
* @param {Object} func
* @param {Object} data
*/
GREUtils.Thread.CallbackRunnableAdapter = function(func, data) {
this._func = func;
this._data = data;
};

GREUtils.Thread.CallbackRunnableAdapter.prototype = {

get func() {
return this._func;
},

set func(func){
this._func = func || null;
},

get data() {
return this._data;
},

set data(data){
this._data = data || null;
},

run: function() {
try {
if (this.func) {
if(this.data) this.func(this.data);
else this.func();
}
} catch (err) {
Components.utils.reportError(err);
}
},

QueryInterface: function(iid) {
if (iid.equals(Components.Interfaces.nsIRunnable) || iid.equals(Components.Interfaces.nsISupports)) {
return this;
}
throw Components.results.NS_ERROR_NO_INTERFACE;
}
};


/**
* WorkerRunnableAdapter
*
* @public
* @class
* @param {Object} func
* @param {Object} callback
* @param {Object} data
*/
GREUtils.Thread.WorkerRunnableAdapter = function(func, callback, data) {
this._func = func;
this._callback = callback;
this._data = data;

if(arguments.length == 2 ) {
this._data = callback;
this._callback = null;
}
};

GREUtils.Thread.WorkerRunnableAdapter.prototype = {

get func() {
return this._func;
},

set func(func){
this._func = func || null;
},

get callback() {
return this._callback;
},

set callback(callback){
this._callback = callback || null;
},

get data() {
return this._data;
},

set data(data){
this._data = data || null;
},

run: function() {
try {
var result = null;
if (this.func) {
if(this.data) result = this.func(this.data);
else result = this.func();
}

if (this.callback) {
GREUtils.Thread.dispatchMainThread(new GREUtils.Thread.CallbackRunnableAdapter(this.callback, result));
}
} catch (err) {
Components.utils.reportError(err);
}

},

QueryInterface: function(iid) {
if (iid.equals(Components.Interfaces.nsIRunnable) || iid.equals(Components.Interfaces.nsISupports)) {
return this;
}
throw Components.results.NS_ERROR_NO_INTERFACE;
}
};


/**
* createWorkerThreadAdapter
*
* @public
* @static
* @function
* @param {Object} workerFunc
* @param {Object} callbackFunc
* @param {Object} data
*/
GREUtils.Thread.createWorkerThreadAdapter = function(workerFunc, callbackFunc, data) {

return new GREUtils.Thread.WorkerRunnableAdapter(workerFunc, callbackFunc, data);
};


使用方式:
利用 GREUtils.Thread.getMainThread() 可以取得主執行緒.
利用 GREUtils.Thread.createWorkerThread() 產生一個新的執行緒.

WorkerThreadAdapter:
則是用以簡化自行撰寫 worker / callback 二個 XPCOM Object, 取而代之的是二個 Function handle 以及要傳入 worker thread 的資料.


var worker = GREUtils.Thread.createWorkerThread();
var execute = GREUtils.Thread.createWorkerThreadAdapter(
/* worker function */
function(data) {
var result = 0;
var i = 0;

while(i <= data) {
result += i;
i++;
}
return result;
},
/* callback function */
function(result) {
alert('sum = ' + result);
},
/* data to worker function */
10000
);

GREUtils.Thread.dispatchWorkerThread(worker, execute);



註1:
Firefox3 的 Thread 由於是以 XPCOM 實作, 所以您只能用於 extension addons 寫作或是 XULRunner 專案中, 如果您需要在一般 Web Application 中使用多執行緒, 可以參考 Google Gears 的 WorkerPool 實作.

註2:
請特別注意 The Thread Manager 那篇的這句重要的警告.
Note: The DOM is not thread safe. You must not access the DOM or user interface from background threads. Doing so will likely crash.
其中要再注意的是, alert() 也是 DOM global scope 哦, 如果您在 background threads 用了 alert(), Firefox 3 也是會當給你看地.


忙裡偷閒寫下本篇, 內容有點雜亂簡單, 但還是希望對大家有幫助.

2008年5月11日 星期日

Processing.js

Processing.js. jQuery 作者 John Resig’s 將 processing.org Java implementation's Processing Language port to JavaScript and Canvas.

而且實測, 在 Firefox 3 執行的很完美, 真是有夠強.

有興趣的可以玩玩 Processing.js 的 Basic Demo.
和 processing.org java 版的 Basic Demo.
只能說..太酷了..

其中有幾樣和 Processing Language 無關的 javascript 實作, 也很值得研究.

  • Types and type casting
  • Classes
  • Method overloading and multiple constructors
  • Inheritance

2008年5月2日 星期五

Nimbus Theme on Ubuntu 8.04


Nimbus ( 各組件詳細 Nimbus SPEC ) 是 Sun Solaris Desktop 預設的就相當有質感的 Theme . 在未來的 JDK 6u10 中也將加入 Nimbus LookAndFeel.
所以利用這次重裝 Ubuntu 8.04 之餘, 順便把 Nimbus GTK2 engine 以及 Icons-theme 加入 Ubuntu 8.04 中.

阿土伯目前的 Ubuntu ScreenShot:


Compile and Install:
首先請先確認您有安裝打包 dpkg 相關的開發環境

sudo apt-get install fakeroot dpkg-dev devscripts icon-naming-utils

接下來就是下載 Nimbus 最新的 0.0.9 Source, 以及 deb 的 patch 包.

wget -c http://dlc.sun.com/osol/jds/downloads/extras/nimbus-0.0.9.tar.bz2
wget -c http://zap.tartarus.org/~ds/debian/dists/sid/main/source/nimbus_0.0.6-1.diff.gz


Compile:

tar xf nimbus-0.0.9.tar.bz2
cd nimbus-0.0.9
zcat ../nimbus_0.0.6-1.diff.gz | patch -p1
chmod +x debian/rules
debchange -v 0.0.9-1
sudo apt-get build-dep
fakeroot dpkg-buildpackage -us -uc

在一陣等待後, 您應該會在您的家目錄得到二個deb, (gtk2-engines-nimbus_0.0.6-1_i386.deb / nimbus-icon-theme_0.0.6-1_all.deb )

安裝 Nimbus dpkg:

sudo dpkg -i nimbus-icon-theme_0.0.6-1_all.deb
sudo dpkg -i gtk2-engines-nimbus_0.0.6-1_i386.deb

您應該可以在外觀設定看到 Nimbus 嘍.

懶人包:
OK!OK! 阿土伯了解大家的痛苦, 懶人包在此, 請直接下載這二個 deb , 然後依照安裝方式安裝即可.
gtk2-engines-nimbus_0.0.6-1_i386.deb(45K)
nimbus-icon-theme_0.0.6-1_all.deb(9M)