2011年11月21日 星期一

Ubuntu 11.10 繁體中文全新安裝後手動修正問題

共同的部份

1. 系統語言變數設定錯誤
直接修改 /etc/default/locale 內容改成
LANG="zh_TW.UTF-8"
LANGUAGE="zh_TW:en"
然後再執行
$ sudo update-grub
2. fontconfig 字型設定錯誤
正常的設定會是以下的結果
$ fontconfig-voodoo -c
Current config: zh_TW
如果不正常就執行以下命令修正
$ sudo fontconfig-voodoo -a
修正完畢後,重新開機應該就會正常了。

Xubuntu 11.10

1. ibus 導致程式崩潰的問題
$ sudo apt-get install ibus-gtk ibus-gtk3
$ cd /usr/lib/gtk-2.0/2.10.0/
$ sudo ln -s /usr/lib/i386-linux-gnu/gtk-2.0/2.10.0/immodules
如果是使用 AMD64
$ sudo ln -s /usr/lib/x86_64-linux-gnu/gtk-2.0/2.10.0/immodules

2011年11月20日 星期日

在 Sony Ericsson Xperia™ X8 刷 MiniCM7

MiniCM 是一個特別為 Sony Ericsson Xperia™  X10 mini / X8 製作 Android 的 CyanogenMod 客製化的計畫



以下是筆者的安裝步驟筆記,自行刷客製的 Android ROM 有一定的風險,請讀者自行負擔風險,筆者不擔保過程中發生的問題。
  1. 首先需要在 Windows 下載安裝 Sony Ericsson PC Companion 2.0 用來升級跟還原出廠預設版本(安裝過程中有任何問題都可以還原手機上的系統)
  2. 如果 [設定] -> [關於手機] 裡面的 [基頻版本] 不是 015 結尾的話,需要下載 Baseband 015 的 firmware 回來使用 Flashtool 來更新,然後重新啟動手機
  3. 在 Windows 上面安裝使用 SuperOneClick 來取得手機上的 root 權限,然後重新啟動手機
  4. 利用 Android Market 安裝 Apk Installer 用來安裝 Root Explorer,然後重新啟動手機
  5. 然後再將 Xrecovery.zip 裡面的三個檔案利用 Root Explorer 複製到手機系統裡的 /system/bin 底下
  6. 重新啟動系統,看見手機畫面上出現 Sony Ericsson 字樣時不斷地連擊手機上的 Back 鍵,順利的話就可以進入 Xrecovery
  7. 在 Xrecovery 裡面安裝 MiniCM7-2.0.7-X8.zip 跟 gapps-gb-20110828-signed.zip,然後再執行 factory reset 再重新啟動手機就大功告成啦!^o^

PS. 筆者所使用的手機型號是 X8i(E15i)

2011年9月26日 星期一

在 Ubuntu 10.10 上修正 NVidia 的 HDMI audio 支援問題

首先要裝上 ppa:fourdollars/nvidia 上面的 nvidia proprietary driver
還要裝上 ppa:diwic/dkms 上面的 alsa-hda-dkms
還要裝上 ppa:ubuntu-audio-dev/ppa 上面的 pulseaudio
然後重新啟動
接下來看看 HDMI 接在哪裡
$ for i in /proc/asound/NVidia/eld*; do echo "<<$i>>"; cat $i; done
<</proc/asound/NVidia/eld#0.0>>
monitor_present		0
eld_valid		0
<</proc/asound/NVidia/eld#1.0>>
monitor_present		1
eld_valid		1
monitor_name		CHIMEI 22SH-L
connection_type		HDMI
eld_version		[0x2] CEA-861D or below
edid_version		[0x3] CEA-861-B, C or D
manufacture_id		0x73b
product_id		0x2d22
port_id			0x10000
support_hdcp		0
support_ai		0
audio_sync_delay	0
speakers		[0x1] FL/FR
sad_count		1
sad0_coding_type	[0x1] LPCM
sad0_channels		2
sad0_rates		[0xe0] 44100 48000 88200
sad0_bits		[0xe0000] 16 20 24
<</proc/asound/NVidia/eld#2.0>>
monitor_present		0
eld_valid		0
<</proc/asound/NVidia/eld#3.0>>
monitor_present		0
eld_valid		0
從上面的紀錄可以看出在 /proc/asound/NVidia/eld#1.0 上面
不過可能會看到都是靜音的狀態
$ amixer -D hw:NVidia
Simple mixer control 'IEC958',0
  Capabilities: pswitch pswitch-joined penum
  Playback channels: Mono
  Mono: Playback [off]
Simple mixer control 'IEC958',1
  Capabilities: pswitch pswitch-joined penum
  Playback channels: Mono
  Mono: Playback [off]
Simple mixer control 'IEC958',2
  Capabilities: pswitch pswitch-joined penum
  Playback channels: Mono
  Mono: Playback [off]
Simple mixer control 'IEC958',3
  Capabilities: pswitch pswitch-joined penum
  Playback channels: Mono
  Mono: Playback [off]
就可以執行
$ alsamixer -D hw:NVidia
在 CUI 設定畫面中全部取消靜音,接下來執行
$ pasuspender -- speaker-test -D hdmi:NVidia,1 -c 2 -t sine -l 1
應該就可以聽到聲音了,確定裝置之後就可以修改 /usr/share/pulseaudio/alsa-mixer/profile-sets/default.conf 當中的
[Mapping hdmi-stereo]
device-strings = hdmi:%f
channel-map = left,right
priority = 4
direction = output
改成
[Mapping hdmi-stereo]
device-strings = hdmi:%f,1
channel-map = left,right
priority = 4
direction = output
再重新啟動後應該就可以聽到 HDMI audio 的聲音了。

其它幫助除錯的方法還有

2011年8月31日 星期三

Project Euler - Problem 12

昨天在 TOSSUG 聚會上 Choupi 提到這個問題 Project Euler - Problem 12 於是就寫了以下的 Vala 程式碼來解這個問題
void main()
{
    int i = 0, number = 0;
    // 用來儲存質數分解的結果
    HashTable<string, int*> factors = null;

    do {
        // 逐個取出三角數
        number = triangle_number(++i);
        // 算出所有因數的個數直到比 500 還要大為止
    } while (factor_number_of(number, out factors) < 500);

    // 把算出來的答案印出來
    stdout.printf("Answer: %d\n", number);

    // 將答案驗算一遍
    print_factors(factors);
}

void print_factors(HashTable<string, int*> factors)
{
    int number = 1;

    List<unowned string> keys = factors.get_keys();
    // 把質因數表的鍵值依照數值大小重新排序
    keys.sort( (a, b) => {
        int num1 = int.parse(a);
        int num2 = int.parse(b);
        if (num1 < num2 ) {
            return -1;
        }
        else if (num1 > num2) {
            return 1;
        }
        else {
            return 0;
        }
    });

    // 驗算過程
    foreach (unowned string key in keys) {
        int* count = (int*) factors.lookup(key);
        int prime = int.parse(key);
        if (*count > 1) {
            stdout.printf("%d^%d*", prime, *count);
        }
        else {
            stdout.printf("%d*", prime);
        }
        // 重覆乘上質因數出現的次數
        for (int i = 0; i < *count; i++) {
            number = number * prime;
        }
        free(count);
    }

    stdout.printf("\b=%d\n", number);
}

// 三角數的計算
int triangle_number(int num)
{
    return num * (num + 1) / 2;
}

// 找出某數值的質因數分解
int factor_number_of(int number, out HashTable<string, int*> table)
{
    table = new HashTable<string, int*>(str_hash, str_equal);
    do {
        // 找出該數值的平方根
        int root = sqrt_floor_of(number);
        int previous = number;

        // 從小到大用質因數去整除直到超過平方根
        for (int i = 0; prime_number_of(i) <= root; i++) {
            int prime = prime_number_of(i);
            if (number % prime == 0) {
                // 遞增質因數表的數值
                int* count = (int*) table.lookup(prime.to_string()) ?? malloc0(sizeof(int));
                *count = *count + 1;
                table.replace(prime.to_string(), count);
                number = number / prime;
                break;
            }
        }

        // 如果 number 沒有變動過,number 就是質數。
        if (number == previous) {
            // 遞增質因數表的數值
            int* count = (int*) table.lookup(number.to_string()) ?? malloc0(sizeof(int));
            *count = *count + 1;
            table.replace(number.to_string(), count);
            break;
        }
    } while (number != 1);

    int result = 1;

    // 計算所有因數的個數
    foreach (int* count in table.get_values()) {
        result = result * (*count + 1);
    }

    return result;
}

// 計算平方根
int sqrt_floor_of(int num)
{
    return (int) Math.sqrt((double) num);
}

// 準備一個用來 cache 計算過的質數表
static List<int> prime_table = new List<int>();

// 質數計算
int prime_number_of(uint index)
{
    if (index < prime_table.length()) {
        // 直接從 cache 中取出
        return prime_table.nth_data(index);
    }

    // 第一個質數為 2
    if (index == 0) {
        prime_table.append(2);
        return 2;
    }
    // 第二個質數為 3
    else if (index == 1) {
        prime_table.append(3);
        return 3;
    }
    // 第三個後的質數計算
    else {
        int candidate = prime_table.nth_data(prime_table.length() - 1) + 2;
        do {
            bool is_prime = true;
            foreach (int number in prime_table) {
                if (candidate % number == 0) {
                    is_prime = false;
                    break;
                }
            }
            if (is_prime) {
                prime_table.append(candidate);
                return candidate;
            }
            candidate = candidate + 2;
        } while (true);
    }
}
將以上程式碼儲存成 p12.vala 或是直接從 gist: 1182715 下載 然後編譯執行
$ valac p12.vala -X -lm && ./p12
Answer: 76576500
2^2*3^2*5^3*7*11*13*17=76576500

2011年7月24日 星期日

關於 uptime 的一些小事

在 GNU/Linux 系統底下如果想要知道電腦開機後使用了多久的時間,可以直接打指令:
$ uptime
 22:35:06 up  6:26,  4 users,  load average: 0.00, 0.03, 0.05
或是利用 /proc/uptime 來取得資料:
$ cat /proc/uptime 
23282.04 41316.79
但是如果想要寫 C 程式來取得資料呢?
我找到一個在 <time.h> 裡面的函式 clock_gettime()
程式碼如下:
#include <stdio.h>
#include <time.h>

int main(int argc, char* argv[])
{
    struct timespec ts;
    if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
        printf("%ld.%ld\n", ts.tv_sec, ts.tv_nsec);
    }
    return 0;                                      
}
在編譯的時候要加上 -lrt 才能通過編譯
$ gcc -Wall -g -lrt uptime.c -o uptime
執行的結果
$ ./uptime 
23637.821285555
因為我想要在 XWindow 底下根據當下的開機時間,製造出新的 XKeyEvent 出來,而所有的 XEvent 都是使用毫秒的時間格式 (ex. 23637821),所以才去找出這個的函式來用。
詳細的使用說明可以看 manpage
$ man clock_gettime

2011年7月12日 星期二

使用 pbuilder-dist/cowbuilder-dist 協助編譯及打包 Debian package

在 Debian/Ubuntu 上面寫好程式並且打包成 Debian source package 之後,可以藉由 Launchpad 上的 PPA 服務來編譯打包成 Debian binary package 給 Ubuntu 的使用者使用,但是在 Debian 這邊目前還沒有像是 PPA 這樣的服務可以使用 (不過Debian 官方已經有計劃要做了),於是現在就只能使用 pbuilder/cowbuilder 這樣工具來建立一個乾境的 chroot 環境來編譯打包 Debian binary package 給 Debian 的使用者使用。

最近發現在 ubuntu-dev-tools 裡面有 pbuilder-dist/cowbuilder-dist 這樣方便的工具,可以透過幾個簡單的指令就完成複雜的動作,雖然它的名稱叫做 ubuntu-dev-tools 其實它也是存在 Debian 官方套件庫裡面可以直接安裝來使用。

例如在 Ubuntu 11.04 (amd64) 底下想要建立 Debian 6.0 squeeze (i386) 的 chroot 環境就可以使用以下的指令:
$ pbuilder-dist stable i386 create

接下來要利用這個環境編譯 Debian 6.0 squeeze (i386) 底下使用的 pcmanx-gtk2,所以要執行以下的指令:
$ pbuilder-dist stable i386 build pcmanx-gtk2_1.0-svn577-1~squeeze1.dsc

最後就可以在 ~/pbuilder/stable-i386_result/ 底下看到編譯好的 pcmanx-gtk2_1.0-svn577-1~squeeze1_i386.deb

當然上面的 stable 在 Ubuntu 底下可以代換成 natty,maverick,lucid,... (如果是要編譯打包 Ubuntu 發行套件) 或是 testing, unstable, experimental (如果是要編譯打包 Debian 發行套件);另外就是 i386 可以代換成 amd64 如果搭配 qemubuilder 也許還可以編譯打包出 arm, mipsel, ... 其它 CPU 架構底下的套件出來使用。

此次編譯出來給 Debian 6.0 squeeze i386/amd64 使用的 pcmanx-gtk2 放在 http://archive.sylee.org/deb/ 底下。

參考文件:https://wiki.ubuntu.com/PbuilderHowto

2011年6月8日 星期三

Ubuntu 11.04 的外接顯示模式切換

在接上外接螢幕後,系統會自動切換到第一順位的狀態,也就是主要顯示為外接螢幕,而次要顯示變成筆記電腦本身的螢幕。

Ubuntu 傳統桌面
順位 主要顯示 (left) 次要顯示 (right)
1 External Laptop
2 Mirror
3 Laptop External
4 Laptop only
5 External only

在按下 WIN + P 或顯示切換的功能鍵之後,在正常的情況下,會依照 1 => 2 => 3 => 4 => 5 => 1 => ... 的順序切換顯示模式。

Unity 2D
順位 主要顯示 (left) 次要顯示 (right)
1 Laptop External
2 Mirror
3 Laptop only
4 External only

Unity 不要問,很恐怖,現在還會是當掉。