Dec 19, 2010

Emacsでドットエディターを作ってみた

ちょっとドット絵を作りたくなったが、適当なツールが思い付かなかった。Windowsの「ペイント」しか思い付かなかったが、それだけのためにWindowsを起動するのは負けのような気がした。
手元で動いているのはMacBookである。「ペイント」に相当するくらいのアプリケーションはプレインストールされているような気がするが、筆者はMacに疎いのである。少なくとも「アプリケーション」の中を眺める限り、それだとわかるものは無い。GIMPはインストールしているのだが、マウスが無いのでしんどそうだし、それだけのために重いGIMPを起動するのも負けのような気がした。

目の前ではCarbon Emacsが動いていた。ふと、Emacs Lispで(if (looking-at ...))とかやれば、1キーで白黒反転するマクロが簡単に書けるのではないか…と思って、やってみたら、思ったより使い易かったので、もう少し進めてみた。

doteditor.el(漢字コードはEUC)

■起動方法
M-x load-fileまたは(load-file)で上のファイルを開き、M-x dot-editor-mode

■キーバインド
SPC: カーソル位置の□と■の反転
M-r: 選択領域の□と■の反転
M-c: 指定サイズの矩形領域を□で作成
M-e: 選択領域をビットマップとみなして16進数に変換したものを、選択領域の直後に挿入
M-d: 選択領域の16進数を□と■のビットマップに変換したものを、選択領域の直後に挿入
M-p: 選択領域の16進数をPBM形式の画像データにしたものを、tmp.pbmというバッファに作成 & image-modeが使用可能ならそれでプレビュー

■使用例1
1. M-cとし、width, heightに32, 24を入力
 → □が32x24個挿入される
2. 編集

□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□
□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□
□□□□□□□□□□□□■■■■■■■■□□□□□□□□□□□□
□□□□□□□□□■■■■■■■■■■■■■■□□□□□□□□□
□□□□□□□□■■■■■■■■■■■■■■■■□□□□□□□□
□□□□□□□■■■■■□■■■■■■□■■■■■□□□□□□□
□□□□□□■■■■■■■■■■■■■■■■■■■■□□□□□□
□□□□□□■■■■■■■■■■■■■■■■■■■■□□□□□□
□□□□□■■■■■■■■■□□□□■■■■■■■■■□□□□□
□□□□■■■■■■■■■■■■■■■■■■■■■■■■□□□□
□□□□■■■■■■■■■■■■■■■■■■■■■■■■□□□□
□□□■■■■■■■■■□□□□□□□□■■■■■■■■■□□□
□□□■■■■■■■■□□□□□□□□□□■■■■■■■■□□□
□□■■■■■■■□□□□□□□□□□□□□□■■■■■■■□□
□■■■■■■■□□□□□□□□□□□□□□□□■■■■■■■□
□■■■■■■■□□□□□□□□□□□□□□□□■■■■■■■□
□■■■■■■□□□□□□□□□□□□□□□□□□■■■■■■□
■■■□■■■□□□□□□□□□□□□□□□□□□■■■□■■■
■■■□■■■□□□□□□□□□□□□□□□□□□■■■□■■■
■■■□■■■□□□□□□□□□□□□□□□□□□■■■□■■■
■■□□□■■■□□□□□□□□□□□□□□□□■■■□□□■■
■■□□□■■□■■■■■■□□□□■■■■■■□■■□□□■■
□□□□□□□■□□□□□□■■■■□□□□□□■□□□□□□□
□□□□□□□□■■■■■■□□□□■■■■■■□□□□□□□□

3. ビットマップ全体を選択し、M-e
00000000
00000000
000ff000
007ffe00
00ffff00
01f7ef80
03ffffc0
03ffffc0
07fc3fe0
0ffffff0
0ffffff0
1ff00ff8
1fe007f8
3f8001fc
7f0000fe
7f0000fe
7e00007e
ee000077
ee000077
ee000077
c70000e3
c6fc3f63
0103c080
00fc3f00

4. 16進データを選択し、M-pで表示確認

5. 16進データを保存

■使用例2
1. 16進テキストのビットマップデータを読み込む

00, 00, 00, 00,
00, 07, f8, 00,
00, 1f, fe, 00,
00, 3f, ff, 00,
00, 7f, ff, c0,
00, ff, e7, f0,
01, ff, ff, fc,
01, ff, ff, e0,
03, ff, ff, e0,
03, ff, ff, d0,
03, ff, ff, d0,
07, ff, ff, 10,
07, ef, be, 08,
07, ef, be, 08,
07, df, bc, 08,
07, df, 78, 08,
07, df, 78, 08,
0f, de, f8, 10,
0f, dd, f0, 10,
1f, dd, f0, 10,
1f, ed, f0, 20,
3d, f3, e0, 40,
38, f3, e1, e0,
60, 3f, ff, f0,

2. データ全体を選択し、M-d
(0-9, a-f, A-F以外の文字は無視されるのでカンマはそのままで良い、"0x"があるとその"0"が展開対象になるので注意)
□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□
□□□□□□□□□□□□□■■■■■■■■□□□□□□□□□□□
□□□□□□□□□□□■■■■■■■■■■■■□□□□□□□□□
□□□□□□□□□□■■■■■■■■■■■■■■□□□□□□□□
□□□□□□□□□■■■■■■■■■■■■■■■■■□□□□□□
□□□□□□□□■■■■■■■■■■■□□■■■■■■■□□□□
□□□□□□□■■■■■■■■■■■■■■■■■■■■■■■□□
□□□□□□□■■■■■■■■■■■■■■■■■■■■□□□□□
□□□□□□■■■■■■■■■■■■■■■■■■■■■□□□□□
□□□□□□■■■■■■■■■■■■■■■■■■■■□■□□□□
□□□□□□■■■■■■■■■■■■■■■■■■■■□■□□□□
□□□□□■■■■■■■■■■■■■■■■■■■□□□■□□□□
□□□□□■■■■■■□■■■■■□■■■■■□□□□□■□□□
□□□□□■■■■■■□■■■■■□■■■■■□□□□□■□□□
□□□□□■■■■■□■■■■■■□■■■■□□□□□□■□□□
□□□□□■■■■■□■■■■■□■■■■□□□□□□□■□□□
□□□□□■■■■■□■■■■■□■■■■□□□□□□□■□□□
□□□□■■■■■■□■■■■□■■■■■□□□□□□■□□□□
□□□□■■■■■■□■■■□■■■■■□□□□□□□■□□□□
□□□■■■■■■■□■■■□■■■■■□□□□□□□■□□□□
□□□■■■■■■■■□■■□■■■■■□□□□□□■□□□□□
□□■■■■□■■■■■□□■■■■■□□□□□□■□□□□□□
□□■■■□□□■■■■□□■■■■■□□□□■■■■□□□□□
□■■□□□□□□□■■■■■■■■■■■■■■■■■■□□□□

3. 編集
以下略

See more ...

Posted at 21:30 in PC一般 | WriteBacks (2)
WriteBacks

おもしろいですね。 ただ、関数名にはprefixをつけましょう。 「doteditor-」あるいは「de:」、「de/」、「de-」あたりですかね。 reverse-regionは標準コマンドにあるのでかぶっています。 [link]

Posted by rubikitch at 12/26/2010 11:32:55 AM

ご指摘ありがとうございます。 修正させて頂きました。

Posted by ynomura at 12/26/2010 07:53:58 PM

Oct 11, 2010

フリーのUMLツールを使ってみる

少し前からUMLを復習していて、UMLを書くためのフリーソフトを探している。
UMLの要素は、丸や四角のような基本図形の組み合わせで書けるので、専門のソフトでなくてもUMLは書ける。むしろ、Visioのような作図ツールや、簡単な図形描画ができるWordやPowerPointで書かれる場合も少なくない。筆者も10年近く前、会社でUMLを書く必要があった時、好んでVisioで書いていた。周囲でもVisioが多数派だったと思う。その後、部署の方針で少数派のRhapsodyだったかRational Roseだったかを使うことになったが、短期間だったし、使いこなせなかったので、全く覚えていない。だから、Visioが手元に無い今、それに近いDiaでUMLを書くのは悪くない選択肢だと思っている。

しかし、ここはやはり、UMLそのものの復習をするなら、UMLの要素を図形でなくUMLの要素として扱う、専門のツールを使ってみたい。四角は四角でなく、クラスかインターフェースかオブジェクトかを区別して管理してほしいのである。それに、専門のツールであれば、UMLとして誤った書き方を避けられる可能性も高い。

商用のソフトなら、Rational製品かEnterprise Architectが有名どころであるが、そんな高いものを買う気はさらさらない。Visual Paradigmというのもすごそうだが、やはり高価なのでパスである。今は無償のソフトでいいのがあれば使いたいという程度である。

今回は次のような条件で探してみた。
・フリーソフト
・UMLの要素をUMLとして管理できること
・UML以外の書き方を許さないこと
・なるべくUML 2.0対応
・WindowsでもMacでも使用可能(最近主にMacBookを使っているため)

触ってみたソフトと、使ってみた感想をまとめる。
1. ArgoUML
最初に興味をそそられたのがArgoUMLであった。正統派というか、見た目より内容重視というか、UMLツールの理想形を目指している、思想的に最も優れたソフトのように思えるのである。
ファイルフォーマットは多分に漏れずXMLベースであるが、当然だと言わんばかりに自動的に圧縮されるのもポイントが高い。
【利点】
・UMLのポリシーに忠実に作られている
・作成した図に対して、UMLとして不適切な箇所を指摘してくれる
・Javaで実装されており、クロスプラットフォームである
・複数言語のソースコードの出力が可能
【欠点】
・UML 2.0に対応していない(UML 1.4のみ)
・全体的にUIに癖があり、最初はコツを掴まないと全然思い通りにならない
・GUIは貧弱で、お世辞にも使いやすいとは言えない
・正しく使わないとおかしな状態になりやすく、しかも落ちずにいつの間にか回復不可能な状態に陥ることも多い
・日本語化されていない
・ドキュメントが不十分

ArgoUML sample image

2. astah* community(旧JUDE community)
日本製ということで、UMLが書けるツールとしては、国内では最も有名であろう。
しかし、名前がAstahになってから、無償版の機能制限が多くなってしまったようだ。
今回、無償版をダウンロードして使ってみたが、トップメニューから製品版の案内が出る上、メニューに有償版のみ有効になる灰色の項目が多すぎて非常に鬱陶しく、イラッと来たので、やめた。
【利点】日本語である
【欠点】何かにつけ、調べた挙句、フリー版ではできないことを知る羽目になる

3. Omondo EclipseUML
Eclipseのプラグインとしては定番のものである。
作成した図を画像ファイルとしてexportする方法がわからなかったので、やめた。

4. eUML2
これもEclipseのプラグインである。
EclipseのSoftware Updateで"UML"で検索したら出てきたので、使ってみた。
また、個人的にSwingのVisual Editorで馴染み深いSoyatec製だということにも興味を惹かれた。(Visual Editorの開発は止まってしまったようだが)
【利点】
・UML2に対応している(が、作成できる図の種類は限られる)
・Eclipseと親和性が高く、極めればEclipseでいろんなことができそう
【欠点】
・動作はとても不安定、よくJavaのエラーが出る(特に

Unhandled event loop exception
java.lang.StackOverflowError
は頻出、筆者の環境ではコンポジット構造図でClass間にnavigableでないAssociationの線を引くだけで出る)
・というか、まだまだバグだらけ
・できる図に違和感を感じることが多い(下のサンプルでは、ポートが要素の枠線上に無い、要求インターフェースの○を消せない(ソケット(半円)のみが正しい)、ボール(丸)とソケットがずれている)
・追加したのに表示されない要素、消すにはXMLを編集するしかない要素がある
・全体的に、XMLの編集を余儀なくされることが多い
eUML2 sample image

5. AmaterasUML
やはりEclipseのプラグインである。(そればかり狙った訳ではないのだが…)
まだまだ開発途上で、作成できる図の種類が少なすぎるので、やめた。

6. Topcased
なぜかEclipseのプラグインである。
Eclipse上で動くが、Eclipseっぽい動き方をしない。Eclipse上で独自の世界を構築してるようである。UMLの使い方としても独特のものがあるように感じる部分がある。
動作は安定しているが、思い通りの図を書くには後少しの所でつまずくことが多い。また、思い通りに要素を配置できない時に何が悪いのかわからないことも多い。
【利点】
・UML2に対応している
・まあまあ綺麗な図が書ける
・動作が安定している
・使い始めは覚えやすい
【欠点】
・Eclipseとの親和性が低い
・完全に思い通りのUMLを書くのは難しい
・というか、たぶん書けないものがある(コンポジット構造図のパートの内部構造など)
・特殊すぎて、UMLを学ぶという用途には適さない気がする
Topcased sample image
(ソケットはGIF形式でexportすると消える、PNG形式なら残るが色数が落とされて汚い)

…どうも、これに決まり、というものが無いなあ。

See more ...

Posted at 23:34 in PC一般 | WriteBacks (1)
WriteBacks

dia使ってみました。日本語化されてました!汎用性があって使いやすいと思います。

Posted by at 06/23/2011 11:20:14 AM

Aug 29, 2010

[WinXP] 2回再起動でCoregaの無線LAN接続不能な場合

Windows XPのセットアップをしていて、Corega製の無線LANアダプターを導入したら、ドライバーをインストールして一度だけ再起動した後はアクセスポイントに繋がるのに、もう一度再起動すると、ワイヤレスネットワークの状態が「限定または接続なし」になり、インターネットには繋がらないという状態に出くわした。
物理層、データリンク層では接続されていたが、DHCPのIPアドレスが取得できない模様であった。
ドライバーを再インストールして、対アクセスポイントの設定を変えたりして、インターネットアクセスに成功して「よっしゃ!」と思って、再起動するとLANにも繋がらなくなったり、再起動しても繋がるようになって「よっしゃ!」と思って、Windows Updateするとネットワークに繋がらなくなったりする。解決したと思って暫くした後に否定されるのを繰り返されるのは、必要以上に疲れるものであることを思い知らされた。

筆者は基本的に無線LANを使わないのであるが、昔ある所に住んでた時、配線の都合で無線LANにせざるを得なかったので、半年だけ無線LANを使ったことがある。その時も最初は結構苦労したが、そのことをすっかり忘れて、同じ器具を使って同じことを繰り返してしまった。

まず、USBのWLANアダプターCG-WLUSB2GSのドライバーをインストールして、1回目の再起動後は繋がったが、2回目の再起動以後はIPアドレスが取得できない状況になった。
アクセスポイント側の設定もかなり疑った。アクセスポイントのIPアドレスがDHCPサーバーから与えられるアドレスと衝突することは無いか、DHCPサーバーは同じMACアドレスを受けているか、DHCPサーバーが持ってるエントリーを使い切ってはいないか、等々。
このCG-WLUSB2GSは昔から、使っているとすごく熱くなって、2〜3時間もするとオーバーヒートして動かなくなったので、使わなくなった物である。やはりハードウェア不良なのだろうと判断して、昔も結局追加購入したPCIのWLANアダプタCG-WLPCI54GLを持って行って、PCに差したが、やはり1回目の再起動後は繋がったが、2回目の再起動以後は繋がらなくなった。CG-WLUSB2GSのハードウェア不良が原因ではなかったようだが、前回も安定動作したCG-WLPCI54GLを使用することにした。

何回もドライバーのアンインストールとインストールを繰り返してやっと、インストールした直後の再起動後の「ネットワークユーティリティ」の画面と、2回目以降の再起動後の「ネットワークユーティリティ」の画面が全然違うことに気付いた。ステータスバーのWLANアイコンをクリックすると、1回目の再起動後は「コレガ無線LANユーティリティ」が起動し、それを操作してアクセスポイントに接続できるが、2回目以降はコントロールパネルの「ワイヤレス ネットワーク接続」が起動するようになって、アクセスポイントへの接続は何回待たされても成功しなかった。
ネット上のいくつかの情報を整理した結果、「ワイヤレス ネットワーク接続」の「Windowsでワイヤレスネットワークの設定を構成する」のチェックを外すと、「ワイヤレス ネットワーク接続」が起動しなくなり、再起動しても無線LANが正常に使える状態に戻った。これはわかりづらい…

さて、完全に解決したと思った爽快感に浸りながら、Windows Updateの指示に従い、WinXPのService Pack 3をインストールすると、

プロシージャエントリポイントapsSearchInterfaceがダイナミックリンクライブラリwlanapi.dllから見つかりませんでした

というエラーが出るようになり、またアクセスポイントに繋がらなくなった。
これは結構メジャーな問題らしく、何とも凶悪なことに、マイクロソフトのページには、ドライバを更新するしかないという意味のことが書かれている。そして、CG-WLPCI54GLは既にサポート対象外らしく、CoregaのWebページには、SP3対応のドライバはリリースされていなかった。
このカードは昔もWinXPで使用していたが、当時はSP3は存在しなかったので、使用実績は無い。さすがにこの状況はどうしようも無かろう、SP3をアンインストールするしかないな、と思ったが、しかしSP3のアンインストールってのはそもそも可能なのだろうか…と悩んだので引き続きネットで情報を探しまくっていたら、Coregaのサポートページのドライバのインストーラーを使わずに「新しいハードウェアの検索ウィザード」を使ってドライバをインストールすること、という情報と、CG-WLPCI54GLのドライバの代わりにCG-WLCB54GLのドライバを使ったら成功したという情報を見つけた。半信半疑で試してみた所、確かにCG-WLCB54GLのドライバを(「コレガ無線LANユーティリティ」無しで)インストールすると、使えるようになった。

See more ...

Posted at 23:42 in PC一般 | WriteBacks (0)
WriteBacks

Aug 09, 2010

Macのターミナルからtelnetして日本語入力する方法

Mac OS X(バージョン10.5.8)の「ターミナル」をEUC-JPモードにしてUNIXにtelnetでログインすると、日本語が入力できないことに気付いた。sshではできていたので、支障がないので放ってあったのだが、今回、sshでは入力できることを忘れていて、調べまくってしまった。

リモート側でod -xして入力を16進表示すると、7bit目が落ちていた。ありがちなパターンである。
しかし、Macの「ターミナル」の設定の「非アスキー入力をエスケープする」はOFFにしてあるし、telnet接続後にstty allとすると、ちゃんと"cs8","-parenb","-istrip"になっていた。念のため"stty pass8"とやったが、変わらなかった。「ターミナル」の問題でもttyの問題でもなく、telnet接続の問題のようである。

そこで、man telnetしたら1ページ目に出てきた、-8オプションを使ってみたが、状況は変わらなかった。ところが、

telnet> set binary
telnet> open ...

すると、日本語が入力できるようになった。それに代えて、telnet接続してからCtrl+]でtelnetモードに入って"set binary"としても日本語が入力できるようになった。しかし、それらと同じ意味のように読める"telnet -8"ではやはりできなかった。

仕方なく、しばらくの間、~/.telnetrcに

(hostname)
 set binary ←先頭はスペース

と書いて回避していたが、その後も気になって複数の接続先に対して色々試している内に、いつの間にか"telnet -8"でも日本語入力できるようになっていた。何だったのだろう??

See more ...

Posted at 21:59 in PC一般 | WriteBacks (0)
WriteBacks

Jul 25, 2010

(Emacs)カーソル位置の単語を取得するマクロ

とうとう、我が部屋は、日光が入らないようにカーテンを閉めてエアコンを付けっ放しにしても、35℃を下回らなくなった。
この部屋がアパートの最上階の西の端の部屋で、建物がコンクリート造りのため、部屋自体が熱を持ってしまっているらしい。床や壁を触ると、ぬくいのである。天井は触っていないが、おそらくヒーターと化しているであろう。
クーラーを動かしっ放しにしてやっと外と同じくらいの気温である。どちらかというと、殺す気かという感じである。
いや、元々殺さない気はないのであろう。一般論として、建物というものが人の生命を守るとは限らない。部屋も凶器になり得るはずである。

従って、頭が働かず、材料が揃わないので、ブログが更新できない。
でも何か書きたくなったので、軽めに、最近やったEmacsのカスタマイズについて書くことにする。

Emacs Lispを書くようになって、C-h fのdescribe-function(関数の説明を見るコマンド)やC-h vのdescribe-variable(変数の説明を見るコマンド)をよく使うようになった。カーソルをelispの関数名や変数名の上に置いてC-h fとすると、デフォルトのでその関数名や変数名が候補になるのが便利である。それに慣れると、カーソル位置にある単語をキルリング(Xで言うセレクション、Windowsで言うクリップボード)にコピーするキー操作が無いことに気付いた。
WindowsやMacだと大抵マウスのダブルクリックでそれができるので、結構無意識にやりたくなる操作である。

単語の先頭に移動するキーはあるので、
M-b (単語の先頭にジャンプ)
C-SPC (マークセット)
M-f (単語の末尾にジャンプ)
M-w (コピー)
とすると一応できるのだが、この8キーは結構打ちにくい。

筆者はこれをよく行うので、そういうことをする関数をキーに割り当てようとしたのだが、そういう関数が見つからなかった。そんな訳で、次のような設定を追加した。

(defun kill-ring-save-current-word ()
"Save current word to kill ring as if killed, but don't kill it."
(interactive)
(save-excursion
(forward-char)
(backward-sexp)
(let ((pos (point)))
(forward-sexp)
(kill-ring-save pos (point)))
))
(global-set-key "\C-xw" 'kill-ring-save-current-word)

これで、C-x wでその位置にある単語をコピーできるようになる。
カーソルが移動することもないので、例えば、これをコピーして別の所に貼り付けたいが、コピーした後に今のカーソル位置で少し編集したい、という時にも邪魔にならない。

See more ...

Posted at 22:57 in PC一般 | WriteBacks (1)
WriteBacks

ナイスな情報でした。

Posted by たろう at 07/01/2012 07:11:02 PM

Jun 07, 2010

Emacsでの全Xフォントの表示を画像化してみた

Emacsで使える色々なX Windowのフォントを、実際にEmacsで表示したらどうなるかを一覧形式で見てみたくなって、自動的にフォントを切り替えながらウィンドウイメージを画像ファイルに保存するEmacs Lispのコードを作った。

コード(elisp)
結果の抜粋
 "tt-数字"の先はTrueType(要xft、Emacs23で表示したもの)
 "tt-noaa"とあるのはTrueTypeの中のアンチエイリアスされないフォント(xft不要、Emacs22で表示したもの)
 それ以外はビットマップフォント

上記コードを実行して、


本日は晴天で酷暑あるいは氷雪でブリザードなり。

のようなバッファを表示した状態でM-x captureなどとして実行すると、次々にフォントが切り替わって画像ファイルに保存されていく。ウィンドウイメージのキャプチャーにはImageMagickのimportコマンドを使用している。
キャプチャー画像からサンプル文字列だけを抜き出すのは、同じくImageMagickのconvertコマンドを使って、シェルスクリプトで一括変換した。
例:
foreach i (*.tif)
convert -crop 700x80+60+30 $i -trim `basename $i .tif`.png
end

Trim(autocrop)できる範囲を切り出せるように、文字列部分の上下左右にたっぷりと余白を取っておくのがコツである。

キャプチャー画像を.tifで保存しているのは、convertで-trimする時に画像圧縮によるノイズに邪魔されないようにするためである。もう少しがんばって、elispで文字列の表示位置を特定してそこだけキャプチャーするようにできればかなりいい感じなのだが、そこまでするためのelispの関数を調べ切れなかった。(というか、なんとなく不可能な気がする。文字列部分を特定して切り出すImageMagickのコマンドをelispに埋め込む方が有望かも)

See more ...

Posted at 00:34 in UNIX | WriteBacks (0)
WriteBacks

Jun 06, 2010

(FreeBSD 7.3) Emacsで多言語フォント表示

FreeBSD 7.3のpackagesの
・ar-ae_fonts1_ttf-1.1_2
・gnu-unifont-ttf-20080907
・indic-ttf-fonts-0.5.6
・junicode-0.6.17
をインストールし、.emacs.elにて

(set-fontset-font (frame-parameter nil 'font)
'ethiopic
(font-spec :family "Goha\-Tibeb Zemen"))

することにより、Emacs23でM-x view-hello-fileすると
HELLO in various languages
ここまで表示されるようになった。

See more ...

Posted at 00:21 in UNIX | WriteBacks (0)
WriteBacks

Jun 02, 2010

EmacsのX Windowフォントの設定方法(3)

次に、X resourcesでEmacsのフォントセットの定義を行ってみる。
今回は、Emacs22用の定義を~/.Xdefaultsに書いた。~/.Xresourcesでも良い。筆者の環境では.XdefaultsはEmacs起動の度に、.XresourcesはXセッション起動時のみ読み込まれ、両方ある場合は.Xdefaultsが無視される。全ユーザー共通の設定なら/usr/X11R6/lib/X11/app-defaults/以下のファイルに書いても良い。それらを以下、リソースファイルと呼ぶ。

説明の前に、リソースファイルでのEmacsのフォントセットの定義の例を示す。(ascii文字は東雲(しののめ)フォント、日本語は東風(こち)フォントにする例)

Emacs.Fontset-0: -shinonome-gothic-medium-r-normal--16-*-*-*-*-*-fontset-kochi16g,\
katakana-jisx0201:-kochi-gothic-medium-r-normal--16-*-*-*-*-*-jisx0201.*-*,\
japanese-jisx0208:-kochi-gothic-medium-r-normal--16-*-*-*-*-*-jisx0208.*-*
Emacs.Fontset-1: -shinonome-mincho-medium-r-normal--16-*-*-*-*-*-fontset-kochi16m,\
japanese-jisx0208:-kochi-mincho-medium-r-normal--16-*-*-*-*-*-jisx0208.*-*,\
katakana-jisx0201:-kochi-mincho-medium-r-normal--16-*-*-*-*-*-jisx0201.*-*

1つのフォントセットの定義は次のようなフォーマットで書く。
Emacs.Fontset-[n]: (asciiのフォント名)-fontset-(フォントセット名),\
 (文字セット名): (フォント名),\
 (文字セット名): (フォント名)...

まずフォント名であるが、筆者のFreeBSD 7.3のEmacs22はxftをサポートしていないので、フォント名は全て、ハイフンで区切られた14個のフィールドからなる、XLFD(X Logical Font Definition)表記である。XftをサポートしているEmacsではxftのフォント名を用いた別の書き方があるのかも知れないが、筆者は今の所知らない。Xftをサポートしている筆者のEmacs23でも、elispのx-list-fontsを実行するとEmacsで使用可能なフォントのリストがXLFD形式で得られるので、X Window上のEmacsのフォント設定において、XLFDと縁が切れることは当分無いと思う。
幸いにして、フォント指定時はXLFDのほとんどのフィールドにワイルドカードが使えるので、全てのフィールドを理解する必要は無い。大体、
-(フォント名)-(ファミリー)-(medium/bold)-(r/i)-normal-*-(サイズ)-*-*-*-*-*-(文字セット名)-(Encoding)
で十分と思う。mediumは通常、boldは太字、rは通常、iは斜体(Italic)である。文字セット名以降の部分は、iso8859-1ならそのまま(1がEncodingの部分)だが、jisx0208の場合はjisx0208.1983-0のようにjisx0208の後にピリオドとさらなる情報があり、さらにEncodingが0だったり1だったり2だったりするので、面倒ならjisx0208.*-*と指定するのが良い。

1行目の[n]の部分は、0から始まる連番でなければならない。Emacs.Fontset-1以上しか無ければ1つも有効にならないし、0,1,2と4以上しか無ければ0,1,2の分しか有効にならない。(過去には連番でなくてもいい方法があったような気がするが、Emacs22のInfoには見つけられなかった)

1行目のasciiのフォント名の部分は、"iso8859-1"の代わりに"fontset-(フォントセット名)"と書く。これにより、新たなフォントセットが定義される。実際のasciiのフォントは、"fontset-(フォントセット名)"の部分を"iso8859-1"に置換されたものが使われる。
iso8859-1に限らず、"fontset-(フォントセット名)"の部分を*-*にして該当する全ての(Emacsがサポートする)文字セットのフォントが、そのフォントセットのデフォルトとして使われるようである。例えば、

Emacs.Fontset-2: -shinonome-gothic-medium-r-normal--16-*-*-*-*-*-fontset-shinonome16

と書くと、iso-8859-1のみでなく、jisx0208やjisx0201についても東雲フォントが使われるようになる。
従って、1行目のasciiのフォント設定だけで足りることもある。その場合は、2行目以降と1行目のカンマ以降は不要である。

最初の例(東雲フォントと東風フォントの例)のように、特定の文字セットに対してasciiのフォントとは別のフォントを指定する時は、"(文字セット名): (フォント名)"という形式で、カンマで区切って書く。次の行に書く場合は(XLFDなら普通次の行に書くであろう)、行末に"\"(バックスラッシュ)を置いて次の行に書く。
Emacsがサポートする文字セット名は、M-x list-character-setsとすると調べられる(Emacs22以前ならM-x describe-fontsetの出力でもわかる)。
同じ行の\の後(改行コードの前)には何も書いてはいけない(直後の改行文字をエスケープするためのものであるため)。カンマの前にはスペースを入れてはいけないが、カンマの後ろなら良い。コロンも同様である。

リソースファイルへのフォントセットの定義が済んだら、それが読み込まれる状態で(自動的に読み込まれないならXを再起動するなりxrdb -mergeするなりして)Emacsを起動して確認する。最初からデフォルトのフォントを定義したフォントセットにするのは、フォントセットの定義に誤りがあるとEmacsが起動しないことがあるので、避けた方がいいと思う。
Emacsのウィンドウ上でShift+左クリックでポップアップメニューを開き、"Fontset"のメニューに定義したフォントセットが出てこなければ失敗である。
Fontsetメニューに出てきて選択可能でも、成功しているとは限らない。定義に問題があると、フォントが切り替わっても、フォントセットの定義がそのまま使われず、自動的にフォントセットが再構築されてしまうことがある。定義通りになっているかどうかは、そのフォントセットに切り替え、定義に関係する全文字セットの最低1文字ずつを含むファイルを開いた後、M-x describe-fontsetして確認する。もし、1行目に出てくるフォントセット名が、定義した名前でなく"fontset-default"や"fontset-auto??"となっていると、失敗している可能性が高い。そこはクリアしていても、一部の文字セットのフォントが正しく読まれていないかも知れないので、[]内のワイルドカードが展開されたフォント名をそれぞれ確認すると良いと思う。

1行目のmedium/bold、r/iの別は、フォントセット名と共に、フォントセットを区別する情報として用いられる。同じフォントセット名に対して、medium-r, bold-r, medium-i, bold-iのそれぞれのフォントセットを定義することが可能であり、そのようにすると、同じバッファにレギュラー体とイタリック体、細字と太字が混在する時も、それらの全てのフォントセットを設定することができる(1つのバッファに指定できるフォントセット名は1つであり、そのフォントセット名のmedium-rのフォントとかbold-rのフォントとかが使われる)。
残念ながら、medium/boldやr/iの部分を*にして、(medium/bold)-(r/i)の4通りのフォントセットを1つのEmacs.Fontset-[n]にまとめて定義することはできないようである。従って、同じフォントセット名で(medium/bold)-(r/i)の4通りを定義するには、Emacs.Fontset-[n]が4つ必要になる。
例:

Emacs.Fontset-20: -kappa-*-medium-r-normal--20-*-*-*-*-*-fontset-kappa
Emacs.Fontset-21: -kappa-*-medium-i-normal--20-*-*-*-*-*-fontset-kappa
Emacs.Fontset-22: -kappa-*-bold-r-normal--20-*-*-*-*-*-fontset-kappa
Emacs.Fontset-23: -kappa-*-bold-i-normal--20-*-*-*-*-*-fontset-kappa

今回、筆者がFreeBSD 7.3のpackagesで手当り次第に日本語のフォントをインストールして、Emacs22で使えそうなフォントを、リソースファイルにフォントセット定義として色々登録してみたものを、参考までに添付する。
リソースファイルへの記述例
Emacs.Fontset-0〜3は、intlfontsというパッケージに含まれるサンプルをそのまま使用したものである。それ以降は、筆者が主に16〜20ドットを使うので、その範囲のサイズを重点的に定義している。

参考:Emacs InfoのDefining fontsetsの章

See more ...

Posted at 22:39 in UNIX | WriteBacks (0)
WriteBacks

May 29, 2010

EmacsのX Windowフォントの設定方法(2)

次に、日本語とかASCIIとかの文字集合の単位で別々のフォントを設定してみる。
日本語と英語しか使わなくても、日本語文字の分しか無いフォントとか、ASCII文字の分しか無いフォントとかを使う場合、そういうことが必要になることがある。アラビア語とかハングルとか、日英以外の文字も表示したいのにフォントが自動的に読み込まれないような時も、必要になる。
Xftが有効なEmacs23を使う場合、fontconfigの設定が適切であれば、そのような事態はあまり起こらないような気がするし、起こってもEmacs側で対処するよりfontconfig側で直すべき話になるかも知れないが、筆者の環境ではEmacs22が現役であるので、そのような事態は基本的に発生するのである。

Emacsのフォントは文字セット(文字集合、charset)とフォント名の組で管理される。その文字セットとフォント名の組のリストをフォントセットと言う。文字セットは、JIS X 0208とかiso8859-1等の単位で指定するのが基本であるが、Emacs23では文字コードの範囲で指定することもできる。Emacsで定義されている文字セットは、M-x list-character-setsするとわかる。日本語文字とASCII文字に関係するのは以下のものである。
・ascii: 言うまでもなくASCII文字
・japanese-jisx0208: 日本語、大体第1〜2水準漢字を含む
・japanese-jisx0212: 大体第3〜4水準漢字
・japanese-jisx0213: JIS X0208 + JIS X0212
・katakana-jisx0201: 日本語のいわゆる半角カナ、Emacs23ではjisx0201
・unicode-bmp: Unicodeの基本面(0群0面、UCS-2で表現できる範囲)(Emacs23のみ)
半角カナを使わなければ、asciiとjapanese-jisx0208のフォントを設定すれば十分である。
フォントセットを意識せずにset-frame-fontとかで1つのフォントのみを指定してフォントを変更しても、裏では何らかのフォントセットが自動的に構成される。

現在使用されているフォントセットは、M-x describe-fontsetでcurrent frameを指定すると表示される。これの出力形式は、Emacs22と23とで全然異なる。Emacs22の方が単純でわかり易い。Emacs23の方がきめ細かな設定ができるので仕方ないのだろうが、非常にわかりづらい。困ったものである。Emacs22で実行すると、以下のような感じになる。

Fontset: -etl-*-medium-r-normal-*-16-*-*-*-*-*-fontset-16
CHARSET or CHAR RANGE FONT NAME
--------------------- ---------
ascii -etl-fixed-medium-r-normal--16-160-72-72-c-80-iso8859-1
[-ETL-fixed-bold-r-normal--16-160-72-72-C-80-ISO8859-1]
[-ETL-Fixed-Medium-R-Normal--16-160-72-72-C-80-ISO8859-1]
latin-iso8859-1 -etl-fixed-*-iso8859-1
latin-iso8859-2 -*-iso8859-2
latin-iso8859-3 -*-iso8859-3
(中略、以下抜粋)
katakana-jisx0201 -*-jisx0201-*
[-Shinonome-Gothic-Medium-R-Normal--16-150-75-75-C-80-JISX0201.1976-0]
japanese-jisx0208 -*-jisx0208.1990-*
japanese-jisx0212 -*-jisx0212-*
[-Misc-Fixed-Medium-R-Normal--16-150-75-75-C-160-JISX0212.1990-0]
japanese-jisx0213-1 -*-jisx0213.2000-1
[-Misc-Fixed-Medium-R-Normal--16-150-75-75-C-160-JISX0213.2000-1]
japanese-jisx0213-2 -*-jisx0213.2000-2
[-Misc-Fixed-Medium-R-Normal--16-150-75-75-C-160-JISX0213.2000-2]

文字セットの右側が指定したフォント名、[]内が実際にロードされたフォント名である。ちなみに、上の出力は、FreeBSD7.3でintlfontsというpackageをインストールして、intlfontsのdocに書かれている設定をそのまま使った状態である。

Emacs23だとこれを読み取るのは困難であるが、同じような意味の設定をすれば十分である。Emacs23だとiso10646とか"unicode-bmp"とかの名前もあって、これを使ってもまあ悪くない。

フォントセットの定義は、Xリソースでも.emacsでもできる。
今回は、Emacs23用に.emacsでやってみた。(筆者のXリソースはEmacs22に合わせている為)
まずは、フォントセットを定義せずに、自動的に作られたフォントセットのフォントを変更してみる。

(when (>= emacs-major-version 23)
(when window-system
;;(1)ASCIIフォント設定
(setq default-frame-alist
(append '(
(font . "Sazanami Mincho:style=Regular:size=22") ;ASCII文字のフォント
(width . 80) ;文字が大きいので、ついでにウィンドウサイズ変更
(height . 24)
)
default-frame-alist))

;;(2)最初のフレームのサイズ変更
(set-frame-size (selected-frame) 80 24)

;;(3)日本語フォント変更
(add-hook 'window-setup-hook
'(lambda ()
;;日本語→VLゴシック
(set-fontset-font (frame-parameter nil 'font)
'japanese-jisx0208
(font-spec :family "VL Gothic"))
;;全角カタカナのみ、さざなみ明朝に戻す
(set-fontset-font (frame-parameter nil 'font)
;;'(#x3041 . #x309f) ;ひらがな
'(#x30a0 . #x30ff) ;カタカナ
(font-spec :family "Sazanami Mincho"))
;;半角カナ→Kappaのイタリック体
(set-fontset-font (frame-parameter nil 'font)
'jisx0201
"-kappa-*-medium-i-*-*-20-*-*-*-*-*-jisx0201.1976-*")
))
))

結果

ASCIIフォントの設定はset-frame-font、現在のフォントセットの一部フォント変更は(set-fontset-font (frame-parameter nil 'font) ...)でできる((frame-parameter nil 'font)は現在のフレームのフォントセット名を返す)ので、それらを単に並べればできそうなものであるが、色々ややこしいことがあってそれではうまくいかなかったので、色々工夫してみた。
(1)のASCIIフォント設定は、default-frame-alistに登録するのでなくset-frame-fontを使うと、少なくとも筆者の環境では、.emacs実行後に(おそらくface設定の処理でdefault-frame-alist等のフォントに)また変えられてしまう。もし変えられなくても、C-x 5 2で開いたフレームにはフォント設定が引き継がれなくなってしまう。initial-frame-alistに登録するのでも同様の問題がある。
(2)のウィンドウサイズ変更は、せっかくdefault-frame-alistに書いても、筆者の環境では、最初のフレームについてはこの後default-frame-alistのwidthやheightが反映されない(fontは反映される)ので、仕方なく加えた。initial-frame-alistに登録してもだめだった。
(3)は、set-fontset-fontをすぐに実行すると、この時点ではまだdefault-frame-alistに登録したフォントに切り替わっていないため、無意味になってしまう(おそらくfontset-startupに対する設定になってしまう)ので、強引だがwindow-setup-hookに登録して後で実行させるようにした。

(face-set-after-frame-default)
(set-fontset-font ...)

とすれば、default-frame-alistのフォントに切り替わり、それに対するフォントセットも作られるようで、(3)と同じ結果が得られることを確認したが、どうせ後でdefault-frame-alistのフォントへの切替が発生するし、筆者がfaceの動作を理解していないので、今回は見送った。
なお、(1)でフォントサイズを22ドットとやたらでかくしているのは、さざなみフォントが20ドット以下だとアンチエイリアスされない(20ドット以下はビットマップフォントが内蔵されているため、TrueTypeでなくそちらが使われる)為である。同様に、東風フォントだと16ドット以下と20ドットがアンチエイリアスされない。
また、筆者の環境(FreeBSD 7.3のデフォルトのfontconfig)では、さざなみフォントの場合は(3)をしなくても日本語や半角カナが表示されない訳ではない。

さて、実際にフォントが切り替わってから現在のフレームのフォントセットに対して変更を加えるのは、set-fontset-fontだけで済むのである意味単純だが、あまり美しくない。上のように苦しくなってwindow-setup-hookのコールバックでフォントを切り替えるのでは敗北感すら漂う汚さである。そもそも、普通は先にフォントセットを定義してからフォントをそのフォントセットに切り替えるものである。Xのリソースでの設定ではそのようにしかできない。

そこで、次にフォントセットの定義をやってみる。フォントセットの定義は、create-fontset-from-ascii-fontしてからset-fontset-fontするのが定跡である。次のように書くと、上の例と同じ設定になる。

(when (>= emacs-major-version 23)
(when window-system
;;(4)フォントセット"fontset-test0"の定義
(create-fontset-from-ascii-font
"Sazanami Mincho:style=Regular:size=22" nil "test0")
;;日本語→VLゴシック
(set-fontset-font "fontset-test0"
'japanese-jisx0208
(font-spec :family "VL Gothic"))
;;全角カタカナのみ、さざなみ明朝に戻す
(set-fontset-font "fontset-test0"
'(#x30a0 . #x30ff) ;カタカナ
(font-spec :family "Sazanami Mincho"))
;;半角カナ→Kappaのイタリック体
(set-fontset-font "fontset-test0"
'jisx0201
"-kappa-*-medium-i-*-*-20-*-*-*-*-*-jisx0201.1976-*")

;;(5)フォント設定
(setq default-frame-alist
(append '(
(font . "fontset-test0")
(width . 80)
(height . 24)
)
default-frame-alist))

;;(2)最初のフレームのサイズ変更
(set-frame-size (selected-frame) 80 24)
))


(2)の部分は不満だが、かなりマシになった。

参考:Emacs InfoのDefining fontsetsの章

See more ...

Posted at 23:57 in UNIX | WriteBacks (0)
WriteBacks

May 23, 2010

EmacsのX Windowフォントの設定方法(1)

筆者は普段EmacsをX Windowで使わない。そもそもX Windowを使っていないからだ。使うのはFreeBSDやLinuxで動くEmacsだが、WindowsからTelnetやSSHでアクセスしているので、キャラクターベースである。マウスも使わ(え)ない。
昔はパソコンの性能に対してWindowsが重かったので、FreeBSD+X Windowを愛用していたが、その時はEmacsも重かったので、Emacsはktermやrxvtの中でしか使わなかった。
そのさらに昔、大学の研究室にはX Windowの端末があったので、X上のEmacsを使おうと思えば使えたのだが、Emacsを知ると同時にTelnetも知ってしまい、EmacsをXで使う利点よりも、コンピューターを遠隔操作することの魅力に取り憑かれてしまったので、やはりEmacsは文字ベースの端末で使っていた。
だから、X上のEmacsのカスタマイズというのはほとんどやったことがなかった。

時代は変わって、Windows上の仮想マシンでX Windowがスムーズに動くようになった。先月、訳あって、仮想マシンにFreeBSD 7.3をインストールした。XもEmacsもインストールした。ところで、筆者は昨年より再びEmacsを使い始め、今Emacsがマイブームなのである。そのため、XのEmacsのカスタマイズもやり始めている。大学の研究室でEmacsに出会ってからの1x年に渡る旧知の仲、しかも歳を重ねて英語もEmacs Lispもそれなりに読めるようになった今、もはや何もつまずくことはなかろうと高を括っていたら、フォントの設定にコテンパンにやられてしまった。何ゆえかくも複雑なのであろうか。

たかがフォントの設定に膨大な時間を費やしてしまったので、調べまくったことをここにメモしていくことにする。

●Emacs 22と23の違い
Xのフォントに関して、Emacsのバージョン22と23とでは大きな違いがある。バージョン23ではXftがサポートされ、アンチエイリアスされた滑らかなフォントが表示できるのである。また、フォント名として、あの長ったらしいXLFD名のみでなく、Xftの短い名前も使える。

・通常のビットマップフォントの例
(東雲ゴシック 16ドット)
-shinonome-gothic-medium-r-normal-*-16-150-75-75-c-160-jisx02081990-0
-shinonome-gothic-medium-r-normal-*-16-150-75-75-c-80-iso8859-1
(Ayuゴシック 20ドット)
-ayu-gothic-medium-r-normal-*-20-190-75-75-c-200-jisx02081990-0
ayu-gothic-medium-r-normal--20-190-75-75-c-100-iso8859-1

・アンチエイリアスされたTrueTypeフォントの例(M+2VM+IPAG circle 14pt)
M+2VM+IPAG circle
M+2VM+IPAG circle

しかしながら、その分ちょっと重い。

●Emacs23起動後のフォント変更方法
Shift+左クリックで開くポップアップメニューの"Change Buffer Font..."を選ぶと、フォント選択ダイアログが出てくる。
ダイアログの下半分のプレビューエリアには、Xのセレクションを使って、日本語をペーストすることもできる。(別プロセスのウィンドウの日本語文字列を左ボタンでドラッグして選択し、ここに中ボタンでペーストする等)

しかし、これで設定したフォントはバッファローカルであり、終了時に保存されないどころか、別のファイルを開くと引き継がれない。

●Emacs23のフォントの設定方法(X resourcesを使う場合)
Emacsのフォントの設定は.emacsの中にも書けるが、.emacsに書くには考慮することが色々あって結構難しい。それに対し、Xのリソースに登録する方法は、無難で手軽である。
例えば、~/.Xdefaultsに次のように記述する。

Emacs.font: M+2VM+IPAG circle

"M+2VM+IPAG circle"は、筆者のお気に入りのフォントの名前である。
M+2VM+IPAG circleにすると、ウィンドウサイズが横に広がりすぎるので、ウィンドウサイズも指定する。
Emacs.geometry: 40x32+30+0

ウィンドウサイズが40×32文字、表示位置が(30,0)という意味である。

フォントサイズを変更するには、フォントの高さをpt単位で指定する。
Emacs*attributeHeight: 140
設定する値は実際のpt数の10倍である。14ptなら140、10.5ptなら105とする。
"*"でごまかすのでなく、default faceのattributeHeightだけ指定すれば良いはずなのだが、書き方がわからなかった。("Emacs.default.attributeHeight: 140"では効かなかった)

万一、デフォルト起動でEmacsのXftが有効にならない場合は、

Emacs.FontBackend: xft

を含めておくと良いらしい。

余談だが、Xのリソース設定を~/.Xdefaultsに書いている場合は、アプリケーションの起動時に毎回自動的に読み込まれるので、ここに書いてEmacsを起動すると、設定したフォントで起動する。Xのセッション起動時に読み込まれる~/.Xresourcesに書いている場合は、追記した内容をすぐに反映させるには、次のコマンドを実行すると、Xのリソースに登録される。

xrdb -merge ~/.Xresources

●Emacs23のフォントの設定方法(.emacsに書く場合)
筆者の環境では、たまにEmacs23は重いと感じることがあるため、Emacs22をデフォルトにしている。そのため、XのリソースをEmacs23の設定にしたくない。そのような場合は、.emacsにてフォントを設定することもできる。

フレームのフォントの変更はset-frame-font、フレームのサイズの変更はset-frame-sizeでできる。また、ありがちな問題として、これらの設定はC-x 5 2で別のフレームを開いた時に引き継がれないということがあるので、こういうのはdefault-frame-alistに登録する必要がある。ついでにEmacsのバージョンもチェックするようにして、

(when (>= emacs-major-version 23)
(when window-system
(set-frame-font "M+2VM+IPAG circle") ;最初のフレームのフォント設定
(set-frame-size (selected-frame) 40 32) ;最初のフレームのサイズ
(setq default-frame-alist ;以後のフレームの設定
(append '(
(width . 40)
(height . 32)
(font . "M+2VM+IPAG circle")
) default-frame-alist))
))

でOKである。

筆者の環境では、ここでset-frame-fontをしなくても、この後の処理で最初のフレームのフォントがdefault-frame-alistに書いたフォントになることが確認できたので、set-frame-fontは外した。フレームのサイズについては、このように明示的にset-frame-sizeしないと変わらなかった。

フォントサイズの設定は、詳細を省くが

(set-face-attribute 'default nil :height 140)

のようにするとできる。これはフレームに対する設定ではなく、"default" faceに対する設定である。.emacsにこれを書いても、最初のフレームに関してはfaceの設定は済んだ後なので、最初のフレームについては、face設定の再読み込みが必要である。
(when (>= emacs-major-version 23)
(when window-system
;;(set-frame-font "M+2VM+IPAG circle") ;最初のフレームのフォント設定
(set-frame-size (selected-frame) 40 32) ;最初のフレームのサイズ
(setq default-frame-alist ;以後のフレームの設定
(append '(
(width . 40)
(height . 32)
(font . "M+2VM+IPAG circle")
) default-frame-alist))
(set-face-attribute 'default nil ;default faceの設定
:height 140 ;フォント高さ(/10pt)
)
(face-set-after-frame-default (selected-frame)) ;;最初のフレームのface再読み込み(NG)
))

…が、筆者の環境ではすぐにフォントサイズが戻ってしまった。Emacsの起動時には.emacsが実行された後も色々な処理が走るので、そのどこかで別の値に再設定されてしまうのだろう。その処理が特定できなかったので、今回はEmacs起動の最後の方で実行されるwindow-setup-hookに登録して乗り切ることにした。
(when (>= emacs-major-version 23)
(when window-system
;;(set-frame-font "M+2VM+IPAG circle") ;最初のフレームのフォント設定
(set-frame-size (selected-frame) 40 32) ;最初のフレームのサイズ
(setq default-frame-alist ;以後のフレームの設定
(append '(
(width . 40)
(height . 32)
(font . "M+2VM+IPAG circle")
) default-frame-alist))
(set-face-attribute 'default nil ;default faceの設定
:height 140 ;フォント高さ(/10pt)
)

;;最初のフレームのfaceの再読み込み(後処理)
(add-hook 'window-setup-hook
'(lambda ()
(face-set-after-frame-default (selected-frame)
))
))

See more ...

Posted at 22:39 in UNIX | WriteBacks (0)
WriteBacks

May 05, 2010

(FreeBSD 7.3) ApacheとTomcatを手早く連携させる

先月この玄箱のwebサーバーが起動しなくなって、復旧に時間がかかると思ったので、PC上の仮想マシンにFreeBSD 7.3をインストールして、代替のwebサーバーを構築し始めた。
幸いにして玄箱がすぐに復旧したので、FreeBSDは中途半端な状態で放ったらかしたが、せっかくなので、予備のサーバーとして最後まで構築することにした。

今回のは、動けばいいだけの環境なので、手間がかからないよう、可能な限りportsを使わず、packagesで統一することに決めた。portsを使い出すと、依存するライブラリのバージョンがpackagesと合わなくなって、以後何もかもportsでインストールしないといけなくなる恐れがあるからである。

このサーバーの代替をするには、HTTPサーバーの機能とJava servletを動かす機能が必要である。そう決めた。TomcatはHTTPサーバーの機能も持つので、全てTomcatに任せるという手もあるのだが、TomcatはJavaで動いており、決して軽くない。当然、通常のHTTPリクエストはApacheで処理し、TomcatはJava servletやJSPを動かすのみとしたい。

ApacheとTomcatがそれぞれ別々のポート(80と8080とか)でリクエストを待つと、外部に2つのポートを公開しないといけないことになるし、アクセスURLにポート番号を含めることが必要になり、美しくないことになる。当然、Apacheが一旦全てのHTTPリクエストを受けて、必要なもののみTomcatに転送するようにしたい。

それは、Apacheのmod_proxyを使えば実現できる。このwebサーバーでもそうやっている。
FreeBSD 7.3のインストーラー(sysinstall)のパッケージ一覧でmod_proxyを検索すると、"mod_proxy_html"と"mod_proxy_xml"が見つかるが、どちらをインストールしてもmod_proxyはインストールされない。mod_proxyはApacheの本体と共に配布されているので、mod_proxyという名前のpackageが無ければ、どこかに含まれているとすればApache本体であるが、packagesのどのApacheをインストールしてもmod_proxyは入らない。従って、mod_proxyを使うにはそのようにオプションを設定してapacheをコンパイルするしか無いようである。セキュリティホールになり得るmod_proxyが不必要に有効にならないようにという配慮であろうか。

mod_proxyを使う以外に方法はあるのだろうか。Apacheから一部のリクエストをTomcatに転送する方法としては、次の3つの方法が一般的らしい。(参考:http://dev.ariel-networks.com/Members/inoue/tomcat-apache
・mod_proxy_http
・mod_proxy_ajp
・mod_jk
上の2つはFreeBSD7.3のpackagesには無いが、mod_jkはある。従って、mod_jkしか選択肢が無い。mod_jkも無ければApacheをコンパイルするしか無いと諦めがついたのだが、あるから仕方がない。mod_proxyが無いと、mod_perlを使うhttpdを別に動かして連携することができないが、仕方がない。packagesにmod_jkがあるので、この代替サーバーでのmod_perlの使用は諦める。

結局、以下の手順で、FreeBSD 7.3のpackagesだけでApache+Tomcatの連携ができるようになった。
1. packagesの一覧からmod_jk-ap2-1.2.30_1を選択してインストールする。
 apacheが入ってなければ、それも自動的にインストールされる。
2. Tomcatはpackagesに4.xも5.5も6.0もあるが、どれでも良いので、インストール動くようにしておく。
3. /usr/local/etc/apache2/のworkers.properties.sampleをコピーしてworkers.propertiesという名前にし、以下の行を書き換える。

worker.list=localhost
worker.jsp-hostname.port=8180
worker.jsp-hostname.host=localhost

4. 同ディレクトリのmod_jk.conf.sampleをIncludes/mod_jk.confとしてコピーし、JkWorkersFileの%%APACHEETCDIR%%の所とJkMountの行を書き換える。
JkWorkersFile /usr/local/etc/apache2/workers.properties
JkMount /*.jsp localhost
JkMount /servlet/* localhost
(以下略)

このようにしてApacheを再起動すると、httpdが受けたhttp://(hostname)/*.jspや
http://(hostname)/servlet/*にマッチするURLのリクエストがTomcatに転送されるようになった。

See more ...

WriteBacks

May 03, 2010

(FreeBSD) Emacs+anthy.elのかなキー入力の設定

以前にFreeBSDで(ローマ字でない)かなキー入力の設定をして、たまにjvim+cannaやEmacs+cannaでかな入力をしていたのだが、先月訳あってFreeBSD 7.3を新規にインストールすると、何と7.2まであったcanna-serverがpackagesから無くなっていた。portsを使えば時間はかかってもトラブル無くインストールできるのだろうが、今回はなるべくインストール作業に時間と手間を掛けたくなかったので、この機会にpackagesだけでインストールできるEmacs+anthy.elに完全に乗り換えることにした。

ところが、使ってみるとanthy.elのかな入力モード(anthy-kana-map-mode)のデフォルトの設定は使いづらいことがわかった。特に、全角数字や全角記号を入力する手段が無い(全角のアルファベットは入力できる)のが個人的に支障がある。漢字変換の辞書として登録しようにも、半角記号は漢字変換の対象にならないし、そして全角記号を片っ端からanthy-conf.elのキーマップに登録すると動かなくなってしまったのである。
丁度、GW開始と同時にえげつない風邪をひいて(咳と痰で窒息死するかと思った)未だ蟄居を余儀なくされており、パソコンに向かえるくらいには回復したものの、これより難しいことに取り組めるほど頭が回らないので、この機会に色々調べてanthy.elをカスタマイズしてみた。

(1) X Windowのキーの設定
以前のエントリーに書いたように、X Windowのデフォルトの設定では「ろ」「を」「ー」キー識別に問題があるので、keysymを変更する。
~/.Xmodmapに以下の2行を加える。

keycode 211 = underscore underscore
keycode 19 = 0 bar kana_WA kana_WO

(2) Emacsの設定
後述のキーマップの設定は文字コードがJISでないといけないので、anthy.el関連の設定は.emacs.elとは別のファイルに書くことにした。また、以前のエントリーではシステムのanthy-conf.elのキーマップの設定を書き換えていたが、ここではkeysymの設定をホームディレクトリに置いてるので、これもホームディレクトリに置くことにした。

~/.emacs.elの記述

(load (concat (getenv "HOME") "/.anthy-conf.el"))

~/.anthy-conf.el(文字コード:JIS)

;;anthy.elの設定
(load-library "anthy")
(setq defualt-input-method "japanese-anthy")
;(global-set-key "\C-o" 'anthy-mode)

(anthy-kana-map-mode) ;かなキー入力モード

;;xmodmapの変更に合わせたキーバインド
(anthy-change-hiragana-map "_" "ろ")
(anthy-change-hiragana-map "|" "を")
(anthy-change-hiragana-map "\\" "ー")
(anthy-change-katakana-map "_" "ロ")
(anthy-change-katakana-map "|" "ヲ")
(anthy-change-katakana-map "\\" "ー")

;;Anthyのひらがなモードとカタカナモードのキーマップを同時に設定する関数
(defun anthy-load-bothkana-map (map)
(mapcar (lambda (x)
(let ((key (car x)) (str (cdr x)))
(anthy-change-hiragana-map key str)
(anthy-change-katakana-map key str))) map))

;;日本語でよく使う記号(ワンプッシュにする)
(anthy-load-bothkana-map '(("{" . "「") ("}" . "」") ("?" . "・")))

;;その他全角記号("Q"+キーにする)
;;="@'+*は元々Shiftとの組み合わせで出るので省略
(anthy-load-bothkana-map
'(
("Q0" . "0") ("Q1" . "1") ("Q2" . "2") ("Q3" . "3") ("Q4" . "4") ("Q5" . "5") ("Q6" . "6") ("Q7" . "7") ("Q8" . "8") ("Q9" . "9")
("Q-" . "-") ("Q^" . "^") ("Q\"" . "\")
("Q!" . "!") ("Q#" . "#") ("Q$" . "$") ("Q%" . "%") ("Q&" . "&") ("Q'" . "'") ("Q(" . "(") ("Q)" . ")")
("Q~" . "~") ("Q|" . "|")
("Q[" . "[") ("Q]" . "]") ("Q{" . "{") ("Q}" . "}")
("Q;" . ";") ("Q:" . ":")
("Q," . ",") ("Q." . ".") ("Q<" . "<") ("Q>" . ">") ("Q/" . "/") ("Q?" . "?")))

;;カタカナは設定数が多いとダメのようなので、_はひらがなのみ
(anthy-change-hiragana-map "Q_" "_")
;;(anthy-change-katakana-map)をこれ以上実行すると固まる(\C-gで抜けられる)
;;(anthy-change-katakana-map "Q_" "_")

;;かな/カナ/全角アルファベットの切り替えのカスタマイズ
(setq anthy-rkmap-keybind
'(
;; \C-j --> ひらがな <=> カタカナ
(("hiragana" . 10) . "katakana")
(("katakana" . 10) . "hiragana")
(("walphabet" . 10) . "hiragana")
;; \C-p --> ひらがな <=> カタカナ
(("hiragana" . 16) . "katakana")
(("katakana" . 16) . "hiragana")
(("walphabet" . 16) . "hiragana")
;; \C-q --> ひらがな <=> ABC
(("hiragana" . 17) . "walphabet")
(("katakana" . 17) . "walphabet")
(("walphabet" . 17) . "hiragana")
;; H --> ひらがな
(("katakana" . 72) . "hiragana")
(("walphabet" . 72) . "hiragana")
;; K --> カタカナ
(("hiragana" . 75) . "katakana")
(("walphabet" . 75) . "katakana")
;; L --> ABC
(("hiragana" . 76) . "walphabet")
(("katakana" . 76) . "walphabet")
))

コメントにも少し書いているが、anthy-change-katakana-mapを使ってカタカナモードのキーマップにあまり多く登録すると、Anthyの応答が無くてEmacsが固まってしまう。その時にCtrl-Gを押すと、Emacs上にSegmentation faultと表示される。その後も日本語入力ができない訳ではない。謎である。

(5) anthy.elの修正
anthy-9100hのanthy.elは、Emacs23で使うと起動や変換候補一覧表示にやたら時間がかかる、よく知られたバグがある。これはanthy.elを書き換えて直すしかない。
ついでに、anthy.elをロードすると毎回

old-style backquotes detected!

と出て鬱陶しいので、それも修正する。

59c59
< (if (string-match "^22\." emacs-version)
---
> (if (>= emacs-major-version 22)
164,168c165,169
< (` (progn
< (defvar (, var) (, default-value)
< (, (format "%s\n\(buffer local\)" documentation)))
< (make-variable-buffer-local '(, var))
< )))
---
> `(progn
> (defvar ,var ,default-value
> ,(format "%s\n\(buffer local\)" documentation))
> (make-variable-buffer-local ',var)
> ))

これをファイルに保存して
cd /usr/local/share/emacs/site-lisp/anthy
patch anthy.el < (ファイル名)

とすると、修正が反映される。

See more ...

Posted at 20:25 in UNIX | WriteBacks (0)
WriteBacks

Apr 18, 2010

FreeBSD 7.xにext3のイメージファイルをmountする方法

Linuxでdd if=/dev/hda1 of=/tmp/ext3image.imgなどとやって作成したext3のディスクイメージをFreeBSD 7.3にマウントするのに手間取ったので、成功した手順を記録する。

(1) カーネルにext2fsモジュールをロードしておく
 例)kldload ext2fs
(2) fsckする必要がある場合は、e2fsprogsをインストールしておく
(3) mdconfig -f (イメージファイル名)
以下、(3)によりmd0と表示された(unit 0に割り当てられた)ものとする。
(4) fsckする場合は、e2fsck /dev/md0
(5) mount -t ext2fs /dev/md0 /mnt

See more ...

Posted at 22:43 in UNIX | WriteBacks (0)
WriteBacks

Apr 11, 2010

玄箱HGのDebianが起動しなくなった

このwebサーバーは、玄箱HGという小型の機械で動いている。モニターもキーボードも接続できない、単なるハードディスクをネットワークに接続するための機械である(一応)。その機械がネットワーク経由でアクセスできない状態になると、機械表面に付いている4つのLEDでしか状態を知る術が無くなる。
先週、その玄箱HGが全く応答しない状態に陥り、電源を抜いて再起動すると、赤色LEDが6回点滅して起動しなくなった。玄箱の説明書によると、赤点滅6回はハードディスク異常を意味するらしい。

この玄箱HGで動かしているOSはDebian Linuxである。2年前にインストールした後、起動しないというトラブルはこれまで一度も無かった。先週まで順調に動いていたものだし、OSが壊れたとは考えにくい。HDD自体が壊れたのだろう。
…と考えて、HDDを取り出して別のPCに接続して、Linuxを動かしてmountを試みると、何の異常もなくmountできて、fsckも無事に終わってしまった。しかし、そのfsckが済んだHDDを再度玄箱に接続しても、やはり赤点滅6回であった。
では玄箱が壊れたのか?と思って別のHDDを接続すると、エラーになること無く、EMモード(FROM内蔵のOS)だが正常に起動した。さらに、玄箱用のHDDのバックアップを取ってフォーマットして以前の手順でDebian(sarge)をインストールすると、問題無く起動した。
正常に起動するsargeのバックアップをddで取ってHDDをフォーマットしてddでリストアしてもsargeが正常に起動することを確認して、ddで元のシステム(lenny)をリストアしても、やはり起動しなかった。どうやらDebianが起動不能になってしまったらしい。

起動しなくなった原因のヒントを求めてネットサーフィンしまくった結果、初期の玄箱のファームウェアは2.6系であるLenny(Debian 5.0)のカーネルを起動できないのが原因であることが判明した。
この玄箱のDebianはインストール時には3.0(sarge)で、aptitudeで更新したら自動的にetch(4.0)になり、aptの設定ファイル(/etc/apt/sources.list)がDebianのstableなバージョンを参照する設定だったので、そのままaptitudeを使い続けたら、去年の3月に自動的に5.0(lenny)になってしまったのである。

という訳で、www.revulo.comの手順を参考にして、Lennyの起動に関連する部分だけ再構築することにより、思ったより楽に復旧できたので、その手順を記録する。

●旧Lennyシステムのバックアップ
 HDDを接続したLinuxを起動して、先頭のパーティションのディスクイメージを作成する。
 dd if=/dev/hdb1 of=/tmp/kuro-debian.img
 (HDDが/dev/hdbとして認識されている場合)

●MontaVistaのインストール
HDDの最初のパーティションにある2.6系のLinux kernelを起動するには、"U-Boot"というものを使う方法があるらしいが、FROMを書き換える必要があり、失敗すると玄箱が使用不能になるリスクがある。それに代えて、HDDの最初のパーティションに2.4系のカーネルを置いて、別のパーティションにある2.6系のカーネルを起動するという方法がある。www.revulo.comにあるのは、後者の安全な方法である。
そこで、まず先頭のパーティションにMontaVistaを再インストールする。

1. 玄箱をEMモードで起動
 先頭のパーティションを削除して玄箱を起動するとEMモードになる。
2. telnetで入る
 IPアドレスは玄箱のファームウェアダウンロードツール(付属CDとか玄人指向のサイトとかにある)の中のKuroBoxSetup.exeを起動するとわかる。
 出荷状態ではrootのパスワードはkuroadminである。
3. パーティション作成
 mfdisk -c /dev/hda とすると、懐かしいfdiskのUIが出て来る。
 dで全てのパーティションを削除した後、nでプライマリパーティションを
  hda1: 256M(MontaVista用)
  hda2: 256M(swap用)
  hda3: 4G(Lenny用)
  hda4: 残り
 と作り、tでhda2のタイプを82にしてwでHDDに書き込む。
4. ファイルシステム作成
 mkswap /dev/hda2
 mke2fs -j /dev/hda1
 mke2fs -j /dev/hda3
 mke2fs -j /dev/hda4
5. hda1をmountする
 mount -t ext3 /dev/hda1 /mnt
6. MontaVista一式の圧縮ファイルを転送
 玄箱のファームウェアの中のimage.zipの中にあるtmpimage.tgzを/mnt/にFTPで転送する。
7. MontaVistaを展開
 cd /mnt
 tar xvfz tmpimage.tgz
8. EMモード終了
 echo -n "OKOK" > /dev/fl3
 reboot

●Lennyのインストール
1. インストーラー一式を転送
 www.revulo.comにある以下のファイルを/tmpに転送する。(hda1が256MでMontaVistaをインストールした直後なら全て/tmpに入る)
 debian-lenny-installer-kuroBOX-20090317.tgz
 debian-lenny-kuroBOX-20090317.tgz
 kuro-bootsel2-debian.tgz
 kuro-bootsel2.20080419.tar.gz
 loader.o
 kernelimage-2.6.25.1-kuroHG.tgz
 modules-2.6.25.1-kuroHG.tgz
2. インストーラー実行
 cd /tmp
 tar xvfz debian-lenny-installer-kuroBOX-20090317.tgz
 sh debian-lenny-installer-kuroHG.sh
3. 電源長押しで再起動
 Lennyが起動していることを確認する。

●旧システムのリストア
1. バックアップを転送
 FTPなりsambaなりで/mntに転送する。FTPでもsambaでも、何らかの設定が必要である。
 別のパソコンにHDDを繋いで4番目のパーティションにコピーしても良い。
 今回はaptitudeを使ってsambaをインストールし、このためだけの設定を行った。
2. ディスクイメージをマウント
 mkdir /mnt/hda1-org
 mount -o loop /mnt/kuro-debian.img /mnt/hda1-org
3. ディスクイメージを展開
 cd /mnt/hda1-org
 tar cf - (dev, proc以外の全て) | (cd /; tar xvf -)
 例: tar cf - bin boot etc home lib opt root sbin selinux sys usr var | (cd /; tar xvf -)
4. 電源長押しでシャットダウン
5. 電源を抜いて差して再起動

See more ...

WriteBacks

Mar 28, 2010

Script-Fuで迷路を描いてみた

今月、GIMPのScript-Fuを試したくなったことがあって、少しやってみたので、忘れない内にメモしておく。ついでに、使い道が考えにくいが、迷路を描かせてみた。

・サンプルスクリプト:maze.scm

上のリンク先のスクリプトを、GIMPのユーザースクリプトディレクトリ(UNIX系だと~/.gimp-2.?/scripts/、WindowsだとC:\Documents and Settings\(username)\.gimp-2.?\scripts、
Macだと~/Library/Application Support/Gimp/scripts/等)に置いて、GIMPを起動して、"File"→"Create"→"Maze"→"in new image"を実行すると、迷路の画像が作られる。または、GIMPで画像ファイルを開いて、"Filter"→"Maze"→"in new layer"を実行すると、その画像上に半透明の迷路のレイヤーが追加される。

original → original

Script-Fuは、SchemeというLisp系の言語をベースにした、GIMPに自動処理をさせるためのスクリプト言語である。Schemeの命令と、ファイルを開くとかレイヤーをコピーするとかファジー選択するとかの一通りのGIMPの操作に対応する、GIMPの関数が使える。Script-Fuコンソール上でGIMPの一通りの操作を行うことも、がんばればきっと可能である。
GIMPの関数の一覧は、"Help"→"Procedure browser"またはScript-Fuコンソールの"browse"ボタンを押すと出てくるProcedure browserで調べられる。
Schemeの命令については、GIMP 2.4以降ではSchemeの処理系がTinySchemeというものらしいが、資料が少ないので、以前のGIMPで使われていたSIODの資料を探すと良さそうである。gimp.orgTinyScheme移行に関するページにはR5RSを見ると良いと書かれているが、例えば実際にScript-Fuで動くrandom関数はR5RSには見当たらない。Script-Fuのlanguage referenceやAPI referenceが整うまでは、Script-Fuコンソールで試しながら手探りするしか無さそうである。

Script-Fuのスクリプトの作り方は、GIMPのマニュアルの"A Script-Fu Tutorial"の項に書いてある。作った.scmファイルに
(script-fu-register)
(script-fu-menu-register)
の記述があると、GIMP起動時または"Script-Fu"→"Refresh scripts"をした時にメニューに追加され、登録した関数がメニューから起動できるようになる。
例:

; 登録する関数((script-fu-register)や(script-fu-menu-register)より上の方に置く)
(define (script-fu-create-maze-image width height size …) …)

(script-fu-register
"script-fu-create-maze-image"  ; 登録する関数の名前
"in new image"   ; メニュー上の名前
"Creates a maze in new image"  ; メニュー項目のヘルプ文
"Y. Nomura"   ; オーサー
"(C)Osaka penguin consortium"   ; コピーライト
"2010.3.22"   ; デート
""    ; カラーモデル(""は指定なしを意味する)
SF-VALUE "width" "12"   ; 1つ目の引数の定義(型、ダイアログ上の名前、初期値)
SF-VALUE "height" "12"   ; 2つ目の引数の定義(同上)
SF-VALUE "cell size" "20"  ; 3つ目の引数の定義(同上)
 …   ; …
)

(script-fu-menu-register "script-fu-create-maze-image"
"/File/Create/Maze") ;メニューの追加先:"File"の下

フィルター形式のスクリプト、すなわち今操作している画像(アクティブイメージ)や今操作しているレイヤー(アクティブレイヤー)に対して処理を行うスクリプトの場合は、(script-fu-register)のスクリプトに与える引数のリストの最初をSF-IMAGEにし、アクティブレイヤーに対する操作ならそれに加えて2つ目の引数をSF-DRAWABLEにすると、アクティブイメージやアクティブレイヤーのIDが追加した関数に渡されるようになる。
例:

; 登録する関数((script-fu-register)や(script-fu-menu-register)より上の方に置く)
(define (script-fu-create-maze-layer image drawable width height …) …)
; imageにアクティブイメージのID、drawableにアクティブレイヤーのIDが入る

(script-fu-register
"script-fu-create-maze-layer"  ; 登録する関数の名前
"in new layer"   ; メニュー上の名前
"Creates a maze in new layer"  ; メニュー項目のヘルプ文
"Y. Nomura"   ;ザ・クリエーター
"(C)Osaka penguin committee" ; コピーライト・ディスクリプション
"2010.3.22"   ; ザ・クリエーション・デート
""    ; カラーモデル(任意)
SF-IMAGE "Image" 0   ; 1つ目の引数、アクティブイメージが入る
SF-DRAWABLE "Drawable" 0 ; アクティブレイヤーのIDも必要な場合
SF-VALUE "width" "12"  ; これ以降の引数は実行時にダイアログで入力する
SF-VALUE "height" "12"  ; 型、ダイアログ上の変数名、初期値(""で括るのが無難)
…   ; …
)

(script-fu-menu-register "script-fu-create-maze-layer"
"/Filters/Maze") ;メニューの追加先:"Filter"の下

デバッグの手段は、エラーコンソールが頼みの綱である。エラーコンソールを開いていないと、エラーメッセージがダイアログで出てしまうので、まずはエラーコンソールを開いておく。
構文エラーや実行時エラーに対するGIMPのエラーメッセージは大変シンプルであるが、(tracing TRUE)としておくと、長めのバックトレースが表示されて、助かることがある。
いわゆるprintfデバッグをしたい場合は、コード中で(gimp-message)を呼ぶと、エラーコンソールに任意の文字列を表示することができる。数字を表示したい時は、(number->string)で文字に変換する。
例:

(gimp-message (number->string x))
(gimp-message
(string-append
"x=" (number->string x)
", y=" (number->string y)))

See more ...

Posted at 21:36 in PC一般 | WriteBacks (0)
WriteBacks

Feb 27, 2010

Emacs Lispでシューティングゲームを作ってみた

・画面イメージ

|                                        |
|                                        |
|                                        |  score: 25
|                                        |
|    G         GG        GG         G    |
|     F        FF        FF        F     |
|      E      E  E      E  E      E      |
|       D    D    D    D    D    D       |
|        C  C      C  C      C  C        |
|         BB        BB        BB         |
|                                        |
|                                        |
|         ^                              |
|                                        |
|          ^                             |
|                                        |
|                                        |
|                                        |
|                                        |
|           A                            |

・プログラム tinyshoot.el

・使い方 Emacsで、M-x load-fileとして、このプログラムをロードする。

See more ...

Posted at 22:50 in PC一般 | WriteBacks (1)
WriteBacks

 elispは面倒だし時代遅れですよね。  Common LispでEmacsをカスタマイズできるようになったらいいのに・・・。[link]

Posted by 藤川浩明 at 04/22/2010 03:18:22 PM

Jan 28, 2010

統計学復習メモ18: 少数のベルヌーイ試行による発生確率の区間推定

問:ある機械が20個の部品を作ったら、不良品が2個出てきた。この機械が1個作る毎に不良品を発生させる確率は一定だとすると、不良品発生率は信頼度95%の信頼区間として何%〜何%の間と推測できるか。

観測誤差を考えなければ、すなわち点推定量としては、推定確率はもちろん2/20=0.1である。しかし、標本はたった20個である。これをもって、だから2000個作ったら200個の不良品が出ることが予想される、と言うのはあまりにも乱暴だし、直感的にナンセンスであろう。サンプルが少なすぎて信憑性が低く、説得力が無いのである。
信頼性を高めるにはサンプル数を増やせば良いが、例えば以前のエントリーに書いたような計算方法では、推定確率が0.1前後の場合に誤差を±0.05以内にするには、(1.96/0.05)2*0.1*0.9=約140個のサンプルが必要になる。サンプル数を先に決められない場合や、サンプルはそれしかないという場合は、推定発生率はこの範囲に入る、という信頼区間を求めるしか無い。

観測されたベルヌーイ試行の成功回数(発生回数)からの元の成功率(発生率)の区間推定については、以前のエントリーに書いたように信頼区間の公式がある。
I \in \hat{p}\pm Z\sqrt{\frac{\hat{p}(1-\hat{p})}{n}} ...(1)
(p^は点推定量、Zは標準正規分布N(0,1)に従う値、nはベルヌーイ試行の標本数)

従って、p^=0.1、Z=1.96(右側2.5%点)、n=20とすると、95%信頼区間は0.1±1.96√0.0045 = 0.1±0.131、すなわち-3.1%〜23.1である。(完)

イエース、公式一発、ビバ統計学!
…ちょっと待て、確率なのにマイナスの値?何を間違えたのだろう?

発生率が一定で、1回の試行の結果は発生するかしないかの2通りしか無い試行(ベルヌーイ試行)を複数回行った時の発生回数は二項分布に従う。そして試行回数が十分大きければ二項分布は正規分布で近似できる。試行回数をn、発生率をpとすると、発生回数は平均np、分散np(1-p)の正規分布に(近似的に)従う。観測される発生率(推定確率)は発生回数を試行回数で割ったものだから、平均p、分散p(1-p)/nの正規分布に(近似的に)従う。母分散が既知の場合、正規分布に従う標本の推定値は毋分散÷標本数を分散とする正規分布に従うとするのが区間推定の定跡である(母分散が未知の時は標本分散を使うのでt分布に従うとする)から、信頼区間Iは
I \in \hat{\theta}\pm Z\sqrt{\frac{\sigma^2}{n}}
(θ^は点推定量、Zは標準正規分布のZ値、このnは正規分布に従う標本の数なので今回は1)
で与えられる。冒頭の問題については、θ^=p、σ2=p(1-p)/nなので、信頼区間はやはり(1)の公式の通りである。

という訳で、二項分布を正規分布に近似しているのが問題のようである。
次のグラフは、n=20として、p=0.5とp=0.1の二項分布とN(np, p(1-p)/n)の正規分布を比較したものである。

青線が二項分布、赤線が正規分布である。p=0.5だとかなり近いが、p=0.1だと差がある。比率が0.5から遠いほど、二項分布の正規分布への近似は悪くなるのである。
大体、正規分布に近似するということは0より小さい確率や1より大きい確率を認めるということであり、n=20でp=0.1の場合、正規分布の左側6.8%は負の値に入り、無効になってしまうのである。この6.8%を全てp=0の所に加算すれば(信頼区間の下限が負の値なら0に補正すれば)いいだけの話とも言えなくはないが、pの推定値が0に近づくと急激にp=0の確率が上昇することになるので、ちょっと強引であろう。

上記の比率の信頼区間の公式(1)は、np<5またはn(1-p)<5の場合は不適、すなわちベルヌーイ試行の成功回数(発生回数)も失敗回数(発生しなかった回数)も5以上でないと使えないと言われているらしい。視聴率調査や投票率予想なら最低5人が観て/投票していないと、この公式を使うのは適当でないのである。それに基づくと、冒頭の問題もnp=2なのでこの公式は使えない。

ではこの場合はどのようにして信頼区間を求めれば良いのだろうか。それを解決してくれるのがClopper-Pearson methodによる通称Exact Confidence Interval(Exact CI)である。
区間推定の原点に立ち返ると、信頼区間とは、ある推定値がある信頼度で収まる値の範囲であり、まともに計算するなら事前確率、事後確率を考慮して計算すべきものであるが、それに代えて、推定の元になった観測値及びそれより稀な値が発生する確率が(1-信頼度)以下であるような推定値の範囲を信頼区間として計算する、というのを二項分布のパラメーター推定について行うのがClopper-Pearson methodである。冒頭の問題なら、95%の確率でpが0.1の前後のどこまでの範囲に含まれるかを求める代わりに、pが0.1よりどこまで小さければ不良品が2個以上出る確率が2.5%になるか、pが0.1よりどこまで大きければ不良品が2個以下である確率が2.5%になるか、を求めるのである。
という訳で、ベルヌーイ試行の確率の推定値の信頼区間の下限Plbと上限Pubを束縛する式は次のようになる。(αは1-信頼度)
\sum_{x=0}^{k}\pmatrix{n \cr x}P_{ub}^x (1-P_{ub})^{n-x}=\frac{\alpha}{2}

\sum_{x=k}^{n}\pmatrix{n \cr x}P_{lb}^x (1-P_{lb})^{n-x}=\frac{\alpha}{2}
これを計算したものがExact CIで、BetaCDF(x,a,b)をベータ分布の累積密度関数として、その逆関数を用いて、
P_{ub}=1-BetaCDF^{-1}\left(\frac{a}{2},n-k,k+1\right)
P_{lb}=1-BetaCDF^{-1}\left(1-\frac{a}{2},n-k+1,k\right)
と書けるらしい。

Maximaにはベータ分布の累積密度関数の逆関数(β値を求める関数)がquantile_beta()という名前で存在するので、これを使って信頼区間の上限を計算できる。

(%i1) load(distrib);
(%i2) Pub(n,k,a) := 1-quantile_beta(a/2, n-k, k+1);
(%i3) Plb(n,k,a) := 1-quantile_beta(1-a/2, n-k+1, k);
(%i4) Pub(20,2,0.05);
(%o4) 0.317
(%i5) Plb(20,2,0.05);
(%o5) .012349

答:1.23%から31.7%の間

参考文献:Understanding Binomial Confidence Intervals

See more ...

Posted at 20:03 in 数学 | WriteBacks (0)
WriteBacks

Jan 09, 2010

PMXで楽譜作成

PMXとは、

こういう楽譜を作るツールである。フリーウェアであること、出力される楽譜が綺麗であることもさることながら、入力データをテキストファイルで書けるのが魅力である。

表示されている楽譜の上にマウス操作で音符を乗せていくようなソフトは多数あるが、入力し易いものに出会ったことが無い。筆者が細かいマウス操作が苦手なこともあるが、五線譜の上から2番目と3番目の線の間に音符を持っていって、次の音符は2番目の線の上に乗せて…という作業は苦痛である。ドラッグしているその音符をあと半音上に動かす必要がある時、今マウスが止まってるので、マウスが反応するぎりぎりの速度を狙ってゆっくりとマウスを前に動かし、マウスが反応したらすぐ手を止めないといけない。手を止めるのが少し遅くて目的地より半音上に行ってしまったら、今度は同様に慎重にマウスをバックさせてカーソルが動いた瞬間に手を止めないといけない。そうこうしていると、ボタンを押す指が疲れて一瞬震え、上か下かに半音ずれた所で音符が確定しまう。それを思い出して文章にしてるだけでイライラしてくる。
昔、MSXの「MUE」(ハル研究所)という、マウスが無かったので当然(パソコンの)キーボードで音符を入力する作曲ソフトを買ったことがあるが、そっちの方がずっと入力し易かった。音符はキーボードで入力できる方が便利なのである。

そこでMusiXTeXである。TeXのマクロであり、当然入力はテキストファイルなので音符はキーボード操作で入力できる。そして、フリーソフトであるにも関わらず、出力される楽譜は出版物並みに綺麗である。
MusiXTeXの書式は大変難しいが、そのプリプロセッサであるPMXM-Txを使うと、かなり容易である。M-Txは楽譜無いに歌詞も書けるようにPMXを拡張したものだが、若干PMXと書式が異なる。M-Txを使うにはPMXの知識も必要になるので、歌詞が要らないならPMXだけで充分と思う。

上の楽譜は、次のソースファイルから生成されたものである。

2 1 3 4 3 4 1 0
0 8 20 0.0

bt
./

It144ipipi
Ap

r4 rp ( a82 e+ a ) r r4 ( e82 e+ gs ) r r4 ( a82 e+ a ) r r4 /
( e85 ds e ds e b dn c a4 ) r8 ( c- e a b4 ) r8 ( e- gs b c4 ) r2 /


"./"までの部分は、PMXファイルとして必須の、楽譜全体に関する設定(ヘッダ)であり、"r4"より下の部分が各小節のデータ(ブロックの集まり)である。最低それらが含まれていれば、PMXのソースファイルとして成立する。
このファイルをforelise.pmxとして保存し、PMXがインストールされている環境で
pmx forelise.pmx

または、
pmxab forelise
musixflx forelise
musixtex forelise

とすると、TeXでお馴染みのDVIファイルができる。dvipsでPSファイルに、dvipdfでPDFファイルに変換できる。上の楽譜画像は、DVIファイルをdvipsでPSファイルにしてImageMagickでPNGに変換したものである。
1つ目のpmxコマンド一発でコンパイルする方法だと、ソースファイルに"I"コマンドがあると、ついでにMIDIファイルもできる。

上のソースファイルを解説する。
●ヘッダーの先頭から12個の数字(必須)


通称上での値意味
nv2パートの数
noinst1楽器の数
mtrnuml3(小節の境目の判定に使う)何分の何拍子の分子
mtrdenl4(小節の境目の判定に使う)何分の何拍子の分母
mtrnump3(実際の表示に使う)何分の何拍子の分子
mtrdenp4(実際の表示に使う)何分の何拍子の分母
xmtrnum01弱起(最初の小節が不完全)の場合の最初の小節の拍子数
isig0五線譜の左端の調を決める#や♭の数(負だと♭)
npages0出力ページ数、0は自動
nsyst8五線譜の段数(全ページ分)npages=0の時は1段当たりの小節数
musicsize20音符のサイズ
fracindent0.0五線譜の1段目のインデント量

●ヘッダーのそれ以降の行(必須)

項目上での値内容
楽器名 (noinst)行分の、楽器名(ここでは空行)
音符記号bt各パートの、ト音記号(t)かヘ音記号(b)かの設定(下のパートから)
出力先./出力先ディレクトリ("./"はカレントディレクトリ)

●楽譜全体の設定
"I"で始まる行はMIDIファイル出力の設定
 "t144"はテンポ
 "i...."は(nv)個分の楽器("pi"はピアノ)
"Ap"はMusiXTeXの「Type Kスラー」(またはPostscriptスラー)という綺麗なスラーを使う設定(要インストール)
●楽譜本体
・下のパートから書く
・パートの切り替えは"/"
・音符と音符の間はスペースで区切る
・音符について
 cdefgabはドレミファソラシ、rは休符
 音符内の数字は、音の長さ(1,2,4,8,16,32分音符はそれぞれ0,2,4,8,1,3)とオクターブ(4がト音記号の普通の所)
  長さを省略すると1つ前の音と同じ長さ
  オクターブを省略すると1つ前の音に一番近い高さ(c b(ド、シ)ならシは1つ下のオクターブのシ)
 +/-はオクターブの上下移動
 "s"は#(♭なら"f")
・()はタイ/スラー
・rpは全休符
・小節の区切りは自動的に計算される

もう1つサンプルを作ってみた。解説は省略する。
csikospost.pmx(PMXソースファイル)
csikospost.pdf(できた楽譜)
csikospost.mid(できた音楽ファイル)

ついでにもう1つ公開する。
Nukenin1.pmx(PMXソースファイル)
Nukenin1.pdf(できた楽譜)
Nukenin1.mid(できた音楽ファイル)

参考資料:マニュアル(英語、PDF)

viやEmacsで楽譜を入力する。TeXで楽譜を作る。何とエレガントな響きであることか。

See more ...

Posted at 22:57 in PC一般 | WriteBacks (0)
WriteBacks

Java3Dの光源と物体の表面属性を操作してみる

Java3Dで物体に色を付けるには、光源と物体の表面属性を設定する必要がある訳だが、光源色と表面属性の色成分の関係がよくわからない。光源色を変えても色が変わらなかったり、物体表面の反射成分を変えても色が変わらなかったりする。いろんなパラメーターをいじって試しても、物体が真っ白のままで何が悪いのかさっぱり見当がつかないと、全く理解が進まない。筆者はもう1年以上わけがわからないままである。

そこで、光源色と物体の表面属性をスライドバーで操作できるアプレットを作ってみた。

光源/表面属性のテストアプレット
ソースコード

点光源が上の方を旋回しており、平行光源は左手前にあって右奥に向けている。2つの小さな円錐は、光源のおおよその位置を表している。

操作できるパラメーターを説明する。

●光源について
・環境光源(Ambient light)
 空間全体に万遍なく存在する光。影を作らない。
・平行光源(Directional light)
 ある一定の方向から全空間を等しく照射する光。
・点光源(Point light)
 ある一点から放射状に放たれる光。光源からの距離に応じて減衰する。

●物体の表面属性(材質、Material)について
・拡散反射成分(Diffuse color)
 入射角に関係なく全方向に反射させる色成分。
・鏡面反射成分(Specular color)
 入射角と反射角の大きさが等しい反射をさせる色成分。
・環境光反射成分(Ambient color)
 環境光を反射させる色成分。
・発光色(Emissive color)
 光源に関係なく、自ら発する光の色成分。
・つや(Shininess)
 鏡面反射の鋭さ。

大体、自然界と同じように、光源色の一部の成分が反射光となる感じである。白色光に対しては、赤色光のみを反射する物体は赤くなるし、緑色光のみを反射する物体は緑色になるが、青色光に対しては、赤色光や緑色光のみを反射する物体は光を反射せず黒くなる。

バーをスライドさせても物体が真っ白のまま変化しなくても、根気よくいろんなバーをスライドさせていれば、どれかを触った時にきっと色に変化が起こる。
どうやら有効なパラメーターはTarget colorによって変わるようであるが、まだ関係がよくわからない。そのうち、ちゃんと理屈を知ってからいじって理解しようと思う。今回はこれを作っただけで満足する。

今回のアプレットでは、Java3Dのシーングラフ(オブジェクトの木構造)を途中で変更している("Change shape"ボタン押下時)。それに関して調べたことを記録する。
・J3Dスレッドが使用中のシーングラフから削除できるノードはBranchGroupノードのみである。従って、後で切り離したいノードは切り離し用のBranchGroupノードの下に配置する必要がある。
・シーングラフを操作するためには、一度Universeから切り離す必要がある。そのため、シーングラフにはALLOW_DETACHを設定しておく。
・SimpleUniverseの場合、シーングラフのdetachは

SimpleUniverse#getLocale()#removeBranchGraph()

で行う。その後のattachは通常のSimpleUniverse#addBranchGraph()で良い。
・BranchGroupノードに繋がる子ノードを追加したり削除したりするためには、そのBranchGroupノードにALLOW_CHILDREN_WRITEを設定する必要がある。
・AppearanceやMaterialのインスタンスは、シーングラフをdetachせずに変更してもJ3Dの描画に反映されるようである。

See more ...

Posted at 22:57 in Java | WriteBacks (0)
WriteBacks

Java3Dの光源と物体の表面属性を操作してみる

Java3Dで物体に色を付けるには、光源と物体の表面属性を設定する必要がある訳だが、光源色と表面属性の色成分の関係がよくわからない。光源色を変えても色が変わらなかったり、物体表面の反射成分を変えても色が変わらなかったりする。いろんなパラメーターをいじって試しても、物体が真っ白のままで何が悪いのかさっぱり見当がつかないと、全く理解が進まない。筆者はもう1年以上わけがわからないままである。

そこで、光源色と物体の表面属性をスライドバーで操作できるアプレットを作ってみた。

光源/表面属性のテストアプレット
ソースコード

点光源が上の方を旋回しており、平行光源は左手前にあって右奥に向けている。2つの小さな円錐は、光源のおおよその位置を表している。

操作できるパラメーターを説明する。

●光源について
・環境光源(Ambient light)
 空間全体に万遍なく存在する光。影を作らない。
・平行光源(Directional light)
 ある一定の方向から全空間を等しく照射する光。
・点光源(Point light)
 ある一点から放射状に放たれる光。光源からの距離に応じて減衰する。

●物体の表面属性(材質、Material)について
・拡散反射成分(Diffuse color)
 入射角に関係なく全方向に反射させる色成分。
・鏡面反射成分(Specular color)
 入射角と反射角の大きさが等しい反射をさせる色成分。
・環境光反射成分(Ambient color)
 環境光を反射させる色成分。
・発光色(Emissive color)
 光源に関係なく、自ら発する光の色成分。
・つや(Shininess)
 鏡面反射の鋭さ。

大体、自然界と同じように、光源色の一部の成分が反射光となる感じである。白色光に対しては、赤色光のみを反射する物体は赤くなるし、緑色光のみを反射する物体は緑色になるが、青色光に対しては、赤色光や緑色光のみを反射する物体は光を反射せず黒くなる。

バーをスライドさせても物体が真っ白のまま変化しなくても、根気よくいろんなバーをスライドさせていれば、どれかを触った時にきっと色に変化が起こる。
どうやら有効なパラメーターはTarget colorによって変わるようであるが、まだ関係がよくわからない。そのうち、ちゃんと理屈を知ってからいじって理解しようと思う。今回はこれを作っただけで満足する。

今回のアプレットでは、Java3Dのシーングラフ(オブジェクトの木構造)を途中で変更している("Change shape"ボタン押下時)。それに関して調べたことを記録する。
・J3Dスレッドが使用中のシーングラフから削除できるノードはBranchGroupノードのみである。従って、後で切り離したいノードは切り離し用のBranchGroupノードの下に配置する必要がある。
・シーングラフを操作するためには、一度Universeから切り離す必要がある。そのため、シーングラフにはALLOW_DETACHを設定しておく。
・SimpleUniverseの場合、シーングラフのdetachは

SimpleUniverse#getLocale()#removeBranchGraph()

で行う。その後のattachは通常のSimpleUniverse#addBranchGraph()で良い。
・BranchGroupノードに繋がる子ノードを追加したり削除したりするためには、そのBranchGroupノードにALLOW_CHILDREN_WRITEを設定する必要がある。
・AppearanceやMaterialのインスタンスは、シーングラフをdetachせずに変更してもJ3Dの描画に反映されるようである。

See more ...

Posted at 22:38 in Java | WriteBacks (0)
WriteBacks