8 月 29 日(日)の日記

日本一時帰国の感想。

8 月 14 日から同 25 日まで、1 年半ちょっと振りに日本へ帰った。主な目的は就労ビザの延長のため、アメリカ大使館で面接を受ける事でした。スケジュールが直前まで決まらずさいごまでばたばたした旅程でしたが、今回はいろいろと思うところがあったのでまとめてみます。

電子マネー

日本ではもう完全に当たり前になった Suica や PASMO のような電子マネーですが、改めて便利さと人々への浸透の深さに驚いた。もちろん、ぼくがハワイに来る前からこれらの電子マネーはみんな当たり前の様に使ったいたんだけど、今年の夏、ついにセブンイレブンでも Suica が使えるようになった事に、ちょっとした時代の流れを感じた。これまでもセブンイレブンは(中身は Suica と同じの)nanaco というカードを発行していて、ぼくも持っているけど、ついに Suica、PASMO の勢いにおされた形になった。

ぼくが自分用に Suica を作ったのは確か 2003 年くらいで、2005 年に一度盗まれて再発行してもらったので、ペンギンの絵が描いてあるちょっと新しいバージョンです。Suica は、最初は JR 東日本の一部の駅の改札機でしか使えなくて、駅内のキオスクなどで使うのは Suica イオカードという、ペイメント機能付きのカードでなくてはいけなかった記憶がある。

それからしばらくして、地下鉄や一部の私鉄・バスで使える PASMO が登場した。しかも、たしか初めから Suica と PASMO は互換性があり、PASMO 用の改札機で Suica も使えたように思う。

2008 年の暮れに一時帰国したときに、西武池袋線の駅のホームで、きゃっきゃと雑談をしている学校の制服を着た女の子が、まったく自然に PASMO で自動販売機の支払いをしているのを見て驚いた。まだ Suica も無かった頃「電子マネー」という概念が語られ始めた時は、彼女たちからは最も離れた場所に位置していたのに。

Suica や PASMO を使って自販機で買い物するときは、支払いをする「前」に商品を選ぶので、従来とは操作の手順が違うんだけど、意外とすんなり受け入れられたようだ。

鉄道

これもいまさらなんですが、東京の地下鉄網には改めて感心させられた。特に副都心線を使うと西武池袋線沿線から渋谷まで 1 本で行けてしまう。便利すぎる。あと、たぶん、すべての地下鉄の駅で NTT コミュニケーションズの無線 LAN アクセスポイントが使えるので、iPhone のデータローミングを使ってなかったぼくはすごく助かった。

ぼくが関西から東京に移った 2000 年頃はちょうど大江戸線が開通したときで、それから 10 年もしない間に副都心線が開通し、いまだに進化を止めない勢いを感じます。

それから、JR 山手線の一部でも、プラットホームに人が誤って飛び込まないように扉付きの「柵」が出来ていたのを確認した。まだ山手線の全駅ではないみたいだけど、ぼくはああいう過保護なサービスが大好きだ。コストもかかるだろうから作るのは大変だろうけど、あれで救われる人の命もそれなりにあるんじゃないだろうか。しかし、あれをもしハワイにでも作ろうものなら、すぐに落書きで汚されてしまうだろうけど、東京の地下鉄や JR の駅の柵はぼくが見た限りみんなきれいだった。

ハワイ(というかオアフ島)には、バスとタクシーしか公共の交通機関がない。ホノルルの市バスは日本から来た人からするとお世辞にもきれいで使いやすいとは言えないけど、どういうわけかあれがアメリカで一番の公共交通機関に選ばれたらしい。さすがにそれは無いと思うけど。

ハワイのバスで嫌なのは、全体的に薄暗くて汚い、バス停に街灯も何も無くホームレスや物乞いがいて怖い、値段が高い(少し前から断続的に値上げが続いていて今ではどこからどこまで乗っても $2.50)こと。ハワイにも鉄道を造る計画があってテレビでもたまに取り上げられるけど、まだ何十年も先の話になりそう。

低価格飲食店チェーン

今回の帰国では、少し意識して、安いチェーンのお店で食事をとるようにした。ぼくは以前は和民とかの安い居酒屋のメニューがあまりにもまずかったので、全体的にそういう低価格帯のお店は避けてた。貧乏な人はこういうまずい物だけを食べさせられ、おいしい物の味を知らずにこういう低質な店にお金をむしり取られてかわいそうとさえ思っていた。

しかし今回行ったところは大体はおいしくて、しかもサービスがまともだった。行ったのは 100 円回転寿司の「くら寿司」と「スシロー」、うどんの「丸亀製麺」、中華の「日高屋」、バーの「プロント・イルバール」。特にサービスが良いと思ったのは日高屋とくら寿司でした。

くら寿司は、注文をほぼすべて機械のパネルで受け、皿を数えるのもほぼ機械化していて、しかも生ビールを注ぐのまで機械でセルフサービスで出来るようになっている。ここまで機械化すると、人間が接客する部分はテーブルへの案内と会計くらいなので、そこをきちんとやりさえすれば客は店員に対して嫌な思いをしなくてすむ。

それから、日高屋はぼくが東京にいるときから 290 円ラーメンとしてたくさんあったけど、どうせまずいだろうと思って、それまで入った事が無かった。だけど、入ってみると生ビールはあるし、単品でおつまみがいろいろ注文できるし、それなりに調理しているみたいでレトルトっぽくないし、接客も比較的まともだし、かなりすすんでいると思った。

店員はチップももらわずに低賃金でこんなにちゃんと働いている。それは、ネガティブに考えればまあネガティブなんだけど、そのかわり彼らは一定の教育を受けられ、それは次の仕事に生かす事が出来るし、店としてもいちいち自分で接客マニュアルなんかを作る必要がないから失敗が少ないのだろう。

日本人はソフトウェアを作るのが苦手というけど、これらのお店のマニュアルや店員の教育プログラムは世界的な基準で見ても相当にレベルが高いんじゃないだろうか。ただ、それと同時に、こういうサービスをたくさんの店舗で一定の質を保って提供できるのは、おそらくは、客の質もそれなりに一定だからだとも感じた。

たとえばハワイとかだと、いろんな人種の人がいるし、アメリカ人の白人だけでもいろんな極端な性格の人がいるので、画一的な接客マニュアルで対応するのは難しいのかもしれない。日本みたいに低価格のサービスがここまで先鋭化した背景には、単一の民族しかいない事がうまく働いたんじゃないだろうか、とか思った。そういう意味で、新しいサービスを開発し試験的に始めてみるには、日本はいい環境なのかもしれない。

携帯電話

ハワイだとバスに乗ったりすると iPhone を使っている人がすごく多いのに気がつく。アメリカには昔からスマートフォンというカテゴリーがあって、ブラックベリーとか Windows モバイルとかそういう多機能携帯はすでに昔からあった。ただ、やっぱりこういうのはちょっとオタクやビジネスマン向けのような扱いだったみたいで、iPhone は、スマートフォンを持つほどじゃないけど、今までの電話しか出来ない携帯電話ではちょっと満足できないという人にうまく届いたんじゃないかと想像しています。

しかし東京では iPhone を使っている人はあまり見かけなかった。あたりまえだけど、iPhone に付いている機能はほとんどすべて、日本で数千円で買える携帯電話に当たり前の機能として付いているものばかりだ。最新型の iPhone 4 で「前面にカメラが付いてテレビ電話ができます」なんて言っているのを聞いても、日本の感覚だと「どこが新しいの?」で終わってしまうレベルだ。

まとめ

たまにテレビとかで、日本人が自虐的に「日本人は便利さと引き換えに心の豊かさを失った」とかいうのを見かけるけど、たぶんそんな事は無い。これだけ便利になると周りの人との利害の衝突(ホームレスに小銭を要求されて嫌な思いをするとか、マナーの悪い人種の人たちがいるところへ行かないといけないとか)が少ないので、精神的にも前向きに暮らしていけると思う。

日本の便利さは確かに「異常」と言えるかもしれないけど、ぼくみたいにこれからソフトウェアとかでサービスを開発する立場からすれば、こういうぬるま湯に入っていないと見えない潜在的なストレスや需要はやっぱりあると思う。だから、これから 10 年くらい先の世界標準を先取りするつもりで、このぬるま湯にしっかり浸かっておくのも悪くはないんじゃないかな。

08 月 05 日(Thu)のアレゲメモ

SWIG を使った Lua バインディングの作り方。(前編)

LibXML の tree ライブラリの Lua バインディングを作ってみました。実際にやってみると途中でいろいろ躓きましたが最終的にはシンプルな形にできたのでやり方をまとめてみました。

今回制作した SWIG のインターフェイスファイルやその他のファイルはひとつの Gist にまとめたのでご自由にご覧ください。

SWIG のインターフェイスファイル

SWIG のインターフェイスファイルで、モジュール名、ヘッダファイルのインクルードの指定と、ラッパーを作りたい関数のプロトタイプ宣言を書きます。基本的には、%include ディレクティブを使ってヘッダファイルをそのままインクルードしてやれば動きます。

単純なラッパ

インターフェイスファイルの基本的な記述方法は、C/C++ のヘッダファイルと同じです。したがって、単純に %include ディレクティブを使ってヘッダファイルをインクルードしてしまえば、一応インターフェイスファイルができたことになります。たとえば、LibXML2 の tree.h に対するインターフェイスファイルの一番簡単な形は次のようになるでしょう。

%module libxml2

%{
  #include <libxml2/libxml/tree.h>
  #include <stdio.h>
%}

%include </usr/include/libxml2/libxml/xmlexports.h>
%include </usr/include/libxml2/libxml/xmlversion.h>
%include </usr/include/libxml2/libxml/tree.h>

最初の行の %module は、Lua からライブラリ API を呼び出すためのモジュール名を指定します。ここでは、libxml2.funcname() のような形で呼び出したいので libxml2 というモジュール名にしました。

次に %{ から %} までに書かれている部分は、生成されるラッパーのソースコードにそのまま書き出されます。実際に生成されたソースコードを覗いてみるとこの様子が確認できます。

そして次の行以降に並んでいる %include ディレクティブが、このインターフェイスファイルの本体部分です。%include は、単に指定されたファイルをこの位置に展開するだけです。%include で読み込まれるファイルはインターフェイスファイルの構文で書かれている必要がありますが、ヘッダファイルに書かれている関数宣言の書き方がそのままインターフェイスファイルでも使えるので、このような手抜きができます。

SWIG 起動

さて、ここまでできたら実際に SWIG を起動してラッパーを生成してみましょう。シェルのコマンドラインから次のように入力してください。

swig -lua libxml2.i

そうすると、libxml2_wrap.c というファイルが生成されます。これを通常の LibXML2 のアプリケーションと同じようにコンパイル、リンクすると Lua のモジュールができます。ただ、語述するようにこれでは役に立たないので、具体的なビルド方法については後回しにします。

typemap

組み込み型や std::string のような基本的な型については、SWIG が自動的に Lua の対応する型に変換してくれます。しかし、ライブラリ固有の型についてはどのように Lua のデータに変換するかを教えてあげる必要があります。

SWIG では、このデータ型の変換のために %typemap というディレクティブを使って変換の方法を指示します。

パターンマッチ

%typemap では、関数の入出力の型と仮引数名をつかって、Lua の値へのマッピングのやり方を記述します。通常、C の関数プロトタイプ宣言では仮引数の名前は意味を持ちませんが、SWIG はこれを型を補うための重要な情報として活用します。これらの情報をパターンとして記述して、SWIG はこのパターンとそれぞれの関数プロトタイプ宣言を比較し、どのようなラッパーを適用するかを決めるのです。

%typemap(in, numinputs=0) (xmlChar ** mem, int * size) (xmlChar *temp, int templen) {
  $1 = &temp;
  $2 = &templen;
}

%typemap(argout) (xmlChar ** mem, int * size) {
  // Append output value $1 to $result
  lua_pushlstring (L, *$1, *$2);
  SWIG_arg ++;
}

この例では、まず xmlChar ** mem, int * size の部分がパターンで、このパターンにマッチする引数を持つ関数に対して、その下に書いた処理を実行します。このパターンはたとえば、次のような関数プロトタイプ宣言にマッチします。

XMLPUBFUN void XMLCALL
                xmlDocDumpFormatMemory  (xmlDocPtr cur,
                                         xmlChar **mem,
                                         int *size,
                                         int format);

ここで、xmlChar **memint *size がこの順番で出てきていることに注意してください。また、同じ型でも、別の仮引数名を使った次のような関数にはマッチしません。

XMLPUBFUN void XMLCALL
                xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc,
                                         xmlChar **doc_txt_ptr,
                                         int * doc_txt_len,
                                         const char *txt_encoding,
                                         int format);

xmlChar** 型の仮引数の名前が mem ではないことに注意してください。

さて、%typemap ディレクティブの中身をもう少し見てみます。最初の %typemap では、まず in と書いて、与えられた引数を入力として使うことを宣言しています。次の numinputs=0 は、「この引数は Lua からの引数を消費しませんよ」っていう意味ですが、あとで詳しく説明します。

次に続く (xmlChar ** mem, int * size) はすでに説明したように、ラッパーを適用したい関数のパターンです。

そして、その次の (xmlChar *temp, int templen) は、ラッパー関数内で使うローカル変数の宣言です。

説明するよりも、実際に生成されたラッパー関数の中身を見るほうが分かりやすいので、ちょっとのぞいてみましょう。たとえば、すでに出てきた xmlDocDumpFormatMemoryEnc のラッパー関数は次のようになりました。

static int _wrap_xmlDocDumpFormatMemory(lua_State* L) {
  int SWIG_arg = 0;
  xmlDocPtr arg1 = (xmlDocPtr) 0 ;
  xmlChar **arg2 = (xmlChar **) 0 ;
  int *arg3 = (int *) 0 ;
  int arg4 ;
  xmlChar *temp2 ;
  int templen2 ;

  {
    arg2 = &temp2;
    arg3 = &templen2;
  }
  SWIG_check_num_args("xmlDocDumpFormatMemory",2,2)
  if(!SWIG_isptrtype(L,1)) SWIG_fail_arg("xmlDocDumpFormatMemory",1,"xmlDocPtr");
  if(!lua_isnumber(L,2)) SWIG_fail_arg("xmlDocDumpFormatMemory",2,"int");

  if (!SWIG_IsOK(SWIG_ConvertPtr(L,1,(void**)&arg1,SWIGTYPE_p__xmlDoc,0))){
    SWIG_fail_ptr("xmlDocDumpFormatMemory",1,SWIGTYPE_p__xmlDoc);
  }

  arg4 = (int)lua_tonumber(L, 2);
  xmlDocDumpFormatMemory(arg1,arg2,arg3,arg4);

  {
    // Append output value arg2 to result
    lua_pushlstring (L, *arg2, *arg3);
    SWIG_arg ++;
  }
  return SWIG_arg;

  if(0) SWIG_fail;

fail:
  lua_error(L);
  return SWIG_arg;
}

順を追ってみてみます。

static int _wrap_xmlDocDumpFormatMemory(lua_State* L) {

Lua が処理できる関数の型は、必ず lua_State* をとって int を返します。

  int SWIG_arg = 0;

SWIG_arg は、引数のカウンタです。

  xmlDocPtr arg1 = (xmlDocPtr) 0 ;
  xmlChar **arg2 = (xmlChar **) 0 ;
  int *arg3 = (int *) 0 ;
  int arg4 ;

これらは、Lua から渡された引数を C の値に変換するときの受け皿となります。

  xmlChar *temp2 ;
  int templen2 ;

ここで、1 つめの %typemap に書いた変数宣言を思い出してください。あれはここにそのまま書かれます。

  {
    arg2 = &temp2;
    arg3 = &templen2;
  }

そしてさらに、1 つ目の %typemap の中身がそのままここにコピーされます。ただし、$1arg2 に、$2arg3 に変換されていることに注意してください。

ここからしばらくは、SWIG が自動生成するラッパーコードです。基本的には型のマッピングです。

  SWIG_check_num_args("xmlDocDumpFormatMemory",2,2)
  if(!SWIG_isptrtype(L,1)) SWIG_fail_arg("xmlDocDumpFormatMemory",1,"xmlDocPtr");
  if(!lua_isnumber(L,2)) SWIG_fail_arg("xmlDocDumpFormatMemory",2,"int");

  if (!SWIG_IsOK(SWIG_ConvertPtr(L,1,(void**)&arg1,SWIGTYPE_p__xmlDoc,0))){
    SWIG_fail_ptr("xmlDocDumpFormatMemory",1,SWIGTYPE_p__xmlDoc);
  }

  arg4 = (int)lua_tonumber(L, 2);
  xmlDocDumpFormatMemory(arg1,arg2,arg3,arg4);

最後の行で、実際に xmlDocDumpFormatMemory 関数を呼び出しています。しかし、この関数は arg2arg3 を出力変数として使うので、これらの値を今度は Lua の値に変換して Lua に返してやる必要があります。

  {
    // Append output value arg2 to result
    lua_pushlstring (L, *arg2, *arg3);
    SWIG_arg ++;
  }

ここで、2 つ目の %typemap が登場です。ここで SWIG_arg という変数をインクリメントしています。これは、Lua に返す値の数を表します。ちなみに lua_pushlstring は文字列を Lua に渡すための関数ですが、第 3 引数には文字列の長さをバイト数で渡すので、文字列中にヌルバイト '\0' を含んでいても正しく渡すことができます。

  return SWIG_arg;

  if(0) SWIG_fail;

fail:
  lua_error(L);
  return SWIG_arg;
}

残りは SWIG が生成するコードです。特に SWIG_arg(返り値の数)を返している事に注意してください。

つづく

%native ディレクティブを使った低レベルな関数の定義や、Lua モジュールのビルド方法など、書くつもり。

最終更新: 2009 年 09 月 06 日 17:26

07 月 31 日(Sat)のアレゲメモ

Lightweight Language Tiger Lightening Talk: Lua でわくわくゲーム開発。

Lightweight Language Tiger で行われた、ライトニングトークセッション 「LL Tiger > LTの虎」 で、CryENGINE2 上で Lua を使ってゲーム開発をする手順をビデオにまとめて発表させていただきました。

動画

実際に上映させていただいた前編:

一回戦で敗退してしまったために上映できなかった後編:

今回のライトニングトーク(LT)のルールでは、8 チームがトーナメント形式で競い合い、それぞれ対戦に勝ったチームが次の発表を許されるということになってました。で、ぼくは初戦で負けてしまったので、後編は上映できませんでした。

ここで紹介している方法は、CryENGINE2 という高価な商用のゲームエンジンを使用しているにもかかわらず、個人的な使用においては完全に無料で実現できます。なので、ゲーム開発に興味のある学生やニートのみなさんにも見ていただければと思います。

スクリプトのソースコード

ここで Lua スクリプトのソースコードを公開しています。 torus / Luna-Landa-on-CryENGINE2

参考 URL

ビデオ中で紹介した各ウェブサイトの URL をここにも記載しておきます。

それから、時間の都合で紹介できなかったサイトもあげておきます。

最終更新: 2009 年 07 月 19 日 23:17

07 月 16 日(Fri)のアレゲメモ

Lua で apply。

JavaScript や Scheme には、配列を引数の並びとして関数に適用する apply という関数がありますが、Lua にはそれに相当する関数はありません。で、しばらく悩んでいたんですが、少し前に同等のことをする方法があるのに気がつきました。

unpack という関数を使います。unpack は、配列をとってその配列の中身を多値として返します。これをつかうと、apply 相当の動作はこんな風にかけます。

func (unpack (array))

JavaScript ではこんな感じ:

func.apply (this, array)
最終更新: 2009 年 07 月 15 日 22:24

Home

Markdown のテストー。

てすとですよ。

  1. Bird
  2. McHale
  3. Parish

Markdown Rocks!!

sub start {
    others->regist_fetch ('.md', \&_fetch);
    1;
 }

sub _fetch {
    my ($fh, $path_file, $title_ref, $body_ref, $raw_ref) = @_;

    chomp($$title_ref = <$fh>);

    if ($body_ref) {
    $$body_ref = Markdown(join '', <$fh>);
    }

    $raw_ref and $$raw_ref = $$title_ref . "\n" . $$body_ref;
}

このサイトの Blosxom は、少し拡張が加えてあるので、それにあわせて修正して使っています。

最終更新: 2009 年 07 月 05 日 22:48

01 月 04 日(Mon)のアレゲメモ

重複している写真ファイルを一気に消す。

携帯電話やデジカメから PC に写真を転送するときに、間違えて同じ写真を何度も読み込んでしまって、無駄なデータがたくさんできてしまってました。しかも、それらのファイルは、フォルダもファイル名も全然違う事があって、簡単にはまとめて消せません。なので、Perl で簡単なスクリプトを書いて重複ファイルの洗い出しをしました。

⇒ 続きを読む

最終更新: 2009 年 06 月 23 日 00:20

12 月 30 日(Wed)のアレゲメモ

Opakapaka: 純粋な CGI プロセスだけでうごくリアルタイムチャット。

少し前から Gauche を使って、チャットの CGI を作っていましたが、なんとなく動くようになったので Opakapaka と名付けて公開します。少しタイプし辛い名前なので既に後悔していますが、まぁ開発コードだからいいや。ちなみにオパカパカとはハワイでよく食べられる白身の魚の名前です。

⇒ 続きを読む

最終更新: 2009 年 06 月 14 日 00:55

11 月 16 日(月)の日記

ハワイで車を買う話。

数週間前に、ついに自動車を手に入れました。2005 年製、日産の SENTRA というモデルです。色は白です。週末になんどか、おどおどしながらも近所をドライブしてみたりしました。

⇒ 続きを読む

10 月 12 日(月)の日記

ハワイで運転免許を取る話。

先週の月曜日にめでたく、ハワイ州の自動車の運転免許を取得しました。日本にいる間も免許は持っていなくて車なんか一度も運転したことがなかったんですが、なんとか試験に合格できました。

⇒ 続きを読む

09 月 11 日(Fri)のアレゲメモ

Flash と Flex の連携

Flash で作ったムービークリップを Flex に埋め込んで、メソッドを呼び出す手順。

⇒ 続きを読む

最終更新: 2009 年 05 月 30 日 00:41