ubuntu natty(11.04) 日本語環境での文字入力のための設定

Acer AspireOne AO753にUSBメモリからUbuntu nattyを入れる - ラシウラでAO753にいれたubuntu natty(amd64)をいれたけど、ここにはAO753関係のことだけ記述しました。

以下はハードに依存しない部分での、nattyで行った個人向けの設定です。デスクトップはUnity日本語環境で、そこでの文字入力における難点を解決しています。

  • 64bit版 flashplayerとfirefox上のflashでのASCII入力を可能にする設定
  • ibus-mozcと変換/無変換によるIMのON/OFF設定
  • ibusのトグルをCtrl+Alt+Shift+スペースキーに変える
  • F10によるメニューへのフォーカス移動の抑制
  • ibus-elによるemacs上でibus入力を可能にする設定

システムのアップデートを妨害しないよう、カスタマイズを最小化するポリシーの上で、日本語環境での文字入力の難点の解消を行っています。

64bit版 flashplayerとfirefox上のflashでのASCII入力を可能にする設定

amd64上での32版flashplayerは文字入力に難があります。64版flashplayerではありませんでした。
https://launchpad.net/~sevenmachines/+archive/flashのppaを使いました。

ルートで、

# add-apt-repository ppa:sevenmachines/flash 
# apt-get update
# apt-get install flashplugin64-installer
現状のfirefox上で、flash上の文字入力をできるようにする

パッケージをいれただけではfirefoxflashでは、ibusで入力できてもASCII入力ができません。以下、その対策です。

firefoxの"about:config"を開き、右クリックのメニューから"新規作成"-"真偽値"を選び、

  • "設定名"をdom.ipc.plugins.enabled.libflashplayer.so、 値をfalse

で作ります。
firefoxを再起動させればASCII入力もできるようになります。

(目玉のプロセス分離を無効にしてしまうので、将来不要になることを期待します)

ibus-mozcと変換/無変換によるIMのON/OFF設定

ibus-mozcのインストール
# apt-get install ibus-mozc mozc-utils-gui ibus-qt4
ibus-mozcの設定

左上のキーボードアイコンの右クリックメニューから"設定"でibus設定ダイアログを開きます。

  • "一般"タブ: "言語パネルの表示"のドロップダウンリストを常に表示するに変えます。
    • "切り替え"で、"..."ボタンを押しダイアログを開き、"Control-space"を選び、"モディファイア"チェックボックス"Control"、"Shift"、"Alt"にチェックを入れ、"適用"ボタンを押す。
  • "インプットメソッド"タブ: "インプットメソッドの選択"ドロップダウンリストで"日本語"-Mozcを選び、"追加"ボタンを押します。リストから"日本語 - Anthy"を選び、"削除"ボタンを押します。
  • (オプション) "詳細"タブ: "すべてのアプリケーション間で同じインプットメソッドを共有する"にチェックを入れる。

ダイアログを閉じ、再び左上のキーボードアイコンの右クリックメニューから"再起動"を選べば、全角半角キーもしくはCtrl+Alt+Shift+スペースキーでmozcが立ち上がり、画面上にMozcのバーが表示されます。

変換キー/無変換キーでのインプットメソッドのOn/Offを可能にする

(mac上のことえり風のOn/Off設定です。ただし、ibus自体は立ち上げたままであり、ASCIIモードと平仮名モードを切り替えるようになります。そのため、"すべてのアプリケーション間で同じインプットメソッドを共有する"によって、各ウインドウ上で最初からibusはonの状態になるようにしています)

その言語バー上で、スパナアイコンをクリックし、"Property"を選べば、Mozcプロパティダイアログが開きます。そこから"一般"タブ、キー設定の"キー設定の選択"で、"カスタム"を選び"編集"ボタンを押し、"Mozcキー設定"ダイアログを開きます。

"編集"ドロップダウンから、"定義済みのキーマップからインポート"-"ことえり"(もしくは"MS-IME")を選びます。
そのあとで再び"編集"から"エクスポート"を選び、適当な"名前"(例: mozc.cfg)を付けて"保存"します。

保存したファイルに以下の2行を追加して上書き保存します。

DirectInput	Henkan	IMEOn
Precomposition	MuHenkan	IMEOff

ファイル編集後、"Mozcキー設定"ダイアログの"編集"から"インポート"を選び、上書きOK?の警告がでるのをスルーし、編集したファイルを開き、読み込ませます。読み込んだら"OK"ボタンダイアログを閉じていきます。

この後、ibus起動中は、"変換"キーでひらがな入力モード、"無変換"キーでASCII入力モードになります(ログイン後に初回だけは、Ctrl+スペースによるibus起動は必要)。

F10によるメニューへのフォーカス移動の抑制

ASCII化キーとしてのF10を使う場合、UnityがF10キーをとってしまうのを避ける必要があります。

# apt-get install compizconfig-settings-manager

"ccsm"コマンドがインストールされます。

ccsmを起動するとダイアログがでます。"デスクトップ"部の"Ubuntu Unity Plugin"をクリックします。"Key to open the first panel menu"が"F10"になっています。このボタンをクリックし、開いたダイアログで"Shift"を押し、"OK"すれば、ボタンが"F10"となります。

最ログインしたあとは、F10キーでメニューにフォーカスが行かなくなります。

ibus-elによるemacs上でibus入力を可能にする設定

emacsのインストール
# apt-get install emacs

GUIemacsはデフォルトでibusが効かないようで、その対策としてibus.el in Launchpadをいれ、設定をします。

ibus-elのインストール
# add-apt-repository ppa:irie/elisp
# apt-get update
# apt-get install ibus-el
ibus.elの有効化

まず、~/.Xresourcesファイルを以下の内容で保存し、再ログインします。

Emacs*useXIM: false

次に~/.emacsで以下の記述を先頭にいれます。

(require 'ibus)
(add-hook 'after-init-hook 'ibus-mode-on)
(ibus-define-common-key [?\C-\s ?\C-/] nil)
(setq ibus-cursor-color '("red" . "blue"))
(global-set-key [?\C-\M-\S- ] 'ibus-toggle)

これによって、emacs上でも他と同じようにibus入力が機能します。

その他.emacsに書いている基本設定
(setq x-select-enable-clipboard t)
(setq interprogram-paste-function 'x-cut-buffer-or-selection-value)

(setq inhibit-startup-message t)
(setq indent-tabs-mode nil)
(setq make-backup-files nil)
(column-number-mode t)

(cua-mode t)
(setq dabbrev-case-fold-search t)
(setq dabbrev-case-replace t)

(require 'font-lock)
(global-font-lock-mode t)

一番上の2行はemacs上でデスクトップクリップボードを使ったコピーペーストを可能にするものです。

おまけ: gcc-4.6のppa

gccgoが統合されたgcc4.6のppaは、Toolchain test builds : “PPA for Ubuntu Toolchain Uploads (restricted)” teamにあります。

# add-apt-repository ppa:ubuntu-toolchain-r/test
# apt-get update
# apt-get dist-upgrade

あとはaptitude等でgcc4.6系パッケージを選んでいけばよいでしょう。

Acer AspireOne AO753にUSBメモリからUbuntu nattyを入れる

AO753を買った当時、Ubuntu 10.10ではネットワークデバイスが使えなかったりグラフィックが対応してなかったりとで諦めていたのですが、今度出るUbuntu 11.04(natty)ではAO753でも動くようになっています。

そこで改めて、Ubuntu natty beta2をインストールしてみました。インストーラ用にUSBメモリを使います。

用意するもの:

  • AO753
  • 空のUSBメモリ16GB(4GBでは無理、8GBはたぶんOK)

(本当はwubi上のubuntuからインストールできるのがいいのですが...)

ざっと手順は、以下のとおり:

事前準備(インストール領域の確保)

AO753でubuntuを入れるためのディスク領域を確保しておきます。(仮想マシンを作るとき、大きくディスクを使うので先に領域確保しておきました)

「コントロールパネル」の「管理ツール」を開き、さらに「コンピュータの管理」を開きます。左のツリーから「ディスクの管理」を選ぶと、ディスク0のC:をクリックし、右クリックで「ボリュームの縮小」を選びます。

「縮小する領域のサイズ」にUbuntuで使うサイズ(MB)を指定します。約半分の150000MB程確保しました。

VirtualBox上のUbuntuでUSBインストーラをつくるまで

AO753はunetbootinで作ったインストーラは起動できませんでした。
しかし、Ubuntuの「スタートアップ・ディスク作成」で作ったUSBインストーラは起動させることができました。

USBインストーラUbuntuがあれば作れます。Windows7VirtualBoxを入れ、まずVMUbuntu natty beta2を入れ、そこからUSBを差してUSBインストーラを作りました。

VirtualBoxのインストール

以下で、VrtualBoxのWindows版とExtension Packをダウンロードし、インストールします。

VirtualBoxをインストールしたあとに、Extension Packのファイルをダブルクリックすれば、VirtualBoxにインストールされます。

仮想マシンUbuntuのインストール

Ubuntuインストーラisoをダウンロードします。

VirtualBox管理パネルを起動し、「新規」で仮想マシン設定を作ります。Linux/Ubuntu(64bit)を選び、インストール用の仮想ディスクは10GB程度で作成します。

作った仮想マシン設定を選び「設定」で開き、左の「ストレージ」を選び、「IDEコントローラ」の右の「+」(CD/DVDデバイスの追加)を選び、インストーラのisoを選びます。

設定を閉じ、仮想マシンを起動し、Ubuntuをインストールします。
インストールではディスクの全領域を使っていれて構いません。

スタートアップディスクの作成

インストール後、仮想マシンを一旦停止し、USBメモリをPCに差し込みます。

VirtualBoxの「設定」の「ストレージ」からインストール用に追加していたisoを選び、下の「-」(割り当ての除去)を押して外します。
そして、左の「USB」を選び、「USB2.0(EHCI)コントローラを有効化」にチェックを入れ、左の「+」(デバイスからフィルタを追加する)から差し込んだUSBメモリを選び、チェックが入った状態にします。

設定後、仮想マシンを起動させます。起動後、ログインすると、デスクトップに差してあるUSBメモリが見えているはずです。

まず仮想マシン上でブラウザを開き、同じようにUbuntuインストーラをisoをダウンロードします。

ダウンロード後、(Ubuntu Classicセッションの)デスクトップの上メニューから、「システム」-「システム管理」-「スタートアップ・ディスクの作成」を選び、起動します。

  • 「その他」ボタンを押し、ダウンロードしたisoを選びます。
  • /dev/sdc1 (16GB)を選び、「ディスクの消去」を押します。
  • 確保する領域(最大4GB)を設定します。
  • 「スタートアップ・ディスクの作成」を押します。

作り終わったら仮想マシンを止め、PCも電源を落とします。

USBからインストール

USBメモリを刺したまま、電源を入れます。すぐ「F12」キーを押せば、ブートセレクト画面になります。そこでUSBメモリを選び、インストーラをブートさせます。

カスタムでパーティションを切りました。空き領域のうち、4096MiB(sda5)をスワップ領域にし、残りすべてをext4にしてそのマウントポイントを「/」に指定しました。また/dev/sdaにブートローダーを入れるようにしました。

あとは同じようにインストールしていきます。

インストール後、AO753のWiFiを使えるようにする

インストール直後の設定では、WiFiが使えないようになっています。以下はWiFiを使えるようにするための手続きです。

(Unity)デスクトップで、左のバーで虫眼鏡+のアイコンを選び、上のアプリケーションの検索に"ter"と打つと出てくる「端末」を開きます。

その端末で"sudo gedit /etc/modprobe.d/blacklist.conf"を実行し、いちばんうしろに以下の行を追加して保存(Ctrl+S)します:

blacklist acer-wmi

Ubuntuを再起動すれば、無線LANを使えるようになります。
上のバーのネットワークアイコンをクリックしたメニューから「無線を有効にする」を選べば、SSIDが見えるようになります。

HTML5 Canvasにベジエでトランプのマークを書くJS

ベジエの例は、ハートマーク以外はあまりみないのでスペードやクローバーも書いてみました。HTML5 canvas 2dの場合、Text APIUnicodeの♡♢♤♧をつかうという手もありますね。

図形データは、各ベジエ曲線[始点, 始点の制御点, 終点の制御点, 終点]の配列で半分だけ用意し、連続で書くようにしています。連続描画させるので終点と次の始点は同じになります。

遺伝的アルゴリズムを書いてみる

hackernewsのリンク記事でに、Genetic Algorithm(遺伝的アルゴリズム)をJavaScriptで書いた

ってのを見たのですが、ソースがわけわからなかったので*1、理解するため、遺伝的アルゴリズムってのを調べて自分で書いてみました。

まず、Wikipediaをみたのですが、日本語と英語の記事に載せてある手続きが違うんですよね。

日本語版では交叉と突然変異は「どちらか」と書いてあるんですが、英語版は交叉したあと突然変異させるというようになってます。で、他のサイトをみると、どうも英語版の手続きが基本のようです。

手続きもすごく短い。簡単に言うと「繰り返し、適当に近そうな奴を選んで混ぜてみたり、たまにちょっとずらしたりしてみてテストさせる」、ってことのようで、遺伝うんぬんとは無関係に、普通に正解探しをやってるのと変わらない気もする。

ということで、それをそのままフレームワーク化したのが、GeneticAlgorithmクラスです。

class GeneticAlgorithm(object):
    def __init__(self, genetics):
        self.genetics = genetics
        pass

    def run(self):
        population = self.genetics.initial()
        while True:
            fits_pops = [(self.genetics.fitness(ch),  ch) for ch in population]
            if self.genetics.check_stop(fits_pops): break
            population = self.next(fits_pops)
            pass
        return population

    def next(self, fits):
        parents_generator = self.genetics.parents(fits)
        size = len(fits)
        nexts = []
        while len(nexts) < size:
            parents = next(parents_generator)
            cross = random.random() < self.genetics.probability_crossover()
            children = self.genetics.crossover(parents) if cross else parents
            for ch in children:
                mutate = random.random() < self.genetics.probability_mutation()
                nexts.append(self.genetics.mutation(ch) if mutate else ch)
                pass
            pass
        return nexts[0:size]
    pass

で、この中で使っている、initial()、fitness(chromo)、parents(pop)、crossover(parents)、mutation(chromo)などを、問題をこのアルゴリズムに合うようにエンコードし、各種戦術を選んで実装し、与えてあげれば計算してくれることになります。

選択や交叉、変異での戦術のほうは典型的なものから選べばいいので、結局重要なのは、「解きたい問題をどうエンコードするか」、であると思います。(でも、これについても英語版Wikipediaにはナップサック問題ではどうするかについて書いてあるけど、日本語版には戦術のバリエーションばかりでエンコードについての言及が一つもない状態だったりします。)

で、例の記事の問題は与えたテキストをGAで推測するもので、それをこのクラスでつかえるようにしたのが、以下です。

    class GuessText(GeneticFunctions):
        def __init__(self, target_text,
                     limit=200, size=400,
                     prob_crossover=0.9, prob_mutation=0.2):
            self.target = self.text2chromo(target_text)
            self.counter = 0

            self.limit = limit
            self.size = size
            self.prob_crossover = prob_crossover
            self.prob_mutation = prob_mutation
            pass

        # GeneticFunctions interface impls
        def probability_crossover(self):
            return self.prob_crossover

        def probability_mutation(self):
            return self.prob_mutation

        def initial(self):
            return [self.random_chromo() for j in range(self.size)]

        def fitness(self, chromo):
            # larger is better, matched == 0
            return -sum(abs(c - t) for c, t in zip(chromo, self.target))

        def check_stop(self, fits_populations):
            self.counter += 1
            if self.counter % 10 == 0:
                best_match = list(sorted(fits_populations))[-1][1]
                fits = [f for f, ch in fits_populations]
                best = max(fits)
                worst = min(fits)
                ave = sum(fits) / len(fits)
                print(
                    "[G %3d] score=(%4d, %4d, %4d): %r" %
                    (self.counter, best, ave, worst,
                     self.chromo2text(best_match)))
                pass
            return self.counter >= self.limit

        def parents(self, fits_populations):
            while True:
                father = self.tournament(fits_populations)
                mother = self.tournament(fits_populations)
                yield (father, mother)
                pass
            pass

        def crossover(self, parents):
            father, mother = parents
            index1 = random.randint(1, len(self.target) - 2)
            index2 = random.randint(1, len(self.target) - 2)
            if index1 > index2: index1, index2 = index2, index1
            child1 = father[:index1] + mother[index1:index2] + father[index2:]
            child2 = mother[:index1] + father[index1:index2] + mother[index2:]
            return (child1, child2)

        def mutation(self, chromosome):
            index = random.randint(0, len(self.target) - 1)
            vary = random.randint(-5, 5)
            mutated = list(chromosome)
            mutated[index] += vary
            return mutated

        # internals
        def tournament(self, fits_populations):
            alicef, alice = self.select_random(fits_populations)
            bobf, bob = self.select_random(fits_populations)
            return alice if alicef > bobf else bob

        def select_random(self, fits_populations):
            return fits_populations[random.randint(0, len(fits_populations)-1)]

        def text2chromo(self, text):
            return [ord(ch) for ch in text]
        def chromo2text(self, chromo):
            return "".join(chr(max(1, min(ch, 255))) for ch in chromo)

        def random_chromo(self):
            return [random.randint(1, 255) for i in range(len(self.target))]
        pass

呼び出し方は、以下のようにするだけ

GeneticAlgorithm(GuessText("Hello World!")).run()

結果は、このようになります。

$ python3 genetic.py
[G  10] score=(-136, -287, -503): 'BqSkp\x1aIri\x85|\x17'
[G  20] score=( -64,  -94, -136): 'Bfgkp\x1a`qwgu\x1b'
[G  30] score=( -39,  -54,  -71): 'Gekkp\x1aVqwku\x1e'
[G  40] score=( -25,  -32,  -44): 'Gflln\x1fVoskt\x1f'
[G  50] score=( -12,  -21,  -30): 'Gemkp Woskd\x1b'
[G  60] score=(  -4,  -10,  -19): 'Gfllo\x1fWorkd!'
[G  70] score=(  -1,   -3,   -9): 'Hello World '
[G  80] score=(   0,   -1,   -6): 'Hello World!'
[G  90] score=(   0,    0,   -8): 'Hello World!'
[G 100] score=(   0,    0,   -7): 'Hello World!'
[G 110] score=(   0,    0,   -8): 'Hello World!'
[G 120] score=(   0,    0,   -6): 'Hello World!'
[G 130] score=(   0,    0,  -12): 'Hello World!'
[G 140] score=(   0,    0,   -9): 'Hello World!'
[G 150] score=(   0,    0,   -9): 'Hello World!'
[G 160] score=(   0,    0,   -5): 'Hello World!'
[G 170] score=(   0,    0,   -8): 'Hello World!'
[G 180] score=(   0,    0,   -8): 'Hello World!'
[G 190] score=(   0,    0,   -6): 'Hello World!'
[G 200] score=(   0,    0,   -6): 'Hello World!'

一般的にはbetterを見つけるものだとは思うんですが、この例ではだいたい70回から130回程度で正解にたどり着くようです。

ソース全体

*1:人工知能とかの分野などは、エンジニアリング技術が弱くてソースが汚いのはよくあることだが

platexをやめてxelatexを使おう

以前、platexUTF-8コードで使うための記事 UTF8でLaTeX(pLaTeX)を使う方法 - ラシウラ出張所 - coders を書いたけど、これからはxetexのxelatexを使うようにします。xelatexだと、フォント設定だけで欧文のスタイル上でUTF-8日本語文章からPDFを生成できるようになっています。

xetexのインストール

  • Windows: platexの"TeXインストーラ3"を使っていれば自動で入ります
  • Windows: 欧文ベースのMiKTeX(2.9)でもxelatexが入っていて、インストールした状態のままで日本語も扱えます。こちらは欧米スタンダードなtex構成であり、外部ツールの対応も充実してオススメです。が、逆にascmac.styのような日本でよく使われるパッケージがないので、別の違和感があるかも。
  • ubuntu: 標準の texlive-xetex パッケージを追加します。

メイリオやMS明朝などのプラットフォーム固有のフォントが使えますが、texソースのプラットフォーム依存をなくすようにIPAフォントを使うほうがいいかもしれません。

Windowsは上記リンクから4種入りzipを取ってきてコントロールパネルのフォントからインストールすることでxetexからも使えるようになります。ubuntuはttf-ipafont-gothicとttf-ipafont-minchoパッケージが標準にあるので、それを追加します。

使い方

xelatexコマンドを使います。texファイルをxelatexコマンドに食わせると、(dviやpsではなく)直接PDFファイルが出来上がります

xelatex hello.tex

texソースはUTF-8で書き、欧文と同じスタイルを使います。ただし、和文フォントの設定が必要です。以下一番シンプルな例。

\documentclass{article}

\usepackage{xltxtra}
\setmainfont{IPAPMincho}
\setsansfont{IPAPGothic}
\setmonofont{IPAGothic}
\XeTeXlinebreaklocale "ja"

\begin{document}
こんにちは世界
\end{document}

\XeTeXlinebreaklocale "ja"がないと、空白がなければ長い文章を途中で折り返してくれなくなります。

和文書類向けのカスタマイズ

欧文文書のスタイルの上での日本語文章が乗るので、少し違和感があるかもしれません。たとえばjarticleなどと比べると余白が大きく感じてしまいます。
以下のように余白を調整すると、若干違和感も薄れるかも。

\documentclass[12pt,a4]{article}

\setlength{\textwidth}{17cm}
\setlength{\textheight}{24cm}
\setlength{\leftmargin}{-1cm}
\setlength{\topmargin}{-2cm}
\setlength{\oddsidemargin}{0cm}
\setlength{\evensidemargin}{0cm}

こういう応急処置ではなく、XeLaTeX で日本語する件について [電脳世界の奥底にて]の"よりよい日本語組版を目指して"のパッケージ群を使えば、日本語として見栄えのよい書類が出来るようです。

cygwin上でnodejsとnpmとCoffeeScriptなどをインストールする

(追記: nodejsのバージョンが0.2時代のやり方です。0.4.8でのやり方はnaveを使ったnode.jsインストールと、最近のnpmの使い方 - ラシウラに書きました)

(まとめ)コマンドラインJavaScript環境nodejsと、そのパッケージマネージャnpmをいれ、npmからスクリプト言語CoffeeScriptを入れる手順です。CoffeeScriptというのは、rubyベースでpython風味を付け足したような文法のJavaScript環境で動く言語です。以下すべてWindow7 Home Premium x64上で行っています。

nodejsのインストールの仕方は、Building node.js on cygwin (windows) · nodejs/node-v0.x-archive Wiki · GitHub にあり、結果的にこの手順で可能です。
注意点は以下:

  • リポジトリのheadはcygwin対応出来ていなかった。最新リリースバージョン(0.2.3)は大丈夫
  • pkg-configパッケージを入れるのを忘れない(openssl等それを使う他パッケージの依存関係では入らない)
  • python.exeでDLLエラーが出る場合は、cygwinを閉じたあと、スタートメニューの検索などからash.exeを開いてそこで"rebaseall"する
  • nodejsからの通信で/etc/resolv.confが必要cygwin上で、/etc/resolv.conf(nameserver 8.8.8.8)を作り、一旦cygwinをログアウトしてからnode.exeを実行する

make installで/usr/localを汚したくないので、以下のような配置にするようにしました

  • ~/.nodejs/bin/node.exe
  • ~/.nodejs/bin/npm
  • ~/.nodejs/share/man/...
  • ~/.node_libraries/...

事前準備

最新版のcygwinで以下のパッケージ(とその依存パッケージ)を入れます

  • gcc-g++
  • make
  • openssl
  • openssl-devel
  • pkg-config
  • zlib-devel
  • python
  • curl

(存在しなければ)/etc/resolv.conf(c:\cygwin\etc\resolv.conf)を作ります(これがないとnpmは動きません)

nameserver 8.8.8.8
nameserver 8.8.4.4

nodejsインストール

curl -O http://nodejs.org/dist/node-v0.2.3.tar.gz
tar zxf node-v0.2.3.tar.gz
cd node-v0.2.3
./configure --prefix=~/.nodejs
make
make install

./configureの結果は、以下の出力になるはずです

$ ./configure --prefix=~/.nodejs
Checking for program g++ or c++          : /usr/bin/g++
Checking for program cpp                 : /usr/bin/cpp
Checking for program ar                  : /usr/bin/ar
Checking for program ranlib              : /usr/bin/ranlib
Checking for g++                         : ok
Checking for program gcc or cc           : /usr/bin/gcc
Checking for program ar                  : /usr/bin/ar
Checking for program ranlib              : /usr/bin/ranlib
Checking for gcc                         : ok
Checking for library dl                  : yes
Checking for openssl                     : yes
Checking for library rt                  : yes
--- libeio ---
Checking for library pthread             : yes
Checking for function pthread_create     : yes
Checking for function pthread_atfork     : yes
Checking for futimes(2)                  : yes
Checking for readahead(2)                : no
Checking for fdatasync(2)                : yes
Checking for pread(2) and pwrite(2)      : yes
Checking for sendfile(2)                 : no
Checking for sync_file_range(2)          : no
--- libev ---
Checking for header sys/inotify.h        : not found
Checking for header sys/epoll.h          : not found
Checking for header port.h               : not found
Checking for header poll.h               : yes
Checking for function poll               : yes
Checking for header sys/event.h          : not found
Checking for header sys/queue.h          : yes
Checking for function kqueue             : not found
Checking for header sys/select.h         : yes
Checking for function select             : yes
Checking for header sys/eventfd.h        : not found
Checking for SYS_clock_gettime           : no
Checking for library rt                  : yes
Checking for function clock_gettime      : yes
Checking for function nanosleep          : yes
Checking for function ceil               : yes
Checking for fdatasync(2) with c++       : yes
'configure' finished successfully (21.674s)

cygwinのpkg-configが入っていなければ、"Checking for openssl"がnoとなるでしょう。
またconfigure実行中に、python.exeで"unable to remap 〜"といったDLLのエラーが出る場合があります。その場合はcygwinを閉じ、rebaseallコマンドをash上から実行すると治ります。

出来上がったnode.exeにPATHを通します。

export PATH=$PATH:~/.nodejs/bin

nodejs.orgのトップにあるexample.jsを実行して確認します。

npmインストール

(npmを入れるためには、nodejsから通信するために/etc/resolv.confが存在する必要があります。)
まず、~/.npmrcを作成します。

root = ~/.node_libraries
binroot = ~/.nodejs/bin
manroot = ~/.nodejs/share/man

rootの~/.node_libraries/は、node.exeがデフォルトでモジュールを読み込むPATHです(0.3では~/.node_modulesも読み込むようになってます)。
それ以外にnpm root置く場合、環境変数NODE_PATHでそこを指定する必要があります。


~/.npmrcをつくったら、以下のコマンドを実行します:

curl http://npmjs.org/install.sh | sh
npm list stable

など実行し、npmコマンドの動作確認します。

CoffeeScriptのインストールとexample実行

npmからCoffeeScriptインストール

npm install coffee-script

coffeeコマンドなどがインストールされます。

以下のコードがnodejsのexample.jsのCoffeeScript版example.coffeeとなります

#!/usr/bin/env coffee
http = require "http"
server = http.createServer (req, res) ->
    res.writeHead 200, {"Content-Type": "text/plain"}
    res.end "Hello World\n"
server.listen 8124, "127.0.0.1"
console.log "Server running at http://127.0.0.1:8124/"

実行は、

coffee example.coffee

jisonインストールと利用

CoffeeScriptで使われてる、パーザーjisonを入れます。

npm install jison

jisonはコマンドラインから文法ファイルをJSに変換するパーザージェネレータですが、JSON形式の文法データを渡してパーザーとなるモジュールとしても使えるようにもなってます。

簡単なLISPインタプリタを、jisonをつかってCoffeeScript(0.9.4)で書いたものが以下です:

#!/usr/bin/env coffee
# for coffee 0.9.4
jison = require "jison"

grammar =
  "lex":
    "rules": [
      ["\\s+",          ""]
      ["\\(",           "return 'LPAREN'"]
      ["\\)",           "return 'RPAREN'"]
      ["\\d+",          "return 'NUMBER'"]
      ["[^\\s\\(\\)]+", "return 'SYMBOL'"]
      ["$",             "return 'EOF'"]
    ]
  "bnf":
    "program": [
      ["exprs EOF", "return $1"]
    ]
    "expr": [
      ["NUMBER", "$$ = parseInt(yytext)"]
      ["SYMBOL", "$$ = yytext"]
      ["LPAREN exprs RPAREN", "$$ = $2"]
    ]
    "exprs": [
      ["expr", "$$ = [$1]"],
      ["expr exprs", "$$ = [$1].concat($2)"]
    ]

lparser = new jison.Parser grammar
lget = (env, name) ->
  return env[name] if name of env
  return lget(env.__parent__, name) if "__parent__" of env
  undefined

leval = (env, expr) ->
  switch typeof expr
    when "number" then expr
    when "string" then lget env, expr
    when "object"
      switch expr[0]
        when "define"
          name = expr[1]
          value = leval env, expr[2]
          env[name] = value
        when "quote" then expr[1]
        when "lambda"
          parent = env
          params = expr[1]
          body = expr[2]
          ->
            frame = {}
            for i in [0...params.length]
              frame[params[i]] = arguments[i]
            frame.__parent__ = parent
            leval frame, body
        else
          [func, args...] = leval(env, e) for e in expr
          func args...

run = (env, code) ->
  trees = lparser.parse code
  #console.log trees
  for tree in trees
    leval env, tree

top =
  "+": (params...) -> params.reduce ((a, b) -> a + b), 0
  "*": (params...) -> params.reduce ((a, b) -> a * b), 1
  "write": console.log

# examples
run top, "(write (+ 10 20))"
run top, "(define sq (lambda (a) (* a a)))"
run top, "(write (sq 5))"

(ubuntu maverickにもnodejsやcoffeescriptパッケージがあるのですが、バージョンが古いのでこのコードは解釈できないでしょう)

ubuntuパッケージをlaunchpad ppaで公開する方法

以前から、バイナリパッケージであるpython-simplexqueryをlaunchpadの自分のPPA(private package archive)上に置いています。

PPAを作ることで、ユーザーがソースパッケージをアップロードすると、launchpad上で各アーキテクチャ用のバイナリパッケージをビルドし、aptでインストール可能にしてくれます。
PPAでビルドが成功したら、以下のようにubuntu上で利用する事が可能になります(ユーザーbellbindでPPA名python-simplexqueryを作り、python-simplexqueryのdebを公開した場合)。

sudo apt-add-repository ppa:bellbind/python-simplexquery
apt-get update
apt-get install python-simplexquery

PPAの作り方は以下の記事(の2ページ目)が一番分かりやすいでしょう

しかしPPA作成前に一度行う必要があるgpg鍵生成登録やCoCについて紛らわしい箇所があるので補足しておきます。

  • gpgコマンドについて
    • gpg --gen-keyでの重要な点は、launchpadに登録したメールアドレスで鍵を生成すること
    • gpg --gen-keyで鍵のオプションの選択がある。アルゴリズムや有効期限などのオプションは(DSA署名専用1yなど)デフォルトでよいです。パスフレーズは付けておくこと。
    • gpg --list-keysで生成した鍵一覧が見れる。gpg --send-keyで送る鍵は、uidが上記のメアドである鍵を使う
    • gpg --send-keyで指定する鍵IDは、"972DB0DC"のような形式です。
    • gpg --send-keyで送ったあと、自分のlaunchpadアカウントの"OpenPGP keys"にfingerprintを追加します。
  • さらに"Signed Ubuntu Code of Conduct"を有効にする必要があります。
    • OpenPGP keysにfingerprintを追加しただけでは、 パッケージをppaに登録できません。CoCがyesになって初めてパッケージ登録が可能になります。
    • HTML上で署名するCoCバージョンは記事上では1.0.1ですが、今は1.1です。
    • いまはCoC署名はファイルダウンロードではなく、ブラウザ上で該当部分をコピペしてファイルを作りそれをgpgで署名し、署名した全体をコピペしてブラウザでアップします。ターミナルを使っている場合、空白や改行が変わらないように注意します。

ソースパッケージのPPAアップロード手順

基本的に"debuild -uc -us"できちんとエラーやlintian警告なしでバイナリパッケージが作れていることが前提です。(ちなみに、pythondebパッケージの作り方は、python3用とpython2用のmultipleなdebパッケージを作るubuntuパッケージの作り方 - ラシウラに書きました。http://github.com/bellbind/python-simplexquery 中のdebian/* はmaverick用のパッケージ記述になっています)

毎回のソースパッケージアップロードで行うのは、以下のようにdebuildとdputの2コマンドだけです(python-simplexquery-1.0.5-0nmu1ppa2例):

cd python-simplexquery-1.0.5.1
debuild -S -sa
cd ..
dput ppa:bellbind/python-simplexquery python-simplexquery_1.0.5.1-0nmu1ppa2_source.changes

dputでppa名をフルに指定すれば上記記事上にある~/.dput.rcは不要です。

またPPAアップロードでも注意点は幾つかあります。

  • パッケージのバージョンには、"1.0.5.1-0nmu1ppa1"などメンテナーバージョン中に"ppa"という文字列が入る必要があります
  • パッケージを署名してない、署名が違う、CoCをyesにしていない、などミスがあるとdputで失敗した旨のエラーメールで送られてきます。
  • launchpad上のビルドは、ビルドマシン待ち時間とビルド時間の双方でそれなりに時間がかかります(速くても1時間ほど、長くて半日)。アップする前にパッケージを十分チェックしておきましょう。
    • 特にdebian/control中の"Build-Depends"と"Depends"は記述漏れがないように注意する
  • ソースアーカイブ(XXX_A.B.C.orig.tar.gzなど)は一度dputでアップすると、同じファイル名でつくり直してdputしても更新されません。
    • ソースを変えたい場合は、圧縮形式を変える(tar.bz2にするなど)か、バージョンを上げるかしたほうがいいでしょう。