TAG

首都機能移轉 (2) 歌詞 (2) 靠北文 (40) 戲言 (30) 糟糕 (7) ACG (23) Assembly (2) Boost (2) C (31) C++ (69) CMake (4) CSIE (67) Debian (34) Design_Pattern (2) Django (1) Eclipse (1) en_US (13) FFmpeg (3) FoolproofProject (26) FreeBSD (2) Git (4) GNU_Linux (65) IDE (5) Java (11) JavaScript (19) KDE (15) Khopper (16) KomiX (3) Kubuntu (18) Life (1) Lighttpd (2) Mac_OS_X (2) Opera (1) PHP (2) PicKing (2) Programing (21) Prolog (1) Python (7) QSnapshot (2) Qt (30) Qt_Jambi (1) Regular_Expression (1) Shell_Script (7) Talk (98) VirtualBox (7) Visual_Studio (13) Windows (18) zh_TW (36)

2009年12月25日 星期五

Suspend USB devices (turn the power off)

昨天朋友問我把 USB 裝置停電的實際命令,Google 了一下找到了方法,筆記一下。
首先要知道你的 USB 裝置代號,可以在插入後使用 dmesg 查看[?]。例:
[ 8944.330557] usb 1-8: USB disconnect, address 8
[ 9023.580525] usb 1-8: new high speed USB device using ehci_hcd and address 9
[ 9023.714733] usb 1-8: New USB device found, idVendor=0b27, idProduct=0163
[ 9023.714737] usb 1-8: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ 9023.714739] usb 1-8: Product: USB Mass Storage Device
[ 9023.714741] usb 1-8: Manufacturer: USBest Technology
[ 9023.714743] usb 1-8: SerialNumber: 000000000016F3
[ 9023.714828] usb 1-8: configuration #1 chosen from 1 choice
[ 9023.715549] scsi7 : SCSI emulation for USB Mass Storage devices
[ 9023.715694] usb-storage: device found at 9
[ 9023.715696] usb-storage: waiting for device to settle before scanning
[ 9028.712208] usb-storage: device scan complete
[ 9028.713173] scsi 7:0:0:0: Direct-Access     Ut163    USB2FlashStorage 0.00 PQ: 0 ANSI: 2
[ 9028.717275] sd 7:0:0:0: [sdd] 1974271 512-byte logical blocks: (1.01 GB/963 MiB)
[ 9028.718294] sd 7:0:0:0: [sdd] Write Protect is off
[ 9028.718299] sd 7:0:0:0: [sdd] Mode Sense: 00 00 00 00
[ 9028.718301] sd 7:0:0:0: [sdd] Assuming drive cache: write through
[ 9028.725637] sd 7:0:0:0: [sdd] Assuming drive cache: write through
[ 9028.725645]  sdd: sdd1
[ 9028.837666] sd 7:0:0:0: [sdd] Assuming drive cache: write through
[ 9028.837672] sd 7:0:0:0: [sdd] Attached SCSI removable disk
[ 9149.868714] Shorewall:net2fw:DROP:IN=eth0 OUT= MAC=00:1f:d0:37:37:0a:00:30:88:12:54:d6:08:00 SRC=189.1.169.123 DST=123.205.248.119 LEN=40 TOS=0x00 PREC=0x00 TTL=92 ID=256 PROTO=TCP SPT=6000 DPT=1433 WINDOW=16384 RES=0x00 SYN URGP=0
[ 9231.369074] sd 7:0:0:0: [sdd] 1974271 512-byte logical blocks: (1.01 GB/963 MiB)
[ 9231.369566] sd 7:0:0:0: [sdd] Assuming drive cache: write through
[ 9231.370687] sd 7:0:0:0: [sdd] Assuming drive cache: write through
[ 9231.370690]  sdd: sdd1
因為它寫 usb 1-8,所以要控制的 USB 接口代號就是 1-8,很簡單吧?反正找有 usb 字樣的就對了。底下的 sd 是表示它被分配到哪個磁區代號,因為這支是隨身碟才會是這樣,其他類型的裝置會有不同的訊息,不過這不是重點,所以沒差啦。
然後請到 /sys/bus/usb/devices 裡找剛剛的接口代號的資料夾,在那裡面找 power/level,該檔是一個文字檔,或者說看起來是文字檔,內容應該是 on。只要把 on 改成 suspend 就可以把電源切斷。注意不是 off,如果輸入錯誤的字串它會無法存檔,不用擔心會改錯。
以本例來說是 1-8 所以是:
# echo suspend > /sys/bus/usb/devices/1-8/power/level
電源燈就會熄了。
噢,當然你要有相當於 root 的權限。

2009年12月18日 星期五

Ubuntu 又被婊了

這陣子為了 CMake 嘗試轉用 KDevelop 做為開發平台,不過在其首頁上看到一個聳動的標題:Don’t install Ubuntu 9.10 if you want a stable KDevelop - apaku。究竟 Ubuntu 哪裡惹到 KDevelop 了呢?
原來是 Ubuntu 把 KDevelop 4 beta 5 放進 Karmic 的官方套件庫裡,導致 KDevelop 的 upstream 被一堆重複回報的 bug 淹沒,而且其中還有己在 beta 6 修正的 bug。
其實作者要抱怨的不是這堆實際上沒什麼用的 bug report,而是 Ubuntu 把尚未正式釋出的軟體放到正式釋出的套件庫裡。然後自動回報又設定成回報給 KDevelop upstream,而不是 Ubuntu 的 package maintainer,因此 upstream 才會一直收到重複的 bug report。
有人反駁目前穩定的 KDevelop 3 使用的是 KDE3,而現在己不再被 upstream 支援,因此對 Ubuntu 來說別無選擇。但是有趣的是 KOffice 在 Karmic 裡就有分成 koffice (for KDE3, stable) 和 koffice-kde4 (for KDE4, unstable)。
由於作者釋出 beta 的目的是為了測試,但是 Ubuntu 的釋出並不是為了讓使用者測試並回報 bug,並且由於 Ubuntu 本身定位成給新手使用的發行版,他們遇到 bug 大多不會自己解決,也不會看 bug 有沒有被回報過,或是自行從 upstream 下載己修正的最新版原碼回來使用。
作者本人的建議是,尚未正式釋出的軟體不是不能放,而是應該放到另外的套件庫,不要預設就能裝這些不穩定的軟體。他用過的其他發行版都不會有這些問題(Arch, Gentoo, Debian)。
以我正在重度使用的 Debian 來說,它雖龜毛,但是也有龜毛的好處。它的 stable 依然停留在 KDE3,避開了 KDE4 目前尚未被證明的穩定度;而 testing 和 unstable 則是用無接縫升級,因為它們一開始就明講這些軟體尚未經過足夠測試,其使用者多少會有點心理準備;它甚至還提供 experimental 來放那些連 unstable 的條件都無法滿足的軟體。Ubuntu 經常為了新軟體而犧牲其穩定度。

2009年12月11日 星期五

CMake to QMake note

前幾天腦袋壞掉把手上的 Qt project 全換成 CMake,原因是 QMake 的功能實在是不太夠用。最糟糕的一點是建置的彈性太差,你很難在 qmake 的執行選項裡更改專案的設定,通常你要直接修改 *.pro files。然後是它的 install 和設定相依性的能力也很差,跟前述的問題一樣,都是寫死的。
CMake 做為一個建置系統(應該說前端)就還算是優秀,對於相依性的處理可以自己寫一套 script 來自動設定,找不到也可以讓使用者手動設定,雖然有些聲音認為 pkg-config 的方式較為方便,但是畢竟在 Windows(Mac 我不確定) 上這東西是不流行的,而且也不是每個專案都有附上 *.pc 設定。
以下是我從 QMake 到 CMake 轉換的對應處理:
前置動作
find_package(Qt4 REQUIRED)
include(${QT_USE_FILE})
這會檢查 Qt4 的設定,然後把該有的 macro 和變數引入。
子專案設定
TEMPLATE = subdirs
SUBDIRS = dir1 dir2
轉換為
add_subdirectory(dir1)
add_subdirectory(dir2)
如果有
CONFIG += ordered
的子專案間相依設定的話,要在各子資料夾內加上設定
add_dependencies(A B)
執行檔的設定
SOURCES = a.cpp b.cpp # ... program sources
TARGET = exec
TEMPLATE = app
改為
set(SOURCES a.cpp b.cpp ... )
add_executable(exec ${SOURCES})
動態連結函式庫
TARGET = shared
TEMPLATE = lib
由於 add_library 預設是生成靜態連結函式庫,要明確指定 SHARED
add_library(shared SHARED ${SOURCES})
Qt plugin
TARGET = $$qtLibraryTarget(plugin)
TEMPLATE = lib
CONFIG += plugin
這裡要自己加上 Qt 的 flags
add_definitions(${QT_DEFINITIONS} -DQT_PLUGIN -DQT_SHARED)
add_library(plugin SHARED ${SOURCES})
Qt 模組,預設是會打開 QtCore 和 QtGui 兩個。
QT += phonon
set(QT_USE_PHONON TRUE)
除了 QtCore 和 QtGui 分別是 QT_DONT_USE_QTCORE 和 QT_DONT_USE_QTGUI 外,其他的都是 QT_USE_XXX。如果發生找不到 header 或是連結錯誤的話,變數分別是 QT_XXX_INCLUDE_DIR 和 QT_XXX_LIBRARY。
QMake 會自動找需要 moc 的 header, 但是 CMake 在這個功能上還沒有完整支援,qt4_automoc macro 需要在原始碼最後加上 #include "header.moc"。如果你不是採用此做法,就只好手動加入需要 moc 的 header;怎麼找呢?找連結錯誤的 compile unit 就好了。
qt4_wrap_cpp(MOC_SOURCES a.h b.h)
add_executable(exe ${SOURCES} ${MOC_SOURCES})
Resource system
RESOURCES = a.qrc b.qrc
一樣要透過 wrapper
qt4_add_resources(RCC_SOURCES a.qrc b.qrc)
add_executable(exe ${SOURCES} ${RCC_SOURCES})
header 位置
INCLUDEPATH += src
include_directories(src)
連結
LIBS += -la -lb
記得也要連結 Qt 自己的 library
target_link_libraries(exe ${QT_LIBRARIES} a b)
如果什麼都沒做的話,在 MSVC 底下會出現多餘的 console prompt,需要做一點手腳
add_executable(exe WIN32 ${SOURCES})
target_link_libraries(exe ${QT_LIBRARIES} ${QT_QTMAIN_LIBRARY})
版本設定
VERSION = 1.2.3
set_target_properties(exe PROPERTIES VERSION 1.2.3)
set_target_properties(lib PROPERTIES VERSION 1.2.3 SOVERSION 1.2.3)
輸出路徑
DESTDIR = build
set(EXECUTABLE_OUTPUT_PATH "${CMAKE_BINARY_DIR}/build")
set(LIBRARY_OUTPUT_PATH "${CMAKE_BINARY_DIR}/build")
基本上是建議除非你真的很閒才轉啦 ...

2009年11月29日 星期日

Array IS NOT pointer

呣,其實我大一的時候也有這種觀念,畢竟那時 pointer 還是個陌生的怪物,那還是個「如果你不會傳 array 就宣告成 global」的時代。
基本上 C 的 array 實在不怎麼討喜,包括它的「陣列大小一定要跟在陣列名稱後面」這種鳥語法,如果再加上 function pointer 那可真是醜斃了。之所以 array 經常和 pointer 混為一談,最大的原因應是 array 會被隱式轉型[?]為 pointer,且 array 變數本身的值就是 array 第一個元素的位址。這讓你可以把陣列丟入如下的函式裡:
void f1( const int * array );
呃,那二維陣列呢?
void f2( const int * * const array );
因為並不存在多維陣列對 pointer 的隱式轉換,因此你無法直接丟進去。
接下來要談談 array 和 pointer 有什麼不同。
最顯著的性質是,array 變數本身是唯讀的,它無法再被賦值,其代表的空間也無法被手動釋放,而 pointer 值則可以變動,指向的內容可能可以被手動釋放;這也是 pointer 令新手感到易混淆的地方,因為它同時有資源的持有者以及迭代性質。
此外,pointer 可以被取址,但是 array 的址和它自己一樣,也就是陣列開始的第一個位址:
int cla[1];
printf( "%p %p\n", cla, &cla );    // the same
另一個較為有用的不同點是,array 可利用 sizeof 求大小,而 pointer 就只是個 pointer。
int8_t a[10];
sizeof( a ); // 10
int8_t * b = a;
sizeof( b ); // 4 or 8, depends on your compiler
那如果你很希望陣列在傳入函式後還是個陣列,C++ 的 template 可以幫得上忙:
template< typename T, std::size_t N >
std::size_t getByteLength( const T ( & array )[N] ) {
    return sizeof( array );
}

// how to use:
int32_t tmp[4];
getByteLength( tmp );  // will return 16
坦白說,我不是很清楚為什麼一定要用 reference to array,不過你的確可以用這個 template function 傳 array。再多維也可以:
template< typename T, std::size_t N, std::size_t M >
std::size_t getByteLength2( const T ( & array )[N][M] ) {
    return sizeof( array );
}
以此類推。

2009年11月18日 星期三

我不喜歡的問題

由於本篇是純粹的靠北文,如果以下內容你看到覺得我很靠北,可以跟我靠北沒關係。 如果你還沒看過提問的智慧,強烈推薦先看過再往下看。
第一個要說的是,在標題打上「急」之類的字眼:
[問題] XXX 不能用 急!!!!
內文如果打「如題」或「餓死抬頭」的更慘,基本上不會有人理你。你的時間是時間,別人的時間也是時間,用這種倉促的標題會讓人感覺你在催促答案,知道答案的人很可能不想淌混水。講白一點,你急不急其實對其他人來說一點關係也沒有,反而會讓人覺得你「沒有誠意,就只是個要答案的」。
然後是那種會在內文最後寫上「請詳細說明,有附圖文最好」之類的問題。大部分的人看到這個附註都會停下腳步,回頭看看有沒有其他可以回答的問題。基本上這就是要人做白工幫你抓圖幫你上傳還要打個幾百字讓你看到懂。換做是你,你要嗎?
上面還有一種變形,就是加上「我是新手」或是「我很笨」之類的附註。其實客觀來說也沒什麼問題啦,只是我個人會看得很不爽。
套上 duck typing 的邏輯:「如果你走起來像新手,知識像新手,問的問題也像新手,那麼我們就會判定你是新手」[?]。是不是菜鳥,老鳥當然一看就知道,還用得著你來講嗎?也許你講這句話是為了謙虛,或是為了怕大家指責你問了鳥問題,但是某些 GY 人(像我)會覺得你想拿這個當擋箭牌,掩飾你不想查資料,不想思考,因為你新你笨所以大家要原諒你要教你教到會。不過很遺憾,並不是新手做什麼都可以被原諒的。
還有一種,就是回文說「上面的太高級了,看不懂,能不能再講詳細一點」。
最糟糕的部分是你沒解釋哪裡不懂,不僅很難回答,還間接讓人認為你可能沒在思考;第二糟的是你無意間甩了前面熱心回答的人一巴掌,至少也回個「謝謝,但是上面提到的 XXX 我不是很懂意思」,意思一樣,但是絕對比原來的說法更能吸引解答出現。
如果整段回覆都是鴨子聽雷呢?那就要列出所有你看不懂的重點,搜尋一下維基百科或 google,找不到或是看不懂才問下一個問題。很多人都會忽略的一個重點是,你必須先知道你的問題才能找到答案。如果你無法凝塑出一個關鍵問題,不了解你到底哪裡不了解,通常代表你的背景知識嚴重不足,你應該先從更基本的地方著眼。
最後一個也是單純我個人很不爽的,客觀上完全沒錯,就是:
都英文,看不懂,能不能換個中文的
基本上我第一個想到的是「怪~我~囉~~」,然後就左轉離開了。
除了客觀上犯了伸手牌的問題以外,言下之意也是希望回答的人可以英翻中一下。現在翻譯用的資源實在很多,就算不是百分之百完全翻譯,靠字典也可以猜出一二,看不懂也猜一下,而不是怪別人只給你英文資料;畢竟很多資料都是英文,不是每個人時間都很多可以打個中文詳解。
我曾看過有人說:那是你們學生才有時間搞這個,上班的人哪有時間去找資料,知道答案直接講就好了啊?
噢,其實我不太相信你們可以用這種態度跟前輩問問題,如果有的話那前輩還真是佛心來的。如果找不到人問你不就擺爛?你的時間是一秒鐘幾十萬上下,別人的時間就不值錢?
你可以想像一下,在數十萬筆的資料中找出有用的,英翻中,抓圖附文,解釋給一個陌生人到懂並解決問題為止,但是不拿任何報酬;你願意嗎?
套某人說的話:「得之,你幸;不得,你命」。如果有那還真是佛心來的,可惜大部分的人都是普通人。
互相減少佔用對方的時間,不也是一種尊重嗎?

2009年11月16日 星期一

Khopper v0.2.3 released

  • 修正 flac 在檔案結尾處可能引發無窮迴圈的問題
  • 修正 flac 沒有 seektable 的問題
  • 修正 ogg 的寫入問題
  • 修正 mp3 vbr 的編碼問題,現在可以正確抓到長度了
  • 修正部分資訊讀取錯誤的問題

2009年11月12日 星期四

X input device setting

原本在找 Kubuntu 9.10 上如何控制觸控版的解法,意外找到這個好像很好用的設定工具。
首先 xinput list 會列出所有己和 X server 連接上的裝置,找出你要設定的裝置,看它的 id,之後用 xinput list-props id 來列出所有可設定的屬性。注意每個屬性的格式都像是:
簡短說明 (屬性 id): 屬性值
找到你想設定的屬性 id,就可以開始改:
xinput set-int-prop 裝置id 屬性id 8 屬性值(空白分隔)
其中的 8 指的是整數長度。

2009年11月11日 星期三

Casting function pointers from void * in C++

在拿 DLL 裡的 symbol 時,它會回傳一個 void *,你必須要自己轉型成對應的 function pointer。不過問題是 C++98/03 都把 void * 視為指向某個物件的指標,而不會是一個 function pointer,所以使用 C++ style 轉型會失敗;既然標準沒有定義,就代表這種行為基本上是依賴實作的,為此我們需要一些怪怪的 reinterpret_cast
作法一,先轉成指標長度的整數,再轉成函式指標。
void * gptr = dlsym( ... );
typedef void ( * fptr )();
fptr my_fptr = reinterpret_cast< fptr >( reinterpret_cast< intptr_t >( gptr ) );
intptr_t 是 C99/C++0x 的新型別,一定是一個指標的大小,如果沒有辦法的話,也可以用 long 代替,大部分的平台上 long 都和指標同長。
作法二,把函式指標的位址轉型成 void * * 再指定。
fptr my_ptr = 0;
*reinterpret_cast< void * * >( &my_ptr ) = gptr;
...

2009年11月9日 星期一

不 try 一下怎麼會知道呢

最近用自己定出的編碼器介面寫外掛時, 才發現原本定的介面怪怪的。
首先是 hook 的呼叫順序。由於 libav* 是先開完檔再呼叫寫入 header 的函式,因此我也讓 openResource 在 writeHeader 之前先呼叫。但是其他的編碼器並不一定是這個順序,其實有的根本就沒有分 setupEncoder 和 setupMuxer 的步驟。反正我也沒有檢查每個 hook 要做什麼事,也不可能檢查 ... 所以這倒是沒什麼關係。
第二個問題是我在抽象類別上有定義 buffer 機制,原本是希望可以減輕具象類別的負擔,沒想到現在用起來覺得有點累贅,多了不必要的介面操作。這部分需要在 0.3 修正。
最嚴重的問題是,編碼器似乎不太需要動態載入外掛,應該說不需要和操作它的圖形介面分開發佈。原本的用意是希望降低耦合度,並且讓其他的外掛也有機會使用它,但是操作用的外掛不可能不知道它要呼叫哪個編碼器,而且分開發佈導致無法使用編碼器特殊的設定,像是壓縮率等。目前看來唯一的好處是其他人也可以産生這個實體 ... so what? 難道 mp3 設定會呼叫 ogg vorbis 的編碼器嗎?總之這個外掛的介面真的有點多餘。

2009年11月5日 星期四

A way to use C++ object in C callback

前幾天在用 libFLAC 的時候[?],它要求 client 註冊一個 callback 給它,prototype 長這樣:
typedef FLAC__StreamDecoderWriteStatus
(* FLAC__StreamDecoderWriteCallback)
(const FLAC__StreamDecoder *decoder,
const FLAC__Frame *frame,
const FLAC__int32 *const buffer[],
void *client_data);
看起來很複雜,其實不會,就是個 function pointer 的 typedef 而己[?]
可以看到最後一個 void * client_data 是用來接受 client 的資料用的,先接 void * 再轉成自己要的型別,算是 C 的老手法了。
Well, 在 C++ 上使用時就沒有那麼簡單。第一個問題是 member function 需要實體才能使用。
簡單一個想法是宣告一個 struct,把實體和 pointer to member function 包起來,再傳給這個 callback function。不過一來這有點麻煩,二來你不能呼叫用 protected 或 private 修飾的 members。
沒關係,我們有 friend!
嗯,不好意思,這的確是可以動,不過真的很爛。
還好我們還有另一顆子彈,就是 static member function。static member 不需要實體,且 member function 可以存取 class 內所有 member,這樣就一次解決了兩個問題。
所以我們的 callback 會長這樣:
static FLAC__StreamDecoderWriteStatus
FlacReader::writeCallback_
(const FLAC__StreamDecoder *decoder,
const FLAC__Frame *frame,
const FLAC__int32 *const buffer[],
void *client_data) {
    FlacReader * self = static_cast< FlacReader * >( client_data );
    // blah blah
}
client_data 那裡傳 this 就好。
不要譴責我沒用 dynamic_cast,我百分之百確定 client_data 是 FlacReader 好嗎?

2009年11月3日 星期二

Khopper v0.2.2 released

Changes:
  • 修正 flac 的解碼問題
  • 新增 mp3 cbr 192 bps 的選項
  • 修正部分環境的編譯問題
看起來很少,可是花了我不少時間在 trace 別人的 code ....

2009年10月30日 星期五

Framework 終究只是 Framework

最近這個禮拜的 debug 過程又讓我深刻地體會到這點。
從以前到現在我遇到的問題:
  • Qt Phonon 的 SeekSlider 沒有訂製點,所以我幹了一個自己的
  • Qt Webkit 沒有 DOM 的存取方法(不過已在 4.6 加入)
  • Java 的 ZipEntry 不支援 unicode
  • FFmpeg 可以編 MP3 VBR,但是沒有寫 VBR 用的 header (I dont think we write the optional vbr tag, so its not a bug. by michaelni)
  • FFmpeg 不能 seek FLAC,解碼出來的時間點也都是垃圾
其他還有很多臨時沒想到的。Framework 只會讓你有機會省一點時間,但是不代表你可以完全依賴它。就跟學了 jQuery 就以為自己懂 AJAX,或是學 Java 就以為不用搞懂指標,不過就是自我感覺良好而已。

2009年10月28日 星期三

PicKing 0.2.1 released

Changes:
  • 增加匯出 K3B 清單功能
  • 部分 GUI 改進
  • 獨立檔案庫
說明: 按下 Export to K3B [!]後,就會把大於 4000 MB 的結果匯出至指定資料夾。可以直接用 K3B 開來燒錄。大於多少可以在 Preference 裡調整。或是直接在想要的結果上按右鍵,也可以無視該項設定直接匯出。
Snapshot:

2009年10月14日 星期三

KomiX v0.1.0 released

  • 增加壓縮檔支援(需安裝 7-Zip)
  • 增加逆向移動
  • Ctrl+滑鼠滾輪可縮放
  • 增加捲動速度調整選項

2009年10月7日 星期三

Mount any VBox-compatible disk image on the host

If you encountered this message while building:
.: 32: Can't open /etc/vbox/vbox.cfg
You should add this line
INSTALL_DIR=/usr/lib/virtualbox
to the building script.
If you encountered fuse mount option error while executing, you should patch the source code:
- fuse_opt_add_arg (&fuseArgs, "");
+ fuse_opt_add_arg (&fuseArgs, "vdi");
and rebuild it.
You can simply unmount it using umount command.

2009年10月4日 星期日

Fix the bitmap render of wqy-zenhei

如果你的文泉驛正黑在升級之後某個 range[?] 的字型變成點陣字,可以用如下方法修正:
# rm /etc/fonts/conf.d/66-wqy-zenhei-sharp.conf
放心,它是個 symbolic link,日後有需要再從 /etc/fonts/conf.avail/66-wqy-zenhei-sharp.conf link 回來就好。
原因?我也不知道,因為 66-wqy-zenhei-sharp.conf 設定的是 12~16 的範圍,不知道為什麼會影響到 8~11 ... 可能是 fontconfig 的 bug 吧。

2009年10月2日 星期五

Brief of some KDE4 application, again

這是繼上次 Brief of some KDE4 application 的更新版,對應 KDE4.3。
Amarok 2.2
評價:二
介面有變漂亮了 ... 這有差嗎?(摔貼紙)
勉強給你加一分,快點把 iPod 的 playlist 做回來啦!
Choqok 1.0
評價:四
目前用起來最順手的 Twitter client。之前的版本會讓 KNotifier 佔滿資源,新版就不會了。
K3B 1.66
評價:二
勉強可以燒東西,但是 bug 一堆。看在是 alpha 的份上就不多說什麼,不過開發進度真的很慢。
Konqueror 4
評價:一
不知所謂的東西。一堆網站不能完整支援,莫名其妙的崩潰,奇異的 wordwrap,還有很多,而且完全沒有改善的跡象。做為一個桌面環境的預設瀏覽器真的很悲哀。
KNetworkManager
評價:三
經歷了三個 milestone 終於回歸的網路管理前端。坦白說有點雞肋,因為經常連不上有加密連線的 AP。
KOffice 2
評價:一
功能缺東少西的套裝。KWord 不能畫表格,好像還堪用的 Krita 還不停地 crash ...

2009年9月29日 星期二

爆了

部落格觀察的貼紙爆了。
我不知道是怎麼回事,也不是很在意。基本上那個 widget 是載入最慢的 widget,我只不過是想把它改成 onload 之後再載入到 DOM,失敗之後 rollback,就變這樣了。
我還是認為 HTML 要有個 post 的機制,讓整個文件 layout 出來之後再載入外部文件。這是為什麼 img 標籤希望你指定圖片的寬高,因為不指定的話就要等圖片載入才能知道大小,然後文件就要重新 render,然後你在看的文件內容就會一直改變位置。
不過這樣就沒計數器了,其實我對排名不是很在意。自己寫一個好像也還好,不過有點麻煩。

2009年9月18日 星期五

如何讓你的程式更難理解(5)

int uglystrieq( const char * l, const char * r ) {
    while(*l&&*r&&(*l++|32)==(*r++|32));return *l--||*r--||(*l|32)!=(*r|32);
}
Compare the equivalence of two strings. Case insensitive.
[Edit]
This implementation while crash when passing a 0-lengthed string. Another version:
int _(const char*l,const char*O) {
    return ((*l|32)-(*O|32))?1:*l?_(l+1,O+1):0;
}

2009年9月13日 星期日

Install Windows XP on VirtualBox with SATA support

Briefly in Windows XP:
  1. Download the drivers from Intel
  2. Extract the archive:
    • Windows: Just extract it. You will get an floppy image named F32.IMA
    • Linux: Because of it is a self-extract archive, you can use unzip or p7zip to extract f6flpy32.exe and can still get F32.IMA
  3. Mount the floppy image. No bother to use a real floppy.
  4. In the initialization stage, press F6 to get the external SATA drivers.
  5. Press S to select driver. Please select Intel(R) 82801HEM/HBM SATA AHCI Controller (Mobile ICH8M-E/M)
  6. Then go ahead

2009年9月11日 星期五

Packages in Opera's FTP repository

There is a deb repository that provides apt service. But packages in that one are still depends on Qt3. Packages which are built with Qt4 are only avaliable in FTP repository. Weird Opera.

2009年9月1日 星期二

Pitfalls in shell scripts

When you iterate paths and do something with them, you might be tempted write this:
find . -name blah | xargs rm -f
yeah, I know there is a switch -exec in find, I just don't like it.
This command looks fine, but has two problems:
  1. The length of arguments maybe exceeds the limit of the shell.
  2. The file path may contains some special characters, such like quotes, spaces.
To solve the first issue, a loop maybe useful:
for path in `find . -name blah` ; do
    rm -f "path"
done
This solves the first issue, but the second one remains. For loop treats spaces and newlines as delimiters. But if paths contain spaces, they will cause error.
You can change the delimiter temporary as a workaround, but this will impacts all actions in the loop, I personally don't recommend this.
Or we can use a while loop:
find . -name blah | while read path ; do
    rm -f "$path"
done
should be just fine.
Another common error , comes from:
if [ $str = blah ] ; then
The problem is, $str maybe unset or a null string, or worse, injected with a string such like -f.
Good practice is:
if [ x"$str" = xblah ] ; then

2009年8月27日 星期四

Enable frame buffer in grub2

With legacy grub, if you want to enable frame buffer built in kernel, the option "vga=xxx" is needed in boot command.
However, grub2 provides a newer way to enable the feature. You should set gfxpayload=1280x1024x32, and insmod vbe manually if needed. So where to add? I write it to /etc/grub.d/40_custom, as it is an user custom hook script.
cat <<EOF
insmod vbe
set gfxpayload=1280x1024x32
EOF
You can use vbeinfo in grub2 shell to look up which modes are available.
By the way, DO NOT FORGET to run:
# update-grub
to make newer grub.cfg generated.

2009年8月20日 星期四

Overview of Observer Pattern

如果想要讓某物件在「發生某事」時通知另一個物件「做某事」,那麼我們會使用 Observer Pattern 來實現。簡單的做法是:
class Sender {
    +__new__() {
        this.listener = []
    }
    +somethingHappend() {
        this.listener.each( lambda( l ) {
            l.refresh( arguments )
        } )
    }
    +addListener( that ) {
        this.listener.append( that )
    }
    -trigger() {
        this.somethingHappend()
    }
}
class Receiver {
    +__new__() {
        sender = Sender()
        sender.addListener( this )
    }
    +refresh() {
        // blah blah
    }
}
當 Sender 的 somethingHappend 執行時,它會通知所有已被 addListener 加入的物件執行 refresh 動作。
這個做法很單純,但是不夠泛化,Sender 可能不只有一個事件,該事件也不一定只會呼叫 refresh。
class Observer {
    +connect( slot ) {
        this.listeners.append( slot )
    }
    +__call__() {
        this.listeners.each( lambda( args, l ) {
            l( args )
        }.bind( arguments ) )
    }
    -listeners = []
}
為此我們需要一個統一的介面來操作,class Observer 就此應運而生。
就 connect 而言,我們關心的是事件發出者是誰,它發生什麼事件,事件接收者是誰,它做了什麼事。
稍後我們會處理好事件發出者以及發生什麼事件的辨別方式,因此在這個 Observer 裡只儲存事件接收者和對應的處理函式。slot 即代表被註冊進來的處理函式,儲存起來以備以後使用。
__call__ 這個函式會在事件發生時被呼叫,它做的事很單純,就是呼叫每一個註冊起來的處理函式,並把自己接收到的參數傳給那些處理函式。
當然在這裡最麻煩的就是參數型態及個數,這裡端看各種語言的特性會有不同的實作。基本上動態語言都不會有什麼大問題,但那些靜態語言就需要一些特殊的手法。
使用時就像這樣:
class Sender() {
    +somethingHappend = Observer()
    -trigger() {
        this.somethingHappend( arguments )
    }
}
class Receiver() {
    +__new__() {
        sender = Sender()
        sender.somethingHappend.connect( this.refresh )
    }
    +refresh() {
        // blah blah
    }
}
可以看到 Sender 本身可以持有數個不同的 Observer,而且不同的 Sender 實體可以各自綁定不同的事件。當 Sender 的 trigger 發出事件通知,Receiver 相對應的處理函式就會被喚起。
這裡並沒有討論細節,比方說 mutex lock,解除監聽,還有 receiver 反查 sender 的機制。

2009年8月13日 星期四

Resolve the BADSIG problem when updating apt list

I recently encounter an update problem during updating sources list:
W: GPG error: SOURCE Release: The following signatures were invalid: BADSIG KEY SENDER
I have no idea how this happened, but have fixed this. First I tried this:
# apt-get clean
# cd /var/lib/apt
# mv lists lists.old
# mkdir -p lists/partial
# apt-get clean
# apt-get update
Well, but no use. So I tried another way:
# apt-get update -o Acquire::http::No-Cache=True
Then it works.

2009年8月2日 星期日

PicKing 0.1.0 released

下載 jar
原始碼
Licinse: LGPLv3 or later
System require: JRE 6.0
用來挑選能夠塞進指定大小的最多檔案或資料夾。我主要在大量備份時使用。
如上圖,左邊是檔案系統,中間是該資料夾底下的內容,選好之後點 start 就會開始作業,花的時間要看選擇的數量,50 個項目大約會花好幾秒;結果會顯示在右邊。
左下角是設定檔案大小上限,預設是 4483MB,也就是一片 DVD 的容量。
按 F5 可以重新整理檔案系統,比方說你可能多新增一個資料夾或插上新硬碟,可以用來更新。
Ctrl+S 可以儲存跑出來的結果。
備註:
十六個項目以內會使用暴力演算法,跑得出全域最佳解,但是時間和空間複雜度皆是O(2^N)。超過十六個項目則會使用基因演算法,會收斂在局部最佳解,不保證是全域最佳解,但是速度很快。因此有時會看到同樣的樣本空間跑出不同結果,乃是正常現象,如不滿意可以再跑一次。
本項目的原型是 PycKer,一個使用 PyQt4 的作品,作者當然也是我,不要告我抄襲自己去年的專案。
由於原本只是想強迫自己練習一下 Java,一開始(半個月前)是放在垃圾碼的沙箱裡,沒想到現在做成這個樣子。

2009年8月1日 星期六

C++ 的多緒安全性

簡單的說,因為標準給編譯器優化的限度太寬鬆,導致編譯器可以很大程度地調換指令的順序,因此 critical section 也有可能無法完全包好。不少人以為 volatile 可以禁止優化,從而確保正確順序,但其實它只保證單緒的順序,多緒的狀況還是無法保證;連鬼才 Andrei Alexandrescu 都在他的神作 Morden C++ Design 裡犯了這個錯誤(我也不認為他示範的 Singleton 真的有 thread-safe)。
也許等 C++0x(呃,可能會變成 C++1X) 釋出之後,可以帶給我們更複雜的 C++ 吧。XD

Demogorgon 還真的滿強的

剛剛心血來潮查了一下 Bordur's Gate II 裡 Demogorgon 的資料,發現還真是超出規格的強:
Level25
Class惡魔
Party叛逆邪惡
力量25
敏捷20
體質22
智力22
智慧22
魅力18
HP290
防禦等級-17
THAC0-19
攻擊次數5
抗魔90
物理10
100
100
50
特殊能力攻擊附疾病和等級吸取效果
特殊能力免疫盲目以外的不利狀態
特殊能力會不停地招喚惡魔助陣
特殊能力HP的回復速度很快
對沒什麼概念的朋友解釋一下好了。在 TOB 釋出的當時,傳奇的大法師伊爾明斯特的等級也才 29 ,25 級算是相當高的等級,一般傭兵隊有個七到八級就很強了,崔斯特也才十二到十四級。
六個屬性最大值是 25,普通人約在 10 左右,18 可以說是強者中的強者,也算是天生的極限,可是這傢伙竟然只有魅力是在 20 以下。
生命值 ... 290 大約比龍再強壯一點,人類大概超過 40 就算是打不死的小強了。
防禦等級在二版的算法是越低越好,什麼都沒穿就是 10,穿上最好的盔甲大約是 0,再加上魔法可以到負的,像 BG2 這種滿地貨的遊戲,正常玩法可以到 -14 左右,拿 BGS 可以到 -23,而這傢伙只有 -17 算是比較人性化的,還不到打不中的地步。
THAC0 是 -19 就太超過了。THAC0 的全名是 To Hit Armor Class 0,也就是如果你要打中一個 AC 為 0 的敵人,需要擲出多少才會命中,骰子是二十面骰,換句話說,THAC0 也是越低越好。-19 就代表只要你的 AC 沒有撐到 -19,只要他沒 BG 就一定打得中你。
一回合攻擊次數五次(最多也就五次) ... 就算是超強戰士,沒打針吃藥或是魔法加持是沒辦法做這種快速攻擊的。 抗性是 100 最高,代表百分百扺抗。對了,這傢伙我記憶中沒錯的話,魔法武器無效= =
等級吸取的意思是每命中一次就會降低等級,法術和能力都會因降低而消失,降到零角色就會死亡。
盲目以外免疫就代表他不會受到牽制,定身、石化、催眠、混亂、弱智等。
然後他召喚惡魔是不用施法的,反正就一直冒出來就對了。
最扯的來了,他似乎是半神還什麼的,所以時間停止對他無效orz,用了之後會發現靜止的世界裡只有他和你的人生是彩色的。噢,不對,因為他是彩色的,你當然就是黑白的。
而且他還會放一些十級法術,像是內爆術之類的(20d6)。
如果你問我是怎麼幹掉他的 ... 在他出現以前在他腳下放三顆尖刺陷阱(3*20d6),他一出現敵意就會瞬間被遺返回外層界 ...

2009年7月28日 星期二

Remove a range from java.util.Vector

There is a method removeRange in AbstractList class, somehow it is protected. So, if you want to remove a range from a Vector, use subList(which is come from List) instead:
v.subList( 0, 12 ).clear();
The subList method returns a view(or a snapshot) instead of a copy to manipulates original container. So if you want to do any operation in specific range, use subList.

2009年7月2日 星期四

Do not install or upgrade ia32-apt-get

ia32-apt-get just breaks your apt repository, it will screw up your package list. So don't upgrade ia32-libs from 2.7 to newer version until it DO fix this mess.
I don't know how can it upload to unstable ... it is just **HORRIBLE**!

2009年6月28日 星期日

2009年6月22日 星期一

如何讓你的程式更難理解(4)

// unique values
var c = [];
// random shuffled keys
var rsk = [];
( function( functor ) {
    jQuery.each( tags, function( key, value ) {
        // random shuffle or just copy. tags -> rsk
        functor( key );
        // unique array to c
        if( jQuery.inArray( value, c ) < 0 ) {
            c.push( value );
        }
    } );
} )( Blog.TagCloud.shuffle ? function( key ) {
    rsk.splice( Math.floor( Math.random() * ( rsk.length + 1 ) ), 0, key );
} : function( key ) {
    rsk.push( key );
} );
以上是我的標籤雲實作的其中一小段,tags 是(標籤,文章數量)的集合,c 放的是不重複的文章數量,Blog.TagCloud.shuffle 是設定要不要打亂標籤的順序,rsk 放的是處理後的標籤順序。
暮然回首才發現我寫出這種東西...= =

2009年6月20日 星期六

Multiboot using Grub2

最近跟著潮流(?)改成 grub2 做為開機管理程式,但是在我升級之後,它沒抓到存在我電腦裡的另一個作業系統。解決方法很簡單,安裝 os-prober 套件,再重新設定一次 grub2 就好。
# aptitude install os-prober
# dpkg-reconfigure grub-pc
第二步會出現選擇 grub 要安裝的硬碟,選 /boot 掛的那顆就好;這樣它就會自動抓到其他的開機區段了。
os-prober 是 grub-pc 的 Suggest 套件,個人認為應該提上 Recommend 才對的。

2009年6月16日 星期二

仰角 10 度

昨天心血來潮問了強者我朋友一些物理問題,中間有提到飛車躍懸崖的狀況。剛剛算了一下這難度有多高。
環境:
假設飛躍的起點和終點高度相同,由於車子在飛出去之後,垂直方向是自由落體,水平方向是等速位移(沒有地面無法施力,故無水平加速度,阻力亦不計),設 Xy 為落下高度,Xx 為水平位移量。
公式:
自由落體:
Xy = 0.5 * g * ( t ^ 2 ),g 為重力常數(m/s^2),t 為經過秒數(s)
平均速度:
v = Xx / t,t 為秒數(s),v 為速度(m/s)
可得出:
v = Xx / ( 2 * Xy / g ) ^ 0.5
假設落下高度最大容許到 20cm(考慮輪胎的高度,否則會撞上平台),水平距離 10m,那衝出去的瞬間速度要大於 178 km/hr;這其實也不是不可能的車速,但是電影通常不會飛這麼保守的距離,起碼 20m 起跳吧,也就是說至少要 357 km/hr ... 不過一般的自小客車有這麼強的馬力嗎?
所以如果看到飛車鏡頭車頭有仰角 10 度的話(有趣的是,很少有側拍,都是從上面拍下來,或下面拍上來),就記住:認真你就輸了。

2009年6月8日 星期一

Uninstall VirtualBox 2.2.0 under Vista

在 2.2.2 之後已修正的 bug,原本會造成 Vista 無法移除 VirtualBox。 中文解法:
  1. 打開 regedit.exe
  2. 找到 HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\DIFxApp\Components
  3. 按右鍵匯出,存到某個檔案
  4. 編輯該檔案,把所有的 HKEY_CURRENT_USER 代換成 HKEY_LOCAL_MACHINE
  5. 匯入修改後的登錄檔
做完就可以正常移除了。似乎是登錄檔沒弄好。

2009年6月7日 星期日

如何讓你的程式更難理解(3)

alert( ( function( list ) {
    return ( function( functor, nullValue, list ) {
        if( list.length == 0 ) {
            return nullValue;
        }
        var head = list.shift();
        return functor( head, arguments.callee( functor, nullValue, list ) );
    } )( function( head, tail ) {
        return head * head + tail;
    }, 0, list );
} )( [1, 2, 3, 4, 5] ) ); // will alert 55
用遞迴的方式算出一個陣列的平方和,使用 JavaScript。
靈感來自於 測測你自己 - The Joel on Software Translation Project
對,我是故意寫成這樣的,這不算是好的風格...

2009年6月4日 星期四

Khopper v0.2.1 released

  • 修正 flac 的編碼問題
  • 修正 vorbis 的編碼問題
  • 修正亂七八糟的 ogg 選單
  • 重新開放 mp3 vbr 的選項
  • 改善時間軸

2009年5月26日 星期二

MPEG Audio Frame Header

FFmpeg 有實作 MP3 的 VBR 編碼,但是竟然沒有寫入能判斷 VBR 長度的 tag,之前還一直以為是我的問題= =。

2009年5月25日 星期一

死亡フラグ

死亡フラグ簡單的說就是死亡的條件,フラグ即 flag,電腦遊戲中標示條件的變數。以下列出比較有趣的部分:
  • 黑道決定金盆洗手時
  • 浪子決定落地生根時
  • 發現戀人懷孕並許下美好的未來後
  • 異常系:
    • 甘草人物突然拿到一整集的戲份
    • 寡言的人突然變多話
    • 嚴格的人突然變溫柔
    • 孤獨的人了解愛和友情,並對他人敞開心胸之後
    • 邪惡的人了解愛和正義,並對叛逃邪惡組織之後
    • 同盟背叛並挾持人質(洗腦除外),特別是原本在主角隊伍中善良派的同伴背叛的話,必死
  • 和同袍提起往事,特別是主角的兄長,死亡率會急上升
  • 迴避過數次死亡フラグ的角色
  • 不能說的台詞:
    • 「如果我能活著回來,就要向 XXX 告白/結婚」
    • 「我在前面等你」
    • 「看來今天會是炎熱的一天」
    • 「我才不要和殺人犯在一起呢,我要睡我自己的房間」
    • 「我絕對不會讓你死」
  • 突然把重要的東西託付給信任的人,或是說起像遺言的話。這時如果被回「別說那種不吉利的事」變不吉利的機率會大增
  • 把最終奧義傳授給徒弟,並把自己當成最後一道障礙。如果徒弟對師父有「因誤會而生的仇恨」的話,必死
  • 一個人淋浴,或是情侶在放閃光時
  • 比主角先發現兇手的人,會成為下一個被害者
  • 在旅館的大廳暴走的人
  • 就任宇宙戰艦大和號的艦長(特別是劇場版,古代進除外)
  • 主角(白人)的搞笑好友(黑人)
  • 主角或女主角以外的美人
  • 犯人對小孩下手
  • 反派突然說明自己之前犯案手法或背景之後,而且都會不小心把下個目標說出來
  • 暮然回首,那人就在燈火闌珊處:
    • 被某個聲響嚇到,說「什麼嘛,只是野貓啊」,回頭之後就會死
    • 因為預感而回頭,再轉回來之後就會死
  • 醫生說手術很成功,只要避免 XXX 就可退院,若是補上一句 XXX 發生的機率很低的話,那發生的機率會是 100%
  • 被主角打敗的反派逃走後說「沒關係我還有 XXX 可以反敗為勝」的時候,會出現更強的反派把他收拾掉
  • 被子彈打中頭盔,因獲救而興奮地拿下頭盔確認的人,下一格就會被爆頭
  • 出陣時軍旗被折斷

2009年5月21日 星期四

苦果

當初在處理時間時沒想太多,用 double 去存秒數,但是完全沒考慮到浮點數很容易發生誤差,傳一傳值就跑掉了,現在又要對底層動刀...

2009年5月20日 星期三

佳句

攻略の鍵はヒロインをひたすらにストーキングすることだそうです。[?]
ロロット @ ティンクル☆くるせいだーす

Khopper 0.2.0 released

修正:
  • 核心模組以 LGPL 2.1 or later 發佈
  • 若開啟 CUE 的對應檔案失敗,可再選擇另一檔案開啟
  • 時間軸現在會對 CUE 做調整
  • 加強錯誤訊息
原則上和 beta 比起來只是小修正...。整個專案全部移向 GitHub,希望不要被英文嚇到了。

2009年5月10日 星期日

堤防に来て花をくれ

在遊戲中看到的鬼故事,還滿有趣的。
故事大意上是說,某天一群學生在玩碟仙的時候,得出了下面的訊息:
テイボウニキテハナヲクレ
意思是「把花拿到堤坊上」。
眾人考慮了很久,怕不照指示做會被做崇,就買了供養往生者的花,拿到堤坊上撤入河中。
唸完了祭詞之後,突然,通往堤坊上的鐵梯傳來了"鏘、鏘、鏘"的腳步聲 ... 當然,梯子上根本看不到人 ... !
其實幽靈給的訊息,也是言靈的一種,預告了接下來發生的事;把字的順序改變一下就是:
テニハボウレイヲキテナク(手には亡霊於きて哭く)
「亡靈表意在於手」,指的就是降靈。
テイボウニキテハナヲクレ(堤防にきて花をくれ)
「把花拿到堤坊上」,便是訊息。
ボクウキテハナヲテニイレ(僕浮きて花を手に入れ)
「我上水來花入手」...
ハレテテイボウナニヲキク(晴れて堤防何を聞く)
「天晴堤上何聲響」...就是最後結局!

2009年5月5日 星期二

夏空少女OP

據說這個因為 bug 的關係導致根本無法正常遊戲= =,不過 OP 倒是不錯。

2009年5月4日 星期一

Qt Solutions

Qt Solutions 是 Qt 的額外組件,在以前是只有買商業授權才能使用。不過在 Qt 4.5 之後,裡面的組件便漸漸地加入了 LGPL 的授權,而我之前就哈很久的 Single Application 組件也終於變成加入 LGPL 了XD。
Single Application 用途就如名字一樣,讓程式同時只能開一個實體,而且可以在實體存在時對己存在的實體發送訊息。基本上只要會 IPC 就可以實作,不過因為各平台的 IPC 技術不同,自己寫起來也是要一番功夫的。

Checked exceptions

Exception 是一種錯誤處理機制,可以在函式無法處理錯誤時拋出,中斷函式流程,並往上 unwind stack,直到有個 try-catch 述句把它捕捉起來為止。比起 error code 或是 assertion,它相對來說是較新的處理方式,也因為它會中斷流程,因此要達到 exception safe 就會變很困難。一些靜態語言則為了此目的提供了受檢測的異常處理模型,限制函式拋出的異常。
C++ 的寫法:
void f() throw(); // no throw
void f() throw( std::exception, std::runtime_error ); // exception and runtime_error only
不過實際上,就算宣告為 no throw,這個函式還是可以拋出其他異常,編譯器一樣會通過,只是這代表了嚴重錯誤,程式會立刻異常終止。你可以註冊一個 unexpected_handler,讓它在檢測到異常時執行這個函式,但是由於整個程式只有一個 handler,而一個程式裡有異常丢擲的函式可能不只一個,實際上來說沒什麼用。這種在執行期才檢測的模型叫動態檢測。
汲取了 C++ 教訓的 Java 則使用了更強硬的方法,實施靜態檢測,也就是在編譯期就檢查異常規格:
public f() throws IOException {}
沒有列出的異常就絕不能丢擲,一定要在函式內捕捉起來,甚至於如果有用到含有異常規格的函式,也一定要把它所列出來的所有異常都處理好。看起來好像很安全 ... 不過這真的是很煩人的設計;因為異常規格算是函式簽名的一部分,要是你修改了某個函式的實作,它改用了一個新的函式,而這個函式會拋出新的異常,因為一些設計上的缺陷無法自行處理,就有可能被迫修改異常規格,而這一改,可能會逼得其他有用到這個函式的函式也要跟著處理這個異常。
採用未受檢的異常處理模型的語言就傾向於不限制異常,沒捉到就讓它終止程式。

2009年5月2日 星期六

Compile C or C++ code from stdin

偶而你會懶得存檔,因此有方法可以直接編出來:
# for C
gcc -xc -
# for C++
g++ -xc++ -

# for example
echo 'main(){puts("Hello world!");}' | gcc -xc - && ./a.out

Down for everyone or just me?

很有趣的網站,根據你輸入的網址去看看是不是只有你連不上。網址形式會是:
http://downforeveryoneorjustme.com/網址
可以把這個網址複製給別人看:P

2009年4月23日 星期四

Updates to Qt, Qt Creator released

一次推出 Qt 4.5.1, Qt Creator 1.1, Qt Visual Studio Add-in 1.0 的更新。據說 Qt Creator 有被增強不少,不過我還沒用過。Visual Studio 的整合先前是只有商業授權的 Qt 才能使用,在改 license 之後也開放給 free license 的版本使用,不過 Express 無法使用該 add-in,而 Express 以上的版本要和微軟買。
說起來 Nokia 接手後就一直對開源釋出善意,包括 Qt 4.5 之後的 LGPL,VS add-in,以及開放部分 Qt Solution 的組件,看來以後 Qt 可能會越來越壯大吧XD。

Khopper 0.2 beta released

現在我會吱吱叫!
好吧,我又很不要臉地先釋出 beta 了。這次的重點在 plugin 的擴充,播放器以及更多格式的支援。事實上 Windows 版的移植也做好了,只是一直很懶得重開機。
Known issues:
  • CUE的播放不會調整時間
  • flac的解碼器怪怪的,也許是FFmpeg的問題
  • ogg似乎不會寫入tag
  • 轉換文字編碼時有機會當掉,尤其是 GB2312
  • 播放器是使用 Phonon,因此能播放的格式取決於 Phonon 使用的 backend,若是遇到不能播放的檔案(比方說ape,ape還有ape等格式),可以換一個 backend

2009年4月15日 星期三

Export DLL symbols to LIB

用 gcc 如果要發佈成 dll,只要編譯器加點選項,就可以發佈給別人連結了。但是 Visual C++ 卻要在每個 symbol 上加上關鍵字 __declspec(dllexport) 才會匯出到 lib,然後才能連結。
__declspec(dllexport) void blah();
class __declspec(dllexport) Blah {};
不管怎麼說,微軟的確是這方面的天才。

2009年4月9日 星期四

ActionScript小感

其實我個人比較 prefer ActionScript 3,ActionScript 2 看起來比較亂,不過其他人都還在用 2,只好入境隨俗。 對它導入的型別系統非常不喜歡。第一個原因是這失去了泛型的靈活性[!]
第二個原因是,它融入了 class-based 物件導向概念,而不是純粹的 prototype-based。這對我來說實在是有點蛇足,因為原本的 ECMAScript 還是有辦法做到 class-based 的功能,只是方式不同罷了。我比較喜歡統一的語法。

Recursive anonymous function

JavaScript 在每個 Function 都維持了一個變數叫 arguments,可以取得 context 的有趣資訊。比如說,arguments.callee 可以拿到目前正在執行的這個 Function 的實體,這有什麼用呢?它可以用來自殺(?),以及實現匿名函式的遞迴。
以自殺來說,比方現在你註冊一個監聽函式,而你需要在某個條件達成後解除監聽,這就很有用了:
ele.addEventListener( 'click', function( e ) {
    // blah blah ...
    this.removeEventListener( 'click', arguments.callee, false );
    // blah blah ...
}, false );
而遞迴就更有趣了,雖然應用上應該很少用到:
alert( ( function( n ) {
    return ( n <= 1 ) ? n : n + arguments.callee( n - 1 );
} )( 100 ) );
以上會跳出 5050。

2009年4月3日 星期五

該死的錯誤訊息

昨天新裝的虛擬機要裝Daemon tools,但是一直出現 Internal error,試過各種方法依然如故,最後只好放棄改用Alcohol 52%。
坦白說我真的很討厭這種錯誤訊息,只知道錯誤但是沒有寫原因,幾乎沒有疑難排解的線索。其他軟體也經常有這種毛病,像是IE8之前的JavaScript錯誤訊息,大部分的圖型介面套件管理程式等。
也許是考慮到使用者不一定看得懂吧,但是某嘴砲曾經說過:
If you think your users are idiots, only idiots will use it.
所以拜託,弄個地球人就能看得懂的錯誤訊息吧。

2009年4月2日 星期四

太嫩了

這是上星期我改的某個程式片段:
template< typename ProductCreator >
class CreatorLoader {
public:
    CreatorLoader( const std::string & plugin ) : plugin_( plugin ) {}
    ProductCreator * operator()() {
        plugin::PluginContext pc;
        ProductCreator * c = qobject_cast< ProductCreator * >( pc.load( this->plugin_.c_str() ) );
        if( !c ) {
            throw Error< RunTime >( "Invalid plugin!" );
        }
        return c;
    }
private:
    std::string plugin_;
};

template< typename Product, typename CreatorFactory >
bool registerProduct( const std::string & key, const std::string & plugin ) {
    return CreatorFactory::Instance().Register( key, CreatorLoader< Creator< Product > >( plugin ) );
}

template< typename Product, typename CreatorFactory >
std::tr1::shared_ptr< Product > createProduct( const std::string & key ) {
    Creator< Product > * tmp = NULL;
    try {
        tmp = CreatorFactory::Instance().CreateObject( key );
    } catch( std::exception & e ) {
        tmp = CreatorFactory::Instance().CreateObject( "*" );
    }
    return tmp->create();
}
現在看就需要點思考時間 ... = =,還是補點註解好了。

2009年4月1日 星期三

安姆真危險

前幾天和室友聊天時聊到,安姆應該是整個費倫大陸上最危險的都市!XD
城門口就有個會用時間暫停和異界之門的巫妖守門。
墓園區有吸血鬼的巢穴和古代巫妖的變性卷軸[?],晚上還有小孩子的幽靈閒晃。
行政區有暴民在燒黑暗精靈,也有和跟流氓差不多的官員和蒙面法師會。
神殿區有守備莫名地強的豪宅,地下有會挖人眼睛的眼魔邪教,還有奪心魔的家。
大橋區有通往異世界的入口,有剝皮人魔,還有一隊強得不像話的怪隊伍在某間房間開會。
碼頭區有影賊本部,而且還會內鬨,半神巫妖也被關在這,還有個老是想置主角於死地的豎琴手。
商業區有通道通向變態法師的地道,還有個瘋子侏儒想成為新世界的神。
貧民區有個異界法球通往外層界,還有奴隸組織在玩羅馬競技場。
其實柏德之門相對來說也很危險,只是一代還不能放太強的生物。XD

2009年3月25日 星期三

Khopper 架構說明

有點久之前和 yen3 提到我想和人共同開發的東西,這裡寫出其中一個,說明架構,也算是留個紀錄吧。
本程式的架構如圖:

上層模組依賴下層模組,下層模組不會使用到上層模組。粗框代表有plugin介面可擴充。
以下就各模組做說明。
Graphic User Interface:
很明顯,就是使用者介面。除了使用Qt之外沒什麼好提的。
Album:
用來描述音軌資料的模組。
主要構成是 Track 和 Index 這兩個 struct。Index 用來表現時間資訊,因為它經常需要單位轉換,運算,故分離出來。Track 則用來裝載音軌的資訊。
CUESheet 則是使用 regex 來解析 cue 檔案的 struct 。
這個模組尷尬的地方在於字串的編碼,因為上層 GUI 的字串統一為 Unicode,但是下層解出來的資訊則是編碼過的字串;目前的重點就是讓它可以很順暢地和上下層溝通。
Panel:
控制輸出格式的使用者介面,為了擴充性而做成 plugin。
它提供輸出格式的選項,並根據選項生出合適的編碼器,轉交給上層進行轉檔。
目前內附有 mp3 的輸出控制。
Codec:
執行音訊解碼編碼的模組,也提供 plugin 擴充,但是較為複雜。
由於 Reader 和 Writer 基本上架構相同,在這裡只說明 Reader,Writer 就比照辦理。
Reader 提供了 AbstractReader 做為抽象介面,客戶若要擴充則必須繼承並實作它。
它要利用 ReaderFactory 這個物件工廠來生成具象物件,客戶必須註冊一個識別字給這個工廠,通常是格式的副檔名,上層模組就是依照這個識別字來產生物件。
若工廠找不到識別字所對應的產品,就會自動使用預設的編解碼器,其識別字為 "*"。
由於 Qt 的 plugin 只能夠產生一個實體,因此 plugin 的本體並不是 Reader 本身,而是一個索然無味的 class ReaderCreator,裡面只有一個成員方法,用來生成 Reader。
總結來說,若要擴展 Reader,增加新格式支援,你必須:
1.繼承 AbstractReader 並覆寫所有 pure virtual function
2.繼承 ReaderCreator 並覆寫 create() 讓它回傳修改過的 Reader:
MyReader * MyCreator::create() const { return new MyReader; }
3.註冊生成器給 ReaderFactory ,己有提供一些函式方便處理;在全域宣告:
const bool reg = registerReader( "mp3", "krp_mp3" );
其中 "mp3" 是程式中使用的識別字,"krp_mp3" 則是 Qt plugin 的名稱,如此一來只要使用:
Reader * r = createReader( "mp3" );
即可取得擴充的物件。使用者不需要了解你擴充的全貌。
以上的做法都是為了讓 Codec 和 Panel 對其他模組的耦合降到最低,事實上就算沒有 Codec 和 Panel 的 plugin,主程式也可以執行,只是不能編碼,也不能解碼。若要擴充也不需更動主程式的程式碼。
Common: 集中了各種雜項工具。
text.hpp 裡放置了各種字串處理函式。
tr1.hpp 是為了調整各編譯器對 TR1 和 C99 支援的不同。
os.hpp 裡放的是依各平台不同實作不同的函式,Linux 上就用 linux.cpp 實作,Windows 就用 windows.cpp 實作。
error.hpp 宣告了異常的基礎類別。
class ErrorBase : std::exception {};

template< typename ErrorType >
class Error : public ErrorBase, public ErrorType {};
ErrorBase 是為了避免 template 造成的隱式程式碼膨脹,ErrorType 則提供一個可訂製點和識別型態。你可以自定義一個型別 NewError,再使用 Error 即可獲得一個新異常類別。
Ablum、GUI 編成執行檔(static link),MP3Panel 和預設的編解碼器為 plugin(dynamic load),Common、Codec、Panel 都包在同一個 dll(dynamic link),因為這三個模組會同時被 plugins 和主程式使用。
大致上是這個樣子...以上有講到一些實作細節,但那是不可靠的,我有可能隨時更改;大致架構則很難再改變,從去年最初交上去的版本開始架構就是這樣,只是擴充方式從靜態編譯變為動態載入,但是程式碼本身卻幾乎全換。
目前比較不穩固的就是 Reader 和 Writer 的介面,兩個都是用 Template Pattern 的方式設計,但是我不確定是否夠通用。
另外 header 似乎也該整理一下...有點雜亂。

2009年3月12日 星期四

Watch out the destructors of super classes

在 C++ 中,如果設計者沒有發生失誤的話,通常可以由 destructor 的宣告來判斷該 class 對繼承的態度:

public and non-virtual

此類 class 不打算讓任何 class 繼承它,繼承可能會導致錯誤行為。

public and virtual

此類 class 提供了多型的特性,並且預期到會有 subclasses 的使用;使用指標刪除物件是安全的。

protected and non-virtual

較為少見,此類 class 提供了介面給 subclasses ,但是卻不希望客戶使用 super class 的指標進行刪除,也不希望客戶具現化出 super class 的實體。

private

這個 class 完全是為了戰術應用而生的,如 Singleton 等;它應該要自己解決生命週期的問題。
說是這麼說啦,不過現在我看過的 code 都是用 public ,只有 virtual or non-virtual 的差別而己。
像是 policy classes 的 destructor 就用途來說似乎都該是 protected and non-virtual ,因為沒人會用 pointer of super class 去刪除它們,也不太可能被實體化。
雖然說語法也只是買保險,真正想亂搞的話誰都擋不住。

2009年3月10日 星期二

エルフェンリート--劇場予告風

比之前我收過的一個偽預告做得還有FU,不過幾乎把重要場面都剪進去了。說起來也太多偽作,連主題曲的完整版都是自己湊出來的...

2009年3月8日 星期日

又要我裝防毒軟體

該怎麼說呢 ... 我一直都是相信「洞」都是使用者自己開的,所以再怎麼強的防毒軟體,只要使用者一根手指就廢了。因此我後來都沒在自己的電腦上裝過防毒軟體,一方面是以前裝的時候它沒幫我擋下多少病毒,反而一直阻撓我連線,另一方面是我使用 Linux 的時間比較長。
現在家裡又要我幫她們裝防毒 ... 實在是提不起勁,反正到時候回來又變得七七八八的。而且新手超幸福的,只要說「我不會」、「我不懂」就好了。以為只要有防毒就天下太平的心態才是一直中招的源頭 ...
我也不會啊 ... 都幾年沒裝過了,還要去找什麼註冊碼,煩死人了。

2009年3月5日 星期四

Brief of some KDE4 application

注意,以下文字包含本人大量的偏見、武斷及胡言亂語成分
KDE4差不多也快用一年了,以下列出我有用過一段時間的KDE4應用程式,並予以評分[?],順序無任何意義,且不包含未釋出正式版的程式:
AmaroK 2
評價:一
我沒給它零分是因為它還是會發出聲音,不過也僅止於此。沒有和iPod整合得很好,某些檔案無法播放,加上常常原因不明地停止播放,可以說是 KDE3 移植到 KDE4 的應用程式中最失敗的一個。
基本上我看不太出來從 alpha 到正式版有什麼差。
KTorrent 3.2
評價:四
雖然在 beta 時經常會 crash ,不過在正式版釋出之後就完全正常了;內附的 torrent search 也不錯用。
Plasma
評價:三
有點微妙。
由於某些 widgets 可能是地雷[!],因此也不能完全怪 plasma 本身,這個設計本質上是好的,只是要看各元件的品質以及個人習不習慣。
KRunner
評價:五
少數從 KDE3 到 KDE4 後評價上升的部分。利用 Alt+F2 就可以使用鍵盤捷徑,範圍包括:應用程式啟動、開啟特定路徑、Konqueror 書籤、計算機、單位換算 ... 等,還有更多!切到其他系統還會覺得怎麼找程式有點慢XD
Konqueror
評價:三
說實在地,它還是沒有很穩定。那麼它的優點是什麼呢?字型的渲染比較好看,且和KDE其他應用程式接得比較完整。
KGet
評價:四
沒什麼大問題的檔案下載器。
Dolphin
評價:四
絕對比 Konqueror 還優秀的檔案管理程式,重點是還有嵌入式終端機可使用。
Kate
評價:四
也是很平滑地移植過來的進階文字編譯器,並在 4.2 之後重新加入了一些有用的 plugins。
Kopete
評價:三
偶而會連不上 MSN ,傳送檔案常發生事故,不過這可算是非戰之罪吧。
Okular
評價:四
很完整的 pdf 和 chm viewer,缺點是需要字型外掛時會找不到字型。
KSnapshot
評價:五
非常好用的抓圖程式,還可以以視窗元件的方式抓圖。
大概就是這樣,沒列出來的不是我不常用就是太甘草,沒什麼變化的。

2009年2月27日 星期五

有感

原來Meteor解散啦 ... 還滿喜歡Clover Point的說,它的OP和夜々真的不錯,沒想到成為遺作了。
不過似乎又重整為Comet ... 期待下個作品吧。

2009年2月25日 星期三

Patch to a tag using git

git checkout -b patch-v1.2.3 v1.2.2    (1)
[... fix your bugs ...]
git commit -a                          (2)
git tag v1.2.3 -m 'Version 1.2.3'      (3)
git checkout master                    (4)
git merge v1.2.3                       (5)
[... fix conflicts ...]
git branch -d patch-v1.2.3             (6)
解說:
  1. 建立一個基於v1.2.2的分支並轉移過去
  2. 送交
  3. 建立新的v1.2.3標記
  4. 回到主幹
  5. 合併v1.2.3的更動
  6. 刪除已不需要的暫時分支
之後就可以把修改過的主幹和新的標記推出去了,別人將不會知道你有暫時分支。
如果有其他的標記要patch(ex: v2.0 ...),則要從第四步開始每個都作一次。

2009年2月23日 星期一

Khopper 0.1.1 released

改版訊息:
  • 修正某些cue檔會崩潰的問題

遊戯王 + チチをもげ!

用的歌似乎是魔法少年賈修裡的某首歌,唱者和城之內的聲優一樣。 不懂的話我大約翻一下(沒有很準確,意思有到就好):
遊戲:是繩文人!(譯註:耶?)
馬利克:摧毀遊戲(的精神)吧!
...
Chi Chi Chi Chi ㄋㄟㄋㄟ 搖啊搖啊 (譯註:ChiChi 在日文也是胸部的意思)
馬利克:三小?!(驚)
...
搓吧揉吧抓吧
搓揉那ㄋㄟㄋㄟ啊
...
遊戲:快回復正常吧!
(城之內還在白目地唱歌)
遊戲:不行,完全被馬利克操縱了
圭:怎麼完全變成另一個人(字幕:並不是)
海馬:這就是馬利克的洗腦嗎...(還好本大爺沒被他洗腦)
(城之內還在唱)
杏子:別這樣,城之內你在衝三小
馬利克:那傢伙...完全只靠著本能在作戰(譯註:這是本能?!這是作戰?!囧)
孔雀舞:城之內...
靜香:哥哥...(準備把繃帶拿下)
杏子:(不行,不能讓靜香看到城之內這個樣子!)(譯註:我也這麼覺得)不可以,靜香不可以把繃帶拿掉!
靜香:咦?!
(字幕:城之內還是唱得很興奮)
杏子:(不能讓靜香看到城之內這個樣子,拿下繃帶第一次見到的那個憧憬中的哥哥,竟然是現在的城之內,那也太悲慘了!)
靜香:哥哥...
孔雀舞:沒問題的,妳要相信城之內
(還在唱白目歌的城之內 <- 憧憬中的哥哥)
(腦內妄想畫面...不過中途出現一個貧乳女讓他受到刺激)
城之內:嗚啊...為什麼...
靜香:哥哥...(拿掉繃帶跳入水中)
城之內:哈哈哈哈哈...抓到妳了
靜香:啊~不要~你看這是你最愛的ㄋㄟㄋㄟ哦
城之內:哈哈哈哈哈...
靜香:哈哈哈哈哈...
彈幕:你們兄妹兩在幹麻啊...
遊戲:城之內,我最喜歡你了!(大心)
(完)

腐り姫MAD - とおりゃんせ

昨天室友問我有沒有恐怖的日本童謠,那最有名的大概就屬かごめかごめとおりゃんせ了,在你管子上很輕易就可以找到。
在ニコニコ上找的時候找到了這首I've remix過的とおりゃんせ,配上我一直沒精神去讀的腐り姫。島みやえい子似乎很適合唱這類型的歌?

2009年2月21日 星期六

タユタマ

剛剛去Getchu上逛了一下,發現タユタマ要發行續作,看來是after story。然後還有TV版發行預定。
接觸它的理由是該社的上個作品いつ空,雖然朱門氏己經離開該社了,不過還是會想看看下一個是不是也是包了糖衣的猛藥。
不過這次它走的是溫馨路線,原本的敵人最後都變成同伴...還算可以啦。
發售前的人氣排名依序是:メアリ、ましろ、美冬、ゆみな。應該是因為到體驗版時的人物表現吧。メアリ擁有強大的恋する幼なじみ屬性,ましろ畢竟是第一女主角[?],美冬則是因為大部分時候都處在生真面目和敵對狀態,魅力無法展現。ゆみな...雖然是很有趣啦,不過這個角色其實比較適合放在配角。
發售後的人氣排名就有點變動了,ましろ、美冬以及鵺佔據了前三名,メアリ和ゆみな則掉到了四五名。而第三名的鵺拿了約兩千票,ましろ和美冬都拿了超過六千票,可知人氣差距。雖然ましろ只以數票之差險勝,不過因為她的熟女型態和幼女型態的票數是另外計算,加起來還是會贏,只能說不愧是第一女主角吧。
另外TV版的demo實在是怪怪的...

2009年2月17日 星期二

2009年2月13日 星期五

Khopper 0.1.0 Released

改版訊息:
  • 修正某些CUE讀取錯誤的問題
  • 修正進度會越跳越快的問題
  • 增加偏好設定儲存功能
  • 檔名增加音軌編號設定
  • 現在取消轉檔應該會正常運作了
  • 現在Windows上可以編譯並執行了
  • 新增程式圖示
  • 其他介面細微修改
套件改變:
  • 新增amd64套件
其他:
  • Windows可使用,但是無法開啟有Unicode字元的路徑
  • MP3的VBR暫時關閉
  • 個人設定會存在~/.config/FoolproofProject/Khopper.ini
學期又要開始了...因此我可能不會再像寒假一樣有這麼多時間,歡迎有興趣的人加入!

2009年2月9日 星期一

該死

我實在不知道該怨恨誰了,就讓我恨天吧...(?)
故事的開頭,是在我想把程式port到Windows的時候發生的。
首先我遇到了TR1和C99名稱缺省的問題,沒關係,我知道每次都要跟上標準很累,VC沒有<cstdint>,gcc也沒實作std::tr1::regex,一人一次很公平,打平了,還好我還有Boost,不怕你。
然而沒想到魔王其實不在這裡,而是Unicode。
先簡單的介紹一下一般處理系統字串的方法好了。
大家都知道早期各國為了顯示自己的文字,定了各種了不起的編碼方式來對應字型,Big5的許功蓋就是這段歷史下的偉大人物,大概比踢牙齒老奶奶這位史詩級人物還要再個高一級左右。
夫天下大勢,分久必合合久必分,某個大有為的組織看不慣這種戰國亂象,於是制定了Unicode的編碼標準,以對應全人類的偉大文化產物,又生出了各種對應Unicode的編碼方式,希望能夠平息亂碼之亂。要注意的是,編碼標準和編碼方式不同,每個文字在Unicode裡只有一種編碼標準,再根據各種不同的編碼方式,比方說UTF-8或UTF-16,UCS4等編成不同的編碼。
那麼我們在程式裡是怎麼處理各種不同的輸入和輸出呢?
最常用的方法就是,把輸入字串解碼成Unicode字串,如此一來就可以在程式裡方便地處理字串,在輸出時再編碼成需要的輸出字串。
那要怎麼存Unicode字串呢?C和C++都提供了wchar_t來存寬字元,你可以用它來存放Unicode化過的字元。但是有趣的地方也在這裡,Windows和其他系統的wchar_t的寬度是不一樣的,Windows是2 bytes,Linux等是4 bytes,因此在Windows上你可能要選擇UTF-16,而在Linux上要用UCS4。
這還不是最糟糕的。
Linux的系統函式都沒有提供wchar_t的版本,因為現在系統上的編碼都是用UTF-8,就算用locale的編碼也不會漏失字元。
但是Windows就提供了另一套w開頭的API,以提供wchar_t的版本,同時系統函式分成兩系,一是W結尾,使用wchar_t,一是A結尾,使用char,而且要編成本地編碼。
於是當某個你碰不到的程式碼內部使用fopen時,在Windows上你一點辦法都沒有,根本不能讀取non-ascii的路徑。

2009年2月8日 星期日

Khopper v0.0 RC released

改版訊息:
  • 修正輸出路徑在使用一個以上專輯時的錯誤
  • 在歌曲清單上的編輯將會反應到轉出的檔案上
  • 增加專輯資訊
  • 輸出格式設定改為跳出式視窗
  • 輸出檔名設定移至選單內
  • 轉檔鍵移至右鍵選單內,並增加熱鍵(Ctrl+Enter)
  • 轉檔進度條介面改善
  • 其他介面細微修改
套件改變:
  • 新增系統選單
如果沒什麼bug的話,這就會是最後的釋出版了。現在只有一個問題--如果不能保證MP3的VBR編碼是正確的,那麼恐怕我必須把它先拿掉。
另外一點很遺憾的是,依然沒有圖示;我可能要自己亂畫一個...

2009年2月6日 星期五

Choise of byte array container

最近需要在函式回傳一個容納二進位資料的陣列,以供C的函式庫使用,因此它最好是在儲存空間上連續,在頭尾加入或刪除資料很快速[?],並且可以隨機存取。
我第一個想到的是std::string。它是一個底部連續的容器,支援隨機存取,可快速在尾端插入或刪除元素,甚至提供了data()函式取得底部資料,似乎很完美。不過我顧慮的有兩點,一是結束字元的判斷--它會不會把'\0'當成字串結束就打亂了字串狀態呢?二是它多了一些其實不需要的字串處理介面。
那麼std::vector怎麼樣?它具有std::string的所有優點,而沒有它的缺點,似乎是個不錯的選擇。要說它唯一缺點就是,在開頭插入或刪除元素的速度很慢。
那麼再看看其他的容器吧,也許std::list?它在頭尾插入很快--事實上它在任何一點都很快,不過它有其他的缺點--它的底部不連續,這讓你要以陣列方式傳給C函式時需要額外的手續。另外不支援隨機存取也會多一些麻煩,以及比較不明顯的問題....list node空間佔用。如果應用並不需要時常存取整段資料,應該會是個好選擇。
到這裡只剩下一個不太常看到的標準容器了--std::deque。它可以隨機存取,在頭尾可以很快速地新增或移除元素,只是它不保證底部會連續儲存。看起來好像是std::vector加上std::list再取平均的特性。
目前我的選擇是std::deque,因為我覺得在大量資料的操作下,std::list似乎會比較慢。實際上可能還要看實作吧。

2009年2月5日 星期四

Khopper v0.0 beta released

改版訊息:
  • 修正編譯錯誤
  • 現在可以刪除歌曲清單了
  • 如果沒有選取音軌會出現警告
  • 加入ID3 tag的寫入功能
  • 改善輸出路徑的操作
  • 加入輸出檔名的自訂功能
  • 加入編碼預覽功能
套件包目前只有i386版,amd64可能會在下一版釋出。Bug可能很多,歡迎回報錯誤。

2009年2月3日 星期二

Khopper v0.0 alpha released

功能:音樂轉檔
簡介:讀入cue,任選幾首歌,點選fire即可轉出音樂,目前只實作MP3。
未來計劃功能:ID3 tag寫入,更多輸出輸入格式支援,播放功能。
一開始的畫面會像這樣:
初始畫面
可以使用File -> Open... 開啟*.cue檔案,或是直接用拖拉的方式開啟,會先出現選擇文字編碼的對話框:
選擇文字編碼
選擇完畢後即會出現該張專輯的內容,如果內容是正確的話:
讀取完畢
之後選擇想要的歌曲(使用ctrl+左鍵選擇複數),按下Fire即可轉檔:
進度顯示
檔名會使用歌曲的標題。

2009年1月15日 星期四

LGPL license option added to Qt

長久使用QPL和GPL雙授權的Qt,在4.5之後要增加LGPL了。
由於GPL具有感染性,使用GPL構件的產品也必須以GPL釋出,因此相較於LGPL授權的Gtk+來說,較為不受商業軟體歡迎[?]。題外話,C和C++的header由於有GPL例外條款,使用標準函式庫不會受到GPL限制。
有趣的是,雖然很多人都在歌頌自由的美好,到處找免費開源的函式庫使用,但是自己寫出來的成品卻很少回饋出來。當然我知道自由的用意,也知道智財有其保護的必要,就是心裡有點不是滋味就是了。

2009年1月12日 星期一

SVG版俄羅斯方塊

其實也就是SVG裡內嵌script而已,不過我還真沒想過可以這樣子搞。