2010年 10月 03日



gerry++

2010年 10月 04日



gerry++

2010年 10月 06日

2010年 10月 07日

vim、三項条件演算子の第二項と第三項を入れかえる

nnoremap e3 :s/?\s*\((.\{-1,})\\|\S\+\)\s*:\s*\((.\{-1,})\\|\S\+\)/? \2 : \1/<CR>

でいける。


以下つくりかたのメモ

#!/usr/bin/env perl
use strict;
use warnings;
use Test::Most;

my $tests = [
	'aa ? bb : cc' => 'aa ? cc : bb',
	'aa ? bb : cc | foobar' => 'aa ? cc : bb | foobar',
	'aa ? (bb bb) : (cc cc)' => 'aa ? (cc cc) : (bb bb)',
];

while (my ($a, $b) = splice @$tests, 0, 2) {
	$a =~ s/\?\s*(\(.+?\)|\S+)\s*:\s*(\(.+?\)|\S+)/? $2 : $1/;
	is $a, $b;
}
done_testing;

みたいなのを書いて正規表現を確定させる

eregex.vim を入れた状態で

:echo E2v('\?\s*(\(.+?\)|\S+)\s*:\s*(\(.+?\)|\S+)')

する

でてきた正規表現でだいたいいいのだけれど .vimrc に書くと \| が | として認識されるので \| は \\| にさらに置換する

2010年 10月 08日

gerry++

2010年 10月 09日

ワンダーワンダーの足利義政の回がおもしろかった

2010年 10月 12日


そういえば、月読尊という神様について、自分は女神だと思っていたけれど、(ハッキリはしないものの) 基本的には男神らしい。松尾大社の月読神社も男神らしい。なんで自分が女神だと思っているのかはよくわからないが (クロノクロスのせい?)、男神ってのは、あんまりピンとこないなあ。

2010年 10月 13日

2010年 10月 14日

BDF フォントを canvas にレンダリングする

ブラウザでアンチエイリアスのきいてない bitmap フォントを使おうと思い webfont でいけるかなと思いきや、手元の環境だとどのブラウザでも bitmap フォントを使用できなかった、ということがありました。(Firefox はオプションを入れればできるみたいなのを最近見たんですが試さず)

で、それなら自力でレンダリングしたらいいんじゃないかなと思いつつ、面倒でやってなかったのですが、bdf のフォーマットがただのテキストファイルということを知って多少やる気が沸いたのでやってみました。

依存しているブラウザの機能は

  • canvas
  • 2d Context
  • fillRect

だけなので canvas が実装されていれば大抵のブラウザで動きます。

日本語も対応 bdf さえあれば描けるのですが、JS の charCodeAt でとれる数値と、bdf のコードポイントが一致していないといけないので、普通は変換が必要です。mplus の bdf 用の変換器 (というか jis から ucs) は書いたのを一緒のレポジトリにいれてあります

どや

2010年 10月 16日

YAPC::Asia 2010 で「映画にでてくるハッカーになりたい」というタイトルで発表してきました

大変恐縮ながら投票でエンターテナー賞を頂きました。聞き間違えかと思うぐらいびびりました。ありがとうございます。ちょうど iPad の Safari でお絵描きツールを作りたいけど、継続的に使える実機がなくて困っていたので嬉しいです。

以下補足

realtime*

realtime* 系は動かすのにちょいと設定がいるので説明しておきますと (この説明でわかるかわかりませんが……)

~/.rrggc に以下のような感じのことを書く

Format::Apache::LogFormat->define_logformats(q[
	LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %D %{X-DCMGUID}i %{X-UP-SUBNO}i %{X-JPHONE-UID}i %{X-SID}i" mylog
]);

これは realtime* が実行されるときに do されるファイルで、define_logformats の中は Apache のログフォーマットをそのままコピペするとたぶん動きます (動かないかも) responsegraph をとりたい場合には %D が必須で、accesstrack をみたいときは X-JPHONE-UID とか、ユーザど同定するセクションが必須です。

それで

tail ... | realtimeresponsegraph.pl --format mylog

とかやるとでてくる気がします。ほか、オプションがいくかありますが --format だけ必須です。

Devel::KYTProf

  • http://github.com/onishi/perl5-devel-kytprof
    • 僕がフォークしてるやつは前パッチ書いたときにやったやつなので、onishi さんのが一番新しいはずです (今はコラボレータに入れてもらったので直接コミットしてます)。

use するだけで

  • DBI
  • LWP::UserAgent
  • Cache::Memcached::Fast
  • MogileFS::Client

のメソッドコールが表示されるようになりますが、任意のメソッドの対して設定できるようになっているので自力で設定することもできるようになっているようです

あと、いくつか正規表現を設定できて、例えば

Devel::KYTProf->namespace_regex(qr/Hatena/);

とかやると、フックしたメソッドが呼ばれたとき、表示されるパッケージ名を、指定した regexp にマッチするパッケージまでたどるので、「自分のアプリ内で、どこからよばれているか」がわかるようになって便利です。

2010年 10月 17日

DSi Browser にも console.log が欲しい

DSi Browser 上で動く JavaScript を書く必要があることがしばしばあると思いますが、今のご時世でもデバッグが面倒で、alert デバッグに頼ったりすることがあります。これは大変今時としてはありえないので、console.log が欲しいところです。とはいえ、DSi Browser の表示領域というのは非常に限らており、console.log を作るにしても表示する場所がありません。

なので以下のようなサーバを立ててやることがあります。

#!/usr/bin/env plackup -s AnyEvent 
# vim:set ft=perl:
use strict;
use warnings;
use lib 'lib/perl/lib/perl5', 'lib/perl/lib/perl5/x86_64-linux-thread-multi';

use Plack::Request;
use AnyEvent;
use JSON::XS;

my $template = <<'EOS';
<!DOCTYPE html>
<title>tail</title>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.4.2.min.js"></script>
<script type="text/javascript">$(function () {
var log   = document.getElementById('log');
var $style = $(document.createElement('style')).appendTo(document.body);

$('.host').live('click', function () {
	var host = $(this).text();
	$style.text( '.line { display: none } ' + '.line.' + classOfHost(host) + ' { display: block }');
});

$(document.body).dblclick(function () {
	$style.text('.line { display: block }');
});

function classOfHost (host) {
	return 'h-' + host.replace(/\./g, '-');
}


function read () {
	$.ajax({
		url: '/api/read',
		dataType : 'json',
		success : function (data) {
			var messages = data.messages;
			for (var i = 0, len = messages.length; i < len; i++) {
				var message = messages[i];
				$('<div class="line"></div>').
					append($('<span class="host"></span>').text(message.host)).
					append($('<span class="body"></span>').text(message.body)).
					addClass(classOfHost(message.host)).
					prependTo(log);
			}
			while (log.childNodes.length > 100) log.removeChild(log.lastChild);
		},

		complete : function () {
			setTimeout(function () {
				read();
			}, 1000);
		}
	});
}

read();

})</script>
<style type="text/css">
pre {
	font-size: 14px;
	line-height: 1.33;
}

.host {
	color: #666;
	margin: 0 1em 0 0;
	cursor: pointer;
}

.body {
}
</style>
<pre id="log"></pre>
EOS

my $i   = 0;
my $sessions = {};

my $app = sub {
	my $env = shift;
	$env->{'psgi.streaming'} or die;
	sub {
		my $callback = shift;

		my $req = Plack::Request->new($env);
		my $res = $req->new_response(200);
		eval {
			+{
				'/' => sub {
					$res->content_type('text/html');
					$res->content($template);
					$callback->($res->finalize);
				},
				'/api/read' => sub {
					my $sid = $req->cookies->{sid} || $i++;
					my $session = $sessions->{$sid} || +{
						sid      => $sid,
						messages => [],
						callback => undef,
						expire   => 0,
						ua       => $req->header('User-Agent'),
					};
					$session->{expire} = time() + 60 * 60;
					$sessions->{$sid} = $session;
					$res->cookies->{sid} = $sid;

					if (@{ $session->{messages} }) {
						$res->content(encode_json +{
							sid => $sid,
							messages => $session->{messages},
						});
						$session->{messages} = [];
						$callback->($res->finalize);
					} else {
						$session->{callback} = sub {
							my $message = shift;
							delete $session->{callback};
							$res->content(encode_json +{
								sid => $sid,
								messages => [ $message ],
							});
							$res->content_type('application/json');
							$callback->($res->finalize);
						};
					}
				},
				'/p' => sub {
					my $message = {
						host => $req->address,
						body => $req->param('m'),
					};
					for my $sid (keys %$sessions) {
						my $session = $sessions->{$sid};
						if ($session->{expire} < time()) {
							delete $sessions->{$sid};
							next;
						}

						if ($session->{callback}) {
							$session->{callback}->($message);
						} else {
							push @{ $session->{messages} }, $message;
						}
					}

					$res->content_type('application/json');
					$res->content(encode_json +{ status => 'ok' });
					$callback->($res->finalize);
				},
			}->{ $req->path }->();
		};

		if ($@) {
			$res->code(200);
			$res->content($@);
			$callback->($res->finalize);
		}
	};
};

use Plack::Builder;

builder {
	enable "Plack::Middleware::ReverseProxy";
	$app;
};

このサーバを立てたうえで、JS で以下のようなコードをつくっておきます。

function toTail (msg) {
	var img = new Image();
	img.src = 'http://tail.psgi/p?m=' + encodeURIComponent(msg);
}

if (typeof console == 'undefined') {
	console = {
		log : toTail
	};
}

どや

複数ブラウザで同時に JS を実行するシェルをつくった

plackup -s AnyEvent psgi.psgi

して、http://localhost:5000/ とかを各ブラウザで開いておく (ここは手動)

でもって ./shell.pl するとプロンプトがでてくるので適当に入力すると各ブラウザからレスポンスがかえってくる。

仕組み

  • 各ブラウザで / をひらくと、それぞれ long poll してスクリプトの実行要求を待つ。
    • 親の iframe がずっと long poll する
  • 実行要求は適当に HTTP で送る (結果がかえってくるまで long poll する)
  • 各ブラウザはそれを受け取って子 iframe で実行する
  • 各ブラウザは結果を HTTP 経由で送る
  • 各ブラウザからの結果が集ったら実行要求の応答をする

二重の long poll になっている。

ブラウザたち → 中継ウェブサーバ ← 実行させたいクライアント

中継サーバは Plack, AnyEvent

どや

2010年 10月 20日

YAPC、相当アウェイ感を感じるんじゃないかと大変不安だったが、それほどでもなかったし、今回は20分枠で喋らせてもらったり (YAPC では初めて)、ハッカソンに参加したり (これも初めて)、いろいろとモチベートされることがあって良かった。僕は何かしら喋らないと主体的に参加できないなあと思った。

今回は「これが流行り!」みたいなトピックはあんまりなかったと思うけれど、むしろ「Welcome Perl」の通り、そのテーマに沿った形のトークがあり、質実剛健な感じがあった。

いろいろ印象的だったことがあるが、いろんな人が笑っていたのが面白かった。トークよりもやはり、そのへんで座ってコード書いたりスライド書いてるハッカーに話を聴く、というのが、YAPC の会場に行かないとできないことであり、最も重要だと更めて感じた。講堂の前で誰か MacBook を広げてるなーと会場につくやいなや遠くから見えて、近付いたら miyagawa さんだった、みたいな、そういう面白さは会場に行かないとわからないことだろう。

今回もいろいろ、会ってみたいなーとなんとなく思っていた人と会えてよかった。

それにしてもこの規模のイベントをやるのはものすごく大変だし、運営に関わった人達に本当に感謝しないといけないと思った。ありがとうございます。

2010年 10月 23日

金曜日、休んで時代祭をスルーしつつ銀閣寺に行った。平日なのですいてるといいなあと思ったけどそうでもなかった。人がいるだけで、あんまり……という感じになってしまう。銀閣寺は良いけど、あんまり行かないなという感じだった。

その後嵐山にいって、野宮神社とか松尾大社とか月読神社とか普通に行ったあと、こっちも平日だから人がいないかと思って鈴虫寺に初めていった。鈴虫寺は思ってたのと違った。なんか、お寺の人が説話するのを聴くって感じだった。まあもう行かないかなと思った。

神社todo

  • 石上神宮
  • 大和神社
  • 廣瀬大社
  • 龍田大社
2010年 10月 24日


2010年 10月 25日

mabinogi Generation13 Chapter4

何も生産したくないときはネトゲに限ると思いました。

チャプターアップデートでタイトルがいい感じの絵になった。C4 のストーリー (ハムレット) 自体はあっさりしてて難しくなかったのでさっさとクリアした。よりによってベータ以来殆ど変わってこなかったステータス画面のレイアウトが大幅に変わったのでちょっと前に書いたステータス抽出スクリプトが動かなくなった。

C4 で実装されたスキルのうち、分身術の前提が Str 150 らしく、結構無理なのでとれてない (高価なアクセが2ぐらい必要そう)。ダウンアタックもスマッシュC前提で、あげる気がないのでとれてない。ボルト合体はよさそうなのでとった。というか合体は、前までの仕様だと普通にプレイしている限りまず使わないので、妥当な感じになった気がする。ヘイルストームもとったけど、新しくスタッフとかいう装備が必要らしく、詠唱すらできなかった。涙

あんまり熱心にやっていない割に累積が1200/400ぐらいになったので、ランク1のスキルが増えてきた。ファイナルショットはマスタータイトルが欲しいのでちまちまやってるがなかなか埋まらない。クールタイムがあるスキルは使うのを忘れてしまう。

あと最近実装されたデザインコンテスト服にいいのがあったので、適当にそれなりのクリ特化エンチャ (不安な盗賊) して使っている。

だいたいゲーム内の服は後姿がイマイチなのだけれど、これは後になんかよくわからないものがついていていいなあと思った。プレイヤーはゲーム中だとキャラクタの後ろ姿ばかり見ることになるので、後ろ姿に特徴があるのはとても良いです。歩くとフリフリしてかわいいです

2010年 10月 27日


2010年 10月 28日


gerry++

2010年 10月 29日


2010年 10月 31日

gerry++