hexadecimal number なディレクトリ群をパッと作る方法

16進数の(00 から FF まで 00,01,..09,0A,..0F,10,..1F,..FF と続く)連番ディレクトリをパッと作る方法。
zsh かつ 00 から 99 とかだと

foreach i in {00..99}
    mkdir $i
end

こんな簡単なんだけど、16進数だとうまくいかないんだよねー。
悩んだ挙句思いついたのはこんな Perlワンライナー

% perl -e 'mkdir sprintf( "%.2X", $_) for (0..255)'

Ubuntu Linux Feisty Fawn -> Gusty Gibbon 移行メモ

若干出遅れた感がありますが、Gusty への移行が結構大変だったのでその移行メモ。

nvidia-glx 問題

envy とかを使って最新の nvidia driver を install してたりすると、Gusty への upgrade 中に nvidia-glx の更新に失敗することがあるみたいです。
このままだと当然 X は起動しないので、今までだと Ctrl + Alt + F1 とかで console におちて作業してたんだけど、Gusty からは BulletProof-X (参考 : BulletProofX - Ubuntu Wiki )というものが導入されているらしく、xorg.conf が間違ってたりして X の起動に失敗しても Windows の safe mode のような低解像度設定の X を代わりに起動してくれます。
BulletProof-X が有効かどうかは /etc/gdm/gdm.conf の

# This runs Ubuntu's BulletProof-X failsafe mode.
FailsafeXServer=/etc/gdm/failsafeXServer

に書いてある。Gusty ではこの BulletProof-X は default で有効になっているらしく、勝手に X が低解像度で起動くれたので、terminal emulator を起動して nvidia 関連の package を再 install して、

% sudo apt-get remove nvidia-glx
% sudo apt-get remove nvidia-kernel-2.6.20-16-generic
% sudo apt-get remove nvidia-kernel-common
% sudo apt-get remove nvidia-kernel-source
% sudo apt-get autoremove
% sudo apt-get install nvidia-glx

として、ログアウトすれば nvidia driver が使えるようになりました(上の例はちょっとやりすぎかも)。BulletProof-X を見るとさらに X の設定変更も出来るみたいですね。Ubuntu (and BulletProof-X) 素晴らしすぎる。

font 描画問題

個人差があるとは思うんだけど、Gusty が Feisty と比べて font の描画が悪いと感じる人は以下を試すといいかも。
システム -> 設定 -> 外観の設定 -> フォントで

    描画方法 : サブピクセルのスムージング(LCDs)

を選択。更に "詳細" ボタンをクリックして、

    滑らかさの補正(スムージング) : サブピクセル(LCDs)
    線幅の補正(ヒンティング)     : なし
    サブピクセルの順番           : RGB

に設定することで Fesity 時と同じレベルのフォント描画になる(ように少なくても僕は感じた)。キモは "ヒンティング : なし" なのかな。
参考 : http://ubuntuforums.org/showthread.php?t=555964

no sound 問題

サウンドバイス不能になる場合があるらしい。僕の環境では 2台に一台発生している。
参考 : https://bugs.launchpad.net/ubuntu/+source/gstreamer/+bug/131711
参考 : https://lists.ubuntu.com/archives/ubuntu-devel-discuss/2007-August/001506.html
未解決...。サウンド鳴らなくてもあんまり困らないけどね。

beryl to compiz fusion

beryl project は既に compiz fusion に統合されているので Gusty にはありません。かわりに compiz fusion が使えるのでこっちを使いましょう。なんか機能がたりない気もするけど。

IPMessenger に UDP hole punching を実装してみる

Skype が NAT 越えに使用しているという UDP hole punching を勉強がてら IPMessenger で実装してみました。UDP hole punching については P2Pとファイアウォール というページが非常に参考になります。
まず、Perl の Net::IPMessenger モジュールを CPAN から持ってきます(自作のモジュールを試しに拡張してみたかっただけ)。そしてこれに二つのメッセージを追加します。ついでにスーパーノードを指定するメソッドを追加するのと、スーパノードに依頼を出すコマンド(examples/ip_messenger.pl が使う)を作っておきます。
% diff -u IPMessenger.pm.org IPMessenger.pm

--- IPMessenger.pm.org  Thu Oct 12 00:58:26 2006
+++ IPMessenger.pm      Thu Oct 11 01:14:58 2007
@@ -8,15 +8,15 @@
 use Net::IPMessenger::RecvEventHandler;
 use Net::IPMessenger::MessageCommand;

 __PACKAGE__->mk_accessors(
         packet_count    sending_packet      user            message
         nickname        groupname           username        hostname
         socket          serveraddr          sendretry       broadcast
-        event_handler   debug
+        supernode       event_handler       debug
 );

 our $VERSION = '0.06';
@@ -73,6 +73,11 @@
 sub add_broadcast {
     my $self = shift;
     push @{ $self->broadcast }, shift;
 }

+sub add_supernode {
+    my $self = shift;
+    $self->supernode(shift);
+}
+
 sub recv {}

% diff -u MessageCommand.pm.org MessageCommand.pm

--- MessageCommand.pm.org  Tue Sep 26 16:47:56 2006
+++ MessageCommand.pm      Tue Oct  2 23:57:49 2007
@@ -32,6 +32,8 @@
     GETDIRFILE      => 0x00000062,
     GETPUBKEY       => 0x00000072,
     GETPUBKEY       => 0x00000073,
+    ASKPUNCHING     => 0x00000080,
+    ORDERPUNCHING   => 0x00000081,
 );

 our $MODE     = 0x000000ff;

% diff -u RecvEventHandler.pm.org RecvEventHandler.pm

--- RecvEventHandler.pm.org  Thu Oct 12 00:16:12 2006
+++ RecvEventHandler.pm      Thu Oct 11 01:26:12 2007
@@ -97,6 +97,53 @@
     );
 }

+sub ASKPUNCHING {
+    my $self = shift;
+    my $them = shift;
+    my $user = shift;
+
+    my $nick = $user->option;
+    my $addr;
+    my $port;
+    for my $val ( values %{ $them->user } ) {
+        if ( $nick eq $val->nickname ) {
+            $addr = $val->peeraddr;
+            $port = $val->peerport;
+            last;
+        }
+    }
+    return unless $addr;
+
+    $them->send(
+        {
+            peeraddr => $addr,
+            peerport => $port,
+            command  => $them->messagecommand('ORDERPUNCHING'),
+            option   => inet_ntoa( $them->socket->peeraddr )
+                            . "\0"
+                            . $them->socket->peerport,
+        }
+    );
+}
+
+sub ORDERPUNCHING {
+    my $self = shift;
+    my $them = shift;
+    my $user = shift;
+
+    my $option = $user->option;
+    my( $addr, $port ) = split /\0/, $option;
+
+    $them->send(
+        {
+            peeraddr => $addr,
+            peerport => $port,
+            command  => $them->messagecommand('BR_ENTRY'),
+            option   => $them->my_info,
+        }
+    );
+}
+

% diff -u CommandLine.pm.org CommandLine.pm

--- CommandLine.pm.org  Thu Oct  5 15:07:47 2006
+++ CommandLine.pm      Tue Oct  2 23:58:45 2007
@@ -83,6 +83,21 @@
     return;
 }

+sub ask {
+    my $self   = shift;
+    my $sendto = shift;
+
+    my $command = $self->messagecommand('ASKPUNCHING');
+    $self->send(
+        {
+            peeraddr  => $self->supernode,
+            command   => $command,
+            option    => $sendto,
+        }
+    );
+    return;
+}
+
 sub exit {
     my $self = shift;
}

こんな順序でメッセージを送信していけば NAT の問題さえなければ UDP hole punching が出来るはず。

                           (4) ORDER_PUNCHING
       (3) ASK_PUNCHING  +---------------------------+
  +--------------------> |                           |
  |    (1) BR_ENTRY          (1) BR_ENTRY            |
  |  +-----------------> E <---------------------+   |
  |  |                                           |   |
  |  |                                           |   |
  |  |                                           |   |
  |  |                                           |   |
  |  |                                           |   |
  |  |                                           |   |
  |  |  NAT                                  NAT |   |
  |  |  ||           (2) BR_ENTRY             || |   |
  +- B  || A -----------------------------> C || D <-+
        ||           (5) BR_ENTRY             ||
        ||   <-----------------------------   ||

A : 192.168.1.2
B : 192.168.246.129
C : 192.168.1.3
D : 192.168.239.128
E : 192.168.1.4

まず、examples/ip_messenger.pl をノード B, D, E で起動します。B, D は E をスーパーノードとして指定しておきます。
ここから、メッセージ送信を開始します。

  1. 最初に B, D は、E 宛に BR_ENTRY メッセージを送信する
  2. B から D に BR_ENTRY メッセージ送信 C までは届くが NAT は越えない
  3. (2) が失敗したので E に ASK_PUNCHING メッセージを送信
  4. E は (1) で D から BR_ENTRY を受信して D を知っているので D に ORDER_PUNCHING メッセージを送信する。これは NAT を越えて届く
  5. D から B に BR_ENTRYを送信する。これも NAT を越えて届く

この後の B <-> D 間の通信は UDP hole punching の状態になり、普通に双方向のメッセージが届くようになります。
NAT によってはこの構成では正しく動かないものをあるみたいですが、UDP hole punching そのものを実装するのは結構簡単な印象でした。どちらかというとNAT 2台とさらに別ノードがある環境を構築するのが大変です。VMWare を使うと NAT の中のノードが簡単に作れるのでこんなテストのときにはお勧めなのかな。

jp.archive.ubuntu.com の feisty-updates が 404 で更新出来ない

どうも今週の始めくらいから jp.archive.ubuntu.com の feisty-updates ディストリビューション404 not found になってアーカイブファイルがダウンロードできない状態が続いているようだ。前から調子が悪かった気もするし、最近だけの気もする。
原因はよくわからないんだけど、これを回避するためには /etc/apt/sources.list を以下のように編集して(jp を消す)、

## Major bug fix updates produced after the final release of the
## distribution.
#deb http://jp.archive.ubuntu.com/ubuntu/ feisty-updates main restricted
#deb-src http://jp.archive.ubuntu.com/ubuntu/ feisty-updates main restricted
deb http://archive.ubuntu.com/ubuntu/ feisty-updates main restricted
deb-src http://archive.ubuntu.com/ubuntu/ feisty-updates main restricted

% sudo apt-get update してから、アップデート・マネージャでアップデートをインストールすれば良い。出来ればローカルミラーを使いたいのでアップデートが終わったら jp を戻しておこう。

XML::LibXML のアップデートで plagger が動かなくなった件

昨日 FreeBSD マシンの XML::LibXML を p5-XML-LibXML-1.65000 にアップデートしたら、plagger が動かなくなった。いろいろ調べた挙句、#29683: Not compatible with XML::LibXML >= 1.64 の patch を p5-XML-RSS-LibXML-0.30.01 にあてれば動くようになった。
直した後に気がついたんだけど、同じ症状の人は他にもいるようだ。[plagger]CPANでXML::LibXML 1.64にするとPublish::Feedがエラーを出すという報告がチラホラ とか。現象は似ているので、同じ方法で直る人はいるかな。

perl.vim で package ファイルを開く

ctagsのPerl拡張サポートがすこぶる素晴らしすぎる件 を見て思ったんだけど、package ファイルにジャンプしたいだけなら、perl.vim 使う方が簡単じゃないの?vim7.x だと標準添付じゃなかったっけ。
perl.vim を使えば package 名の下にカーソルがある状態で gf (goto file) コマンド入力すれば新しいバッファで package ファイルを開けます。package 名とファイル名が一致してないと無理だけど。
僕は perl.vim

"setlocal include=\\<\\(use\\\|require\\)\\>

コメントアウトして (Ctrl+N, Ctrl+P の入力補完時に path のファイルを見に行かないようにする)
.vimrc に

autocmd FileType perl set isfname-=-

と書いて (CGI->new; を CGI と認識するために '-' はファイル名から外す) 使ってる。
最も、これ(perl.vim)だとメソッドジャンプはできないので ctags は ctags で便利なんだけど。