2010年 09月 01日

Chemr-js

Chemr という .chm を読む Mac 向けのツールを作っていたのですが、環境の変化か何かで動かなくなってしまい、いろいろやってみたけどどうやっても直らなかったので代替を考えて実装しなおしました。

やはり、普段使ってるフィールドの技術でつくるのが最もメンテナンスしやすいと思い、ブラウザ+Greasemonkey で実現することにしました。実際のところ、僕が欲しいのは .chm を読むツールではなく、適切にインデックスが貼られたドキュメントをインクリメンタルサーチして統一した操作方法で読めるツールなので、別に .chm じゃなくても良いのです。高級なリファレンスツールやら拡張やらを使用していらっしゃるかたには必要ないかと思いますが個人的には便利に使えるようになったので紹介したいと思います。

使いかた

対応サイトにアクセスすると検索ボックスがでてくる

C-l (Cmd-L) で検索エリアにフォーカス、C-n で次を選択、C-p で前を選択、tab で最上位にある候補を補完、C-u でクリア、C-w でワード削除などとなっています。検索ボックスが邪魔なら ESC で消せる。C-l したらもっかいでてくる。

スペースは正規表現の .* みたいにふるまいます。pla midd とかで Plack::Middleware がマッチ

各種サイトにアクセスしたときにそのサイトをクロールしてインデックスをつくります。サイトによっては時間かかりますが大抵すぐおわります。 (Android のドキュメントとかは2000ページ近くクロールするので40分ぐらいかかりますし、静的ファイル相手とはいえ普通にDOSってる感があるので逮捕されても僕は責任とれません)

対応サイト

とかにいくと勝手にサーチウィンドウがでます。Android のサイトはこわいのでリンクはりません。

工夫した点

キーイベント

iframe を使っているのですが、iframe 内部にフォーカスがあるとショートカットキーが効かなくなってうざいので少々頑張っています。具体的には、iframe 内部の場合、親ウィンドウにキーイベントを伝播 (postMessage) するようにしてあります。postMessage なのは iframe 内のリンク遷移で外部ドメインにいってしまってもいいようにです。

高速な検索

mala さんが昔つくっていた http://la.ma.la/blog/diary_200604021538.htm のコードを参考にしつつ、一定数ヒットしたものを適当に好みでスコアリングして表示しています。URL のデータを追加したりしてるのでほんのすこし工夫してます。

html 入れ替え

サイトによってサーチウィンドウのフォントが変わったりして嫌だったので document.replaceChild(html, document.documentElement) という荒技をしてます。

対応サイトにアクセスしたとき、ロードしたページは iframe の中でロードされなおされ、本来読まれたページは chemr.user.js が乗っ取ります。ページ内のリンクは iframe の中なので、クリックしてもいちいち index を読みなおすこともなく快適です。

独立したアプリケーションのように

レポジトリに createapp.rb というのが入っていて、これをうまく使うと普段使いのブラウザとは別に、リファレンスひき専用のブラウザをつくれて便利です。特に Mac の場合、Cmd-Tab でアプリ間しか移動できないので必須です。

手順としては

  • 既存の Firefox プロファイルに加え "chemr" という名前のプロファイルをつくる。
  • createapp.rb を実行する ( /Application/Firefox.app と chemr というプロファイルが必要です)
  • /Application/Chemr.app ができるのでこれを起動
  • 普通の Firefox と同じように Greasemonkey (ほか好みで Stylish など) をインストール
  • about:config で dom.storage.default_quota を大きく (しなくてもいいけど、100MB ぐらいにしとけば十分)
  • chemr.user.js をインストール
  • アドレスバーを消すとか、セッション復帰を有効にしたりする

です。非常に便利です。普段 Firefox を使わない方なら createapp.rb 使わず、普通に一個 profile 潰してもいいと思います。

2010年 09月 02日

2010年 09月 03日

2010年 09月 06日



金曜日、帰宅後に御苑を歩いていたら気持ちよかったので、そのまま夜の嵐山へ。野々宮神社あたりまでいったがそれ以降は明りが全くないので戻り、桂川を下り、松尾大社、月読神社を通って自宅へ。思うところあって夜の嵐山には前々から行きたいと思っていたのだけど、タイミングがつかめず行けてなかったので、行けてよかった。いくつか撮影したいポイントがあったが、全く機材を持っていかなかった (カメラさえ) ので何もしていない。

土曜日、行ったことない神社に行こうと思い、賀茂波爾神社へ。こじんまりとした神社だった。深泥池にも行ったけど特に何もなかった。

日曜日、最近ちゃんと写真を撮れてないので、目的地をあまり定めずぶらぶら歩くことにした。とはいえある程度どこ歩くかとかがないと歩けないので、哲学の道を歩いてきた。残暑厳しい中、人が少なかったのでゆっくり歩けた。大豊神社に行ったことがないので行ってみたりした。なんとなく静かな休日だった。歩いていくにはちょっと遠い。

四葉のヤサカタクシーを初めてみかけた。思いのほか普通に嬉しい気分になった。

いつ見た夢か忘れてしまった。

誰かの結婚式だった。誰かというのは、顔も知らないが知り合いの女の子 (矛盾するが、夢なので) で、相手は全く知らん男だった。その子は大変素敵な女の子なので、くそー相手が羨ましいと思いつつ、幸せになって良かったなあと思う夢だった。

情熱大陸で探検昆虫学者・西田賢司というのがやっていて、とにかく、まさに情熱というものがあってカッコよかった。全然違う世界を見ているであろう眼をしつつ、落ち着いて話すので、悟りを開いている人みたいだった。

おかえりピアニカ (Cue comics) - 衿沢世衣子

衿沢世衣子

3.0 / 5.0

静かで意味不明で面白かった。

THE 世界遺産でクエバ・デ・ラス・マノスが取り上げられていて面白かった。

9000年ほど前から2000年前ぐらいまでの間に描かれた洞窟壁画の話で、特に手形がたくさん描かれていて、それだけで圧巻なのだけれど、それほど前から、長い年月をかけてずっと描かれ続けたというのが信じられない感じがした。それに、手形の壁画というのは、ここに限らず世界にあるというのも驚きだった。

手形を残したのは狩猟民族だった彼らにとって手が重要な象徴だったからという話がされていて、逆にいえば現代人は後生に手形を残したいと思うほどには手が重要な象徴ではなくなってるということだけれど、では現代人にとって最も重要な象徴って何なのだろうと思った。ほんの少し前までは日本人には稲作がものすごく重要であったから、稲作関係ものは象徴的で、風習的にはちゃんと今もたくさん残っている (全国の稲荷社とか新嘗祭とか) けれども、それも今飽食の時代がやってきて、もはやそこまで重要視されているようには思えない。発達・発展するにつれてそういうものはいらなくなるのだろうか?

2010年 09月 05日

gerry++

2010年 09月 07日



2010年 09月 09日


重要なのは他人が造るのをやめないことだと思うのでクソみたいな茶々は本当に無駄だし害でしかない。そういうことする人、心底軽蔑するし、自分があのようになっていないかと本当に不安である。

いじめっこから逃げてまわるようなことを、もっと大きなレベルでやらないといけないとか、アホくさいなあと思う。

情報量が多すぎるのだから、積極的に (自分の責任において) 情報をフィルタリングするのは全く間違っていない。それは他人によるブロッキング (検閲) とは全く別の性質のものである。

2010年 09月 10日



「今に見てろ」みたいなこと、小学生だったころに泣かされたりしたときから思っているけど、見返したことはないので、あんまり意味がないと思います。

歩いて東京都にいけるぎりぎりの場所に長いこと住んでいたからか、東京への憧れみたいなのは全く一切なく、地方と海外への憧れはあります。

あと賑やかな孤独は孤独を全く靭くしないように思われる。

どうやったら道徳が一変するのだろう。70年そこらで起こったことではそういったことは起こらなかったようだし、よくわかりません。

悪い方向へ変わっていってるように思えて仕方ない。もっとみんな前へ進んでいって賢くなっていくのが当たり前だと思っていた。バカになるばかりだ。

gerry++

2010年 09月 13日


フィリップス ヘッドフォン SHL9560/10 - Philips(フィリップス)

Philips(フィリップス)

3.0 / 5.0

断線したのでまた PHILIPS の新しいのを購入した。着け心地も良いし、前のやつよりも好みの音を鳴らしてくれるので良かったです。ただ、フレームのプラスチックが硬くて、すぐに折れてしまいそう。

PHILIPS は (少なくとも僕が買ったことあるやつに関しては) 安くても高い音を繊細に鳴らしてくれるのでコストパフォーマンス高くてとても良いです。オーテクだと1万後半あたりじゃないとそうなってこなくて手を出しにくい。

『彼女のひとりぐらし』玉置勉強

彼女のひとりぐらし 1 (バーズコミックスデラックス) - 玉置 勉強

玉置 勉強

3.0 / 5.0

すごく面白かった。なんかこう、めちゃくちゃになって不細工な顔になったシーンがあって、それがすごく可愛いらしくて良かった。声出して笑いながら二回読んだ。おすすめしたい。

『誰が為に鋼は鳴る』天乃タカ

誰が為に鋼は鳴る (ビームコミックス) - 天乃 タカ

天乃 タカ

3.0 / 5.0

面白かった。展開が早い (というか一巻で完結する) のでちょっとびっくりする。出てくる神様、ちょっと残念な感じで舞台から消えてしまうけど、そういうのも含めてとても良かった。

ほかいろいろ

むすんでひらいて (1) - 水瀬 マユ

水瀬 マユ

3.0 / 5.0

表紙がいいですね。内容は男の子にしても女の子にしても可愛い顔描くなあと思いながら読んだ。王道の幼馴染可愛い。なんかこう、しれっとパンツ見せたりするカットがあって雰囲気がギャルゲみたいな感じだった。

有識故実図典―服装と故実 - 鈴木 敬三

鈴木 敬三

3.0 / 5.0

日本の伝統服に興味あったので買ってみた。もうちょい図が多いかと思ったら結構字で説明だったので想像力がないとつらい感じだった。なんか他に写真集みたいのがあると良さそうだと思った。YouTube とかで現代の祭祀の映像はいくつか見れるのでそういうを見ながらがいいかもと思った。

祭祀以外でも、庶民の服の話もあって、どちらかといえばそっちのほうが興味深かった。平安装束みたいなのは、しばしば映像として作られたり、保護されていたり、神社で継承されていたりするけれど、庶民の服ってのは殆ど話題になってこないので全く想像できない。それに古い庶民の伝統なんてのは殆ど残っていないから実際に見ることはまずできない。平安時代とかの庶民の服は記録自体がないらしいけど、実際この本も鎌倉自体以降の話だけだった。

2010年 09月 14日



納得いかないなぁ

2010年 09月 15日


@amasawa さんへ

心底軽蔑とはなんだったのか - Togetterまとめ というのがあって (id:kageroh_ さんによる纏めです)、さっき日記のリファラを見ていて気付いてなんだなんだと思ったのですが、なんか誤解の元の編集をされていて困ったというところです。一応誤解を解くためにいっておくと以下の通りです。

まず僕は $ 記号がどうとかいう話に関しては殆どどうでもよいと考えていて興味があまりなかったので (機械生成用でなければならないという話の根拠には興味がありましたが、調べたら仕様にハッキリ書いてあったので)、深く追っておらず、また @uupa さんのこともフォローしていないし、僕個人的には uupa.js にも今そんなに興味がないので、そもそもの流れがいまいち読めておらずそれに殆ど絡んでもいませんし、Twitter でも $ なんちゃらに関しては 1言2言言及したに留まって頭から消えさっていました。

日記に書いたことは上記 $ がどうとかいう話とは関係なく、ネットの特定のメディア記事に関して思ったことを書いたまでで、@amasawa さんとは全く関係ありませんし、そもそも僕は上記の通り $ なんちゃらに関して興味があまりなくて流れを追っていないうえに、Twitter において @amasawa さんをフォローしていない (ブロックもしてませんが) ため (ダイアリは興味深く読ませてもらっています)、その発言自体を読んでいなかったため、日記にてそのことに言及することはありえないです。

いろいろとしがらみがあってハッキリ書けないことが多く、もちろんそれなら書くなという話ですし、前にも誤解を元にこんなことがあり卑怯だと言われましたが (まぁ卑怯なのは前のときも言った通り事実なのですが、誤解を元に卑怯と言われるのは本意ではありません)、いずれにせよ僕が曖昧な書きかたをしがちなのが悪いのだろうとのことと、僕が勝手なことを書いているのはその通りですが、「書くな」と言われましても、日記に思ったことを書くというのは、インターネットをはじめた当初からやっていることで、なかなかすぐにはい辞めますと、そうはいかないので、どうしたものかなあと思うところですが、いかがでしょうか……

2010年 09月 16日


2010年 09月 15日

Plack-Middleware-StaticShared

http://github.com/cho45/Plack-Middleware-StaticShared

js とか css を纏めていっこにして配信してくれる Middleware を書きました。Plack::Middleware::JSConcat というが既にありますが、キャッシュコントロールがうまくできなかったのと、css も纏めたかったのでつくった次第です。

      enable "StaticShared",
          cache => Cache::Memcached::Fast->new(servers => [qw/192.168.0.11:11211/]),
          base  => './static/',
          binds => [
              {
                  prefix       => '/.shared.js',
                  content_type => 'text/javascript; charset=utf8',
                  filter       => sub {
                      WebService::Google::Closure->new(js_code => $_)->compile->code;
                  }
              },
              {
                  prefix       => '/.shared.css',
                  content_type => 'text/css; charset=utf8',
              }
          ];
        [% css = [
          '/css/base.css',
          '/css/site.css',
        ] %]

        [% IF debug %]
        [% FOR c IN css %] 
        <link rel="stylesheet" type="text/css" href="[% c %]"/>
        [% END %]
        [% ELSE %]
        <link rel="stylesheet" type="text/css" href="/.shared.css:[% version %]:[% css.join(',') %]"/>
        [% END %]


        [% js = [
          '/js/jquery-1.3.2.min.js',
          '/js/site-script.js',
        ] %]

        [% IF debug %]
        [% FOR j IN js %] 
        <script type="text/javascript" src="[% j %]"></script>
        [% END %]
        [% ELSE %]
        <script type="text/javascript" src="/.shared.js:[% version %]:[% js.join(',') %]"></script>
        [% END %]

みたいに使えます。version + ファイル名 をキーにキャッシュをつくり、クライアントにもほぼ無期限のキャッシュをさせます (update した際に version を更新する必要があります)。

悪意をもった人によって version を変えてアクセスされまくると、キャッシュが溢れそうなので verify する仕組みがほしいですがいいのが思いつかなかったのでとりあえず放置してあります。

2010年 09月 18日


2010年 09月 19日



2010年 09月 20日



2010年 09月 19日

JSDeferred のテストを node.js で動かすように変更

0.3.2 をリリースしました

http://github.com/cho45/jsdeferred

本体以外の部分でシンタックスエラーがでてたので 0.3.3 をリリース


今までコマンドラインのテストは Rhino を用いてやっていたわけですが、node.js のほうがインストールしやすく、テストの実行スピードが早いためそのようにしました。ブラウザのテストは特に変わりません。

IE でまだテストを走らせていないのでリリースはしてないのですがいくつかバグを潰しました

  • Opera で全く動かないことがあった
    • キャッシュによるもの。コード中のゆのっちは削除されました
  • Deferred.connect をネストして使ったとき実行順がおかしかった
  • node.js 環境下で var Deferred = require('./jsdeferred.js').Deferred; とできるように this.Deferred へ代入するように

とかです。

ついでにドキュメントを jsdoc-toolkit 可読なものに変え、テスト実行時に http://closure-compiler.appspot.com/ で警告なくパック可能なことを確かめるようにしました。API ドキュメント も jsdoc-toolkit で作るようにしました。

型も書いてますがこれらもうまくチェックさせるにはどうしたらいいのかよくわからず。

2010年 09月 20日

gerry++

zsh とかの alias

好きかってやったらいいとは思うのですが、一文字の alias とか、C-r で探しにくいのでやめたほうがいいかなあと思っておりまして、できるだけ動的展開に頼るようにしています

2010年 09月 21日


2010年 09月 22日


2010年 09月 24日

2010年 09月 25日

画像のテンプレートマッチの覚書

練習がてら、ゲームのスクリーンショットからステータスの数値を抜きだすのをやってみた。本当に何の知識もなくて苦労した…… 結局のところナイーブに書いたけど、とりあえず動いたのでよかった。

こういう画像から、こういう感じで抜きだせる。

コードは Inline::C + Imager で書いた。CをLL化して書けるので便利です。

  • 画像とテンプレート画像をわたして、マッチした位置を返す template_match を定義
  • 前もって画像を二値化
  • まず必要そうな部分を抜きだすために「Attack」と書かれたテンプレを画像全体でマッチさせて、決め打ちで指定領域を抽出
    • マッチした時点でマッチをうちきればこのままでももうちょい早くなりそう
  • その領域の数値を全て抽出
  • Perl でソートして、一行目が damage, 二行目が wound と決め打ちして出力
package Mabinogi::Extractor::Attack;

use strict;
use warnings;

use Path::Class;
our $TEMPLATE_DIR = file(__FILE__)->parent->subdir('tmpl');
our $DEBUG = 0;
use Carp;

use Imager;
use Inline with => 'Imager';
use Inline C => <<'EOS';
void template_match(Imager::ImgRaw img, Imager::ImgRaw tmpl, int all) {
	int x, y, tx, ty;
	i_color tmp_color;
	unsigned char img_color, tmpl_color;
	unsigned char is_white;
	// printf("img: w:%d h:%d, tmpl: w:%d, h:%d\n", img->xsize, img->ysize, tmpl->xsize, tmpl->ysize);

	Inline_Stack_Vars;
	Inline_Stack_Reset;

	for (y = 0; y < img->ysize - tmpl->ysize; y++) for (x = 0; x < img->xsize - tmpl->xsize; x++) {
		// if (img->ysize == 50 && y == 1) printf("(x:%d, y:%d)\n", x, y);
		for (ty = 0; ty < tmpl->ysize; ty++) for (tx = 0; tx < tmpl->xsize; tx++) {
			i_gpix(tmpl, tx, ty, &tmp_color);
			tmpl_color = tmp_color.gray.gray_color;
			i_gpix(img, x + tx, y + ty, &tmp_color);
			img_color  = tmp_color.gray.gray_color;
			is_white = img_color == 255;
			if (tmpl_color == 255 && !is_white) {
				goto next;
			} else
			if (tmpl_color ==   0 &&  is_white) {
				goto next;
			}
		}

		Inline_Stack_Push(sv_2mortal(newSViv(x)));
		Inline_Stack_Push(sv_2mortal(newSViv(y)));
		if (!all) goto done;

		next:;
	}

	done:;
	Inline_Stack_Done;
}
EOS

sub extract {
	my ($class, $image) = @_;

	my $tmpl = Imager->new;
	$tmpl->read(file => $TEMPLATE_DIR->file('attack.png'));
	$tmpl = $tmpl->crop(left => 1, top => 1); # 枝刈り用に白が最初にくるように調整

	my $img = Imager->new;
	$img->read(file => $image) or croak $img->errstr;
	$img = $img->convert(preset => 'grey');
	$img = $img->map(all => [ map { $_ > 127 ? 255 : 0 } (0..255)  ]);

	$DEBUG and ($img->write(file => '/tmp/test.png', type => 'png') or die $img->errstr);

	my ($x, $y);
	($x, $y) = template_match($img, $tmpl, 0);
	defined $x or croak "couldn't find template";
	$img = $img->crop(left => $x + 15, top => $y + 10, width => 80, height => 55) or die $img->errstr;

	$DEBUG and ($img->write(file => '/tmp/test.png', type => 'png') or die $img->errstr);

	my $numbers = [
		map {
			my $img = Imager->new;
			$img->read(file => $TEMPLATE_DIR->file("$_.png")) or die $img->errstr;
			+{
				n => $_,
				tmpl => $img,
			};
		}
		(0 .. 9, '~', '.')
	];

	my $chars = {};
	for my $number (@$numbers) {
		my @matched = template_match($img, $number->{tmpl}, 1);
		my $n = $number->{n};
		while (my ($x, $y) = splice @matched, 0, 2) {
			$chars->{$y}{$x} = $n;
		}
	}

	my $res = [];
	for my $y (qw/2 15 28 41/) {
		push @$res, '';
		for my $x (sort { $a <=> $b } keys %{ $chars->{$y} }) {
			$res->[-1] .= $chars->{$y}{$x};
		}
	}

	my %ret;
	@ret{qw/damage wound critical balance/} = @$res;
	\%ret;
}


1;
__END__
2010年 09月 26日


2010年 09月 27日

2010年 09月 29日


gerry++

2010年 09月 30日


npm install jsdeferred できるようにした

node.js の package システムに登録した

npm install jsdeferred

とやって

var Deferred = require('jsdeferred').Deferred;

で使える。

2010年 09月 25日

出雲大神宮に行こうと思い電車で行ってきた。千代川駅までいってから歩くのだけど結構駅から遠かった。千代川のあたりは米農家が多くてすごく雰囲気が良かった。最も近い橋が月読橋だったり、駅の近くに月読神社があったりしておもしろかった。

風がつよくて晴れている日にああいう場所を歩くのはとても幸せだ。