2009年12月14日 星期一

Delegation in C - 在 C 語言當中實作委派方法 (2)

延續前一篇文章的想法 Delegation in C - 在 C 語言當中實作委派方法 (1)
像是
invoke_all_func(&list, "Hello World");
這樣的函式顯然不夠彈性
於是想到一個解決方法就是傳入一個 function pointer 給 invoke_all_func() 於是就變成像是下面這樣
invoke_all_func(&list, my_cb_func, "Hello World");
讓 invoke_all_func() 內部去 callback 這個傳入的 function pointer
再利用 <stdarg.h> 所提供相關的函式將傳入的參數取回
因為只有呼叫 invoke_all_func() 的地方才知道傳入的參數有哪些
所以負責將參數取來出也是相當合理的於是 my_cb_func() 的實作就會像下面這樣
static bool my_cb_func(func_t func, va_list ap)
{
    my_func_t my_func = (my_func_t) func;
    const char* value = va_arg(ap, const char*);
    return my_func(value);
}
其中的 my_func_t 是
typedef bool (*my_func_t)(const char*);
於是就可以定義不一樣的 my_func_t 跟 my_cb_func() 來使用同樣 event bubbling 的方法
達到程式碼可以重複使用的好處
詳細的程式碼實作放在 http://fd.idv.tw/tux/callback.tar.bz2
沒有版權也不負責任更不保證沒有長蟲~ :P

2009年12月13日 星期日

Delegation in C - 在 C 語言當中實作委派方法 (1)

原本的想法是想要能夠在 C 語言中實現 event bubbling
提供一些函式去註冊需要被 callback 的函式
然後在 event 發生時去呼叫所有註冊過的函式
於是就有了以下的程式碼

首先來看一段程式碼片段
int main(int argc, char* argv[])
{
    list_t* list = NULL;

    add_func(&list, funcA);
    add_func(&list, funcB);
    add_func(&list, funcC);

    invoke_all_func(&list, "Hello World");

    return 0;
}
這邊利用 add_func() 將 funcA, funcB, funcC 註冊到某個 double linked list 上面
然後呼叫 invoke_all_func() 去呼叫註冊好的 funcA, funcB, funcC
static bool funcA(const char* str)
{
    fprintf(stderr, "%s says %s\n", __FUNCTION__,  str);
    return true;
}

static bool funcB(const char* str)
{
    fprintf(stderr, "%s says %s\n", __FUNCTION__,  str);
    return true;
}

static bool funcC(const char* str)
{
    fprintf(stderr, "%s says %s\n", __FUNCTION__,  str);
    return true;
}
執行後的結果是
funcC says Hello World
funcB says Hello World
funcA says Hello World
這邊的設計上是越後面註冊的函式越先被呼叫到
如果把 funcC() 的回傳值改成 false 結果就會變成
funcC says Hello World
只要某個註冊過的函式先回傳了 false 接下去的函式就不必再去執行了
於是這兩個負責註冊跟呼叫的函式的 prototype 應該就長得像是下面這樣
bool add_func(list_t** list, bool (*func)(const char*));
bool invoke_all_func(list_t** list, const char* msg);
然後再去實作這些函式的剩餘部份,不過問題來了...
當 funcA, funcB, funcC 換成了
static bool funcA(int val)
{
    fprintf(stderr, "%s count %d\n", __FUNCTION__,  val);
    return true;
}

static bool funcB(int val)
{
    fprintf(stderr, "%s count %d\n", __FUNCTION__,  val);
    return true;
}

static bool funcC(int val)
{
    fprintf(stderr, "%s count %d\n", __FUNCTION__,  val);
    return true;
}
或者是換成了
static bool funcA(const char* msg, int val)
{
    fprintf(stderr, "%s says '%s' count: %d\n", __FUNCTION__, msg, val);
    return true;
}

static bool funcB(const char* msg, int val)
{
    fprintf(stderr, "%s says '%s' count: %d\n", __FUNCTION__, msg, val);
    return true;
}  

static bool funcC(const char* msg, int val)
{
    fprintf(stderr, "%s says '%s' count: %d\n", __FUNCTION__, msg, val);
    return true;

可是 event bubbling 的方法還是一模一樣的,這時候我們應該怎麼辦呢?
有一種最不用花腦袋最快速可以解決問題的辦法就是去複製貼上程式碼,然後將參數換一換,有幾種不同的函式就重複幾次同樣的工作

待續...

2009年12月6日 星期日

在 Linux 系統上面合併多個 PDF 檔案成為一個 PDF 檔案

今天臨時興起想要去複習一下 Advanced Linux Programming 這本相當不錯的電子書
於是就把網頁上面的 PDF 檔案都下載回電腦裡面
這時候突然覺得要這樣分別開啟多個 PDF 檔案實在是麻煩
於是在網路上面找了一些方法
第一個方法是利用 ImageMagick 這個套件裡面的 convert 指令
$ convert alp-toc.pdf alp-ch*.pdf alp-ap*.pdf alp-index.pdf alp.pdf
不過製作出來的 alp.pdf 品質感覺不是很好
第二個方法是用 ghostscript 的 gs 指令
$ gs -dNOPAUSE -sDEVICE=pdfwrite -sOUTPUTFILE=alp.pdf -dBATCH alp-toc.pdf alp-ch*.pdf alp-ap*.pdf alp-index.pdf
製作出來的 alp.pdf 品質不錯,不過花了不少時間
第三個方法是用 pdftk 這個套件當中的指令 pdftk
$ pdftk alp-toc.pdf alp-ch*.pdf alp-ap*.pdf alp-index.pdf cat output alp.pdf
這個方法比之前的方法都要來的快速~
另外有網友提到可以使用看看 pdfsam 因為有太多相依上的套件要額外安裝就沒有想要繼續試下去啦~ :P

2009年12月2日 星期三

GNU Build System 執行檔案的分類 {bin,sbin,libexec,pkglib,noinst,check,EXTRA}_PROGRAMS

關於 {bin,noinst,check,EXTRA}_PROGRAMS 在之前的文章已經介紹過了
剩下來的 {sbin,libexec,pkglib}_PROGRAMS 跟 bin_PROGRAMS 其實都是在 $make install 會安裝到預設的目錄底下
差別只在於安裝到哪個目錄底下,例如以下的 Makefile.am
bin_PROGRAMS = main1
sbin_PROGRAMS = main2
libexec_PROGRAMS = main3
pkglib_PROGRAMS = main4
noinst_PROGRAMS = main5
check_PROGRAMS = main6
EXTRA_PROGRAMS = main7

main1_SOURCES = main.c
main2_SOURCES = main.c
main3_SOURCES = main.c
main4_SOURCES = main.c
main5_SOURCES = main.c
main6_SOURCES = main.c
main7_SOURCES = main.c
如果沒有特別指定或改變 prefix 最後安裝的情況會像下面這樣
usr
`-- local
    |-- bin
    |   `-- main1
    |-- lib
    |   `-- hello
    |       `-- main4
    |-- libexec
    |   `-- main3
    `-- sbin
        `-- main2
main1 這個執行檔如預期會安裝到 bin 底下
main2 類似 main1 會安裝到 sbin 底下
另外比較不常見的 libexec_PROGRAMS 則會讓 main3 安裝在 libexec 底下
還有 pkglib_PROGRAMS 會讓 main4 安裝在 lib/hello 底下,其中的 hello 就是 configure.ac 裡面的 package name
configure.ac 如下:
AC_PREREQ([2.63])
AC_INIT([hello], [0.0], [fourdollars@gmail.com])
AC_CONFIG_SRCDIR([main.c])
AC_CONFIG_HEADERS([config.h])
AM_INIT_AUTOMAKE([-Wall -Werror foreign])

# Checks for programs.
AC_PROG_CC

# Checks for libraries.

# Checks for header files.

# Checks for typedefs, structures, and compiler characteristics.

# Checks for library functions.

AC_CONFIG_FILES([Makefile])
AC_OUTPUT
當然有點經驗的 Autotools 使用者都會知道這個 configure.ac 是用 $ autoscan 產生的 configure.scan 修改而來的
剩下的 main5, main6, main7 如前一篇文章所介紹的一樣,是不會安裝進系統之中的

2009年11月28日 星期六

GCC 最佳化參數對 const 變數的影響

之前有寫過幾篇關於 const 變數的文章
這次要實驗的程式碼為
/* main.c */
#include <stdio.h>

void foo(const int* const);
void bar(int);

int main(int argc, char* argv[])
{
    const int value = 11;
    printf("%d\n", value);
    foo(&value);
    bar(value);
    printf("%d\n", value);
    return 0;
}

void foo(const int* const value)
{
    int* tmp = (int*) value;
    *tmp = 22;
    printf("%d\n", *value);
}

void bar(int value)
{
    printf("%d\n", value);
}
以及
/* main.cpp */
#include <cstdio>

void foo(const int* const);
void bar(int);

using namespace std;

int main(int argc, char* argv[])
{
    const int value = 11;
    printf("%d\n", value);
    foo(&value);
    bar(value);
    printf("%d\n", value);
    return 0;
}

void foo(const int* const value)
{
    int* tmp = const_cast<int*>(value);
    *tmp = 22;
    printf("%d\n", *value);
}

void bar(int value)
{
    printf("%d\n", value);
}
為了要實驗各個參數寫了一個 Makefile
all:
    $(CC) -Wall -g -O0 main.c -o main-O0
    @echo main-O0 && ./main-O0
    $(CC) -Wall -g -O1 main.c -o main-O1
    @echo main-O1 && ./main-O1
    $(CC) -Wall -g -Os main.c -o main-Os
    @echo main-Os && ./main-Os
    $(CC) -Wall -g -O2 main.c -o main-O2
    @echo main-O2 && ./main-O2
    $(CC) -Wall -g -O3 main.c -o main-O3
    @echo main-O3 && ./main-O3
    $(CXX) -Wall -g -O0 main.cpp -o main-O0
    @echo main-O0 && ./main-O0
    $(CXX) -Wall -g -O1 main.cpp -o main-O1
    @echo main-O1 && ./main-O1
    $(CXX) -Wall -g -Os main.cpp -o main-Os
    @echo main-Os && ./main-Os
    $(CXX) -Wall -g -O2 main.cpp -o main-O2
    @echo main-O2 && ./main-O2
    $(CXX) -Wall -g -O3 main.cpp -o main-O3
    @echo main-O3 && ./main-O3
執行 make 後得到的結果為
cc -Wall -g -O0 main.c -o main-O0
main-O0
11
22
22
22
cc -Wall -g -O1 main.c -o main-O1
main-O1
11
22
11
11
cc -Wall -g -Os main.c -o main-Os
main-Os
11
22
11
11
cc -Wall -g -O2 main.c -o main-O2
main-O2
11
22
11
11
cc -Wall -g -O3 main.c -o main-O3
main-O3
11
22
11
11
g++ -Wall -g -O0 main.cpp -o main-O0
main-O0
11
22
11
11
g++ -Wall -g -O1 main.cpp -o main-O1
main-O1
11
22
11
11
g++ -Wall -g -Os main.cpp -o main-Os
main-Os
11
22
11
11
g++ -Wall -g -O2 main.cpp -o main-O2
main-O2
11
22
11
11
g++ -Wall -g -O3 main.cpp -o main-O3
main-O3
11
22
11
11
由結果可以看出 C++ 對於 const 變數的處理都一樣
反而在 C 上面對預設的 -O0 參數不會執行任何常數字面的最佳化處理

2009年11月27日 星期五

GNU Build System 當中 {bin,noinst,check,EXTRA}_PROGRAMS 使用上的分別

在 Automake 的腳本檔 Makefile.am 裡面,要編寫一個執行檔案的規則可以這樣寫
bin_PROGRAMS = mp3player
mp3player_SOURCES = mp3player.c

這樣在 $ ./configure 之後就可以使用 $ make 編譯出 mp3player 這個執行檔
甚至於 $ make install 還可以幫你安裝到預定的目錄底下
這個預定的目錄是像 $ ./configure --prefix=/opt 這樣指定的
如果沒有特別指定的話,通常預設值都會是 /usr/local

如果只想要編譯出執行檔卻不想要在 $ make install 時,被安裝到預定的目錄底下,在腳本檔應該要這樣寫
noinst_PROGRAMS = mp3player

如果想要在 make 時,不會去編譯執行檔的話,只有在 $ make check 時才會去編譯執行檔,可以這樣寫
check_PROGRAMS = mp3player

如果想要在 $ make 跟 $ make check 都不會去編譯執行檔,只有在 $ make mp3player 時才會去編譯執行檔,可以這樣寫
EXTRA_PROGRAMS = mp3player

更詳細的說明請看 $ info automake

P.S. 有 $ 開頭代表在命令列下輸入的指令

2009年11月16日 星期一

GCC C++ Compiler 根本沒有還原 const 變數的數值,只不過先行代換掉使用 const 變數的地方。

延續前三篇文章的討論
C++ Programming: Call by Reference/Value/Pointer and const_cast
GCC C++ Compiler 會聰明地幫你還原 const 變數的數值
GCC C++ Compiler 對於 const 變數的處理到底會有多聰明呢?
這次實驗的程式碼如下
#include <iostream>

void foo(const int&);
void bar(const int&);

using namespace std;

int main(int argc, char* argv[])
{
    const int value = 11;
    cout << value << endl;
    foo(value);
    cout << value << endl;
    bar(value);
    cout << value << endl;
    cout << *(int*)&value << endl;
    return 0;
}

void foo(const int& value)
{
    int& tmp = const_cast<int&>(value);
    tmp = 22;
}

void bar(const int& value)
{
    cout << value << endl;
}
正如網友 jclin 提到的「我比較不相信 GCC 會幫你還原 const value 的作法. 只是 compiler 知道那是 const, 基於 optimization 的角度
還有 chihchun 提到的「main::value 是一個 alias, compiler (g++ 4.3.4) 會替換成 integral literal,但是依然會在 Stack 中配置此變數供人使用。
GCC C++ Compiler 只不過是把原始碼先轉換成以下這段
#include <iostream>

void foo(const int&);
void bar(const int&);

using namespace std;

int main(int argc, char* argv[])
{
    const int value = 11;
    cout << 11 << endl;
    foo(value);
    cout << 11 << endl;
    bar(value);
    cout << 11 << endl;
    cout << *(int*)&value << endl;
    return 0;
}

void foo(const int& value)
{
    int& tmp = const_cast<int&>(value);
    tmp = 22;
}

void bar(const int& value)
{
    cout << value << endl;
}
const 變數並不代表它無法被改變數值,透過 const_cast 還是可以改變數值的,只不過已經先被當作字面常數替換掉的地方,在 C++ 程式碼的運作上不是那麼容易瞭解。

2009年11月15日 星期日

GCC C++ Compiler 對於 const 變數的處理到底會有多聰明呢?

延續前兩篇文章的程式碼實驗
C++ Programming: Call by Reference/Value/Pointer and const_cast
GCC C++ Compiler 會聰明地幫你還原 const 變數的數值
這次想要實驗的程式碼片段如下
#include <iostream>

struct Foo {
    const int value;
};

void foo(const struct Foo* const);
void foofoo(const struct Foo* const);

using namespace std;

int main(int argc, char* argv[])
{
    const struct Foo bar = {11};
    cout << bar.value << '\t' << &bar.value << endl;
    foo(&bar);
    cout << bar.value << '\t' << &bar.value << endl;
    foofoo(&bar);
    cout << bar.value << '\t' << &bar.value << endl;
}

void foo(const struct Foo* const bar)
{
    static struct Foo inner = {22};
    struct Foo** tmp = const_cast<struct Foo**>(&bar);
    cout << *tmp << '\t' << bar << '\t' << bar->value << endl;
    *tmp = &inner;
    cout << *tmp << '\t' << bar << '\t' << bar->value << endl;
}

void foofoo(const struct Foo* const bar)
{
    int &value = const_cast<int&>(bar->value);
    value = 22;
}
編譯後執行的結果為
11    0xbfbb3090
0xbfbb3090    0xbfbb3090    11
0x804a034    0x804a034    22
11    0xbfbb3090
22    0xbfbb3090
對照程式碼就可以發現呼叫 foo() 後 const 變數 bar 被還原成原本的數值了
不過呼叫 foofoo() 後 const 變數 bar 底下的 const 變數 value 並沒有被還原成原本的數值
所以 GCC C++ Compiler 對 const 變數數值的還原保護僅限於直接傳入函式的變數本身
並不包含該 const 變數底下的 const 變數,到這時總算是解決了 $4 心中的疑惑
為什麼兩三年前寫 C++ 時,使用 const_cast 可以改變 const 變數的數值
而在 H4 聚會的實驗時反而遇到了跟 $4 過去經驗乍看下相衝突的結果 :-)

2009年11月14日 星期六

GNOME Global Menu

官方網站 http://code.google.com/p/gnome2-globalmenu/
首先看一下使用前

面板上面並沒有加入很多應用程式的啟動圖示
所以在右上角有一塊區域一直沒有使用到
首先新增加 GNOME Global Menu 的 GPG Key
wget http://gnome2-globalmenu.googlecode.com/files/GlobalMenuKey.gpg
sudo apt-key add GlobalMenuKey.gpg
然後新增一個檔案在 /etc/apt/sources.list.d/gnome2-globalmenu.list
# gnome2-globalmenu
deb http://ppa.launchpad.net/globalmenu-team/ppa/ubuntu jaunty main
deb-src http://ppa.launchpad.net/globalmenu-team/ppa/ubuntu jaunty main
然後在面板上面增加一個 Applet

最後調整 GNOME Global Menu 的設定

於是就把 GTK+ 的選單列都移動到面板上面了~ :D

2009年11月13日 星期五

GCC C++ Compiler 會聰明地幫你還原 const 變數的數值

關於前一篇文章 C++ Programming: Call by Reference/Value/Pointer and const_cast 所留下的問題
再寫一段簡單的程式碼來作實驗
/* main.cpp */
void funcA(const int &);
void funcB(int);
void funcC(const int *);

int main(int argc, char* argv[])
{
    const int value = 11;
    funcA(value);
    funcB(value);
    funcC(&value);
    funcB(value);
    return 0;
}

/* Call by Reference */
void funcA(const int& value)
{
    int& tmp = const_cast<int&>(value);
    tmp = 22;
}

/* Call by Value */
void funcB(int value)
{
    value = 33;
}

/* Call by Pointer */
void funcC(const int* value)
{
    int* tmp = const_cast<int*>(value);
    *tmp = 44;
}
這次利用 GCC 來產生 x86 的組合語言看看到底發生了什麼事情
$ g++ -S main.cpp
就會產生 main.s 檔案
來看看其中的片段
    call    _Z5funcARKi
    movl    $11, (%esp)
    call    _Z5funcBi
    leal    -8(%ebp), %eax
    movl    %eax, (%esp)
    call    _Z5funcCPKi
    movl    $11, (%esp)
    call    _Z5funcBi
答案是在呼叫完 funcA 跟 funcC 之後
GCC 聰明地將 value 的值給還原成 11 了
如果在 C++ 程式碼中第二次呼叫 funcB 給拿掉就不會看到第二個
    movl    $11, (%esp)
聰明的 GCC 只會在適當的時候幫你還原 const 變數的數值,造成 const 變數值從來沒被改變過的假象 :)

jQuery 實戰手冊 (JQuery in Action) - 第四章閱讀心得分享

ISBN 978-986-181-638-8
範例程式可以在 http://www.manning.com/bibeault 下載
此書的範例程式都是使用 jquery-1.2.1.js
所以先手動替換成 jquery-1.3.2.js
find -type f -name '*.html' -exec sed -i 's/jquery-1.2.1.js/jquery-1.3.2.js/' {} \;
第四章的範例 Bamboo Asian Grille - Online Order Form 不知道為什麼下面這行程式碼無法正常運作
$('~ span:first',this).text(...);
於是改成下面這段程式碼就可以正常運作了
$(this).next('span').text(...);
另外就是下面這一段程式碼其實有點多餘
.each(function(){ if (checked) this.focus(); });
可以改成下面那樣就可以達到同樣的功能
.focus();
主要是作者想要拿來玩弄 closure 的東西

C++ Programming: Call by Reference/Value/Pointer and const_cast

昨天晚上 H4 的聚會上面在討論這個問題
所以寫了一小段 C++ 程式碼來作實驗
/* main.cpp */
#include <iostream>

using namespace std;

void funcA(int&);
void funcB(int);
void funcC(int*);

int main(int argc, char* argv[])
{
    int value = 10;
    cout << value << endl;
    funcA(value);
    cout << value << endl;
    funcB(value);
    cout << value << endl;
    funcC(&value);
    cout << value << endl;
    return 0;
}

/* Call by reference */
void funcA(int& value)
{
    value = 20;
}

/* Call by value */
void funcB(int value)
{
    value = 30;
}

/* Call by pointer/address */
void funcC(int* value)
{
    *value = 40;
}
將上面這段程式碼儲存成 main.cpp
再使用 GCC 編譯執行
$ g++ -Wall -g main.cpp -o main
$ ./main
10
20
20
40
對照程式碼應該就可以看出這三者之間的差異了

不過後來有人有提到 const 的問題
於是將程式碼改寫成
#include <iostream>

using namespace std;

void funcA(const int&);
void funcB(int);
void funcC(const int*);

int main(int argc, char* argv[])
{
    const int value = 10;
    cout << value << " " << &value << endl;
    funcA(value);
    cout << value << " " << &value << endl;
    funcB(value);
    cout << value << " " << &value << endl;
    funcC(&value);
    cout << value << " " << &value << endl;
    return 0;
}

/* Call by reference */
void funcA(const int& value)
{
    int &tmp = const_cast<int&>(value);
    tmp = 20;
    cout << "\t" << value << " " << &value << endl;
}

/* Call by value */
void funcB(int value)
{
    value = 30;
    cout << "\t" << value << " " << &value << endl;
}

/* Call by pointer/address */
void funcC(const int* value)
{
    int* tmp = const_cast<int*>(value);
    *tmp = 40;
    cout << "\t" << *value << " " << value << endl;
}
編譯執行的結果為
$ ./main
10 0xbfb17040
    20 0xbfb17040
10 0xbfb17040
    30 0xbfb17020
10 0xbfb17040
    40 0xbfb17040
10 0xbfb17040
為什麼會這樣呢?

2009年10月17日 星期六

在 Ubuntu 9.04 上面手動安裝 hgview

這次要安裝的是 http://www.logilab.org/project/hgview
首先直接從 repository 抓下來
hg clone http://hg.logilab.org/hgview
然後建一個 symbolic link 到 ${HOME}/bin/ 下面
ln -snf $(readlink -f hgview/bin/hgview) ${HOME}/bin/
然後安裝相依的套件
sudo aptitude install pyqt4-dev-tools python-qscintilla2 python-egenix-mxdatetime
然後就可以在 Mercurial 的開發目錄底下直接執行 hgview 了~ ;)

2009年10月1日 星期四

Vim 編輯 Python 的設定

最近空閒時間都在學習寫 Google App Engine 上面的 Python 程式
剛剛研究了一會整理出這個簡單的設定
function! s:python_custom()
    function! s:man(keyword)
        execute '!pydoc ' . a:keyword
    endfunction
    setlocal tabstop=4 expandtab shiftwidth=4
    setlocal foldmethod=indent foldcolumn=4 foldlevel=3 foldnestmax=3
    command! -nargs=1 Man call s:man(<f-args>)
    cnoremap K :!pydoc <cword><CR>

endfunction
if has("autocmd")
    autocmd Filetype python call s:python_custom()
endif
開啟 Python 檔案時自動用縮排來 Folding 最多三層
縮排跟 Tab 都設定為 4 個空白
在關鍵字上按下 K 會透過 pydoc 去查詢使用說明
或是直接輸入 :Man list 這樣的指令
把上面那段 script 加到 .vimrc 裡面就可以使用了

2009年8月28日 星期五

快速製作 Ubuntu 9.04 (Jaunty) alternate 安裝用的 USB Stick

並不是每台電腦都有光碟機的,加上燒錄光碟片也不太環保,所以能用 USB Stick 來安裝 Ubuntu Linux 作業系統就盡量使用 USB Stick 囉。
  1. 首先準備一個可以完全亂玩的 USB Stick
  2. 下載 boot.img.gz
    $ wget http://archive.ubuntu.com/ubuntu/dists/jaunty/main/installer-i386/current/images/hd-media/boot.img.gz
  3. 將 boot.img 內容 dump 至 USB Stick
    $ sudo su -c "zcat boot.img.gz > /dev/sdb"
  4. 拔起 USB Stick 重新接到電腦上
    $ df -h /dev/sdb
    Filesystem Size Used Avail Use% Mounted on
    /dev/sdb 782M 23M 760M 3% /media/Ubuntu Inst
  5. 然後把 ubuntu-9.04-alternate-i386.iso 複製到 USB Stick 裡面
    $ cp -av ubuntu-9.04-alternate-i386.iso /media/Ubuntu\ Inst/
    $ df -h /dev/sdb
    Filesystem Size Used Avail Use% Mounted on
    /dev/sdb 782M 722M 61M 93% /media/Ubuntu Inst
以前在 Debian 也使用過同樣的方法 使用 USB stick 來安裝 Debian GNU/Linux 5.0 (Lenny) rc1

2009年8月26日 星期三

將 Subversion Repository 搬進 Google Code 裡面

由於 http://pcmanx.csie.net 的管理者 lwhsu 好像去玩國軍 Online 了
加上網頁一直無法更新還有常常會遇到網站掛點的狀況
所以動起了幫 PCManX GTK+ 搬家的念頭
以下是筆記將 Subversion Repository 搬進 Google Code 的過程
  1. 首先建立本地端的 mirror
    $ svnadmin create pcmanx
    $ cat <<'EOF' > pcmanx/hooks/pre-revprop-change
    #!/bin/sh
    USER="$3"
    if [ "$USER" = "svnsync" ]; then exit 0; fi
    echo "Only the svnsync user can change revprops" >&2
    exit 1
    EOF
    $ chmod +x pcmanx/hooks/pre-revprop-change
    $ svnsync init file://`pwd`/pcmanx https://svn.csie.net/pcmanx
    $ svnsync sync file://`pwd`/pcmanx
  2. 然後將 mirror 同步到 Google Code 上面
    $ svnsync init --username fourdollars https://pcmanx-gtk2.googlecode.com/svn file://`pwd`/pcmanx
    $ svnsync sync --username fourdollars https://pcmanx-gtk2.googlecode.com/svn
  3. 如果中途中斷遇到 lock 問題, 可以這樣解決, 不過要確定沒有人在使用該 Subversion Repository
    $ svn pdel --revprop -r 0 svn:sync-lock https://pcmanx-gtk2.googlecode.com/svn
    $ svnsync sync --username fourdollars https://pcmanx-gtk2.googlecode.com/svn
這樣就大功告成啦~ 以後如果有類似的狀況可以把粗體字的部份換掉就可以了~ :D

2009年8月22日 星期六

利用 caff 來加速 GPG sign 的過程

Debian Birthday Party 2009 in Taiwan 上面 PaulLiu 介紹了 GPG 簽章的過程
當中提到了為了防止有人偽造他人的 Email 所以我們在得到對方的 Finger Print 之後
進行簽署的過程當中的最後不應該直接把簽好的金鑰上傳到伺服器上面
反而是要使用對方的公鑰加密寄到對方的 Email 信箱當中
由對方去上傳你/妳已經簽署過的金鑰
而這之間的冗長又重覆的動作可以透過 signing-party 套件當中的 caff 來簡化這些動作
$ sudo apt-get install signing-party
例如你/妳拿到 $4 的金鑰的 Finger Print 後
D51B 8601 C9AE 0E87 A0BE  7795 BCB0 2784 A55D A068
然後執行
$ caff A55DA068
這樣就會自動從網路上面取得 $4 的公鑰, 然後進入 gpg command mode
Command> sign
Command> save
就會自動直接將加密好的文章跟簽署過的金鑰寄給我
(前提是你/妳已經設定好文字模式下的寄信方法, 像是上一篇 "利用 ssmtp 透過 Gmail 在文字模式下寄信" 所提的)

利用 ssmtp 透過 Gmail 在文字模式下寄信

sudo aptitude install ssmtp
然後編輯 /etc/ssmtp/ssmtp.conf 加入
AuthUser=user.name@gmail.com
AuthPass=password
FromLineOverride=YES
mailhub=smtp.gmail.com:587
UseSTARTTLS=YES
之後就可以透過 mailutils 套件中的 mail 指令來寄信
$ echo "This is a test mail." | mail -s "test mail" user.name@gmail.com
當在你/妳收到自己寄出來的信就可以確認是正常運作的

2009年8月18日 星期二

COSCUP 2009 簡報:使用 Redmine 做專案管理

整個投影片的重點其實在最後一張... Work Flow

而 Redmine 本身只是個工具用來輔助這個 Work Flow 的進行
http://archive.sylee.org/slides/COSCUP/2009/Redmine.pdf

2009年8月17日 星期一

Commit your git changesets into Subversion

Commit your git changesets into Subversion
  • First prepare your Subversion target folder, ex. http://svn.example.com/svn/git-backup
    $ svn mkdir --parents http://svn.example.com/svn/git-backup
  • Configure your git-svn on your original git working folder.
    $ git-svn init http://svn.example.com/svn/git-backup
  • Fetch Subversion changesets.
    $ git-svn fetch
  • Manually graft relationship.
    $ git show-ref git-svn
    8ec71dda61a3a32d9cf0c00e51a0c1ca3ea39f0e refs/remotes/git-svn
    $ git log --pretty=oneline master | tail -n1
    bcbd25a12642e98e1c54a8e51abacd85222b79a7 Your latest git commit log.
    $ echo "bcbd25a12642e98e1c54a8e51abacd85222b79a7 8ec71dda61a3a32d9cf0c00e51a0c1ca3ea39f0e" >> .git/info/grafts
  • Then push all git changesets into Subversion repository.
    $ git-svn dcommit
With Standard Layout
  • First prepare your Subversion target folder, ex. http://svn.example.com/svn/git-backup/{trunk,branches,tags}
    $ svn mkdir --parents http://svn.example.com/svn/git-backup/trunk http://svn.example.com/svn/git-backup/branches http://svn.example.com/svn/git-backup/tags
  • Configure your git-svn on your original git working folder.
    $ git-svn init --stdlayout http://svn.example.com/svn/git-backup
  • Fetch Subversion changesets.
    $ git-svn fetch
  • Manually graft relationship.
    $ git show-ref trunk
    8ec71dda61a3a32d9cf0c00e51a0c1ca3ea39f0e refs/remotes/git-svn
    $ git log --pretty=oneline master | tail -n1
    bcbd25a12642e98e1c54a8e51abacd85222b79a7 Your latest git commit log.
    $ echo "bcbd25a12642e98e1c54a8e51abacd85222b79a7 8ec71dda61a3a32d9cf0c00e51a0c1ca3ea39f0e" >> .git/info/grafts
  • Then push all git changesets into Subversion repository.
    $ git-svn dcommit

2009年8月2日 星期日

使用 GnuPG/GPG 來簽署別人的 GPG Key

關於 GPG 的觀念請先參考 Tetralet 寫的 用 GPG 來保護您的郵件!(一)
以下只是筆記金鑰簽署過程的指令操作與步驟
  1. 首先要實際見過面並且透過身份證或是護照確認對方的身份
  2. 抄下對方的金鑰指紋, 例如: D51B 8601 C9AE 0E87 A0BE  7795 BCB0 2784 A55D A068
    (同時也將自己的金鑰指紋給對方, 也是要檢查過身份證或是護照, 對外國人最好準備好護照)
  3. 去金鑰伺服器取回對方的公鑰
    $ gpg --recv-keys A55DA068
  4. 然後比對金鑰指紋是否相符
    $ gpg --fingerprint A55DA068
  5. 進行簽署動作
    $ gpg --sign-key A55DA068
  6. 檢查簽署結果
    $ gpg --check-sigs A55DA068
  7. 將簽署結果更新至伺服器
    $ gpg --send-keys A55DA068
  8. 然後寫一封信通知對方已經簽署過對方的金鑰了
    Hi $4,
    我已經簽署過你的金鑰並且上傳至伺服器 subkeys.pgp.net
    然後使用明碼簽章
    $ gpg --clearsign email.log
    產生一個 email.log.asc
    就可以將 email.log.asc 寄給對方了
    對方收到後可以使用
    $ gpg --verify-files email.log.asc
    透過你當初給對方抄的金鑰指紋來驗證這封 Email

2009年7月31日 星期五

製作 deb package for Ubuntu Linux 並且上傳至 Launchpad PPA

這篇是練習過程的筆記, betaradio 現在還是處於 broken 的狀態

準備好原始碼
$ wget http://betaradio.googlecode.com/files/betaradio-0.1.2.tar.bz2
$ tar xf betaradio-0.1.2.tar.bz2 && cd betaradio-0.1.2
初始化動作
$ export DEBFULLNAME="Shih-yuan Lee (FourDollars)"
$ export DEBEMAIL="fourdollars@gmail.com"
$ dh_make -s -c gpl -f ../betaradio-0.1.2.tar.bz2
然後編輯 debian/control
Source: betaradio
Section: net
Priority: extra
Maintainer: Shih-yuan Lee (FourDollars) <fourdollars@gmail.com>
Build-Depends: debhelper (>= 7), autotools-dev, libgstreamer0.10-dev, libcurl-dev, libgtk2.0-dev
Standards-Version: 3.8.0
Homepage: http://code.google.com/p/betaradio/

Package: betaradio
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, gstreamer0.10-plugins-base, gstreamer0.10-plugins-bad, gstreamer0.10-plugins-ugly, gstreamer0.10-ffmpeg, gstreamer0.10-alsa
Description: hiChannel electric radio client
 With this client you can listen to the hiChannel electric radio (http://hichannel.hinet.net/radio/index.jsp) without opening a browser.
 It displays a icon on system tray that you can click and select the channel you want to listen to.
編輯 debian/changelog
$ debchange
修改內容
betaradio (0.1.2-1ubuntu1) karmic; urgency=low

  * Initial release.

 -- Shih-yuan Lee (FourDollars) <fourdollars@gmail.com>  Fri, 31 Jul 2009 00:03:22 +0800
產生 deb source package
$ debuild -S
上傳 deb package 至 Launchpad PPA
$ dput ppa:fourdollars/ppa betaradio_0.1.2-1ubuntu1_source.changes
上傳的動作需要先註冊 Launchpad 帳號並且設定好 SSH public key 跟 GPG public key 還有產生 PPA 設定之後才能夠正常上傳

2009年7月24日 星期五

Enable Flash support for Google Chrome Dev Build on Ubuntu 9.04

喜歡嘗鮮的網路宅宅應該多多少少都知道
Google Chrome 有 Debian/Ubuntu 的開發中版本可以安裝
http://dev.chromium.org/getting-involved/dev-channel
目前官方釋出開發中版本的最新版已經可以使用中文輸入了
不過一直都沒有看到有 Flash 的支援
剛剛看到一篇 Flash player in Google Chrome for Linux 有提到解決方法
於是在 Ubuntu 9.04上面嘗試了一下

1. 首先要找到 libflashplayer.so 的位置
$ locate libflashplayer.so
/usr/lib/adobe-flashplugin/libflashplayer.so
2. 在 Google Chrome 的目錄下建立一個 symbolic link
$ cd /opt/google/chrome/
$ sudo ln -s /usr/lib/adobe-flashplugin/libflashplayer.so .
3. 最後啟動 Google Chrome 時要多加一個參數
$ google-chrome --enable-plugins
還真的可以用耶~ :D
放了一張 YouTube 上的日蝕影片來當真象~ ^w^


2009年7月13日 星期一

在 Ubuntu 8.10 (intrepid) 上面安裝 Firefox 3.5

LaunchPad 上面有個 Ubuntu Mozilla Daily Build Team
裡面就有 PPA 可以用了
所以接下來的動作就很簡單了
首先是取得該 PPA 使用的  GPG public key
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 247510BE
然後執行 sudo apt-key list 就可以看到多下面這個資訊
pub   1024R/247510BE 2009-02-05
uid                  Launchpad PPA for Ubuntu Mozilla Daily Build Team
接下來把該 PPA 的 sources.list 內容抄到 /etc/apt/sources.list.d/ 底下的 ubuntu-mozilla-daily.list
deb http://ppa.launchpad.net/ubuntu-mozilla-daily/ppa/ubuntu intrepid main
deb-src http://ppa.launchpad.net/ubuntu-mozilla-daily/ppa/ubuntu intrepid main
最後就是使用 APT 的前端程式來安裝囉
sudo aptitude update
sudo aptitude install firefox-3.5
這個方法同時支援 Ubuntu 8.04/8.10 只是換掉 codename (intrepid 換成 hardy) 而已~
至於 Ubuntu 9.04 的官方套件庫裡面已經有放 firefox-3.5
不過目前安裝起來都還是有英文版
所以還要下載中文語系包 http://releases.mozilla.org/pub/mozilla.org/firefox/releases/3.5/linux-i686/xpi/zh-TW.xpi
這樣就大功告成啦~ :-D

2009年7月4日 星期六

將在 COSCUP 上面分享 Redmine

COSCUP 活動網站

主題:
使用 Redmine 做專案管理
議程簡介:
關於軟體寫作這件事,常常可以聽到有人在分享程式語言以及相關的技術、開發框架(Framework)、分散式版本管理系統(DVCS),卻鮮少聽到有人在分享軟體專案管理系統使用上的經驗,像是使用 Python 開發的 Trac,用 Ruby 開發的 Redmine,用 PHP 開發的 dotProject 等,還有真正執行一個軟體專案或是同時進行多個軟體專案上面的實務經驗分享,趁著這次 COSCUP 的機會跟大家分享一些 Redmine 上面的使用心得。
內容大綱:
  • 為何會開始注意專案管理
  • Redmine 簡介
  • 專案的成長過程
  • 角色扮演與責任分配

2009年6月28日 星期日

apt-get/aptitude update 時 GPG error 問題的發生與尋找解決之道

剛剛在 Ubuntu 8.10 上執行
sudo aptitude update
時遇到一個錯誤訊息
W: GPG error: http://download.virtualbox.org intrepid Release: 下列的簽名皆不合法: BADSIG DCF9F87B6DFBCBAE Sun Microsystems, Inc. (xVM VirtualBox archive signing key) <info@virtualbox.org>
於是就到 http://www.virtualbox.org 上面去尋找 GPG 這個關鍵字
果然找到了一篇相關的 bug report 裡面提到一篇郵件清單上面的文章 apt-get update problem: GPG error ... The following signatures
were invalid

文章當中提到了
rm /var/lib/apt/lists/*
就可以解決問題了
可是我不想要把 /var/lib/apt/lists/ 底下的東西都刪光光
於是看了一下 /var/lib/apt/lists/ 底下
[前面省略]
archive.ubuntu.com_ubuntu_dists_intrepid_main_source_Sources
archive.ubuntu.com_ubuntu_dists_intrepid_Release
archive.ubuntu.com_ubuntu_dists_intrepid_Release.gpg
archive.ubuntu.com_ubuntu_dists_intrepid_restricted_source_Sources
download.virtualbox.org_virtualbox_debian_dists_intrepid_non-free_binary-i386_Packages
download.virtualbox.org_virtualbox_debian_dists_intrepid_Release
[後面也省略]
跟之前的錯誤訊息比較看起來只是 VirtualBox 的 Release 這個檔案缺少了相對應的 Release.gpg 檔案
於是就把 download.virtualbox.org_virtualbox_debian_dists_intrepid_non-free_binary-i386_Packages download.virtualbox.org_virtualbox_debian_dists_intrepid_Release 這兩個檔案刪除掉
重新執行
sudo aptitude update
結果問題就... 還是沒有解決... 冏rz

好吧... 重新找線索看看發現 /var/lib/apt/lists/ 底下有個唯一的目錄 partial 底下也有 VirtualBox 相關的檔案
partial/
|-- download.virtualbox.org_virtualbox_debian_dists_intrepid_Release
`-- download.virtualbox.org_virtualbox_debian_dists_intrepid_Release.gpg
那麼試試看把這兩個檔案也刪除掉再執行一次
sudo aptitude update
結果就... 成功地解決掉這個問題啦~ ^o^

再看看 partial 目錄底下還是空空的
不過 partial 上層的目錄底下就看到了
download.virtualbox.org_virtualbox_debian_dists_intrepid_non-free_binary-i386_Packages
download.virtualbox.org_virtualbox_debian_dists_intrepid_Release
download.virtualbox.org_virtualbox_debian_dists_intrepid_Release.gpg
看起來就是 Release 檔案有了相對應的 Release.gpg 檔案
所以才能夠正常地執行~ :-D

2009年6月17日 星期三

FreedomHEC Taipei 2009 - Day 2

第一個議程由 CIH 介紹 Linux Kernel Module 的逆向工程
背景故事是說老闆要他 porting 一個 WLAN driver 可是沒有 datasheet 可以參考
剛好那個 WLAN driver 少了四個整數值的 header file
問題是他也不熟 ARM 的組合語言 於是他就憑藉著 GCC 的 Cross Compiler 還有中斷向量表的基本觀念
在程式碼裡面填入 asm("nop"); 指令識別透過 arm-linux-gcc -S 的指令轉譯成 ARM 的組合語言
利用這樣的技巧找出無限迴圈跟函式執行進入點 ARM 的組合語言
然後將記憶體整個 dump 出來分析 (通常網通裝置的 Linux 系統所使用的記憶體不會太大, 一般在 64M 以下)
還有透過將無限迴圈放到中斷向量表裡面一步一步抽絲剝繭地將四個重要的整數值找出來

第二個議程由 Peter Stuge 來介紹 CoreBoot (前身為 LinuxBIOS)
CoreBoot 最早叫做 LinuxBIOS 就名稱上看來就是用來啟動 Linux 的 BIOS
後來因為它也可以載入 Linux 以外的 Payload (Payload 不負責任譯為"某種會花費硬體資源的載體")
就連 GRUB 也算是一種 Payload 更多的 Payloads 在 http://www.coreboot.org/Payloads 可以看到
這東西的概念簡單說就是 GPL 授權的 BIOS 讓從事 BIOS 開發不用再從頭寫起
目前已經支援某些特定主機板的清單可以在 http://www.coreboot.org/Supported_Motherboards 上面看到
另外有趣的小東西是 BSD 授權的 Libpayload 讓你寫出自己的載體讓 CoreBoot 來載入

第三個議程由 Jon Corbet 來介紹 Kernel Community
介紹整個 Linux Kernel 開發的合作模式
就是 Linus Torvalds 本人並不會直接收別人給他的 Patch
所以別天真的以為可以把自己的 Patch 直接送給 Linus Torvalds
Linus Torvalds 只會從幾位重要的 Developer 那邊接收 Changesets
Linux Kernel 是個相當活耀開發的計畫有上千個活躍的開發者
Linus Torvalds 不可能一個人去處理所有的程式碼合併跟衝突解決
當然這所有的工作都是靠優秀的 Git 分散式版本控制系統還有優秀的同伴們協力達成的 (他們演講時沒怎麼提到 Git)
簡單說就是 Linus Torvalds 會收一小群人給的 Changesets 然後那一小群人又會從其他人那邊收 Changesets 或是 Patch
最後在 Merge Window 的時候全部再匯集在一起然後釋出 rc1
然後就是 Stabilization 所以不會再接受任何新功能
經過好幾次的 rcN release 覺得差不多了就正式 release 然後再繼續下一個 cycle
一個 cycle 大約 8~12 個星期
一個 stable 的 release 只會維護半年的安全性跟嚴重錯誤修正
另外就是有兩個特別的開發樹
一個是 linux-next 提前為下一個 mainline cycle 的 patches 整合做測試
一個是 -mm 以 linux-next 為基底收集更多雜七雜八的 patches 來做測試
最後子系統的維護者們其實才是把關者也就是所有的 patches 應該要直接送給這些維護者們去做 merge 才對
但是這些子系統的維護者們也並不是擁有絕對的權利
也就是說凡是都還是有商量的餘地

第四個議程 Greg KH 介紹 Linux Driver Project
總之 Greg KH 說把你的 Linux Driver 送交到這個計畫吧
這邊會收任何 Kernel Module 的 patches
也歡迎硬體廠商提供測試機器協助他們測試驅動程式是否正常
就算硬體都還沒有生出來也沒關係

反正早點送 patches 早點 Code Review

不用等到都做完再去送 patches
或者是你的硬體需要有人寫 Linux Driver 嗎
這邊有太多閒著沒事想要寫 Linux Driver 的人
要簽署 NDA 文件也是可以接受的
Linux Driver Project 的網址在 http://www.linuxdriverproject.org/
台灣的硬體廠商們還不快點行動嗎~ :P

第五個議題 Harald Welte 介紹 GPL Compliance
簡單講就是你有用 Linux System 做硬體嗎?
那麼你最好依照相關的規定把該放出來的 Source Code 放出來
人在做 天在看 還有我們一群擅長逆向工程的高手在看 前面 CIH 就介紹過一些方法了
不然我們找到證據就會跑去告你喔~ :O
你看我們有很多合作的模範廠商
咦~ 有些被我們告過囉~ 不過沒關係~ 後來大家都和好了~ :P
另外就是提醒程式開發者們
如果程式碼裡面有一些錯字沒關係就留在那邊
那些錯字可以方便以後我們逆向工程找證據出來

最後就是所有的講者上台接受大家問問題~
照片可以在 http://www.flickr.com/photos/acelan/3617233294/
然後就聽到大長輩田欣先生在用英文一些問題
還有這個活動籌辦人之一的 Scott Tsai 提供即時的中英雙向翻譯
Scott 自己本身也問了一些問題
在聽眾們沒有什麼問題的情況下
講者反問了聽眾們一些問題
然後又聽見田欣先生在用英文回答
還有幾位強者 Matt Hsu, Thinker, ... 也是用英文在問問題回答講者的問題

這兩天的活動於是就圓滿的結束了~
中午提供的便當還蠻好吃的~ :P
第一天中午的便當主菜有雞腿副菜有豬肉
第二天中午的便當主菜有魚副菜也有豬肉
中午吃飯的時候旁邊的窗簾被整個拉開
可以從 14 樓的窗戶看到一排山還有內湖的摩天輪
景色相當好看~ :D

以上是筆者參加過後得心得分享
因為過了一星期才憑回憶攥寫
內容不一定與當天實際情狀相符

FreedomHEC Taipei 2009 - Day 1

FreedomHEC 的全名是 Freedom Hardware Engineer Conference
中文應該是翻成『自由硬體工程師研討會』
如果沒弄錯今年是第二次舉辦 (因為第一次我沒跟到... >_<)
這次的活動總共兩天的議程
網址 http://freedomhectaipei.pbworks.com/

FreedomHEC Taipei 2009 - Day 1

第一個議程由 Jon Corbet 介紹 2.6.X 每個正式 Release 版本改進了哪些功能

只是單純地介紹歷史帶過... 不過內容好像在跟 Jon Corbet 在 LWN 上面寫的都一樣
也就是說他的投影片就是那些每次 Linux Kernel Release 時都會在 LWN 上面寫的東西是一樣的

第二個議程由 Jim Huang (jserv) & Matt Hsu 講 Qi (气) 這個簡單化的 bootloader

內容主要是在講 Qi 將 bootloader 的功能盡量地簡化把複雜的功能交給一個客製化的 Linux Kernel 來處理
也就是說 Qi 只專注在載入一個客製化的 Linux Kernel 然後再讓客製化的 Linux Kernel 透過 kexec() 來載入另一個 Linux Kernel
好處是那個客製化的 Linux Kernel 可以透過許多原本就已經支援的網路裝置
將另一個放在 TFTP 或是 NFS 上面的 Linux Kernel 載入記憶體中並且執行起來
或是載入執行在 SD / USB 等裝置上面的 Linux Kernel
在一些 Flash 儲存裝置的 Linux Driver 還沒有 Ready 前就可以做先期的開發工作

第三個議程是由 Fred Chien 介紹 Linux 快速開機的方法

像是分析啟動時的開機時間統計然後調整 /etc/init.d 裡面 script 執行的順序
或是利用一些 readahead 之類的工具事先將需要載入系統的函式庫提先載入
還有把不需要的 Linux Kernel Module 拿掉 把需要的 Linux Kernel Module build-in
改 XWindow 的滑鼠驅動程式 ... (這個筆者兩三年前在前公司也弄過, 還有改 VGA Driver)
另外就是利用休眠的功能將記憶體的資料寫到儲存裝置上
下次開機再將那些資料讀回記憶體之中
還有關閉掉一些在 BIOS 裡面不需要啟動的硬體功能減少 BIOS 啟動時間
或是將一些系統服務的啟動放在 XWindow 起來之後再去做

第四個議題是由在 VIA 服務的 Joseph Chan 介紹 VIA 是怎麼將他們公司的硬體驅動程式提交進 Linux Kernel mainline 裡面

有兩點需要注意的

第一點 Coding Style
Linux Kernel 有著慣用的 Coding Style 沒理由 Linux Kernel 的 Source Code 要去 follow 某間公司的 Coding Style
所以想要提交程式碼進去 Linux Kernel 的廠商首先就是要調整 Coding Style 去適應 Linux Kernel
而不是自己關上門來硬幹等到最後提交的時候才發現 Coding Style 要大修改

第二點 Mailing List 上面的 Review Feedback
並不是將程式碼提交出去就算是交差了事了,更重要的是要聆聽開發者的意見還有耐心等待
並不是開發者都閒閒沒事做在那邊等著別人送 Patch 給他 Review,所以要等到開發者有時間才會去看你的程式碼去給 Review Feedback
還有要注意的是收到回應後應該要馬上給對方回應儘快去修改程式碼再去做提交

而 Joseph Chan 正是將 VIA 所遭遇到的慘痛經驗分享給與會者

第五個議題是由 Greg KH 帶著大家一步一步去寫出 Linux Kernel 上面的  USB 溫度計的 Kernel Module

Greg KH 與前面的講者 Jon Corbet 剛好都是  Linux 驅動程式這本書籍的作者
所以其實 Greg KH 介紹的東西在看過這本書之後,其實很快就可以上手了
主要的重點在於 Greg KH 介紹了 USB Subsystem 的基本架構
介紹 Interface/Config 跟  IN/OUT/Endpoint{Interrupt,Bulk,Isolate} 這些觀念
然後就是一個範例一個範例地帶大家一步一步地寫出 USB 溫度計的驅動程式

2009年6月7日 星期日

SCons 簡單介紹一下

apt-cache show scons 裡面的描述是
 SCons is a make replacement providing a range of enhanced features such
 as automated dependency generation and built in compilation cache
 support.  SCons rule sets are Python scripts so as well as the features
 it provides itself SCons allows you to use the full power of Python
 to control compilation.
一個 C/C++ 的軟體專案一定需要一個自動化編譯的工具作為輔助來管理,這樣可以簡化許多繁複的步驟,所以也有人將 SCons 拿來跟 GNU Build System (Autotools) 還有 CMake 做比較。

例如要編譯一個簡單的 Hello World 執行程式
/* hello.c */
#include <stdio.h>
int main(int argc, char* argv[])
{
    printf("Hello World!\n");
    return 0;
}
最初的方法一定是直接下指令
$ gcc -o hello hello.c
如果是學過 GNU Make 的話就會知道要寫一個 Makefile 來用,內容像是
# Makefile
hello: hello.c
    $(CC) -o $@ $<
clean:
    $(RM) hello
.PHONY: hello clean
不過如果是 SCons 的話,就是寫一個 SConstruct 的文字檔,內容像是
# SConstruct
Program('hello.c')
接下來就可以下指令 scons 來編譯,如果要清除的話就可以下指令 scons -c 來做
這樣是不是感覺輕鬆許多了呢~ ;-)
當然如果熟悉原本 GNU Make 的人也可以寫一個 Makefile 來用,內容像是
# Makefile
all:
    @scons -Q
clean:
    @scons -Q -c
.PHONY: all clean
這樣就可以利用 SCons 簡潔的語法而且又維持原本 GNU Make 的使用習慣了~ ;-)

SCons 更詳細的使用方法請見官方的說明文件 http://www.scons.org/documentation.php

2009年5月25日 星期一

減少打字 ssh -p xxxx username@host.com -> ssh host

一般的情況下,要使用 Console 下的 ssh 連線到某台 server 會這樣下指令
ssh -p xxxx username@myhost.com
不過我們可以下更短的指令
ssh myhost
要做到上面這樣的方法是編輯 ~/.ssh/config 這個檔案加入
host myhost
    Hostname myhost.com
    User username
    Port xxxx

2009年5月18日 星期一

Vim 套用 Markdown syntax

Markdown 是一套類似 WIKI 語法,可以快速生成 HTML 文件的工具。
因為自己有在使用 Vim 去編輯 Markdown 的檔案
所以找了一下給 Markdown 使用的 syntax
下載回來後放在 ~/.vim/syntax 底下
然後再新增編輯 ~/.vim/filetype.vim
augroup filetypedetect
    au BufNewFile,BufRead *.mkd      setfiletype mkd
augroup END
這樣一來就可以指定 .mkd 副檔名的檔案都使用 Markdown 的 syntax
另外 Markdown 也是 GitHub 上面官方支援的文件格式之一

2009年5月4日 星期一

git format-patch --no-prefix -p

一般的 git diff 輸出長得像是這樣子
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 6853012..baecc35 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -9,3 +9,4 @@ src/view/telnetview.cpp
 src/emoticondlg.cpp
 src/autologinpage.cpp
 src/downarticledlg.cpp
+src/pcmanx_gtk2.cpp
其中有 a/... b/... 實在不是很喜歡
改用 git diff --no-prefix 輸出就變成了
diff --git po/POTFILES.in po/POTFILES.in
index 6853012..baecc35 100644
--- po/POTFILES.in
+++ po/POTFILES.in
@@ -9,3 +9,4 @@ src/view/telnetview.cpp
 src/emoticondlg.cpp
 src/autologinpage.cpp
 src/downarticledlg.cpp
+src/pcmanx_gtk2.cpp
同樣的用法也可以使用在 git format-patch --no-prefix
From 66038b61719904c16147945d8c68a0773ef65846 Mon Sep 17 00:00:00 2001
From: jasonxh <jasonxh+c73c965c-c2fa-0310-9a63-82392b9be63f>
Date: Thu, 19 Feb 2009 05:58:15 +0000
Subject: [PATCH] 2009-02-18  Jason Xia  <jasonxh+gmail.com>

    * po/POTFILES.in, po/zh_CN.po, po/zh_TW.po: Update po files. Fix
    Simplified Chinese translation of "Line" and "Col".


git-svn-id: https://svn.csie.net/pcmanx/trunk@464 c73c965c-c2fa-0310-9a63-82392b9be63f
---
 ChangeLog           |    5 ++
 po/POTFILES.in      |    1 +
 po/zh_CN.po         |  174 +++++++++++++++++++++++++++------------------------
 po/zh_TW.po         |  167 +++++++++++++++++++++++++-----------------------
 src/pcmanx_gtk2.cpp |    2 +-
 5 files changed, 186 insertions(+), 163 deletions(-)

diff --git ChangeLog ChangeLog
index ffd2d02..ef74622 100644
--- ChangeLog
+++ ChangeLog
@@ -1,3 +1,8 @@
+2009-02-18  Jason Xia  <jasonxh+gmail.com>
+
+   * po/POTFILES.in, po/zh_CN.po, po/zh_TW.po: Update po files. Fix
+   Simplified Chinese translation of "Line" and "Col".
+
 2009-02-07  Youchen Lee  <copyleft+utcr.org>

    * src/mainframe.cpp: For availability to build under (gtk+ < 2.10),
diff --git po/POTFILES.in po/POTFILES.in
index 6853012..baecc35 100644
--- po/POTFILES.in
+++ po/POTFILES.in
@@ -9,3 +9,4 @@ src/view/telnetview.cpp
 src/emoticondlg.cpp
 src/autologinpage.cpp
 src/downarticledlg.cpp
+src/pcmanx_gtk2.cpp
不過 patch 檔前面會多一些統計資料也不是很喜歡
於是改用 git format-patch --no-prefix -p
From 66038b61719904c16147945d8c68a0773ef65846 Mon Sep 17 00:00:00 2001
From: jasonxh <jasonxh+c73c965c-c2fa-0310-9a63-82392b9be63f>
Date: Thu, 19 Feb 2009 05:58:15 +0000
Subject: [PATCH] 2009-02-18  Jason Xia  <jasonxh+gmail.com>

    * po/POTFILES.in, po/zh_CN.po, po/zh_TW.po: Update po files. Fix
    Simplified Chinese translation of "Line" and "Col".


git-svn-id: https://svn.csie.net/pcmanx/trunk@464 c73c965c-c2fa-0310-9a63-82392b9be63f

diff --git ChangeLog ChangeLog
index ffd2d02..ef74622 100644
--- ChangeLog
+++ ChangeLog
@@ -1,3 +1,8 @@
+2009-02-18  Jason Xia  <jasonxh+gmail.com>
+
+   * po/POTFILES.in, po/zh_CN.po, po/zh_TW.po: Update po files. Fix
+   Simplified Chinese translation of "Line" and "Col".
+
 2009-02-07  Youchen Lee  <copyleft+utcr.org>

    * src/mainframe.cpp: For availability to build under (gtk+ < 2.10),
diff --git po/POTFILES.in po/POTFILES.in
index 6853012..baecc35 100644
--- po/POTFILES.in
+++ po/POTFILES.in
@@ -9,3 +9,4 @@ src/view/telnetview.cpp
 src/emoticondlg.cpp
 src/autologinpage.cpp
 src/downarticledlg.cpp
+src/pcmanx_gtk2.cpp
因為老是會忘記這個用法,所以寫篇 blog 紀錄一下。:-P

2009年4月27日 星期一

如何在 Linux System 當中偵測網路線是否有接上?

其實方法很簡單,檢查 /sys/class/net/eth0/carrier 這個檔案就可以了

如果值為 1 的話代表有接上網路線

如果值為 0 的話代表沒有接上網路線

不過這也要看該網路卡的驅動程式有沒有實做這個部份

2009年4月23日 星期四

2009年4月5日 星期日

hiChannel.sh v1.3.1

這個版本重新整理播放電台並且把免費影視都移除掉了
( 因為免費影視都要使用 MS DRM 在 Mac/BSD/Linux 都沒有支援 )
另外就是加強 Mac OS X 上的鬧鐘支援
./hiChannel.sh -a
下載點
wget http://fd.idv.tw/tux/hiChannel.sh

2009年3月30日 星期一

在 Lenovo ThinkPad X200-RL2 上面安裝 Ubuntu 8.10

小筆電來當作自己私人程式開發的平台已經一年多了
最後還是發現在荼毒自己過著苦行僧般的日子
最近跟著身邊友人的腳步買了 Lenovo ThinkPad X200 這系列的筆電
果然是好用好多啊~ XD
  1. 無線網路設定
    無線網路驅動程式只要安裝上 linux-backports-modules-2.6.27-??-generic
    然後如下圖所示把另一個原本的驅動程式 disable 掉就可以了

  2. XWindow 顯示設定
    XWindow 的顯示設定就新增加一個檔案 /etc/X11/xorg.conf 填入

    Section "Monitor"
        Identifier    "Configured Monitor"
    EndSection

    Section "Monitor"
        Identifier    "HDMI-1"
        Option        "Ignore" "True"
    EndSection

    Section "Monitor"
        Identifier    "HDMI-2"
        Option        "Ignore" "True"
    EndSection

    Section "Screen"
        Identifier    "Default Screen"
        Monitor        "Configured Monitor"
        Device        "Configured Video Device"
        DefaultDepth     24
        SubSection "Display"
            Modes "1280x1024" "1280x800" "1024x768"
            Virtual 2640 1024
        EndSubSection
    EndSection

    Section "Device"
        Identifier    "Configured Video Device"
        Driver        "intel"
        Option        "monitor-HDMI-1" "HDMI-1"
        Option        "monitor-HDMI-2" "HDMI-2"
    EndSection
  3. Menu 鍵
    至於 Menu 鍵的設定則是新增一個 ~/.xmodmap 填入

    keycode 151 = Menu
    然後再 xmodmap ~/.xmodmap 馬上就可以使用了
    下次進入系統會自動問要不要自動 import ~/.xmodmap
  4. Console (Ctrl+Alt+F1~F6) 底下的 1280x800 解析度
    修改 /boot/grub/menu.lst 當中的 defoptions 改成

    # defoptions=quiet vga=0x0368
    然後再使用 sudo update-grub
  5. 小紅點滑鼠
    新增一個檔案 /etc/hal/fdi/policy/mouse-wheel.fdi 填入

    <match key="info.product" string="TPPS/2 IBM TrackPoint">
    <merge key="input.x11_options.EmulateWheel" type="string">true</merge>
    <merge key="input.x11_options.EmulateWheelButton" type="string">2</merge>
    <merge key="input.x11_options.YAxisMapping" type="string">4 5</merge>
    <merge key="input.x11_options.XAxisMapping" type="string">6 7</merge>
    <merge key="input.x11_options.Emulate3Buttons" type="string">true</merge>
    <merge key="input.x11_options.EmulateWheelTimeout" type="string">200</merge>
    </match>
硬體相關的校調設定我只做了這些事情,過程還算簡單順利。
網路上也很容易就 Google 到許多的文章可以參考
其中最詳細的大概就是這篇

另外比較特別的是以 wicd 取代掉常見的 Network Manager

2009年2月22日 星期日

EeePC 8G BIOS 0309 -> 0502

1. 先準備好要升級的 BIOS ROM

首先到 ftp://ftp.asus.com/pub/ASUS/EeePC/EeePC8G/ 上面下載 EeePC8G0502.zip
解開 EeePC8G0502.zip 後把裡面的檔案改名稱為 702.ROM

2. 把系統還原成原始出廠狀態

使用 ASUS 所附的系統還原光碟可以將 EeePC 8G 還原成原本的那個 Linux 系統版本
然後使用原本系統當中的 BIOS 升級
不過這個 BIOS 升級功能是有問題的
它會將 701.ROM 的升級檔案寫在 /dev/sda3 裡面
可是開機的時候 BIOS 的升級程式會去找 702.ROM
所以就導致怎麼升級 BIOS 都會失敗的情況

3. 手動將 BIOS ROM 放到 /dev/sda3 裡面

使用 Ctrl + Alt + T 打開終端機後輸入
sudo mkdir /mnt/sda3
sudo mount /dev/sda3 /mnt/sda3
sudo cp /media/DEVICE/data/702.ROM /mnt/sda3
接著再使用原本的 BIOS 升級程式隨便選一個 BIOS ROM 重新啟動後
就會找到 /dev/sda3 裡面的 702.ROM 開始自動執行 BIOS 更新了

0309
12/14/2007
2007.10.19 10:45

2009年2月15日 星期日

Google Reader 的復活節彩蛋

上上下下左右左右BA
然後你就會看到 Google Reader 裡面的隱藏功能啦~ XD

1234567890

$ date +%s --date='20090214 07:31:30'
1234567890
祝大家情人節快樂~ ^_^

2009年2月8日 星期日

Install Ubuntu 8.10 on EeePC 900HA

因為我買的 EeePC 900HA 裡面就有裝 Windows XP
所以就先用 wubi 試裝一下 Ubuntu 8.10 "Intrepid"
重點是把所有可以用的 apt repository 都打開
然後裝上 linux-backports-modules-intrepid 重開機
什麼無線網路還是視訊裝置就都可以正常使用了
還算是蠻簡單地 只不過那些音量之類的 Fn Hotkey 就沒有辦法正常使用了
另外就是我發現 EeePC 900HA 的外接顯示有問題 (硬體本身的問題)
不曉得是我這台偶然的問題還是所有的 EeePC 900HA 都有問題
總之我想要退掉了 因為外接顯示對我來說相當重要
如果外接顯示不正常 我之前買的 IOGEAR KVM 就變成是白花錢買的
--
EeePC 900HA
CPU ATOM N270 1.6G
硬碟 160G
記憶體 1G

2009年2月6日 星期五

在 Ubuntu 8.04.2 裡面設定自己的 git:// 分享給別人用

首先裝上 git-daemon-run
sudo aptitude install git-daemon-run
然後參考裡面的 /usr/share/doc/git-daemon-run/README.Debian

例如要將 /home/user/git/Project 這個已經是 git 的工作目錄分享出來
就執行
sudo ln -s /home/user/git/Project/.git /var/cache/git/Project.git
然後根據 Git Book - Setting Up A Public Repository 上面所提到的
要多做一個動作
touch /home/user/git/Project/.git/git-daemon-export-ok
最後就是重新啟動 git-daemon
sudo sv restart git-daemon
這樣別人就可以透過
git clone git://XXX.XXX.XXX.XXX/git/Project
來一起協同工作啦~ :D
這種方法在區域網路裡面分享程式碼特別快速方便~ ^o^

2009年1月25日 星期日

dvtm: Tiling window management for the console

簡單說就是類似 screen 加上 dwm 的功能

上面這張圖片左邊是主要的 console 右邊最上方是 ydict 中間是 htop 下方是 screen + irssi
整個畫面的配置就像是在使用 dwm 一樣 相當有趣~ :D

2009年1月15日 星期四

以 meld 當外部程式來使用 git diff

首先要建立一個簡單的 shell script

/usr/local/bin/git-meld
#!/bin/sh

meld $2 $5
然後執行
git config --global diff.external /usr/local/bin/git-meld
接下來就是爽爽地用 meld 來看 diff 囉~ :D

2009年1月4日 星期日

在 Debian Lenny 上使用 sudo

大概是 Ubuntu 使用久的關係有許多的習慣都已經在 Ubuntu 上面養成了
像是不直接使用 root 而是透過 sudo 來達成

於是將 sudo 裝起來
# aptitude install sudo

然後再執行
# visudo
增加一行 %sudo ALL=(ALL) ALL

然後再將使用者加到 sudo 這個群組裡面
# gpasswd -a fourdollars sudo

這樣就大功告成了~ :D

P.S.
$ sudo -k 可以馬上將暫時記住的 root 權限強制移除 (感謝 paulliu 提供的協助)