2007/02/14

qemu network on debian HOWTO 如何讓你的 qemu 上網?

qemu 確實不錯用,唯一的缺點就是網路照著網路上的文章,還不止一篇,怎樣試都不太能動。我的 qemu 是 0.9.0, 原因不明。後來照著眾多文章,試出底下的心得,或多或少你可以找到相關文章:

先說說我的狀況,我有兩張網卡,eth0 為對內用的,eth1 為對外用的。
先不管 eth1, 但是對內的也是用 dhcp, 底下的步驟您也可以改成靜態的。
另外,以這邊的例子,在 qemu 啟動後的系統,也一樣採用 dhcp 取得 IP 即可。
也就是說,若 eth0 是靜態的,那 qemu 也就要設定成與 br0 同網段的位址即可。因為大家狀況不一,我也不一一羅列,有問題請留言。


  1. 在 /etc/network/interfaces 加入
    iface br0 inet dhcp
  2. 把 eth0 弄乾淨
    ifconfig eth0 0.0.0.0 promisc up
  3. 手動加 bridge 網卡 br0
    brctl addbr br0

  4. 設定屬性

    brctl setfd br0 0
    brctl sethello br0 0
    brctl stp br0 off

  5. 繫結 eth0
    brctl addif br0 eth0
  6. 啟動 br0
    ifup br0
  7. 若系統有多張網卡,而這張繫結到 eth0 的 br0 只是內網使用,則
    route del default br0
  8. 啟動 qemu

    qemu -kernel-kqemu -localtime -soundhw all -net nic,vlan=0 -net tap,vlan=0,ifname=tap0,script=/etc/qemu-ifup -localtime -hda gx.img

  9. 其中 /etc/qemu-ifup 的內容如下

    ifconfig ${1##/*/} 0.0.0.0 promisc up
    brctl addif br0 ${1##/*/}

2007/02/13

freevo2 ui plugin for pygame: pytetris

請參考 pytetris

之所以要拿它來安裝,主要是因為在玩 GeeXboX, 其開發版使用freevo2當 UI, 也就讓我得試著了解 freevo2. 發現問題還不少。因此底下要講的主要目的就是為了研究 GeeXboX。

pytetris 有使用 gif, jpeg 的圖檔,不知道為何 GeeXboX 開發版並未支援,所以我得把圖檔改成 png 格式。

在安裝到 GeeXboX 時,雖自認安裝好了,但是卻無法控制,因此我就先想辦法裝到我的主機上,底下的經驗也是在主機上的心得。

在用前一篇安裝好 freevo2 到 ~/freevo2 之後,首先我無法在 directfb 下使用,事實上光為了支援 DirectFB 我就偷吃步修改 xine/setup.py, 不過雖然可以在 framebuffer 下看到畫面,卻無法控制。因此後來我還是放到 X11 下玩。

我模擬 ui/plugins/shutdown.py 改寫了 pytetris.py, 也在 skins/main/basic/fxd 加入 pytetris 的項目,還是看不到它。

接下來,找半天,找不到讓 freevo2 啟動 pytetris 的地方。後來發現修改 .freevo/data/freevo_config.py:
1. 我是修改 share/freevo/config/config.cxml 模仿一下,加入 pytetris, 這樣 freevo_config.py 就多了下面的內容:

Group(name='pytetris', desc='A pygame named pytetris', schema=[

Var(name='activate', default=0),

]
),

2. 在 plugins 加入 'plugin.pytetris'

3. 在最後加入 config.plugin.pytetris.activate = True

freevo2 install 安裝

在玩 GeeXboX 時,因為使用的是 freevo-r8861, 應該屬於某個 freevo2 的 shapshot, 因此裝 freevo2 來玩。當然遇到不少問題,現已更新至 freevo-2.0 Installation。

第一次執行時,會要你執行 freevo setup, 若是以非 root 執行,會幫你安裝設定檔到 ~/.freevo

底下先把安裝過程寫下來,請參考上面的網站,也許您得修改 /etc/ld.so.conf, 或設定 LD_LIBRARY_PATH 到適當的目錄:



  1. 首先要有 svn, 假設您要安裝的是 freevo2, 則請 cd freevo2 先!

  2. Install Kaa

    svn co svn://svn.freevo.org/kaa/trunk kaa
    cd kaa
    python setup.py build
    python setup.py install
    cd ..


  3. Install pysqlite2

    wget http://initd.org/pub/software/pysqlite/releases/2.3/2.3.3/pysqlite-2.3.3.tar.gz
    tar -zxvf pysqlite-2.3.3.tar.gz
    cd pysqlite-2.3.3
    python setup.py build
    python setup.py install
    cd ..


  4. Install imlib2

    wget http://jaist.dl.sourceforge.net/sourceforge/enlightenment/imlib2-1.3.0.tar.gz
    tar -zxvf imlib2-1.3.0.tar.gz
    cd imlib2-1.0.6
    ./configure && make && make install
    cd ..


  5. Install DirectFB

    cvs -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/pydirectfb login
    cvs -z3 -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/pydirectfb co pydirectfb
    cd pydirectfb
    python setup.py build
    python setup.py install
    cd ..


  6. Install freevo2.0

    svn co svn://svn.freevo.org/freevo/trunk freevo
    cd freevo
    python setup.py build
    python setup.py install --prefix=/usr/local/src/freevo
    cd bin
    ./freevo
    ./freevo setup

2007/02/12

grub on usb disk - 快速製作開機隨身碟

上週貼了一篇關於 qemu 啟動開機系統影像檔的文章後,今天又試了一段,可以做到快速將 grub 安裝到隨身碟的方法。不屬於正統作法,但是可以工作。

首先,要有 Linux 系統,且是安裝 grub(不保證 lilo 能工作), 也就是要有一台用 grub 來當 boot loader 的系統。另外,可以準備一台隨身碟,否則用影像檔也是類似原理。底下先以影像檔當範例。


  1. # dd if=/dev/hda of=dd.grub bs=512 count=63
    上述是將硬碟的開機磁區備份下來,根據 fdisk -l 的資訊,每個磁軌(track)含 63 個磁區(sectors), 每個磁區 512 bytes, 第一個磁軌也就是 bootloader 所在地,因此備份下來。
    ps: 若是隨身碟,可以先將它分割好,假設該裝置是 /dev/sda, 且只有一個分割區,則以 dd if=/dev/hda of=/dev/sda bs=512 count=63來寫入隨身碟
  2. # dd if=/dev/zero of=dd.zero bs=512K count=####
    上面需視你的需求而更改 count。若是要安裝到隨身碟,這兩部份加起來的大小要 >= 隨身碟的大小。假設要寫入隨身碟,則此步可改成 dd if=/dev/zero of=/dev/sda1 bs=512K count=####,或者直接跳過下一步繼續進行格式化
  3. # cat dd.grub dd.zero > myDisk.img
    這一步是將上面兩個合成一個,若是隨身碟可以略過此步。之後要將之設定到虛擬裝置: losetup -o 32256 /dev/loop0 myDisk.img
  4. # mkfs.ext3 /dev/loop0
    格式化第一個磁區。若是隨身碟,則是 mkfs.ext3 /dev/sda1
  5. # mount /dev/loop0 /mnt/myDisk; cp -a /boot /mnt/myDIsk
    將 /boot 複製到第一個磁區。若是隨身碟則為: mount /dev/sda1 /mnt/myDisk; cp -a /boot /mnt/myDisk
  6. 接下來就是將您的檔案放到 /mnt/myDisk 中即完成。


以上做法並非傳統做法,對會使用 grub-install 的人來說也不見得較快,但是卻對不熟悉的人來說方便許多。

2007/02/09

debian NO_PUBKEY 讓你無法更新套件?

偶而在更新套件時出現 NO_PUBKEY 很煩惱,記性差讓我在遇到時得查半天,因此特別寫下來,別再忘了才好,底下的範例以 BC40ED2499419355 為例,應該大部份 KEY 都能用:


  1. # gpg --keyserver subkeys.pgp.net --recv-keys BC40ED2499419355
  2. # gpg --fingerprint BC40ED2499419355
  3. # gpg --armor --export BC40ED2499419355 | apt-key add -

geexbox devel + qemu + vnc

先說說為何要這樣做,知道動機就比較好辦。
我最近在玩 GeeXboX devel, 想了解其中整合 freevo 及其功能。當然透過 GeeXboX 的開發系統可以做出 iso 檔,燒錄,開機的一系列步驟來玩。相信沒幾個人想要這樣修改一個系統。

我早期曾將 GeeXboX 安裝到硬碟中,變成多重開機選項,這樣做也不錯,可以把東西事先解開來研究。但是因為變動頻繁,這樣的步驟會變成:
開機進 native linux, 修改 GX, 重開機進 GX, 重開機進 native linux 這樣的循環,也是非常慢的。

Ok, 不管燒成 iso, 或安裝成多重開機,都很麻煩。因此就想要找簡單的方法,我想到的是 Qemu, 從 iso 開機很正常,當然這樣已經非常舒服了,不過我這個人是非常懶的。因此就想讓 Qemu 從我的多重開機硬碟啟動 GX, 結果發現 GX devel 無法這樣啟動,得修正 kernel 把 CDROM 打開選項,這個表過不提。今天還想說,這樣啟動每次都會讓我的系統變得有點慢,因此就想到加上 vnc 功能。

先說說語法:
$ qemu -vnc :1 -hda gx.img

上面的 -vnc :1 是要啟動 vnc session, 號碼可能是 ;1, 也可能系統已有得換成別的
至於這個 gx.img 怎麼做,做法如下:


  1. $ dd if=/dev/zero of=gx.img bs=1M count=128
  2. $ qemu -hda gx.img -cdrom geexbox-1.0-en.i386.iso -boot d
    用 iso 當光碟開機,開機時記得在 boot: 時打 install 來安裝到你指定的 gx.img 所指向的硬碟,也就是 /dev/hda
    到這邊您也可以試試用 devel 版的 iso 來做這一步試試,若失敗才需要下一步,否則請跳過下一步。
  3. 此時的 gx.img 應該就可以開機,只是這是 1.0 版的。要怎樣才能把 devel 版的放進來呢?簡單的作法就是你自己透過 mount 的方式進去修改,當你把 devel 版的 /GEEXBOX 複蓋掉 1.0 版的時候,開機時用到的 initrd, vmlinuz 都還是指向 /initrd, /vmlinuz, 因此你可以:

    1. 修改 /boot/grub/menu.lst 讓它指向新的,或者
    2. 從新的 /GEEXBOX/boot 下將 initrd, vmlinuz 搬至根目錄中

    個人比較傾向前者,因為這樣不必每次有變動到就要改東改西的,menu.lst 若設得好,以後就不必改了。
    至於怎麼掛這個 gx.img 呢?這邊也提供兩個方向:

    1. 透過 qemu -hda gx.img 啟動時進 debug 模式。這一點算是相對上較易理解,但是因為 GeeXboX 提供的 busybox 工具不多,操作上可能有點麻煩,我也不想寫下來。簡單說是 GeeXboX 會把真正的硬碟分割區掛載成唯讀的,你得先掛成可讀寫的,而系統的 mount 不支援 mount -o remount,rw, 因此我是 umount, 再 mount。再來就是沒有 vi, 那就只好用 echo 了。
    2. 若你的 host 有支援 loop device, 那也可以 losetup -o 32256 /dev/loop0 gx.img 之後再 mount /dev/loop0 iso -t ext3。這樣進 iso 修改後再 umount iso 即可。
      註: losetup + mount 可以合而為一: mount -o loop,offset=32256 gx.img iso -t ext3
      註二: 32256 是怎麼算出來的?因為 fdisk -l gx.img 顯示的資訊如下,每個 track 共 63 sectors, 每個 sector 是 512bytes, 而第一個 partition 是從第一個 track 開始的,因此第一個分割區的位移是 63 x 512 也就等於 32256。因此若你的分割區不是如此的話請類推。

      255 heads, 63 sectors/track, 0 cylinders
      Units = cylinders of 16065 * 512 = 8225280 bytes

      Device Boot Start End Blocks Id System
      gx.img1 * 1 16 128488+ 83 Linux


  4. $ qemu -vnc :1 -hda gx.img
    這也就是一開始說的語法啦!


還有一個我遇到的問題,就是我的系統 /dev/shm 掛太少,若執行時有報告此問題,請照著指示做即可,不過要以 root 來執行。

另外,bin.tar.lzma 是可以先解開的,這樣開機會快一點,而且你就可以修改到裡面重要的內容。
最後,當然在別台找個 vncviewer 來看它了:
$ vncviewer XX.XX.XX.XX:1

2007/02/06

freevo 中文化

因為決定採用 geexbox devel, 且打開 freevo 選項,對其中文化也非常有必要,但是一直無法解決。今天終於給我看到曙光了!

首先,你得翻譯 freevo.po <-- 來自 freevo.pot, 這個檔我是用 gtranslator 翻譯的,您可自行下載修改

其次,得修改設定檔,一個是預設的是 /usr/share/freevo/freevo_config.py, 另外也可以設在 $HOME/.freevo/local_conf.py。你可以修改前者,或者因為後者沒字型相關設定,也就是直接放進後者即可。
假設字型是 OpenSung.ttf, 例如是在 /usr/share/fonts/chinese/TrueType/OpenSung.ttf,底下的內容請參考前面說的設定檔來修改。

OSD_DEFAULT_FONTNAME = 'OpenSung.ttf'
OSD_DEFAULT_FONTSIZE = 18
OSD_FORCE_FONTNAME = None
OSD_FORCE_FONTSIZE = None
OSD_EXTRA_FONT_PATH = [ '/usr/share/fonts/chinese/TrueType' ]
OSD_FONT_ALIASES = { 'arial_bold.ttf' : 'OpenSung.ttf',
'vera.ttf' : 'OpenSung.ttf',
'veramono.ttf' : 'OpenSung.ttf',
'verabi.ttf' : 'OpenSung.ttf',
'verabd.ttf': 'OpenSung.ttf' }


若您想要上面的設定正常運作的話,需要修改 osd.py, 否則 OSD_DEFAULT_FONTNAME 及 ALIASES 裡的字型要設成絕對路徑才行。

osd.py 可以在 /usr/lib/python2.4/site-packages/freevo 找到,其中需要修改的只有 __getfont__(), 如下:


def __getfont__(self, filename, ptsize):
#print 'getfont %s with size %d' % (os.path.basename(filename), ptsize)
ptsize = int(ptsize / 0.7) # XXX pygame multiplies by 0.7 for some reason

if hasattr(config, 'OSD_FORCE_FONTNAME') and config.OSD_FORCE_FONTNAME:
filename = config.OSD_FORCE_FONTNAME
ptsize *= hasattr(config, 'OSD_FORCE_FONTSIZE') and config.OSD_FORCE_FONTSIZE or 1.5

#print '\tloadfont %s with size %d' % (filename, ptsize)
font = self.__loadfont__(filename, ptsize)
if not font:

# search OSD_EXTRA_FONT_PATH for this font
fontname = os.path.basename(filename)
for path in config.OSD_EXTRA_FONT_PATH:
if fontname.lower() in config.OSD_FONT_ALIASES:
fname = os.path.join(path, config.OSD_FONT_ALIASES[fontname.lower()])
else:
fname = os.path.join(path, fontname)
#print '\ttrying to loadfont %s with size %d' % (fname, ptsize)
font = self.__loadfont__(fname, ptsize)
if font:
break

if not font:
for path in config.OSD_EXTRA_FONT_PATH:
fname = os.path.join(path, os.path.basename(config.OSD_DEFAULT_FONTNAME))
ptsize = config.OSD_DEFAULT_FONTSIZE
#print '\ttrying default font: %s with size %d' % (fname, ptsize)
font = self.__loadfont__(fname, ptsize)
if font:
break

if not font:
print 'Couldnt load font "%s"' % config.OSD_DEFAULT_FONTNAME
raise

return font

2007/02/02

debian i18n for zh_TW.UTF8

有篇文章不錯,在最底下參考資料最後一條,不過已經不見了,我將之貼下:

From wiki.gentoo.tw
目錄
1 前言

1.1 作者
1.2 目的
1.3 需求
2 環境變數設定 for zh_TW.UTF-8

2.1 使 kernel 支援 unicode
2.2 使 gcc 支援 unicode
2.3 設定使用者環境變數
2.4 設定全域環境變數
2.5 mount

2.5.1 在utf-8 下顯示中文目錄或檔案的方法
3 X window 安裝 for zh_TW.UTF-8
4 X 字型安裝 for zh_TW.UTF-8

4.1 gtk1 for zh_TW.UTF-8
4.2 建議字型
5 中文輸入

5.1 xcin
5.2 gcin
5.3 scim
6 個別程式設定

6.1 X terminal

6.1.1 gnome-terminal
6.1.2 mlterm
6.1.3 urxvt

6.2 網路

6.2.1 samba

6.3 網路: p2p

6.3.1 amule
6.3.2 Azureus
6.3.3 mldonkey
7 編碼轉換問題

7.1 檔案名稱編碼轉換: convmv
7.2 檔案內容編碼轉換: iconv
8 中文列印
9 參考資料

前言

作者

* --betaparticle 12:00 2006年一月23日 (CST): 我只是自願來整理這一篇。如果有什麼問題、需要改進、需要討論的地方,可以跟我討論或是直接更改。


目的

* 讓使用者,在 X Window 環境下,使用 zh_TW.UTF-8 的環境。


需求

* GOT Ebuilds (http://www.gentoo.tw/proj/ebuild/ebuild.xml)


環境變數設定 for zh_TW.UTF-8

使 kernel 支援 unicode

在 kernel 部份,以下部份要編譯:

File Systems -->
Native Language Support -->
(utf8) Default NLS Option
<*> NLS UTF8


還有在 character sets 裡面,選擇必要的語系以下是一般人會用到的:

(todo)

使 gcc 支援 unicode

#localedef -i en_US -f UTF-8 zh_TW.UTF-8

#nano -w /etc/locales.build

en_US/ISO-8859-1
en_US.UTF-8/UTF-8
zh_TW.UTF-8/UTF-8

#emerge glibc -pv

看看USE中有沒有使用userlocales

最後

#emerge glibc

注意: 如果你需要使用到 iconv 轉換其他編碼,請記得加入相關 locale

在 locales.build 中可能會需要的中文地區編碼代號

台灣地區

zh_TW.EUC-TW/EUC-TW
zh_TW.UTF-8/UTF-8
zh_TW/BIG5

簡體地區

zh_CN.GB18030/GB18030
zh_CN.GBK/GBK
zh_CN.UTF-8/UTF-8
zh_CN/GB2312

香港地區

zh_HK.UTF-8/UTF-8
zh_HK/BIG5-HKSCS


設定使用者環境變數

系統 如果是單一 user 使用, 只要在各別 user 的目錄下的 ~/.bash_profile 或 ~/.bashrc 加入 LC_ALL 及 LANG 的設定, 如果要全部都使用, 則可以在 /etc/env.d/ 中加入一個新檔 02locale, 並內部加入 LC_ALL 與 LANG.

#vi /etc/environment

LANG="en_US.UTF-8"
LC_ALL="en_US.UTF-8"

# source /etc/profile

最後可以用 locale 指令看看是否成功...

# locale
LANG=en_US.UTF-8
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=en_US.UTF-8


X Window

修改.xinitrc(不過,我都是使用startx來進入x-win的喔)

export LANG="zh_TW.UTF-8"
export LC_ALL="zh_TW.UTF-8"
export LC_CTYPE="zh_TW.UTF-8"

如果是使用XDM之類的進入,Gnome則在/etc/X11/Xsession.d/99x11-common_start 增加或修改

export LANG="zh_TW.UTF-8"
export LC_ALL="zh_TW.UTF-8"
export LC_CTYPE="zh_TW.UTF-8"

如果是使用VNC則修改~/.vnc/xstartup,一樣增加如上。

設定全域環境變數

mount

在utf-8 下顯示中文目錄或檔案的方法

修改/etc/fstab,參數加上nls=utf8即可。

EX:(p.s.這是我mount我的windows分割區的方式。)

/dev/hdaX /mnt/win ntfs noauto,user,rw,nls=utf8,umask=0 0 0
/dev/hdaX /mnt/fat32 vfat user,rw,iocharset=utf8 0 0

ntfs 可以用 nls vfat 要用 iochatset (PS: 我這邊要用 iocharset=utf8 才行, nls=utf8 會出現錯誤訊息. Kernel=gentoo-sources 2.6.11-r9)

vfat 可使用 utf8=1,取代 iocharset=utf8。

X window 安裝 for zh_TW.UTF-8

X 字型安裝 for zh_TW.UTF-8

gtk1 for zh_TW.UTF-8

cp /etc/gtk/gtkrc.zh_TW.big5 /etc/gtk/gtkrc.zh_TW.utf8
編輯 /etc/gtk/gtkrc.zh_TW.utf8 如下:

style "gtk-default-zh-tw" {
fontset = "
-misc-ming(for iso10646)-medium-r-normal--20-0-0-0-c-0-iso10646-1,\
-misc-wcl_07-medium-r-normal--20-0-0-0-c-0-iso10646-1,\
-*-*-medium-r-normal--16-*-*-*-*-*-iso10646-1,*-r-*"
}
class "GtkWidget" style "gtk-default-zh-tw"

將字型更改為使用 iso10646-1 的 unicode 編碼字型 (可用 $ xlsfonts | grep iso10646 找出)

建議字型

* Firefly Sung
* wangttf
* MingLiU (如果弄得到合法版本的話,還不錯看。)


中文輸入

xcin

gcin

不需額外特別設定,參閱 gcin

scim

參閱 Scim-chewing

個別程式設定

X terminal

gnome-terminal

參閱 Gnome-terminal

mlterm

urxvt

urxvt

網路

samba

網路: p2p

amule

參閱Amule

amule 似乎不穩,請考慮使用 ed2k-gtk-gui + overnet

--betaparticle 11:56 2006年一月23日 (CST)(現在還有不穩的情況嗎?我用起來還可以的樣子…)

Azureus

在語系 zh_TW.utf8、檔案系統也是 UTF8 的情況下、使用上無任何問題 :)

mldonkey

參閱 Mldonkey

編碼轉換問題

編碼轉換有兩方面需要解決,一個是檔案名稱的編碼轉換,一個是檔案內容的編碼轉換。
兩者需要分開轉換。

檔案名稱編碼轉換: convmv

它在 portage 的位置是:app-text/convmv
需要轉換的是 vfat,NTFS 之外的檔案系統。
如果您的檔案是放在 vfat,NTFS 的檔案系統內的話,
只需要改變 mount 的參數就可以了。
(原因似乎是 vfat,NTFS 已用 utf-8 為檔名編碼存放檔案)

(from UTF-8教學)

接著就可以開始轉換作業:
直接執行 convmv 它並不會真的轉換,而是列出它會轉換的檔案及轉換結果

$ convmv -f big5-eten -t utf-8 -r <要轉換之目錄>

執行了上述命令,確定它轉換結果沒問題後,接著就可以使用 --notest 參數讓它真的轉換

$ convmv -f big5-eten -t utf-8 -r --notest <要轉換之目錄>


檔案內容編碼轉換: iconv

(from http://www.gentoo.org/doc/en/utf-8.xml)

它是跟著 glibc 一起安裝的。

舉例來說,從 big5 轉到 utf-8
# iconv -f big5 -t utf-8 filename
(建立一個檔存放轉換過的內容)
# iconv -f big5 -t utf-8 filename > newfile

參考資料

http://www.gentoo.org/doc/en/utf-8.xml
http://wiki.gentoo.tw/mediawiki/index.php/Utf-8_env
http://wiki.gentoo.tw/mediawiki/index.php/X-l10n-guide
取自"http://wiki.gentoo.tw/mediawiki/index.php/Zh_TW.UTF-8"

GeeXboX on QEMU

最近使用 QEMU 來啟動 GeeXboX 有一個問題,就是開發版的 GeeXboX 會在開機過程找不到 CDROM 因而無法繼續開機程序,既然知道問題,就比較好解決,可以將 kernel 跟 cdrom 有關的選項打開即可。因為 geexbox 更新頻繁,這邊就不提供 patch 檔,我已經將之反應給 devel@geexbox.org。

2007/01/30

embedded mozilla / YUI CustomEvent

今天用 mozilla 的 TestGtkEmbed 這支程式來測試我寫的 UI 時,發現會當掉,根據追蹤發現是因為 YUI 在對 CustomEvent 要 fire() 時產生的,真正原因尚未追蹤到。可疑的碼如下:

container_core.js: this.renderEvent.fire();

據查,不是因為 renderEvent 未定義或 fire() 未定義。這讓我無法用 YUI 中很多東西。

2007/01/29

如何善用 gmail 空間?

gmail 有接近 3G 的空間,雖然人家提供這樣的空間是為了讓你放心的使用 email, 拿來當網路儲存空間似乎濫用別人的好心,但是網路本就是娛樂、儲存、運算、知識多位一體,再加上 google 本就想擴大戰果,我們也只是推波助瀾而已。因此就來說說怎麼利用 gmail 吧。

若是 windows, 可以使用什麼 gdrive 之類的,不在我的思考內。而 linux 上有 gmailfs,經試用的結果,非常不好用,有個非常嚴重的缺點,反應非常遲頓。正因為反應遲頓,我也就沒多試其他的缺點。底下介紹一個 firefox 的擴充套件,叫 gspace, 請見 https://addons.mozilla.org/firefox/1593/ 。要讓它看得懂中文檔名作法有點麻煩,作法有二:
一、請先行安裝原作者發行的,Version 0.5.3, released on Nov 7, 2006,然後下載 http://wade.fs.googlepages.com/gspace.jar 取代原來的套件安裝後的同名檔即可。當然也可以直接下載 http://wade.fs.googlepages.com/gmail_space-0.5.3-fxfl.xpi 來安裝即可。
二、自行解開 gspace.jar 進去修改二個檔,一個是 gactions.js, 找 GSPACE 會有二處,在該行的前面(前一行)加入 fileName = encodeURIComponent(fileName); 此外這個 gactions.js 還有一個 DownloadFile(), 在最開頭加上 fname = decodeURIComponent(fname);
前者是將上傳檔名編碼,後者是將下載檔名解碼。另一個是 common.js 裡要找 gs_gRemoteFileInfo(), 在最前面加入 fileName = decodeURIComponent(fileName); 這一行。這個類似 ls 時要看的檔名,自然是要解碼。

使用第一步要小心,不保證別的版本使用上沒問題。事實上這個 gspace.jar 就是核心所在,若對新版 gspace.xpi 覆蓋上頭的 gspace.jar 的效果就是變成 0.5.3 版。另外若有新版的話,也不能保證會不會是上面的修正方式。

2007/01/26

配合動態載入,撰寫多國語言介面

我是還沒去了解 gmail 怎麼做的,自己想了個解決的方法,讓我們可以動態載入必要的語言檔,當然要搭配昨天的 loader.js, 因為這個 loader.js 需要用 new 產生,因此必須在網頁開始處先產生一個名為 JsLoader 的物件。


/*
author: wade.fs@gmail.com
version: 0.1.0 20070126
Code Licensed in GPL
Desc: for i18n, always using utf8
must: using loading.js + JsLoader in global variable space
*/
/*
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<HTML>
<HEAD>
<TITLE>WadeFS</TITLE>
<script type="text/javascript" src="js/yahoo.js"></script>
<script type="text/javascript" src="js/connection.js"></script>
<script type="text/javascript" src="js/loader.js"></script>
<script type="text/javascript" src="js/i18n.js"></script>

<script type="text/javascript">
var JsLoader;
function JsLoadHandler(file) {
if (file.substr(0,4) == "i18n") {
alert ("i18n.$('hdd') = " + i18n.$("hdd"));
}
}
function init() {
JsLoader = new YAHOO.Loader;
JsLoader.onFileLoad = JsLoadHandler;
i18n.load("zh_TW"); // 要在 JsLoader 之後使用
}
</script>
</HEAD>
<BODY onLoad="init()"></BODY></HTML>
*/
/* i18n/zh_TW.js, 請用 utf8 格式編輯
{
"mainboard": "主機",
"hdd": "硬碟",
"usb-disk": "隨身碟",
"cdrom": "光碟機",
"display": "顯示卡",
}
*/
var i18n = {
id: "en",
lang: {},
load: function(lang) {
if (typeof(lang) != "string") { this.id = "en"; }
else { this.id = lang; }
this.lang = {};
if (this.id !== "en") {
JsLoader.load("i18n/"+this.id+".js");
}
},
$: function(token) {
if (typeof(this.lang[""+token]) != "undefined") {
return this.lang[""+token];
}
else { return token; }
},
};

2007/01/25

動態載入 javascript

在發展 AJAX 應用時常常會把 javascript 寫的太大了,分成好幾個檔當然是應該的,但是對載入卻無法加速,底下片斷是改來的,不過寫法差異很大,想要真正能用的話還得下載YUI才行。


/**
* Author: wade.fs@gmail.com
* Original author Dav Glass <dav.glass@yahoo.com>
* version 0.2 20060126
* desc: 本程式必須配合 YUI 使用
*/
/*
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<HTML>
<HEAD>
<TITLE>YAHOO</TITLE>
<script type="text/javascript" src="js/yahoo.js"></script>
<script type="text/javascript" src="js/connection.js"></script>
<script type="text/javascript" src="js/loader.js"></script>

<script type="text/javascript">
var ob = {
'A': "a char A",
'Z': "char Z here",
};
function act(o, keyCode, status) {
if (keyCode == 65) { alert (o['A']); }
else { alert (o['Z']); }
}
function keyLoad() {
document.onkeydown = Key.pressed;
Key.addListener(act, ob, ""); // register any key for ob
}
function init() {
var myJsLoader = new YAHOO.Loader;
myJsLoader.onFileLoad = keyLoad;
var urls = [ "js/key.js" ];
myJsLoader.add(urls);
myJsLoader.load();
}
</script>
</HEAD>
<BODY id="ss-body" onLoad="init()">
</BODY>
</HTML>
*/
YAHOO.Loader = function() { this.init(); };

YAHOO.Loader.prototype = {
id: null,
scripts: {},
isLoaded: {},
holder: null,
init: function(id) {
this.holder = document.createElement('script');
this.holder.id = 'wadefs_loader_holder';
this.holder.type = 'text/javascript';
document.getElementsByTagName('body')[0].appendChild(this.holder);
},
onFileLoad: function(fileName, o) {},
onFileFail: function(fileName, o) {},
transActions: [],
add: function(file) {
if (file instanceof Array) {
for (var i = 0; i < file.length; i++) {
this.scripts[file[i]] = file[i];
}
} else {
this.scripts[file] = file;
}
},
insertScript: function(name) {
if (typeof(name) == "undefined") return;
if (!this.isLoaded[name]) {
var req = YAHOO.util.Connect.asyncRequest('GET', name, {
success: this.insertGood,
failure: this.insertBad,
caller: this,
});
this.transActions[req.tId] = name;
this.isLoaded[name] = name;
}
},
insertGood: function(o) {
if (o.responseText !== "undefined"){
var file = this.caller.transActions[o.tId];
if (file.substr(0,4) == "i18n") {
i18n.lang = eval('(' + o.responseText + ')');
}
else
this.caller.holder.innerHTML += o.responseText;
this.caller.onFileLoad(this.caller.transActions[o.tId], o);
}
},
insertBad: function(o) {
o.fileName = this.caller.transActions[o.tId];
this.caller.onFileFail(this.caller.transActions[o.tId], o);
},
load: function(thisFile) {
if (thisFile) {
if (thisFile instanceof Array) {
for (var i = 0; i < thisFile.length; i++) {
this.insertScript(thisFile[i]);
}
} else {
this.insertScript(thisFile);
}
} else {
for (var i in this.scripts) {
this.insertScript(this.scripts[i]);
}
}
},
};

Firefox 的按鍵事件簿

在以 firefox/embedded mozilla 當 UI 或是設計網頁時,按鍵是非常需要處理的元件,底下的程式碼目前只能處理任意按鍵,可自行下載修改成讓物件只聆聽特殊按件。測試網頁在註解中。


// Author: wade.fs@gmail.com
// Version: v0.1 20070126
// Code licensed under GPL
// Desc: javascript keyboard event handler
// 預計將來會處理中文輸入法,目前只有簡單的按鍵處理
/*
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<HTML>
<HEAD>
<TITLE>WadeFS</TITLE>
<script type="text/javascript" src="js/key.js"></script>

<script type="text/javascript">
var ob = {
'A': "a char A",
'Z': "other char",
};
function act(o, keyCode, status) {
if (keyCode == 65) { alert (o['A']); }
else { alert (o['Z']); }
}
function init() {
document.onkeydown = Key.pressed;
Key.addListener(act, ob, ""); // register any key for ob
}
</script>
</HEAD>
<BODY id="ss-body" onLoad="init()">
</BODY>
</HTML>
*/
var Key = {
status: 0, // NumLock, CapsLock, ScrollLock, Full(全半)
registered: [],
keyCode: 0,
addListener: function(f, o, keys) {
this.registered.push ([f, o, keys]);
return this.registered.length;
},
setNumLock: function(numLock) {
if (numLock) { this.status |= 0x01; }
else { this.status &= 0xFE; }
},
getNumLock: function() {
return this.status &= 0x01;
},
setCapsLock: function(capsLock) {
if (capsLock) { this.status |= 0x02; }
else { this.status &= 0xFD; }
},
getCapsLock: function() {
return this.status &= 0x02;
},
setScrollLock: function(scrollLock) {
if (scrollLock) { this.status |= 0x04; }
else { this.status &= 0xFB; }
},
getScrollLock: function() {
return this.status &= 0x04;
},
keyName: { 8: "BackSpace", 9: "Tab", 13: "Enter", 19: "Pause", 27: "Esc",
32: "Space", 33: "PgUp", 34: "PgDn", 35: "End", 36: "Home",
37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScreen",
45: "Ins", 46: "Del", 106: "NMultiply", 107: "NPlus",
109: "NMinus", 110: "NDot", 111: "NDivide",
},
showKeyMsg: function() {
var keyCode = this.keyCode & 0xFF;
if (keyCode > 0) {
var msg='(';
msg += (this.status & 0x01) ? 'N' : 'n';
msg += (this.status & 0x02) ? 'C' : 'c';
msg += (this.status & 0x04) ? 'S' : 's';
msg += ')';
if (this.keyCode & 0x100) msg += 's';
if (this.keyCode & 0x200) msg += 'c';
if (this.keyCode & 0x400) msg += 'a';
if (this.keyCode >= 0x100) msg += '-';
// 數字鍵
if (keyCode >= 96 && keyCode <= 105) { keyCode -= 48; }
// 文數字
if ((keyCode >= 65 && keyCode <= 90) ||
(keyCode >= 48 && keyCode <= 57))
{
msg += String.fromCharCode(keyCode);
}
// F1-F12
else if (keyCode >= 112 && keyCode <= 123) {
keyCode -= 111;
msg += 'F' + keyCode;
}
else if (typeof (this.keyName[""+keyCode]) != "undefined") {
msg += this.keyName[""+keyCode];
}
else { msg += keyCode; }
alert (msg);
}
},
processKey: function() {
if (this.registered.length <= 0) { this.showKeyMsg(); }
else {
// [[f, o, key],...]
var idx;
for (idx=0; idx<this.registered.length; idx++) {
if (this.registered[idx][2].length == 0) { // for any key
var f = this.registered[idx][0];
var o = this.registered[idx][1];
f(o, this.keyCode, this.status);
}
}
}
},
pushKey: function(key,shift,ctrl,alt) {
this.keyCode = 0;
if (key == this.K_NumLock) { this.status ^= 0x01; }
else if (key == this.K_Caps) { this.status ^= 0x02; }
else if (key == this.K_ScrollLock) { this.status ^= 0x04; }
else {
var ctrlKey = 0;
// check if composed with control key
if (shift) { ctrlKey |= 0x100; }
if (ctrl) { ctrlKey |= 0x200; }
if (alt) { ctrlKey |= 0x400; }
// check if control key only
if (key == this.K_Shift) { this.keyCode = 0x100 | ctrlKey; }
else if (key == this.K_Ctrl) { this.keyCode = 0x200 | ctrlKey; }
else if (key == this.K_Alt) { this.keyCode = 0x400 | ctrlKey; }
else if (key == this.K_shiftAlt) { this.keyCode = 0x100|0x300|ctrlKey; }
else {
this.keyCode = key | ctrlKey;
}
this.processKey();
}
},
pressed: function(e){
Key.pushKey(e.keyCode, e.shiftKey, e.ctrlKey, e.altKey);
// stop key event propagation to browser
e.preventDefault();
e.stopPropagation();
},
K_: function(ctrl) {
var i=0, keyCode=0;
while (i < ctrl.length) {
if (ctrl.charCodeAt(i) == 'a') { keyCode += 0x400; }
else if (ctrl.charCodeAt(i) == 'c') { keyCode += 0x200; }
else if (ctrl.charCodeAt(i) == 's') { keyCode += 0x100; }
else if (i == (ctrl.length-1)) { keyCode += ctrl.charCodeAt(i); }
else { keyCode = 0; }
}
return keyCode;
},
K_BackSpace: 8,
K_Tab: 9,
K_Enter: 13,
K_Shift: 16,
K_Ctrl: 17,
K_Alt: 18,
K_Pause: 19,
K_Caps: 20,
K_Esc: 27,
K_Space: 32,
K_PgUp: 33,
K_PgDn: 34,
K_End: 35,
K_Home: 36,
K_Left: 37,
K_Up: 38,
K_Right: 39,
K_Down: 40,
K_PrintScreen: 44,
K_Ins: 45,
K_Del: 46,
K_N0: 96,
K_N1: 97,
K_N2: 98,
K_N3: 99,
K_N4: 100,
K_N5: 101,
K_N6: 102,
K_N7: 103,
K_N8: 104,
K_N9: 105,
K_NMultiply: 106,
K_NPlus: 107,
K_NMinus: 109,
K_NDot: 110,
K_NDivide: 111,
K_F1: 112,
K_F2: 113,
K_F3: 114,
K_F4: 115,
K_F5: 116,
K_F6: 117,
K_F7: 118,
K_F8: 119,
K_F9: 120,
K_F10: 121,
K_F11: 122,
K_F12: 123,
K_NumLock: 144,
K_ScrollLock: 145,
K_shiftAlt: 224,
};

2007/01/17

cdrom tray status: 偵測光碟機狀態



/*
* cdstatus.c <device>
*
* This loads a CDROM from a specified slot in a changer, and displays
* information about the changer status. The drive should be unmounted before
* using this program.
*
* Based on code originally from Gerhard Zuber .
* Changer status information, and rewrite for the new Uniform CDROM driver
* interface by Erik Andersen <andersee@debian.org>.
*/

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/cdrom.h>

int
main (int argc, char **argv)
{
char *program;
char *device;
int fd; /* file descriptor for CD-ROM device */
int status; /* return status for system calls */

if (argc != 2) {
fprintf (stderr, "usage: %s \n", program);
exit (1);
}

program = argv[0];
device = argv[1];

/* open device */
fd = open(device, O_RDONLY | O_NONBLOCK);
if (fd < 0) {
fprintf (stderr, "%s: open failed for `%s': %s\n",
program, device, strerror (errno));
exit (1);
}

status = ioctl (fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
if (status<0) {
perror(" CDROM_DRIVE_STATUS");
} else switch(status) {
case CDS_NO_INFO: printf ("NO_INFO\n"); break;
case CDS_NO_DISC: printf ("NO_DISC\n"); break;
case CDS_TRAY_OPEN: printf ("TRAY_OPEN\n"); break;
case CDS_DRIVE_NOT_READY: printf ("NOT_READY\n"); break;
case CDS_DISC_OK: printf ("DISC_OK\n"); break;
default: printf ("ERROR: %d\n", status); break;
}

/* close device */
close (fd);
exit (0);
}

2007/01/11

reverse text file order

今天想著要怎樣把一個純文字檔反向排列,當然寫個 c file 是很簡單,但是我現在的原則是儘量用 busybox 能提供的工具來完成,底下有個小片斷可以參考一下,或使用 tac 命令:


  • cat -n $FILE | sort -rn | cut -f2


當然上面的做法比較能理解,不過還有兩個用 sed 完成的範例:


  1. sed '1!G;h;$!d'
  2. sed -n '1!G;h;$p'



順便提供反轉行的寫法, 或使用 rev 命令:

  • sed '/\n/!G;s/\(.\)\(.*\n\)/&\2\1/;//D;s/.//'

2007/01/09

AJAX, Javascript 處理 XML/JSON 資料

在 javascript 中處理 XML 一直沒機會玩,最近玩還真的覺得怎麼跟很多人在網站上說的不一樣,後來找到 Ajax 處理資料方法比較 裡頭說的非常清楚。僅供參考

另外,因為資料型態不一樣,server 端的 Content-type 要設對,例如 XML 要設成 text/xml, 而 JSON 則是 text/plain

最後,我選擇了 JSON 方法,因為一來這是瀏覽器剖析資料的格式,想來會是最有效率的,另外,雖然 XML 較一般性,但是其實就閱讀而言 JSON 也差不多,只是有一點,刮號配對也許較易出錯,對於 {}, [] 的使用時機若怕搞錯,就多比較看看吧。

註: {} 是用來形成物件,而 [] 則用來建構陣列
註二:{} 用來形成不同屬性的物件,而 [] 用來建構相同屬性名稱的不同物件相當好用

2007/01/05

在 shell script 內處理網頁的 Form Data

為了讓 geexbox 方便遠端管理,就上網找了個 ProcCGI,底下是一般流程。

  1. 選定 Applet 名稱,這是用來設定 CONFIG_NAME 用的,此處是用 PROCCGI,也就是 CONFIG_PROCCGI
  2. 將 source code 放到適當的目錄,我是放到 networking 下,並將proccgi.c的 main() 改成 Applet_main(),即 proccgi_main()。
  3. 修改networking 目錄下的 Config.in,找適當的地方新增選項,請參考其他選項作適當的編修,我是放在照字母順序放在 Router 前:

    config CONFIG_PROCCGI
    bool "proccgi"
    default y
    depends on FEATURE_HTTPD_CGI
    help
    proccgi is s utility for web cgi-bin

  4. 同樣在 networking 目錄下,修改 Kbuild,在適當的地方加入:

    lib-$(CONFIG_PROCCGI) += proccgi.o

  5. 修改 include/applets.h,它與底下的 usage.h 都必須按照字母順序排列,因此請自行在適當的地方加入:

    USE_PROCCGI(APPLET(proccgi, _BB_DIR_USR_BIN, _BB_SUID_NEVER))

    不知道您有沒有注意到這跟前二條的說明是配合的。
  6. 修改 include/usage.h,加入命令輔助訊息,一樣要注意按照字母順序:

    #define proccgi_trivial_usage "eval \"`proccgi $*`\""
    #define proccgi_full_usage "eval \"`proccgi $*`\"\n" "will set the form variable into env"

  7. 記得將 proccgi.c 中的 main() 改成 proccgi_main()
  8. 參考適用於busybox-1.3.1的 patch。

跑馬燈

原本只有 IE 支援的 <marquee>, 現在連 firefox 也支援了,省卻自己寫 javascript 控制的時間。這邊分享個小心得,我無法透過 CSS 將 <marquee> 定位在特定位置,是用 <table> 才做到,僅供參考。

2006/12/28

利用 SVG 建立 UI

SVG 拿來建 UI 其實有很多範例,這邊拿兩個來供各位參考。
「嵌在頁面裡」的時鐘
嵌在頁面裡的俄羅斯方塊

最近在思考想要用 XUL, SVG, AJax 等來建立 UI, 不過若考慮 RUI 的話,應該還是要用一般 HTML 而非 XUL.