StoryEdit 開発日誌

ウェブアプリ StoryEditを作ってましたが延期。普通のブログ。

Windows XP (English version)で日本語を読む

Microsoftがウェブサイトなどの閲覧確認のために、無料のVMを配布しているのはご存知のとおりだろう。LinuxからでもMacからでも、VirtualBoxさえあれば、WindowsXPとかWindows Vistaとかが試せる。
http://www.microsoft.com/en-gb/download/details.aspx?id=11575

しかし、この配布されているWindows, 英語版であるため、日本語のサイトを表示すると、□がたくさん表示されてしまう。こうして、我々の多くは、無料VMの日本語化に挑戦することになる。


XPのIE8あたりで日本語のサイトを開くと、「Language Pack」をインストールするかどうかのシステムメッセージが表示される。しかし、clpexeだかなんだかが見つからないといって、XPのインストールディスクを求められる。


無料配布されているVMを使っているから、そのようなモノはない。ネットの情報では、どうやらXP日本語版のCDをもっている人のみが入手できる、プロプライエタリなソフトウェアのようだ。clrexeでググって落とせ、みたいな乱暴なことを書いてあるサイトもあるが、不正に入手したソフトを使うと、当然ライセンス違反となる。(そしてそのソフトが悪さをしないとも限らない)


うーん、せっかくVMでWindows使えても日本語使えないなんて、使い物にならん。と思って諦めている。って話を聞いた。


実際は、日本語は表示できる。日本語版のWindowsは手に入らないが、日本語を扱えるWindowsにはなる。(つまり、マイクロソフトが日本語化のために金をかけた部分はお金を払わないと手に入らないが、それ以外は手に入る)


このブログでもフォントファイルを読み込んできて、それをメモリマップに貼りつけたことがあるが、これと同じだ。
フォントとは、広大な画像ファイルであって、ある文字コードに対応する場所に、その文字の画像がある、とざっくり理解できる。(フォントサイズやベクターフォントなど考えればわかるとおり、ここまでシンプルではないが)


したがって、日本語フォント(日本語の文字コード部分に画像があるファイル)をインストールすればよい。M+やIPAフォントあたりを引っ張ってインストールで完了。

Google Guavaいい。

ランダムにJavaでも。

List<String> strings = new ArrayList<String>();

なんて書くのはだるい。そこで、Guava.jarを参照させて、使うと、あら簡単。

List<String> strings = Lists.newArrayList();

Genericsの二度書きを防いで、可読性をあげます。Javaにもこういう遊び心がある文化があってひと安心。しかし、Googleが出す前はどうしてたのだろう。。。

日本語版WordNetから、英語 --> 日本語の翻訳を探す。

お盆休み!、ということで興味の赴くまま、また別のウェブアプリをつくってます。
英単語勉強アプリ。Coffee Script + nodejs で作成中です。

このメイン機能で、英単語いれたら、その意味をだしてくれる必要があるんですが、そのときに、翻訳が必要。翻訳APIとか、フリーの英和辞書とか探したけど、なかなかいいのがなくて、みつけたのがこちら。

日本語 WordNet: http://nlpwww.nict.go.jp/wn-ja/

詳しくは、本家ウェブサイトの解説を参照してほしいが、学術用(?)に作られた単語間の関連性をもったデータベースらしく。そんなNLPなデータなんだから、単語の意味くらい入ってるだろと思って調べていった結果の途中報告。(内部情報が見つけられなかったため、対訳探すのに苦労した)

1. wnjpn.dbをダウンロード、接続。

# .schema

sqlite> .schema
CREATE TABLE ancestor (synset1 text,
                          synset2 text,
                          hops int);
CREATE TABLE link_def (link text,
                          lang text,
                          def text);
CREATE TABLE pos_def (pos text,
                          lang text,
                          def text);
CREATE TABLE sense (synset text,
                          wordid integer,
                          lang text,
                          rank text,
                          lexid integer,
                          freq integer,
                          src text);
CREATE TABLE synlink (synset1 text,
                          synset2 text,
                          link text,
                          src text);
CREATE TABLE synset (synset text,
                          pos text,
                          name text,
                          src text);
CREATE TABLE synset_def (synset text,
                          lang text,
                          def text,
                          sid text);
CREATE TABLE synset_ex (synset text,
                          lang text,
                          def text,
                          sid text);
CREATE TABLE variant (varid integer primary key,
                          wordid integer,
                          lang text,
                          lemma text,
                          vartype text);
CREATE TABLE word (wordid integer primary key,
                          lang text,
                          lemma text,
                          pron text,
                          pos text);
CREATE TABLE xlink (synset text,
                        resource text,
                        xref  text,
                        misc text,
                        confidence text);

なるほど。まったくわからん。

どうやらwordというテーブルに、単語が入っている模様。

sqlite> select * from word where lemma="dog";
85237|eng|dog||n
152987|eng|dog||v

やっぱり意味は入ってないのね。そこで、wordidというのを含んでいるschemaをさがすと、senseというのがそれっぽい。とりあえず、wordid=85237でsenseを検索。

sqlite> select * from sense where wordid=85237;
02084071-n|85237|eng|0|1|42|eng-30
10114209-n|85237|eng|0|2|0|eng-30
10023039-n|85237|eng|0|3|0|eng-30
09886220-n|85237|eng|0|4|0|eng-30
07676602-n|85237|eng|0|5|0|eng-30
03901548-n|85237|eng|0|6|0|eng-30
02710044-n|85237|eng|0|7|0|eng-30

これで、synsetというのがとれる。ここから、単語の意味をもっているであろうと思われる、synset_defなぞをたたいてみる。(defってそれっぽく聞こえるから)

sqlite> select * from synset_def where synset="02084071-n";
02084071-n|eng|a member of the genus Canis (probably descended from the common wolf) that has been domesticated by man since prehistoric times; occurs in many breeds; "the dog barked all night"|0
02084071-n|img|animals/mammals/dog_06_drawn_with_strai_02|0
02084071-n|img|animals/mammals/dog_05_drawn_with_strai_02|1
02084071-n|img|animals/mammals/dog_on_leash_gerald_g._01|2
02084071-n|eng|a member of the genus Canis (probably descended from the common wolf) that has been domesticated by man since prehistoric times|0
02084071-n|jpn|有史以前から人間に家畜化されて来た(おそらく普通のオオカミを先祖とする)イヌ属の動物|0
02084071-n|eng|occurs in many breeds|1
02084071-n|jpn|多数の品種がある|1


日本語にしぼったほうがよさそうだな。というわけで、lang=jpnで再検索。

sqlite> select * from synset_def where synset="02084071-n" and lang="jpn";
02084071-n|jpn|有史以前から人間に家畜化されて来た(おそらく普通のオオカミを先祖とする)イヌ属の動物|0
02084071-n|jpn|多数の品種がある|1


う。。。そうかぁ。。。「イヌ」ってでてきて欲しかったけど、けっこうな訳がでてきてしまいましたね。。。



しかし!!ここであきらめない!!
他にsynsetを使っているテーブルをとりあえずみてみる。

sqlite> select * from sense where synset="02084071-n" and lang="jpn";
02084071-n|176027|jpn||||hand
02084071-n|180438|jpn||||hand
02084071-n|185856|jpn||||hand
02084071-n|196135|jpn||||hand
02084071-n|207353|jpn||||hand
02084071-n|212666|jpn||||hand

うむぅ。。。わけがわからん。。。この番号は、、、wordidか。。。あれ、"dog"のwordidと違うぞ。

ん?

まさか?

sqlite> select * from word where wordid=175027;
175027|jpn|下し金||n

おぉぉぉぉぉ!!! 

なんか日本語の単語がでてきたぁ!!!もしやこれは、いけるか?

sqlite> select * from word where wordid=180438;
180438|jpn|ドッグ||n
sqlite> select * from word where wordid=185856;
185856|jpn|犬||n

よっしゃーーーーーーー!!!ψ(`∇´)ψ

まぁしかし、何番目のwordidをとれば、一番適切なのかはどうやってわかるんですかねぇ?


追記:
http://ejje.weblio.jp/content/dog

ここのWordnetをみれば、たしかに同じ定義がとってこれている。

class Hoge:と、class Hoge(object):の違い

定義は以下のとおり。

class Hoge:
  def __init__(self):
    self.x = 'hoge'

class Hoge(object):
  def __init__(self):
    self.x = 'hoge'

これをhelp()で比較してみた。

Help on class Hoge in module __main__:

class Hoge
 |  Methods defined here:
 |
 |  __init__(self)
Help on class Hoge in module __main__:

class Hoge(__builtin__.object)
 |  Methods defined here:
 |
 |  __init__(self)
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |
 |  __dict__
 |      dictionary for instance variables (if defined)
 |
 |  __weakref__
 |      list of weak references to the object (if defined)

とまぁ、このとおり。
__builtin__.objectを継承すると、__dict__とか、__weakref__とかのメソッドが追加される。
__dict__はわかるとして、__weakref__ってなんや。笑

追記:
http://docs.python.org/2/library/weakref.html

ということで、いわゆる弱参照を保持する為のもの。

うーん、、、__dict__は、dynamic assignmentを可能にするためのものだと理解していたが、objectを継承しないのに、self.xに値を保持できるのはなんでだ?
とおもい、object継承なしのHogeで実験。

>>> h = Hoge()
>>> h.x
'hoge'
>>> h.x = 'hi'
>>> h.x
'hi'
>>> h.y = 'bu'
>>> h.y
'bu'
>>> h.__dict__
{'y': 'bu', 'x': 'hi'}

んん?__dict__いるし。笑
後日追求する必要あり。

TODO: class Hoge: と、class Hoge(object): の違い

表題がわからない。

とりあえず、どっかのOSSに従って、class Hoge(object):と書いていたんだが、
vars()が使えないことがあり、class Hoge: にしたら、使えた。

ここはどっかで調べる必要がある、ということで、TODO。

tmux 1.8 on MacOSX

コンパイルエラーがでたので、解決法メモ。

EVBUFFER_LENGTHがどうのこうの、というエラーが発生。

libevent2.0.xを使っていたのだが,libevent-2.0.5だということが発覚。

最新は、2.0.21.stable。

したがって、libeventを更新したら、うまくインストールできました。


StoryEditはできそうもない。。orz

nginx、つれづれリーディング。

ウェブサーバの仕組みを知る為に、とりあえずnginxを読む。
だらだらと読みながらのログとなるので、解説と間違わないように。

nginx.c

main関数がある。
いろんな機能をinitしたあとに、init_cycleというのがある。どうやら、ここで、ウェブサーバの起動がありそう。cycleというのが何を指すのかはわからないが。

ngx_cycle.c

init_cycleの中でやってるのは基本的に、以下の流れ。

  1. poolの確保。そこから、cycleを確保。(init_cycleという構造体へ書き込まれる。)
  2. list_initというものを行う。(listが何かは不明)
  3. コンフィギュレーションファイル構造体?(conf_ctx)を確保
  4. hostnameを取得
  5. モジュールのコンフィギュレーション構造体を確保
  6. コンフィギュレーションファイルのパース(エラーチェック)
  7. モジュールのコンフィギュレーション初期化
  8. pidファイルを作る(後のデーモン化に備えて、最初の一回目はつくらないらしい)
  9. ファイルを作る(なんのため?)
  10. SharedMemを確保
  11. ソケットのハンドリングと書いてある部分。(なにしてるか不明)
  12. ngx_open_listening_sockets(cycle)で、ソケットを開く。
  13. 続く。(ngx_cycle.c: 573以降)

というわけで。ngx_open_listening_socketが怪しいので、こちらを読んでいく。
いきなり、TODOにぶつかったが、いわゆる、socket, setsockopt, bind, listenの流れを5回試みる。
再試行時に、ngx_msleepで、500ミリ待つようだ。この辺は経験則として参考になると思う。

さて。listening_socketsでは、cycleに持たせているlistening_socket (ls)を、開いて、
コネクトするようだ。既にCycleに持たせているソケットってのがなんなのかはわからない。まだ、Acceptしてないよね??? 初回起動時を区別する分岐が入っていたので、init_cycleは何度も使われる関数なのだろう。一回目の起動はきっと関係ないはず。
そして、init_cycleの処理は、引き続き、必要のないlistening socket, filesなどを閉じていく。

init_cycleをでて、mainに戻ろう。

cycleの初期化などが終わったら、deamonizeに入る。
そして、master_process_cycleか、single_process_cycleに入っていく。(どうやら、ここがacceptが入るべき場所のようだ)

この、masterとsingleは、プロセスが増えたときにどのみちとおるパスなのか、実行モデルの違いなのかは、定かではないが、とりあえずmasterのほうをのぞいてみよう。

ngx_process_cycle.c