2010/07/02

SLaTeXを使う。Gaucheで。

SLaTeXをGaucheで使いたい。

SLaTeXは、Schemeのコードを装飾するためのtex->texコンバータ。\scheme|...|とか\begin{schemedisplay}...\end{schemedisplay}といった感じでSchemeのコードを(La)TeXの原稿中に書いておくと、その各部分に装飾を施した一時的なtexファイルをSchemeスクリプトで大量に生成してくれる。それをTeXの処理系に渡すところまでやってくれるslatexというシェルスクリプトがついているので、latex foo.texのかわりにslatex foo.texとすればよい。

よいのだけど、実際に使うとなんとなく微妙。一時ファイルが大量にできるのは気持ちが悪いし、添付のスタイルが(少なくとも日本語環境では)あんまりうまくない。プリティプリンタというわけでもなさそうで、インデントの面倒も見てくれない。

あと、現時点ではそのままGaucheで使えない。とりあえず使えるように、次のようなパッチをあてた。これでgosh /(path to scmxlate)/scmxlate.scmのようにすると、Gauche用のslatex.scmと、platexを使うシェルスクリプトができる。
diff -rupN slatex/dialects/dialects-supported.scm myslatex/dialects/dialects-supported.scm
--- slatex/dialects/dialects-supported.scm 2002-11-24 05:06:34.000000000 +0900
+++ myslatex/dialects/dialects-supported.scm 2010-07-02 16:31:41.000000000 +0900
@@ -1,6 +1,7 @@
bigloo
chez
gambit
+gauche
guile
mitscheme
mzscheme
diff -rupN slatex/dialects/gauche-slatex-src.scm myslatex/dialects/gauche-slatex-src.scm
--- slatex/dialects/gauche-slatex-src.scm 1970-01-01 09:00:00.000000000 +0900
+++ myslatex/dialects/gauche-slatex-src.scm 2010-07-02 18:08:41.000000000 +0900
@@ -0,0 +1,12 @@
+(define getenv sys-getenv)
+
+(define *scheme-version*
+ (string-append "Gauche " (gauche-version)))
+
+(define void
+ (lambda ()
+ (if #f #f)))
+
+(scmxlate-postprocess
+ (define *scheme-command-name* "gosh")
+ (load "./dialects/make-echo-script.scm"))
diff -rupN slatex/dialects/make-echo-script.scm myslatex/dialects/make-echo-script.scm
--- slatex/dialects/make-echo-script.scm 2002-03-25 01:26:22.000000000 +0900
+++ myslatex/dialects/make-echo-script.scm 2010-07-02 17:13:53.000000000 +0900
@@ -3,12 +3,16 @@
(rename-file "my-slatex-src.scm" "slatex.scm")
(delete-file "slatex")
(delete-file "callsla.scm"))
+ ((gauche)
+ (sys-rename "my-slatex-src.scm" "slatex.scm")
+ (if (file-exists? "slatex") (sys-remove "slatex"))
+ (if (file-exists? "callsla.scm") (sys-remove "callsla.scm")))
(else
(system "mv my-slatex-src.scm slatex.scm")
(system "rm -f slatex callsla.scm")))


-(load "dialects/make-callsla.scm")
+(load "./dialects/make-callsla.scm")

(call-with-output-file "slatex"
(lambda (o)
@@ -18,11 +22,7 @@
(display ")" o) (newline o)
(display ";check pathname above is correct for you" o)
(newline o)
- (display "(slatex" o)
- (display (if (eqv? *dialect* 'bigloo)
- "$$"
- "::") o)
- (display "process-main-tex-file \"'$1'\")" o)
+ (display "(process-main-tex-file \"'$1'\")" o)
(if (eqv? *dialect* 'scsh)
(begin
(newline o)
@@ -32,10 +32,11 @@
(newline o)
(display "if test -f pltexchk.jnk" o) (newline o)
(display "then tex $1; rm pltexchk.jnk" o) (newline o)
- (display "else latex $1" o) (newline o)
+ (display "else platex $1" o) (newline o)
(display "fi" o) (newline o)))

(case *dialect*
((scsh) (run (chmod "+x" slatex)))
+ ((gauche) (sys-chmod "slatex" 484))
(else (system "chmod +x slatex")))

diff -rupN slatex/scmxlate-slatex-src.scm myslatex/scmxlate-slatex-src.scm
--- slatex/scmxlate-slatex-src.scm 2009-09-29 08:28:56.000000000 +0900
+++ myslatex/scmxlate-slatex-src.scm 2010-07-02 17:07:17.000000000 +0900
@@ -16,10 +16,10 @@

(scmxlate-eval
;on denali
- ;(define *target-file* "/home/dorai/.www/slatex/slatex.scm")
+ (define *target-file* "/home/kshikano/src/slatex/slatex.scm")

;on mac
- (define *target-file* "/Users/doraisitaram/public_html/slatex/slatex.scm")
+ ;(define *target-file* "/Users/doraisitaram/public_html/slatex/slatex.scm")
)

;You may define slatex::*texinputs* here. Eg,
@@ -30,7 +30,7 @@
;(define slatex::*texinputs*
;"/home/dorai/tex:/usr/local/lib/tex/macros") ;in Unix

-;(define slatex::*texinputs* (getenv "TEXINPUTS"))
+(define slatex::*texinputs* (sys-getenv "TEXINPUTS"))

;Unfortunately, that last one is not really as convenient as
;it seems, even if your Scheme has a getenv procedure.

2010/06/24

The WYSIWYG Conundrum: The Solid Cloud � An American Editor

The WYSIWYG Conundrum: The Solid Cloud � An American Editor:
"Success is much more than the number of downloads of free or 99� ebooks, especially when there is no way to know how many of those downloads actually were read or well thought of. Instead, success is having readers clamor for your books, talk about your books, express a willingness to pay a higher price for your books — all things that a professional editorial eye can help an author achieve by preventing the kinds of mistakes that turn readers away."


「(本の)成功とは、タダだったり100円だったりするebookがたくさんダウンロードされることじゃない。そのうち何冊が読まれたか確かめようがないなら、なおさらだ。成功というのは、そんなことではなく、読者がその本を話題にしてくれて、もっとお金を払いたいと思ってくれることにある。その本を読んだ人をがっかりさせるようなミスを防ぐことにこそ、プロの編集者の役割がある。」

これ以上なにも付け足すことがない。

2010/06/03

Emacs上での正規表現による検索で結果をハイライトしっぱなしにする

たまーに、「emacs」「検索」「ハイライト」で過去のエントリを見てもらっているようなのですが、あれはバグっているのです。バグっているというか、フォントロックの仕組みをちゃんと理解していなかったので、実行するとメジャーモードの色づけを葬ってしまう。

いまは改良してこうなっています。(Emacs 22.2.1)
(defun keep-highlight-regexp (re)
(interactive "sRegexp: \n")
(make-face 'my-highlight-face)
(set-face-foreground 'my-highlight-face "black")
(set-face-background 'my-highlight-face "yellow")
(defvar my-highlight-face 'my-highlight-face)
(setq font-lock-set-defaults nil)
(font-lock-set-defaults)
(font-lock-add-keywords 'nil (list (list re 0 my-highlight-face t)))
(font-lock-fontify-buffer))

(defun cancel-highlight-regexp ()
(interactive)
(setq font-lock-set-defaults nil)
(font-lock-set-defaults)
(font-lock-fontify-buffer))

(global-set-key "\C-f" 'keep-highlight-regexp)
(global-set-key "\C-d" 'cancel-highlight-regexp)
[Ctrl]-[f]で検索開始、[Ctrl]-[d]でハイライト解除。それぞれ、自分では通常のキーバインドとして使ってないので、グローバルに設定しています。

2010/03/26

稼働中のマシンのHDDから、VMware Player用の仮想マシンを作る

稼働中の物理マシンの HDD を、そっくり仮想イメージに変換して、 VMware Player で再生できるようにしたい。手順としてはこれだけなんだけど……
  1. 対象の HDD をダンプする(partimage を使う)
  2. VMware 用の仮想ディスクを空っぽの状態で作る(QEMU を使う)
  3. 2.の空っぽ仮想ディスクに領域を作る(fdisk を使う)
  4. 1.のダンプを、3.の領域へとリストアする(partimage を使う)
それなりに広大な作業スペースが必要だし、個々の作業に時間がかかるので(待ち時間にこんな記事がかけるくらい)、次回以降はできるだけ要領よく済ませたい。だから自分用にメモ。もちろん無保証です。

用意するもの。
  • 作業場
    ここでは Windows マシンを使う。対象の HDD 上で動いてなくて、VMware と QEMU が使えて、でかいディスク容量があるマシンなら、何でもいいと思う。

  • 起動環境
    ここでは Knoppix の iso イメージを使う。VMware 用の仮想イメージ以外で、fdisk と partimage が使える環境を VMware Player から起動できるものなら、何でもいいと思う。

  • QEMU
    空っぽの仮想ディスクを作るのに使う。ここでは QEMU on Windows の qemu-img コマンドを使う。


実際の作業の流れ。
  1. partimage で対象の HDD をダンプして、作業場からファイルとして見える場所にイメージファイル(群)として保管する。

  2. Windows のコマンドプロンプトで、qemu-img コマンドを使って空っぽの VMware 用仮想ディスクを作る。対象の HDD と同じサイズで vmdk 形式にする。対象が 120Gバイトならこんな具合。
    > qemu-img create -f vmdk hokansaki.vmdk 120G
    これでhokansaki.vmdkという仮想ディスクができる。

  3. 空っぽの仮想ディスクをフォーマットしたいのだけど、空っぽなので、当然のことながら VMware Player で仮想マシンを起動することができない。そこで、何かしら起動環境が必要になる。空っぽの物理ディスクに OS をインストールするときと同じ理屈ですね。つまり、BIOSチップ を CD/DVDブートにするのと同じ要領で、VMware Player の BIOS を CD/DVD ブートに設定し、ROM ドライブに Knoppix のディスクを入れて Player を再起動すればいい。VMware Player の起動時に F2 を押せば BIOS 画面に入れる。
    ただ、せっかく仮想マシンなんだから、わざわざ物理的な起動ディスクを使う必要もない。作業場の HDD 上に Knoppix の iso を置いておいて、それを Player の起動時に読むようにしたほうが手っ取り早いというもの。つまり、こんな vmx ファイルで仮想マシンを読み込めばいい。(この例では Windows の Fドライブ以下に Knoppix 5.1.1 の iso が置いてある。guestOS の一覧はこのへんを参考に。ide1 の deviceType を cdrom-image としているため、この場合も BIOS で CD/DVD ブートに設定する必要あり)
    .encoding                = "Shift_JIS"
    config.version = "8"
    virtualHW.version = "4"
    memsize = "512"

    ide0:0.present = "TRUE"
    ide0:0.fileName = "hokansaki.vmdk"
    ide0:0.mode = "persistent"
    ide0:0.deviceType = "disk"

    ide1:0.present = "TRUE"
    ide1:0.fileName = "F:\knoppix-iso\KNX5.1.1J_AC.200.iso"
    ide1:0.deviceType = "cdrom-image"

    ethernet0.present = "TRUE"
    ethernet0.connectionType = "nat"

    usb.present = "TRUE"

    displayName = "hokan saki"
    guestOS = "other26xlinux"
    nvram = "hokansaki.nvram"
    この構成で仮想マシンを起動する前に、仮想マシンから作業場(具体的には、ダンプしたイメージファイルの置き場所)が見えるようにする設定を忘れずに。VMware Player のバージョン3 には、「仮想マシン設定の編集」という GUI が用意されているので、そこから作業場のハードディスクを追加するだけだった。

  4. 空っぽの仮想ディスクを fdisk でフォーマット。上記の構成なら、くだんの空っぽの仮想ディスクは /dev/hda として認識されているはずなので、
    $ sudo fdisk /dev/hda
  5. partimage で、ダンプした対象 HDD のイメージファイルを /dev/hda1 にリストア。partimage を実行する前に、対象 HDD のイメージファイルの置き場所をマウントしておくこと。イーサネットだと、たぶんすごい時間がかかる。ついててよかった eSATA。

  6. ブートローダの修復。GRUB ならこんな感じ。
    $ sudo mount /dev/hda1 /media/hda1
    $ sudo chroot /media/hda1
    $ grub-install /dev/hda
    (マウントのときは Knoppix の UI を使わず、コンソールから mount コマンドで実行すること(Knoppix についてくる /etc/fstab の設定のせいで読み取り専用になってしまうため)
    あと、fdiskで領域(この場合は/dev/hda)をブート可能に設定しておくこと。

  7. BIOS の CD/DVD ブートを解除すれば、物理マシンで稼動していたシステムがそっくり VMware Player 上で起動するようになるはず。

2010/03/22

TeXでFizzBuzz

shibuya.lisp の テクニカルトーク#5 で、はやみずさんが「LaTeXでFizzBuzzを書く気になるか?」的な話を一瞬されたので反応しておく。そう言われて始めて書いてみようかと思うくらいだから、「書く気になるか?」という問いに対する答えは否定的なものであっていると思う。
\newcount\a \newcount\b \newcount\c
\newcount\n \newcount\i
\newif\ifdivisable

\def\fizzbuzz#1{%
\n=#1 \i=1
\loop \ifnum\i<\n
\printffizzbuzz
\advance \i by 1
\repeat}

\def\printffizzbuzz{%
\testdivisable{\i}{15} \ifdivisable fizzbuzz\par \fi
\testdivisable{\i}{3} \ifdivisable fizz\par \fi
\testdivisable{\i}{5} \ifdivisable buzz\par \fi
\ifdivisable\else \number \i\par \fi}

\def\printffizzbuzz{%
\testdivisable{\i}{15} \ifdivisable fizzbuzz \else
\testdivisable{\i}{3} \ifdivisable fizz \else
\testdivisable{\i}{5} \ifdivisable buzz \else
\number \i \fi\fi\fi \par}

\def\testdivisable#1#2{%
\a=#1 \b=#2 \c=#1
\divide \a by \b
\multiply \a by \b
\advance \c by -\a
\ifnum\c=0 \divisabletrue \else \divisablefalse \fi}

\fizzbuzz{30}

\vfill
\eject
\end
(2010.3.23 rudolphさんの指摘を受けて\printffizzbuzzを修正)

LaTeXじゃなくて素のTeX。これを fizzbuzz.tex のような名前で保存して tex fizzbuzz と実行すれば dvi ができる。

整数の計算には、\newcountコマンドでグローバルなレジスタをいくつか用意して、これを使う。これは文字通りのレジスタ計算で、レジスタに入っている値をadvancedivideといったコマンドを使って書き換えながら計算を進めていく。

リストやシーケンスのような気が利いたデータ構造は当然存在しないので、ループを使ってFizzBuzzするしかない。素のTeXでは、\loop... \repeatという構文が用意されていて、これでループが書ける。

あとトリッキーなのは、\newifというマクロを使って\ifdivisableという特定用途のための条件文を用意するところだろう。まあ、なんていうか、このへんはイディオムなので深く考えない。最初に見るとぎょっとするし、もっとうまい記述方法がないか考えても見るけど、結局こういうイディオムを使って書くのがいちばんしっくりくることに気がつくものだ。

2010/03/04

pLaTeX+dvipdfmxで基本じゃないOTFフォントを使う

ヨドバシカメラのソフト売り場で大枚はたいてOTFフォントを買ったならば、とりあえずpLaTeXでも気軽に使いたい、それもWordくらい気軽に、という話。

具体的には、「本文のゴシックはヒラギノ基本書体の角ゴW3でいいんだけど、強調したいところで角ゴW4を使いたい。ヒラギノ角ゴW4は買ってきた。原稿で\hirakakufour{モナド}って使いたい!」という状況がままあって、場当たり的な試行錯誤で「とりあえず」期待どおりの結果は得られているが、なにぶん試行錯誤でたどりついた方法なので正解かどうかはわかりません、つっこみ求む、という話。

TeXにおけるフォントとは何か、を整理する必要があるので、肝心の手順にいたるまでの説明が長くなります。まずは基礎知識。
買ってきたフォントの実体は .otf ファイルだけど、TeXが必要としているのは .tfm というファイルである。(.vf ファイルもあるけど、ややこしいので省略)
TeXのソースで指定するのは、あくまでも .tfm ファイルの名前である。.tfm ファイルには、TeXがそのフォントの文字を配置するときの幅とか前後の文字とのアキといった数値情報(メトリック)だけが入っている。これはバイナリファイルで、極端にいうとフォントの実体とぜんぜん関係ない値であっても、とにかく数値情報が決まったフォーマットでエンコードされていればいい。TeX のコマンド(platex とか)にとっては、フォントの実体なんて知ったことじゃないのである。TeX の仕事は、各ページへの要素の配置を決めるアルゴリズムを駆使して、その結果を dvi ファイルとして埋め込むだけ。それにはフォントのグリフを並べるのに必要な数値情報だけ知っていればいい。(この「なんでも数値にしてアルゴリズムさえ考え抜けばいいじゃん」という方針をクヌーシズムと称したい。)
TeX は、「この要素には○○というフォントを使って!」という情報だけをdviファイルに書き出す。
○○は、この場合は .tmf ファイルの名前。
フォントの実体は、dviファイルを解釈するDVIウェアと呼ばれるソフトウェアが扱う。
dvipdfmx や dviout といったDVIウェアが、フォントの実体である .otf ファイルを扱うので、彼らに .tfm ファイルと .otf ファイルとの対応付けを教えなければならない。

次に、ここでまとめる手順の前提条件。
ようやく手順。
  1. 何はともあれヒラギノ角ゴW4用の .tfm ファイルが必要。ここが肝要なんだろうけど、まあ角ゴW4のメトリックは角ゴW3とそんなにかわらないはずだよね、と仮定して、齋藤さんのOTFパッケージの nmlgothb-h.tfm および nmlgothb-h.tfm をそっくりコピーして使わせていただく。このへんが「とりあえず」なゆえん。(もしかするとヒラギノ角ゴW8用の tfm のほうが適切かも。)
    $ cd (TEXMF)/fonts/tfm/ptex/otf/otf  # パスとコピー先は各自でてきとうに
    $ cp nmlgothb-h.tfm nmlgothlb-h.tfm
    $ cp nmlgothb-v.tfm nmlgothlb-v.tfm
    (本来は、メトリックをS式っぽいもので記述したPLファイルというのを作って、それをpltotfというツールで変換してtfmファイルを作るらしいが、自分でやったことはない。OTFパッケージのうれしさは、ヒラギノ基本6書体に対してこれらをすべてお膳立てしてくれることにある。)
  2. dvipdfmxに、.tfm ファイルと .otf ファイルの対応付けを教える。これは、次のような map ファイルを書いて、dvipdfmx の実行時に -f オプションで指定すればよい。
    $ cat hirakakufour.map
    nmlgothlb-h H HiraKaku-W4.otf
    nmlgothlb-v V HiraKaku-W4.otf
  3. フォントの実体 HiraKaku-W4.otf を、dvipdfmx から見える場所(/usr/share/texmf/dvipdfmx/fonts/ とか)におく。

これで、たとえばこんな風にすれば、ヒラギノ角ゴW4を \hirakakufour コマンドで使えるようになる。
\DeclareFontShape{JY1}{gt}{lb}{n}{<-> nmlgothlb-h}{}
\DeclareFontShape{JT1}{gt}{lb}{n}{<-> nmlgothlb-v}{}
\def\hirakakufour#1{%
{\usefont{JY1}{gt}{lb}{n}#1}}

2009/12/30

年賀状かいた。
%!
<< /PageSize [285 420] >> setpagedevice

1 1 25 {
/n exch def
0 12 360 { % for
/i exch def

newpath
gsave
/r1 {rand 5 mod 2 div} def
/r2 {rand 2 mod 2 div} def
/r3 {rand 2 mod 2 div} def
r1 r2 r3 setrgbcolor
140 220 moveto
i rotate
/Times-Bold findfont 10 scalefont setfont
( ) show
0 10 20 { % for
/j exch def
/AgentOrange findfont j 12 add scalefont setfont
(2) show
/AgentOrange findfont j 14 add scalefont setfont
(0) show
/AgentOrange findfont j 16 add scalefont setfont
(1) show
/AgentOrange findfont j 18 add scalefont setfont
(0) show
} for
grestore
} for
220 45 moveto
/Georgia-BoldItalic findfont 10 scalefont setfont
n =string cvs show
(/25) show
showpage
} for

DSC_0178

こちらのAgentOrangeというフリーフォントを使わせていただきました。ありがとうございます。

http://www.1001freefonts.com/AgentOrange.php

2009/12/28

Gauche の CGI スクリプトを lighttpd + FastCGI で動かす手順

Gauche の CGI スクリプトを lighttpd + FastCGI で動かす手順。自分用の備忘録。

FastCGI は、Web サーバと外部プログラム間のやり取りを規定した一種のプロトコル。外部プログラムは起動しっぱなしになっていて、Web サーバは、その起動しっぱなしのプロセスと必要に応じてやり取りする。したがって、外部プログラムには、起動しっぱなしで Web サーバとおしゃべりできる仕組みが必要で、Web サーバのほうも、そんな外部プログラムとおしゃべりできないといけない。

外部プログラム側で必要となる仕掛けは、Gauche の場合、Gauche-fastcgi が提供する with-fastcgi という関数で cgi-main をくるむだけでいい。Gauche-fastcgi のインストールには FastCGI の開発ツールキットが必要。

Web サーバのほうは、lighttpd を使う場合、mod_fastcgi を有効にして、しかるべき設定をする。lighttpd の設定ファイルは /etc/lighttpd/lighttpd.conf なので、まあこれを編集してもいいのだけれど、Debian では lighty-enable-mod というユーティリティがあるのでこれを使う。具体的には、/etc/lighttpd/conf-available/ 以下に nn-name.conf という形式の名前を付けたファイルで設定の断片を用意し(nn は優先順、name は名前)、lighty-enable-mod name を実行する。最初から用意されている nn-name.conf ファイルもいくつかあって、10-fastcgi.conf という FastCGI 用のものもあるけれど、きっと Gauche で書いた FastCGI スクリプトには対応していない。だから、代わりに次のような内容の 10-fastcgi.conf を用意する。
server.modules   += ( "mod_fastcgi" )

fastcgi.server = (
"sample.fcgi" => ((
"host" => "127.0.0.1",
"port" => 1026
)),
"index.fcgi" => ((
"host" => "127.0.0.1",
"port" => 1027
))
)
sample.fcgiindex.fcgi が、 Gauche で書いた実行可能なスクリプトのファイル名。この設定は、「クライアントから sample.fcgi を要求されたら、localhost 上のポート 1026 で動きっぱなしの sample.fcgi に処理させますよ」などと読む。というわけで、事前に localhost 上のポート 1026 で sample.fcgi を動きっぱなしにしておく必要がある。そのために使うのは spawn-fcgi という lighttpd に付属するコマンド。
$ sudo spawn-fcgi -f /var/www/sample.fcgi -p 1026 -u www-data -g www-data
$ sudo spawn-fcgi -f /var/www/index.fcgi -p 1027 -u www-data -g www-data
これで、FastCGI でのおしゃべりをポート 1026 (あるいは 1027)で待ち受けるプロセスが立ち上がる。なお、sample.fcgiindex.fcgi に実行権限が付与されてないと(chmod 755 されてないと)、spawn-fcgi がエラーになる。また、Gauche のエラーでプロセスが死んでも spawn-fcgi そのものは成功してしまうので、spawn-fcgi の実行後に ps awx | grep gosh して起動しっぱなしのプロセスがあることを確認したほうがいい。

この後、lighttpd を起動する。すでに起動していて再起動する場合は、設定ファイルの再読み込みもしておく。
$ sudo /etc/init.d/lighttpd force-reload
$ sudo /etc/init.d/lighttpd restart
これで準備はおしまい。リロードしまくっても新しい gosh プロセスが毎回起動しなければOK。

なお、この手順は、事前に動きっぱなしにしておいた外部プログラムをIPアドレスとポートで識別する方法。識別に UNIX ドメインソケットを使うこともできる。また、外部プログラムを事前に起動しておかず、初回は lighttpd から起動させることもできる。細かい話は lighttpd の mod_fastcgi のドキュメントにいろいろと書いてあった。

2009/07/29

DebianでWillcom端末からPPP接続

Debian/GNU Linux(squeeze)に Willcom の PHS 電話端末 AH-J3003S(ウィルコム定額プランで契約)を USB でつなぎ、契約なしで利用できるプロバイダ PRIN にダイアルアップして PPP でインターネットに接続するときのメモ。

まず、避けて通れないプロバイダについて。Willcom 端末からのダイヤルアップ接続には、事前契約が不要な PRIN というプロバイダが使える。使えるんだけど、ずっと料金体系や支払い方法がよくわからず、こわくて使ってなかった。最近になって Windows XP から勇気を出して使ってみたところ、ちょっと外出先で接続するくらいなら気にならない程度の金額だとわかったので、Debianマシンでも使ってみることにした。気になるお値段はPRIN/サービス案内に一覧表がある。Willcom の電話端末を「ウィルコム定額プラン」で契約していれば、「リアルインターネットプラス」を契約していなくても 10円/分 くらい。料金の支払いは、電話料金と一緒に引かれているっぽい(金額が微妙でよくわからないけど、ほかから請求がこないので)。

AH-J3001S という端末は、Linux Kernel からは ACM デバイスとして認識される。cdc-acm モジュールが有効になっていれば、USB ケーブルでつなぐだけで、こんな感じに認識されるはず。
$ tail /var/log/messages
...
... cdc_acm 4-2:1.0: ttyACM0: USB ACM device
... usb 4-2: New USB device found, idVendor=1145, idProduct=0001
... usb 4-2: New USB device strings: Mfr=0, Product=0, SerialNumber=0
...
というわけで、必要な作業は、PPP の設定のみ。

Debian での PPP 接続には ppp パッケージが必要。それと、設定ファイルを編集する pppconfig というユーティリティーを使いたいので、 pppconfig パッケージもインストールする。
$ sudo apt-get install ppp pppconfig
インストールできたら、pppconfig を使って、モデムのデバイスファイルやプロバイダの情報(ダイアルアップ先やユーザ名やパスワードなんか)を設定する。モデムのデバイスは /dev/ACM0 にする。プロバイダがらみの設定値は、PRIN/サービス案内(アクセスポイント一覧がある)やPRIN/各種設定・利用案内(Windows XP のウィザード設定画面の説明がある)とかから探せば見つかる。

pppconfig による設定は /etc/ppp/peers/ および /etc/chatscripts/ 以下にテキストファイルとして保存される。手元の設定結果はこんな感じ。
$ cat /etc/ppp/peers/willcom
# This optionfile was generated by pppconfig 2.3.18.
#
#
hide-password
noauth
connect "/usr/sbin/chat -v -f /etc/chatscripts/willcom"
debug
/dev/ttyACM0
115200
defaultroute
noipdefault
user "prin"

ipparam willcom

usepeerdns
$ cat /etc/chatscripts/willcom
# This chatfile was generated by pppconfig 2.3.18.
# Please do not delete any of the comments. Pppconfig needs them.
#
# ispauth CHAP
# abortstring
ABORT BUSY ABORT 'NO CARRIER' ABORT VOICE ABORT 'NO DIALTONE' ABORT 'NO DIAL TONE' ABORT 'NO ANSWER' ABORT DELAYED
# modeminit
'' ATZ
# ispnumber
OK-AT-OK "ATDT0570570611##61"
# ispconnect
CONNECT \d\c
# prelogin

# ispname
# isppassword
# postlogin

# end of pppconfig stuff
なお、このファイルには書き出されてないけど、プロバイダのパスワードにはユーザ名と同じ prin を設定する(公開情報)。

で、いよいよ接続するには pon コマンドを使う(利用するユーザは dip グループに入っていないといけない)。
$ pon willcom
willcom の部分は、pppconfig による設定の際に指定する設定名。これは /etc/ppp/peers/ なんかの下にあるファイル名でもある。ifconfig してみると ppp0 みたいな名前のインタフェースが新たに現れているはず。切断は poff で。

2009/07/10

LaTeX におけるページをまたいだ囲み記事スタイルのまとめ

追記(2014年11月7日)

いまなら、囲み記事を書きたい場合には tcolorbox パッケージを使うのがよさそうです。 さらに脚注問題については footnoteパッケージというのが 1997 年からありました orz 方法は違うけど、以下の記事でやっている「段落ボックス中の \footnote を外側に追い出す」ができます。 まとめるとこんな書き方をすればよさそう。
\documentclass[a4paper]{article}
\usepackage{lipsum}
\usepackage[most]{tcolorbox}
\usepackage{footnote}
\tcbuselibrary{breakable}
\newtcolorbox{mybox}{breakable, enhanced jigsaw}
\makesavenoteenv[myftnbox]{mybox}

\begin{document}
\lipsum[1]

\begin{myftnbox}
\lipsum[1]

First footnote\footnote{first footnote}.

\lipsum[1-10]

Second footnote\footnote{second footnote}. 
\lipsum[1]
\end{myftnbox}

\lipsum[1]

\end{document}

ただし、tcolorbox に breakable を設定した環境では、minipage でもないのに minipage 専用の独立した脚注番号用のカウンタ mpfootnote が minipage っぽく使われてしまっているため、footnote パッケージはこれを通常の mpfootnote のように外側の脚注番号用カウンタと同期できません。そのため、上記のままでは、myftnbox 環境内だけは脚注番号が毎回 a, b, ... になってしまい、外側の 1, 2, ... と同期できません。ページをまたいだボックス環境で、ドキュメント内で一貫した脚注番号を使うには、何か自分で工夫をするしかなさそうです。

というわけで、以下の本文では、そのための工夫の一例を紹介します。実際に適用してみた結果はこちら


LaTeX でページをまたいだ囲み記事を実現するスタイルはいくつかあって、今のところ回避困難な制限がある。そのまとめ。

基本は framed.sty だろう。角が四角くてもいいなら、これがいちばん素性がいい感じ。ただし、ページをまたぐときに、前のページの末尾と次のページの先頭に罫線が入る。標準的なパッケージなので、いろんな環境で利用できる可能性が高い。たぶん中身をボックスにいれて \vsplit で一行ずつページを構成する垂直ボックスに渡していく方式。

もうひとつ、 eclbkbox.sty というのもある。これはページをまたぐ箇所に罫線が入らない。これもやはり角は四角い。これも \vsplit を使う方式。

同じく \vsplit を使ったページ分割手法で、しかも角丸に対応したスタイルとして、emath の itembkbx.stymultipagebox.sty がある。

さて、以上の4つのパッケージには共通する悩ましい制約条件がある。\footnote がまったく使えない。翻訳なんかだと囲み記事に脚注入れたい場合もあるというのに、いれられない。いろいろ回避策を考えてみたけど、\vsplit を使うにはいったん囲み記事にしたい中身をボックスに入れるしかなく、その時点で \footnote を見るしかなくて、\vsplit するときには手の出しようがない。そもそも \vsplit はインサートの分割アルゴリズムを利用するためのプリミティブだから、やはりインサートである \footnote に対応できなくてもしょうがないか(実際には直接の関係はないけど)。

以下のようにして簡単に \footnote を有効にできる場合がある(全部試してない。使えない環境も多々あるはず)。
\newtoks\mftn
\def\mfootnote#1{%
\footnotemark
\edef\@tempa{\the\mftn\noexpand\footnotetext[\the\c@footnote]}%
\global\mftn\expandafter{\@tempa{#1}}}%
\def\mfootnoteout{%
\the\mftn
\global\mftn{}}

\begin{...}
\let\footnote\mfootnote
...
\end{...}
\mfootnoteout
ただしこの回避策だと、\footnote の項目がページごとではなく最後のページにまとめて出てしまう。まあ、最後の手段ということで。

ページをまたぐ囲み記事で、しかも \footnote に完全対応する方法として、longtable.sty を使って独自の環境をでっちあげるという手がある。(。汎用性がないのでそのままの状態ではたぶん利用不可能。囲み記事の段落を longtable の行に対応させるという荒業のため、段落ごとにしか改ページできない。これが最大の難点。でもまあ、この \longtable を使う方法の難点こそが、\footnote をページごとに出力するための直接の代償でもあるわけだ。)

というわけで、だれか footnote を華麗に再定義して footnoteanyware.sty みたいなのを作ってください。

2009/06/22

Lisp!

Golden Lucky - Lisp (via Keiichirou Shikano)
Lisp

発作的に作ってしまった。

2009/05/24

Goodby Bafana

『マンデラの名もなき看守』を見た。見ることができた。赤ちゃんがいると映画館にいく機会は限られるのだけど、今日はたまたまそういうチャンスだった。そして、たまたま今週の早稲田松竹のラインナップが『マンデラの名もなき看守』だった。ついてた。

映画では、旧体制の南アにおける黒人差別政策についてどうこう言うこともなく、看守としてマンデラとかかわるたびに気がついたら人生の窮地に立っている男とその家族の話をテンポよくつないで、1990年2月11日の釈放シーンで締めくくっている。じわじわくる。ラストまでのエピソードのおかげで、最後の"goodbye bafana"というセリフの手前くらいで涙が出そうになる。そして釈放シーンの看守の奥様がとてもきれい。この2つのシーンは、もっと感動的に演出してもよさそうなものだけど、これでちょうどよかったのだろうな。

現代史に散らばっている社会問題って、「かわいそう」駆動型の活動や「正義感」駆動型の行為、あるいは思考停止になりがちだ。自分は正直なところ思考停止していると思う。それを「娯楽」の形で消化する贅沢に折り合いを付けるのは難しいし、たぶん付かない。『ホテルルワンダ』もそうだった。でも、たとえばダライ・ラマ14世の亡命後の半生を描いた映画ができれば、きっと見に行く。贅沢はくせになる。

2009/05/23

A rant about happiness

タイ料理屋でしこたまのみながら、「幸福」を定義した。
手元にメモが残っているので、思い出しつつ書き起こしておく。

「幸福」とは何かよくわからないので、まずは「幸福でない」について考えよう。

レベル1の「幸福でない」とは、幸福の軸が定まっていて、幸福の側にいない状態。
レベル2の「幸福でない」とは、レベル1の「幸福でない」を定めるすべがない状態。つまり、この場合は、レベル1における幸福の軸を見出せていない状態。

この定義から、レベルnの「幸福でない」を自然に拡張できる。
レベルnの「幸福でない」とは、レベルn-1の「幸福でない」を定めるすべがない状態だ。

で、レベルωの「幸福でない」とは何かを考えてみる。ωは最初の可算無限基数。たぶん、任意の可算基数レベルの「幸福でない」を定めるすべがない状態、なんだろうな。

ということは、ある可算基数があって、そのレベルで「幸福でない」を定めるすべがあれば、レベルωで「幸福でない」ではないといえる。「幸福でない」の逆が「幸福」とは限らないけど、まあ、「幸福になりうる」っていうくらいならいいだろう。とくに、レベル1で「幸福でない」を定めるすべがあれば、レベルωで幸福になりうる。

ここまで書いて気づいたけど、べつに無限基数まで拡張する必要なかったか。
レベル1で「幸福でない」を定めるすべがあれば、どんなレベルでも幸福になりうる。

ところで、いまうちらはレベル1の「幸福でない」を定めるすべを持っている。実際、定めることができている。したがって、うちらはどんなレベルでも幸福になりうる。

おや、なんだかあたりまえの結論じゃないか。
そんな話だったっけかなあ。これだから酔っ払いは。

2009/04/23

LaTeXでSubversionのキーワード展開を使うパッケージ

LaTeX で Subversion のメタ情報(つまり、$Id$ とかのキーワード展開)を使いたい。

Subversion におけるキーワード展開について基本をまとめると、たぶんこんな感じ。
  • 各ファイルのsvn:keywords属性を展開したいキーワードに設定する。
  • 原稿ファイル中にある $Id: ... $ などが展開されるのは、svn checkout や svn update でリポジトリの変更を取ってきた時点。
困っちゃうのは、ファイルごとにしかメタ情報を使えないところ。LaTeX で原稿を複数のファイルに分けて執筆している場合に、1ページめに原稿全体としての最新リビジョンを出力するようなことができない。1ページめをコンパイルする時点では、そのページの元になっている *.tex ファイルの $Id: ... $ しか展開されなからだ。後ろのほうのファイルだけが更新されたら、その新しいリビジョン番号には追随できなくなってしまう。
この悩みを解決する LaTeX のパッケージがいくつかある。svn-multi が新しいめで高機能そうなんだけど、今回は svninfo を使うことにした。以下は備忘録。

book.tex から zenhan.tex と kouhan.tex を include していて、Id キーワードの情報が使いたいとする。
% プリアンブルいろいろ
\begin{document}
\include{zenhan}
\include{kouhan}
\end{document}
まずは svninfo パッケージを利用できるようにする。\usepackage{svninfo} は \begin{document} の直前に置かないといけないようだ。
% プリアンブルいろいろ
\usepackage{svninfo}
\begin{document}
\include{zenhan}
\include{kouhan}
\end{document}
つぎに以下のような行を zenhan.tex と kouhan.tex に追記する。最後の $ のあとにスペース必須。 "file rev YYYY-MM-DD hh:mm:ss owner" の部分は、現在のファイルの情報(svn log -rHEAD zenhan.tex とかで得られる情報)か何かを手書きしておく。
\svnInfo $Id: file rev YYYY-MM-DD hh:mm:ss owner $ ← スペースあり
忘れずに svn:keywords を設定してコミット。
> svn propset svn:keywords "Id" *.tex
> svn commit -m"added svnInfo Id"
準備はこれでOK。この情報を LaTeX で出力するには、\svnId とか \svnInfoRevision といった svninfo のコマンドを使う。
複数のファイルにある $Id: ... $ を全部チェックして最新のリビジョン番号をとってきてくれる \svnInfoMaxRevision というコマンドもある。この \svnInfoMaxRevision をzenhan.tex に書いておけば、最新のリビジョンで更新されたのが kouhan.tex だけでも、その最新のリビジョン番号に展開される。たとえば、zenhan.tex に対する最後の変更がリビジョン 1000 で、kouhan.tex だけが 1001 で変更されたとすると、どんなに svn up しても zenhan.tex にある $Id: ... $ の部分はリビジョン 1000 に相当する情報にしか展開されない。ところが \svnMaxRevision のほうは 1001 に展開されてくれる。
svninfo に用意されているほかのコマンドは、マニュアルのPDFを参照。

The svninfo package(PDMマニュアル)
http://ftp.yz.yamagata-u.ac.jp/pub/CTAN/macros/latex/contrib/svninfo/svninfo.pdf

2009/04/21

Gauche の string-split が便利だ。便利なんだけど、セパレータとしてプロシージャを渡したとき、文字列にある各文字に対してプロシージャが順番に呼ばれないっぽいのが困る。
まずはふつうの例。こんな文字列があったとき、
(define text-with-block
"words, |entering a block|, got out of the block.")
スペースかどうか判断するプロシージャを is-space? 渡して、この文字列をぶったぎりたい。
(define is-space? (pa$ char=? #\space))
(string-split text-with-block is-space?)
=> ("words," "|entering" "a" "block|," "got" "out" "of" "the" "block.")
これは問題ない。
今度は、文字列のうちで縦棒 "|" でくくられている部分を塊とみなし、その内部にあるスペースは無視したいとする。つまりこんな結果がほしい。
(string-split text-with-block is-isolated-space?)
=> ("words," "|entering a block|," "got" "out" "of" "the" "block.")
クロージャーの出番です。is-isolated-space? はこんな定義でいいだろう。
(define is-isolated-space?
(let ((inblock? #f))
(lambda (c)
(cond ((char=? c #\|)
(set! inblock? (if inblock? #f #t))
#f)
(inblock?
#f)
((char=? #\space c)
#t)
(else
#f)))))
実際、 text-with-block に対して is-isolated-space? を繰り返し呼べば、縦棒 "|" でくくられた内部がセパレータとみなされないことが確かめられる。
(let R ((ls (string->list text-with-block)))
(cond ((null? ls)
'())
((is-isolated-space? (car ls))
(cons 1 (R (cdr ls))))
(else
(cons 0 (R (cdr ls))))))
=> (0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 1 0 0 1 0 0 0 1 0 0 0 0 0 0)
見づらいけど、 "|entering a block|," の位置に相当する部分がぜんぶゼロになっているのがポイント。
だから、string-split に渡したプロシージャが文字列にある各文字に対して順番に呼ばれるなら、目的の結果が得られるはず。でも得られない。
(string-split text-with-block is-isolated-space?)
=> ("words," "|entering" "a" "block|, got out of the block.")
しかも、もういっかい呼び出すと結果が変わる。
=> ("words, |entering" "a" "block|, got out of the block.")
ということは、各文字ごとに is-isolated-space? の抱えているクロージャがクリアされているわけではないんだよな。2回目の呼び出しでは、inblock? の初期値が #t になっているようだ。
ちなみに、マニュアルにはこうある。

splitter に手続きが与えられた場合、string にある各文字に対してその手続きが呼ばれ、
splitter が真の値を返すような連続した文字群がデリミタとして使われます。
また、ソースの stringutil.scm にある string-split の定義を見ると、ふつうに文字列の先頭から各文字をプロシージャーで処理してるっぽい。なにがおかしいのかなあー。
仕方がないので代わりの関数をでっちあげる。
(define (string-split-by str proc)
(let ((n (string-index str proc)))
(if n
(receive (h r)
(values
(string-take str n)
(string-drop str n))
(if (= (string-length r) 0)
'()
(if (> n 0)
(cons h (string-split-by (string-drop r 1) proc))
(string-split-by (string-drop r 1) proc))))
`(,str))))

(string-split-by text-with-block is-isolated-space?)
=> ("words," "|entering a block|," "got" "out" "of" "the" "block.")

2008/12/30

ようやく年賀状を作る。

DSC_0201

どうみても図形言語です。

にしても今年は一年中なんだか余裕がなかった。来年はなんとかする。

2008/09/26

Scheme どう書く?的 - ひげぽん OSとか作っちゃうかMona-
http://d.hatena.ne.jp/higepon/20080925/1222326246

こんなことをしていられる状況ではないんだけど、mapAccumLを使いたい衝動を抑えられなかった。
compactNumberList :: [Int] -> [[Int]]
compactNumberList = snd . partition ([]==) . tail . snd . mapAccumL collect [-1] . (++[-1])
where collect xx@(x:xs) y | y - x == 1 = (y:xx, [])
| xs ==[] = ([y], [x])
| otherwise = ([y], [last xx, head xx])

2008/09/12

IO型は、使うだけなら簡単に思える。たとえば String -> IO () という型の putStr に文字列を渡せば、それが画面に印字される。
Main >putStr "abcdef\n"
abcdef
putStr の出力は IO () 型なので、結果として印字された「abcdef」は文字列ではない。じゃあ、IO () 型の出力はどこにいったんだろう? Show クラスのインスタンスがないということ? でも、だとしたらGHCがエラーを出力するんじゃなかったっけ?

とにかく絶対に IO () な何かが関数の結果として返ってきているはずなので、IO () -> String な関数を定義してそれに putStr をつないでみた。
vacant :: IO () -> String
vacant o = "munashii"
Main >vacant $ putStr "subarashii\n"
"munashii"
どうして「subarashii」が印字されないん?

結局、これはやっぱり副作用じゃないってことなんだろうな。Scheme でも同じことをすると、
gosh> (define (vacant o) "munashii")
vacant
gosh> (vacant (print "subarashii"))
subarashii
"munashii"
これが本物の副作用ということなのか!

2008/09/11

Haskellでプログラムを書くときは、まず関数の型を妄想してHoogleしろ

Haskellでは、型を「利用して」プログラミングができるという。つまり、「あーなんかこんな型の関数ねえかな」というところからプログラムを書き始めるものらしい。だから haskell.org では型からAPIを検索することができる。その名も Hoogle。Gauche のリファレンスマニュアルさえあれば誰にでも Scheme のプログラムが書けてしまうように、Hoogle があれば誰にでも Haskell のプログラムが書ける。気がする。ところで、Yahooみたいな名前の APIサーチエンジンもあるそうなのですが、見つかりません。
(追記)Hayooでした。ありがとうございます > nobsun(ここまで追記)

たとえば、10進の整数を各桁からなるリストだと思って map したい。
*Main> intMap (*2) 12345
[2,4,6,8,10]
*Main> foldr (+) 0 $ intMap id 123456789
45
こういうintMapをどうやって作っていくか。(以下、とりあえず正の整数の場合だけを考える。)

Scheme脳の正攻法は、各桁の再帰だろう。1の位を head、それより大きな位を tail にして再帰的にリストを作り、reverse すればよさそうだ。10進数の 1の位の数は (mod 10) だし、10で割って floor を取れば 1の位より前にある数字を並べた数になるので、型を考えずにこんなナイーブな定義が書ける。
intMap p n | n < 10 = [p n]
| otherwise = reverse (p last : reverse front)
where
last = mod n 10
front = intMap p (floor (n/10))
ちなみにこれはコンパイルに通らない。floor とか (/) とかは、そのままでは Int型に対して使えないので。コンパイルするには最後の front を次のようにする必要がある。
front = intMap p $ fromEnum $ floor $ toEnum n/10
(追記)整数の割り算がありました。front = intMap p (div n 10) でOK。(ここまで追記)

本来なら順番が逆だけど、ここで初めて intMap の型について考える。intMap は、ふつうの map のように、1引数関数とリスト代わりの整数をとってリストを返すようにしたい。つまり、こういう型だ。
intMap :: (Int -> a) -> Int -> [a]
自分が求めている型が分かったので、これをキーワードにして Hoogle で検索してみる。結果はいっぱい出るけど、その先頭には iterate という関数がひっかかるはずだ。リンクをクリックすると、GHCのドキュメントの iterate の項目にジャンプする。その説明によれば、iterate はこんな関数らしい。
iterate :: (a -> a) -> a -> [a]

iterate f x returns an infinite list of repeated applications of f to x:

iterate f x == [x, f x, f (f x), ...]
見るからに intMap の定義に使えそうだ。f として先ほどの定義の front に相当するものを与えてやれば、iterate f 1234 -> [1234, 123, 12, 1, 0, ...] といった具合にリストが得られるので、あとは各要素から mod 10 で 1の位を抜き出せばいい。
(追記)f の定義を fromEnum $ floor $ toEnum m/10 から div m 10 に修正(ここまで追記)
intMap :: (Int -> a) -> Int -> [a]
intMap p n = map (p . lastDigit) $ reverse $ takeWhile (> 0) $ iterate f n
where
f m = div m 10
lastDigit m = mod m 10
再帰がなくなり、標準関数をごにょごにょするだけで求める関数を作ることができた。

まとめ
「Haskellでプログラムを書くときは、まず関数の型を妄想して Hoogle しろ」

おまけ
ナベアツ問題とか。
nabeatsu = [p i | i <- [1..]]
where has3 n = or $ intMap (== 3) n
p i | has3 i || mod i 3 == 0 = "aho"
| otherwise = intMap intToDigit i

2008/08/03

Panasonic CF-R4JにDebianを入れるまとめ

正月に液晶を割ってしまった Panasonic CF-R4J のパーツを入手できたので、修理ついでに Debian GNU/Linux を入れることにした。いままでは購入時にプリインストールされていた Windows XP 上で VMware を使って Ubuntu を利用していたが、やっぱりたまにいらりってくる。
最近は Debian も簡単にインストールできるけど、CF-R4J には光学ドライブがないし、内蔵の無線LANのように使えないと困る機能もある。あと、いままで使っていた Windows XP の環境をそのまま使い続けられるようにしたい。そこで備忘録として作業のまとめ。

目標

プリインストールされている Windows XP はそのままにして、Debian を追加でインストールしたい。

戦略

  1. USBメモリから KNOPPIX を起動し、ntfsresize と cfdisk を使って、Windows XP がプリインストールされた HDD の後半に Debian 用の新しいパーティションを作る。
  2. 別のUSBメモリから Debian のインストーラを起動し、新しいパーティションにインストールする。
  3. 内蔵されている無線LAN を有効にする。

用意するもの


USBメモリから起動するKNOPPIXのイメージを作る

この作業は、プリインストールされた Windows XP 上で行う。以下のサイトの手順に従っただけ。

  [USBメモリでKNOPPIXを起動する]
   http://ryusai.hp.infoseek.co.jp/KNOPPIX_on_USB-01.htm

まとめると以下の通り。
  1. KNOPPIX の iso イメージを入手して DAEMON tools でマウント
  2. 1Gバイトの USBメモリを FAT32 でフォーマット
  3. DAEMON tools でマウントした KNOPPIX をエクスプローラで開き、KNOPPIX フォルダ全体と /boot/isolinux 以下のファイルを、フォーマットした USB メモリの直下にコピー
  4. /isolinux.cfg を /syslinux.cfg にリネーム
  5. syslinux -a :f

USBメモリから起動する Debian のインストーラを作る

この作業は、上で作った KNOPPIX で行う。これも以下のページの手順に従っただけ。

  [USB メモリでの起動用ファイルの準備]
   http://www.jp.debian.org/releases/stable/i386/ch04s04

まとめると以下の通り。デバイス名とかは適宜。
  1. (ここだけ Windows XP でやっておく)128Mバイトの USBメモリを FAT32 でフォーマット
  2. boot.img.gz を入手し、zcat boot.img.gz > /dev/sdb
  3. sudo mount /dev/sdb /mnt/sdb
  4. cp debian-40r4etchnhalf-i386-netinst.iso /mnt/sdb/

HDD のパーティションを切り直す

この作業は、KNOPPIX 上で行う。
  1. (ここだけ Windows XP でやっておく)Cドライブのデフラグ
  2. ntfsresize -i /dev/hda1 で、リサイズできる HDD 領域の大きさを調べる
  3. ntfsresize -s 30000M /dev/hda1 (30000M のところは、上で調べた大きさを参考に適宜)
この時点で Windows XP からは、C ドライブの大きさが指定した大きさに縮小されて見える(この場合だと30Gバイトしか見えなくなる)。ただしパーティションが変わったわけではないので、管理ツールからローカルディスクを見れば、やはり元の大きさのHDDがCというドライブ名の1つのパーティションに占有されているように見える。ちょっとへんな状態。
実際にパーティションを切るには fdisk をするしかない。そこで cfdisk /dev/hda1 を実行する。

ntfsresize 後の cfdisk でやること

ここからが危険なところ。
  1. もともと Windows XP がプリインストールされていたパーティションを削除する。最初に cfdisk を実行すると、HDD の末尾に 3G くらいの空き領域があるように見える。これは CF-R4 のリカバリ領域。Windows XP が入っているパーティションを削除することで全体が1つの空き領域になるため、空き領域として見えていたリカバリ領域が cfdisk からは識別できなくなってしまう。この領域は BIOS レベルで fdisk などでは削除できないようになっているらしいが、それを確かめる勇気はないので、本当のことは知らない。個人的には用心しておいたほうがいいと思う。実際、あとでパーティションの設定を誤って Windows XP が起動しなくなったとき、KNOPPIX からは /dev/hda4 としておもいっきり見える状態になっていた。たぶんこの領域を隠蔽するのに、プリンストールされた Windows XP の機能を使っているんだろう。
  2. 全体が1つの空き領域になっているところに、まずはプリインストールされている Windows 用のパーティションを作る。先に ntfsresize で縮小したサイズ以上の大きさのパーティションにすること。ぴったり同じバイト数で指定すると、ntfsresize で縮小したサイズよりもfdiskで作ったパーティションのほうが小さくなってしまうようだ。そうすると Windows XP が起動しなくなる。もし後続の空き領域に Debian 用のパーティションを作ってフォーマットしようものなら、あふれた部分が失われてしまって Windows XP の環境が復旧できなくなってしまうはず。大きい分には問題ないので、1Gバイトくらい多めの大きさのパーティションにしたほうがいいと思う。
  3. この時点でパーティションテーブルを書き込み、Debian のインストールに使う領域の設定はインストーラにまかせてしまってもいいが、リカバリ領域を失うのは怖いので、この時点で最後に 5G くらい残るようにして、スワップ用とルート用のパーティションを切ってしまう。
  4. 書き込む。もう戻れない。

Debian のインストール

いつもどおりなので省略。ネットインストールに無線LAN が使えないので、有線をつないで実行する必要がある。

無線LANを有効にする

ラップトップ向けのインストールをすれば wlan-tools はインストールされる。CF-R4J の内蔵無線LAN は Intel PRO/Wireless 2200BG で、そのドライバは ipw2200-source というパッケージでインストールすることができる。lenny ならパッケージのインストールは不要。ただし lenny であってもファームウェアは入らないので、別途 ipw2200-fw-3.0.tgz をダウンロードして /lib/firmware に手動で置いておく必要がある。
あとは /etc/network/interfaces をこんな感じに設定しておけば、有線LAN との使い分けも適当にできると思う。
# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
allow-hotplug eth0
iface eth0 inet dhcp

# Wireless LAN
auto eth1
iface eth1 inet dhcp
wireless-essid ******
wireless-key **************************