2008年5月25日 星期日

讓我們輕鬆自在設計自己的 LXPanel Plugin

Standard
今年度『LXDE』發展蓬勃,陸續有新血加入,無論是國內外各個 Distribution 的 Package Maintainer 亦或是 Developer、翻譯者,都讓整個 Project Team 充滿熱血的氣氛。 除了已加入的成員外,其他持有興趣者也越來越多,開始有人提出『如何讀 LXDE 的 Source Code』、『該從哪對 LXDE 著手』等議題。充份顯示出目前 LXDE 缺少 Development Primer 和相關開發文件。

其實,只要你願意,你可以從最困難又複雜的『PCManFM』和『LXPanel』逐行讀起,這似乎是一種方法,但我並不建議用這種痛苦的方法參與 LXDE 的計劃。如果真的想讀一個完整的 Source Code,極為簡單的『LXSession-lite』是一個不錯的選擇。不過,就算完全讀通『LXSession-lite』 這類子專案,一般人還是無法在上面有所著力,因為這類子專案之所以簡單,是因為功能需求不複雜且沒有太多需要擴充的空間。不過,要是有人純粹想練功夫, Just do it!

那麼,如何開始在 LXDE 上開發程式呢?建議從 LXPanel Plugin 上起步最佳。就如同研究『Linux Kernel』 一般,入門的第一步通常都是『Writing Module』。你不用完全了解 LXPanel 的架構,只要遵守規範,就可以在上面開發你自己的 Plugin/Module,其撰寫就如同寫一般的 GTK+ 程式,非常容易。

撰寫 Plugin 的準備,是先下載 LXPanel 的 Source Code,然後在『src/plugins』之下建立一個新 Plugin 的目錄,在這次範例中我們建立一個『src/plugins/explugin』目錄,並將程式碼放在裡面。

這邊講一個簡單的 LXPanel Plugin 範例,其功能是載入並顯示一張 PNG 圖檔在 LXPanel 上。

這裡是原始程式碼〔src/plugins/explugin/explugin.c〕:
#include <stdlib.h>
#include <glib/gi18n.h>

#include "panel.h"
#include "misc.h"
#include "plugin.h"
#include "dbg.h"

typedef struct {
GtkWidget *main;
GtkTooltips *tip;
} ex_plugin;

static int
explugin_constructor(Plugin *p, char** fp)
{
ex_plugin *exp;

ENTER;

/* 建立一塊記憶體 */
exp = g_slice_new0(ex_plugin);

g_return_val_if_fail(exp != NULL, 0);

/* 設定 Plugin 的私有記憶體區塊 */
p->priv = exp;

/* 讀取一張圖並建立一個 GtkWidget */
exp->main = gtk_image_new_from_file("/usr/share/lxpanel/images/example.png");

/* 顯示 GtkWidget 的所有內容 */
gtk_widget_show_all(exp->main);

/* 建立一個 tooltips */
exp->tip = gtk_tooltips_new();
#if GLIB_CHECK_VERSION( 2, 10, 0 )
g_object_ref_sink( exp->tip );
#else
g_object_ref( exp->tip );
gtk_object_sink( exp->tip );
#endif

/* 將已建立的 Plugin 內容加入並放在 LXPanel 上 */
p->pwid = exp->main;

RET(1);
}

static void
explugin_destructor(Plugin *p)
{
ex_plugin *exp = (ex_plugin *)p->priv;

ENTER;

/* 釋放 tooltips */
g_object_unref(exp->tip);
/* 釋放 GtkWidget */
gtk_widget_destroy(exp->main);
/* 釋放私有記憶體區塊 */
g_slice_free(ex_plugin, exp);

RET();
}

/* LXPanel Plugin 的相關設定 */
PluginClass explugin_plugin_class = {
fname: NULL,
count: 0,

type : "explugin",
name : N_("Example Plugin"), /* Plugin 的名稱 */
version: "1.0",
description : N_("This is a Example Plugin"), /* Plugin 的簡介和描述 */

constructor : explugin_constructor, /* Plugin 建立時的函式 */
destructor : explugin_destructor, /* Plugin 被釋放時的函式 */
config : NULL,
save : NULL,
orientation : NULL
};


除程式碼外,還得建立一個 Makefile 的設定〔src/plugins/explugin/Makefile.am 〕:
INCLUDES = \
-I. \
-I$(top_srcdir)/src \
$(PACKAGE_CFLAGS) \
$(G_CAST_CHECKS)

module_LTLIBRARIES = explugin.la

moduledir = $(libdir)/lxpanel/plugins

explugin_la_SOURCES = \
explugin.c

explugin_la_LIBADD = \
$(PACKAGE_LIBS)

explugin_la_LDFLAGS = \
-module \
@LXPANEL_MODULE@


加上設定〔粗體字部份〕,讓 Autotools 去產生 explugin 的 Makefile〔./configure.ac〕:
AC_CONFIG_FILES([
Makefile
src/Makefile
src/plugins/Makefile
src/plugins/netstatus/Makefile
src/plugins/netstat/Makefile
src/plugins/volume/Makefile
src/plugins/volumealsa/Makefile
src/plugins/cpu/Makefile
src/plugins/deskno/Makefile
src/plugins/batt/Makefile
src/plugins/kbled/Makefile
src/plugins/xkb/Makefile
src/plugins/explugin/Makefile
po/Makefile.in
data/Makefile
data/default/panels/panel
man/Makefile
])


編譯 Plugin 的方法〔在 LXPanel 的原始碼根目錄下〕:
# ./autogen.sh
# ./configure
# cd src/plugins/explugin
# make


測試 Plugin〔在 src/plugins/explugin 目錄下〕:
# make install
# lxpanelctl restart

* 之後可在 LXPanel 的工作列元件清單看到『Example Plugin』

現在來談到程式碼的說明,LXPanel Plugin 有幾種 handler 設定:
constructor - 指向 Plugin 建立時的函式
destructor - 指向 Plugin 被釋放時的函式
config - 指向 Plugin 設定視窗的處理函式
save - 指向 Plugin 儲存設定的處理函式
orientation - 指向直向或橫向的處理函式

若某些 handler 對此 Plugin 非必要,可設為 NULL。一般來說,一個正常的 Plugin 最少要有 constructor 和 destructor 的 handler,可參考本文的範例程式。至於 config 、save 以及 orientation 的部份,由於牽涉到設定檔等等問題,要花不少篇幅說明,所以在此先不詳述,日後有機會再撰文補上。

LXPanel 對 Plugin 有一個設計 -『私有記憶體區塊』,顧名思義就是 Plugin 私有的記憶體存取空間,可讓 Plugin 裡每一部份的程式存取和共用。其原理是 LXPanel 提供了一個『priv 指標』,讓我們可以指向自己為 Plugin 建立的記憶體區塊。所以,在使用上我們不必再煩腦函式之間的傳值問題,直接透過標準的『priv 指標』去存取共用區的資料即可。

後記
截至這篇文章為止,LXPanel 還未提供一個完整的 plugin-dev package,所以我們在開發 Plugin 時需要 LXPanel 的 Source Code,而且必須要在『src/plugins/*』底下做編譯。

2008年5月23日 星期五

輕輕鬆鬆玩 8x51 的 Serial Port 控制

Standard
使用 Serial Port 是一個很基礎且簡單的通訊方式,從中可以很容易了解到 RXD/TXD 的運作原理,而常見的網路卡、電話等等通訊都是建構在相同的原理之上。Serial Port 在電路上很單純,對兩個要互通的電路來說,就是『你的傳送 TXD 是我的接收 RXD 』,很簡單的觀念,只要跳線就可完成。

整個實作目標,是按下開始傳送按鈕後,將透過 Serial Port 傳送 2 Bytes 的資料到另一個外部裝置,當外部裝置傳送 2Bytes 的資料過來時,將此資料顯示在七段顯示器上。其中這 2 Bytes 分別為『個位數』和『十位數』,必需先加總成一個 8bits 的數值,再送到顯示器上。

其程式的設計流程大致如下:


詳細程式碼和註解:
ORG 00H          ; 程式開始處
JMP BEGIN ; 跳到 BEGIN
ORG 03H ; 停止按鈕的外部中斷程式
JMP STOP ; 跳到 STOP
ORG 13H ; 開始按鈕的外部中斷程式
JMP START ; 跳到 START

BEGIN:
; 設定一組號碼 06,並拆成十位和個位兩數
MOV R0, #6 ; 設定第一個 Byte 記錄個位數
MOV R1, #0 ; 設定第二個 Byte 記錄十位數
MOV A, R0 ; R0 無法直接 mov 到 R2,故先暫存到 A
MOV R2, A ; 將 A 的值移到 R2
MOV A, R1 ; R1 無法直接 mov 到 R3,故先暫存到 A
MOV R3, A ; 將 A 的值移到 R3
CALL BOND ; 呼叫 BOND 去將兩個位數加總成一個數字到 A
CALL INIT_SERIAL ; 初始化 Serial Port 相關設定
MOV IP, #00000000B ; 低位觸發
MOV IE, #10000111B ; [EA][--][ET2][ES][ET1][EX1][ET0][EX0]

WAIT:
MOV P1, A ; 將 A 輸出到顯示器
JB RI, RXD ; 當 RI 被設為 1 ,跳到 RXD 接收資料
JMP WAIT ; 跳回 WAIT 顯示 A 和持續等待接收

RXD:
CLR RI ; 清除 RI
MOV R2, SBUF ; 接收個位數『第一個 byte』到 R2
JNB RI, $ ; 等待下一個 byte,RI 變成 1 之前停止不動
CLR RI ; 清除 RI
MOV R3, SBUF ; 接收十位數『第一個 byte』到 R2
CALL BOND ; 呼叫 BOND 去將兩個位數加總成一個數字到 A
JMP WAIT ; 跳回 WAIT 顯示 A 和持續等待接收

START:
JNB TI, $ ; 等待可傳送狀態,TI 變成 1 之前停止不動
CLR TI ; 清除 TI
MOV SBUF, R0 ; 將『個位數』傳出去
JNB TI, $ ; 等待可再傳送狀態,TI 變成 1 之前停止不動
CLR TI ; 清除 TI
MOV SBUF, R1 ; 將『十位數』傳出去
RETI ; 中斷程式結束,回到原本主程式流程

STOP:
MOV A, R0 ; R0 無法直接 mov 到 R2,故先暫存到 A
MOV R2, A ; 將 A 的值移到 R2
MOV A, R1 ; R1 無法直接 mov 到 R3,故先暫存到 A
MOV R3, A ; 將 A 的值移到 R3
CALL BOND ; 呼叫 BOND 去將兩個位數加總成一個數字到 A
RETI ; 中斷程式結束,回到原本主程式流程

BOND:
MOV B, #10 ; 設 B = 10
MOV A, R3 ; 設 A = R3 (十位數值)
MUL AB ; A = A*10 = R3*10
ADD A, R2 ; A = A + R2 (個位數值)
DA A ; 針對顯示器做十進位處理
RET

INIT_SERIAL:
MOV SCON, #50H ; 設定 Serial Port 為 mode 1
; SCON: [SM0][SM1][SM2][REN][TB8][RB8][TI][RI] = 1010000
MOV TMOD, #20H ; 設定『計時器1 』為 mode 2 (00100000)
MOV TH1, #1DH ; 鮑率設定,使用 137.6Hz
SETB TR1 ; 啟動計時器1
SETB TI ; 設定可傳送狀態
RET


後記
延續『8x51 起手式 -LED 跑馬燈』,這又是一次學校的作業,在此筆記之。

2008年5月19日 星期一

Linux Kernel 2.6.25 - ACPI 的電池狀態大變動

Standard
截至這篇文章為止,『Linux Kernel 』的 latest stable version 是 2.6.25-4,或許是因為 2.6.25 正式 release 才約短短一個月左右,多數人應該都還停留 2.6.24 以下的版本。原本用得好好的人,應該也不會去趕流行而換上最新的 kernel,畢竟人人都不願意當白老鼠呀。

今天,不怕死的將 EeePC 裡面 Debian 的 kernel 從 2.6.24-2 換成了 2.6.25-2 ,因為原本 Kernel 的 snd-hda-intel driver 一直無法正確驅動 EeePC 900 的聲音晶片〔EeePC 900 和 701 的晶片有出入〕,所以我換上最新版的 kernel 碰一碰運氣。不過運氣真是不錯, Linux kernel 2.6.25-2 讓 EeePC 900 不再是啞巴了,成功解決 EeePC 900 沒聲音的問題〔不然原本打算要跟 Asus 要 Source Code 了〕。

升級 kernel 後,一切看起來都很正常,唯獨 LXPanel 的電池狀態是壞掉的。追了一下 kernel source code 和 debien bugs 發現, /proc/acpi/battery 和 /proc/acpi/ac_adapter 已經在 2.6.25 被拿掉,統一轉移到 2.6.23 之後被加入的 /sys/class/power_supply。

這樣的大改動,意味著許多 userspace 的電池狀態偵測程式要做改寫才能在 Linux kernel 2.6.25 之後的系統上運作正常。還好,這問題並不大,至少支援 Hal 的電池狀態偵測程式可不用擔心,Hal 早在數個月前已處理好這問題,唯有少數幾個不愛 Hal 的程式會受到影響,如 LXPanel batt plugin 。:-(

後記

已著手在修正這問題,未來幾天在 LXDE 的 SVN 上,應該就會出現改好的 code。

2008年5月10日 星期六

你的『EeePC』今天 LXDE 了沒?

Standard
『EeePC』的確造成一股低價電腦熱,其 Easy Mode 更成為各家大廠爭相花大錢模仿的對像,這似乎成了一種莫明的噱頭,彷彿沒有 Easy Mode 就不叫做簡單好用一樣。暫且不論 Easy Mode 好不好用,我相信所有人的看法都不一樣,但就功能而言『LXDE Project』輸人不輸陣,當然也就會來實作一下 Easy Mode 的 Launcher。

這兩個月來,『LXDE』有許多方面的進步,從功能的完備性、穩定性、資源消耗到操控設定,都有穫得很大的改良,這也多虧了許多『朋友』和『廠商』的設備贊助,還有 Bug Reports。當然,開發者放棄『睡眠時間』更是促使這專案進步的關鍵。如今, LXPanel 已經可以支援 Multi-panel ,可以被設定成上下兩個 panel ,就算要模仿 Gnome 也不是問題;而系統時鐘也可以使用 Calender 日曆的功能;在 Panel 上的各個功能,也都可以直接在上面直接點選滑鼠右鍵設定。

LXPanel Plugin 方面,則增加了『鍵盤燈號顯示』,可在 Panel 上顯示『CAPS LOCK』等鍵盤鎖定燈號,尤其在『EeePC』這種沒有 LED 鍵盤燈號的機器上相當實用。在背景圖上,捨棄了原有的『bgBox』設計,直接畫在 Panel 底層,以增加效能和減少資源消耗,也因此修正了許多 GTK+ 無法令人掌控又惱人的 bug。 :D

這兩個月也新增了一些子項目,像是『lxsession-lite』,用來取代 lxsession。過去,我們密集測試了 lxsession 後,發現原先的 lxsession 有許多難解的問題,而且有許多 Code 是各個大型專案借過來的,其複雜度相當令人難以維護,於是就重新創造了 lxsession-lite。顧名思義,這是一個非常 lite 的 Session 控制程式,不過,雖然看似簡單,目前卻已支援監測 Process 狀態並自動重啟程式的功能。如果你沒使用到『記錄工作行程』的功能,或是根本不曉得這在做什麼的人,可以改用 lxsession-lite 以求更高的穩定性。

圖中所看到的 Launcher(Easy Mode),在先前已經提到過,這是為了提供低價電腦解決方案的實作,lxluncher 是以 FreeDesktop.org 的 Spec 當做標準,會讀取 Desktop Files 顯示 Icons ,理論上只要 Package 裡的 Desktop File 設定正確,圖示就會出現在正確的分類裡頭,完全符合原本 Unix-like Desktop 的標準,所以不管使用者是用 Debian、Ubuntu、Fedora 或是 BSD 系統,都可以正確相容。




更多的修正無法一一詳述,不少 memory leaks 和 Crash Bugs 都已經被抓出來並解決了,現在穩定性應該比兩個月前更高才是。

值得一提,『LXDE Project』陸續開始受到國內外所囑目,有 Distributions 已經在考慮甚至使用 LXDE 當作其桌面系統。最近,有幸碰到一位印度朋友『Pradeepto』 -『KDE』的開發者之一,在他的幫助下,『LXDE』現在有了自己的網域名稱『lxde.org』,這原本小小的專案已經開始邁向國際化的大舞台,相當值得令人高興。〔一時找不到他的 Blog 網址,日後補上〕

話說回來,『LXDE』現在已經可以模擬原本 EeePC 上的樣貌,其效能和流暢更是原本『 Xandros 環境』無法與之比擬的,已經無法再找出 Xandros 環境的其他優勢了。在 EeePC 上使用 LXDE ,如今是很棒的享受。

那麼,你的『EeePC』今天 LXDE 了沒?

2008年5月6日 星期二

從 Information Elements 解析無線網路的加密細節

Standard
無線網路的訊號是公開發送的,雖然無法攔截,但只要你有無線裝置,基本上都能『監聽』空氣中的無線網路封包。也因為無線通訊的本身是不安全的,就如同傳統網路可能被 ISP 或連線路徑中的 Route Node 所監聽一樣,所以無論是哪一種通訊,目前的解決方式都是採用封包或資料加密,以達成安全連線的目的。在一般網路通訊中,常聽到的方法有 Secure Sockets Layer(SSL) 這一類,而對於無線網路通訊來說,就有所謂的 WEP、WPA、WPA2 等等眾多規格。嚴格來說,SSL 和無線網路的加密並不算同一層面的實作,但是他們有相同的目的和類似的原理。

最早的無線加密非常單純,可以用 WEP 一種加密方式走遍天下,只要判斷出遠端無線基地台或存取點需要加密金鑰,我們就可以假設該加密是 WEP 。不過由於 WEP 並不安全,有心人經過封包收集後,還是能很快破出金鑰,所以,日後就出現了 WPA、WPA2 種種加密方法的進階補強版。

想要知道該無線訊號是哪一種加密方法,可以從無線裝置所提供的『Information Elements』去得知,從事件 IWEVGENIE 中,就可取得加密的細節 ,這部份可參考 iwlist 或 LXPanel netstat plugin 內部的實作。

Informations Elements(IEs) 的結構定義,分為兩種:

  1. 當加密方式是 WPA or Others,這也是最 IEs 原始的定義,結構如下:



  2. 當加密方式是 WPA2 時,則沒有 OUI 欄位,定義如下:


  • Type 欄位:
    • 0xdd: WPA or Others
    • 0x30: WPA2
  • OUI 定義(3 Bytes)
    • WPA: 0x00, 0x50, 0xf2
    • WPA2: 0x00, 0x0f, 0xac
* 若有 OUI 欄位(4 Bytes),最後 1 Byte 為 0x01
  • Data 欄位

* 所有數值皆採用 Little Endian

因為 WPA 和 WPA2 是後來擴充上去的定義,並不在原始的 IEs 標準裡,所以許多欄位可能依遵循的標準而有所增減,不過,除非是發射端過於老舊,理論上都應該會遵循後來 WPA/WPA2 擴充的標準。在程式實作解析WPA/WPA2 時,原則上只要是無法辨別的 Type,一律視為 TKIP 就可以向下相容了,可以從 『Wireless Tools』的 Source Code 中找到這樣的處理原則。

關於 Cipher Type 和 Authentication Suite(key_mgmt) 的定義可參考:
static const char * iw_ie_cypher_name[] = {
"none",
"WEP-40",
"TKIP",
"WRAP",
"CCMP",
"WEP-104",
};

static const char * iw_ie_key_mgmt_name[] = {
"none",
"802.1x",
"PSK",
};


LXPanel netstat plugin 在這部份的實作摘錄:
void
wireless_gen_ie(ap_info *info, unsigned char *buffer, int ielen)
{
int offset = 2;
int count;
int i;
unsigned char wpa1_oui[3] = {0x00, 0x50, 0xf2};
unsigned char wpa2_oui[3] = {0x00, 0x0f, 0xac};
unsigned char *wpa_oui;

/* check IE type */
switch(buffer[0]) {
case 0xdd: /* WPA or else */
wpa_oui = wpa1_oui;

if((ielen < 8)
|| (memcmp(&buffer[offset], wpa_oui, 3) != 0)
|| (buffer[offset + 3] != 0x01)) {
if (info->haskey)
info->en_method = NS_WIRELESS_AUTH_WEP;
else
info->en_method = NS_WIRELESS_AUTH_OFF;

info->key_mgmt = NS_IW_IE_KEY_MGMT_NONE;
info->group = NS_IW_IE_CIPHER_NONE;
info->pairwise = NS_IW_IE_CIPHER_NONE;

return;
}

/* OUI and 0x01 */
offset += 4;
break;

case 0x30: /* IEEE 802.11i/WPA2 */
wpa_oui = wpa2_oui;
break;

default: /* Unknown */
if (info->haskey)
info->en_method = NS_WIRELESS_AUTH_WEP;
else
info->en_method = NS_WIRELESS_AUTH_OFF;

info->key_mgmt = NS_IW_IE_KEY_MGMT_NONE;
info->group = NS_IW_IE_CIPHER_NONE;
info->pairwise = NS_IW_IE_CIPHER_NONE;
return;
}

/* assume TKIP */
info->en_method = NS_WIRELESS_AUTH_WPA;
info->key_mgmt = NS_IW_IE_KEY_MGMT_NONE;
info->group = NS_IW_IE_CIPHER_TKIP;
info->pairwise = NS_IW_IE_CIPHER_TKIP;

/* 2 bytes for version number (little endian) */
offset += 2;

/* check group cipher for short IE */
if ((offset+4) > ielen) {
/* this is a short IE, we can assume TKIP/TKIP. */
info->group = NS_IW_IE_CIPHER_TKIP;
info->pairwise = NS_IW_IE_CIPHER_TKIP;
return;
}

/* 4 Bytes for group cipher information [3 bytes][1 Byte] */
if(memcmp(&buffer[offset], wpa_oui, 3)!=0) {
/* the group cipher is proprietary */
info->group = NS_IW_IE_CIPHER_NONE;
} else {
/* pick a byte for type of group cipher */
info->group = buffer[offset+3];
}
offset += 4;

/* check pairwise cipher for short IE */
if ((offset+2) > ielen) {
/* this is a short IE, we can assume TKIP. */
info->pairwise = NS_IW_IE_CIPHER_TKIP;
return;
}

/* 2 bytes for number of pairwise ciphers (little endian) */
count = buffer[offset] | (buffer[offset + 1] << 8);
offset += 2;

/* if we are done */
if ((offset+4*count) > ielen) {
return;
}

/* choose first cipher of pairwise ciphers to use,
* FIXME: Let user decide the cipher is the best way. */
for(i=0;i<count;i++) {
if(memcmp(&buffer[offset], wpa_oui, 3)==0) {
/* pick a byte for type of group cipher */
info->pairwise = buffer[offset+3];
}
offset += 4;
}

/* check authentication suites */
if ((offset+2) > ielen) {
/* this is a short IE, we can assume TKIP. */
info->key_mgmt = NS_IW_IE_KEY_MGMT_NONE;
return;
}

/* 2 bytes for number of authentication suites (little endian) */
count = buffer[offset] | (buffer[offset + 1] << 8);
offset += 2;

/* if we are done */
if ((offset+4*count) > ielen) {
return;

/* choose first key_mgmt of authentication suites to use,
* FIXME: Let user decide the key_mgmt is the best way. */
for(i=0;i<count;i++) {
if(memcmp(&buffer[offset], wpa_oui, 3)==0) {
/* pick a byte for type of key_mgmt */
info-&gtkey_mgmt = buffer[offset+3];
}
offset += 4;
}
}


在之前,LXPanel netstat plugin 對 WPA/WPA2 IEs 支援一直有問題,在最近改寫後的 SVN 最新版已經可以很好的處理 IEs,當然這部份是參考 iwlib 的 iwlist.c 寫出來的,其目的是判斷加密的方式,以通知 LXNM 做相對應的處理。如果想要使用這功能,請使用最新 SVN 版本的 LXPanel 以及LXNM,因為改寫過後的 netstat plugin 和舊版 LXNM 完全不相容。

後記

本文的示意圖表是大略畫出來的,其中可能會用到些縮寫或簡化的名詞表示。

2008年5月5日 星期一

從國外社群身上學到的事

Standard
近來不少人問我一些事,是關於前些日子所寫的『彼此需要的 Open Tech Summit Taiwan 2008』一文,其中強烈的言詞造成社群內許多衝擊和回應,從許多社群朋友的傳話中發現,有不少人連續看了『OSDC.tw 2008!』與該文,更是誤以為我在指著『某些人』叫罵。事實上,我不過在抒發心情罷了,簡單說出幫忙過程中所遭遇的狀況,並沒牽扯到這麼多利益、人事方面的糾葛,畢竟,這只是 Blog 上的心情筆記。更何況,我與眾社群的前輩們接觸並不深,也沒什麼可罵或值得罵的。當然,許多大家都在罵的我是都罵了,這也不用我一一枚舉了。

回顧這次『OTStw2008』(4/25~4/29)活動,或許不像前輩們辦的活動如此人山人海,門票那樣供不應求,但能感覺到每個參與者的熱情不遜於其他的活動。或許是因為這活動並不是從大規模的金錢和宣傳去著手,而是一個人一個人辛辛苦苦的邀請和接觸,其中可以發現到不敢真正踏入 Open Source Community 的那群有心人,其實一直在等待我們釋出善意。從許多完全不了解 Open Source/Open Hardware 的人來參加和擁抱,就能感受到這現象。更重要的是,他們並未成為活動的局外人,反而興趣高昂呀。 :)

Community 本來就不只限於技術交流,過程中的互動,也使得各種不同領域的朋友可以相互敞開心胸。有人對許多困苦的第三世界有理想和實踐,對不同國家人文有所著墨,當然技術方面的 Geeks 是少不了的,更多文化和職業差異的趣味也是令人收獲良多。如此技術性的活動,卻可以意外在不同層面有如此豐富的互動,真的是前所未見。原來,這群外國人一直嘗試告訴我的 Community 感覺,就是如此,實在特別!

對我來說,這次活動最有趣的議程就是『EeePC Hacker Show』,因為『LXDE Project』一定會出席和上台〔這議程是我排的嘛!當然 Hacker 優先!〕,也算幫 cwhuang 展示一下他之前說服『Asus』上司提供機器給社群的成果。在這議程中,『PCMAN』把『Xandros』系統殺的悉哩嘩啦,展現 LXDE 的效能和資源低消耗,在 EeePC 機器裡連開一堆 OpenOffice 、Firefox 以及 File Manager 後照樣流暢快速!其整體執行效能可能連某些 Laptop 都望塵莫及,更別說到 EeePC 只有顆 600MHz 的 CPU 和 512MB 的記憶體了。

如今,『Xandros』現在唯一可反擊的藉口,只剩下 Launcher 功能,這就是所謂的『easy mode』,說得好像很困難一樣。不甘受激的 PCMAN ,當場馬上花了兩個 Session 的時間 coding,說什麼也要強硬的把 Launcher 功能寫出來,為 LXDE 反擊!當時的確在華碩內投下了顆震憾彈。

當然,LXDE 這在整個活動中是個小插曲。要是提到 Jserv 的機器人壞掉變成『人形疆屍』,這才有看頭。 :P

在 Asus 場次的第二天結束後,許多國外講者和國內講者以及一些同伴們,就去淡水『紅樓』享受晚餐,最後還一同合影:


值得一提的是,站在『Jserv』和『Paulliu』身後的黑衣男子,是 Debian Developer -『Martin Michlmayr』,當晚是他留在台灣的最後一夜,第二天早上就搭機離開了,並未參加到活動最後一天。更可惜的是,我來不及跟他換 GPGKey 呀!殘念。