2007年 12月 01日

ただ生きることよりルール

じわじわくる!!

jQuery Deferred

http://svn.coderepos.org/share/lang/javascript/jquery-deferred/sample.html
http://jquery.com/plugins/project/deferred

いろいろサンプル書いてつかいみちを考えているとたのしい。

var list = [];
list.push($.get("a.html").next(function (data) { return data.match(/<title>([^<]+)<\/title>/) } ));
list.push($.get("b.txt" ).next(function (data) { return data.match(/##\s*([^<]+)\s*##/) } ));
list.push($.getJSON("c.json").next(function (data) { return data.title } ));

parallel(list).next(function (values) {
	print("Titles "+values.join(", "));
});

みたい書ける。たのしい。(うえのコードがうごくかはためしてない)

それぞれ、べつべつのフォーマットのリソースをとってくる。タイトルを抽出するところまでは個々の Deferred が処理して、そいつらを parallel (DeferredList) であつめてくる。

でもそういうふつうの (謎) 非同期処理より、ループの分割のほうがおもしろい。

loop({begin: 1, end:100, step:10}, function (n, o) {
	print(["Processing devided loop:n=", n].join(""));
	for (var i = 0; i < o.step; i++) {
		var j = n + i;
		print(j);
	}
});

function print (m) { $("#loop-code1").append("\n// "+m) }

1 から 100 までをループする。ただし最大 10 個に制限して分割してループする (o.step を条件にしているのは、境界付近でよしなにするため。最後 (o.last == true) 以外は常に渡した step と一緒)。定期的にブラウザに処理がもどるので固まったようにならない (100 ぐらいじゃ固まらないけど)。固まりさえしなければある程度時間がかかってもストレスがたまらないから嬉しい。

ディレイいれながらループも簡単にかける

loop(5, function (i, o) {
	print(i);
	return o.last? i : wait(1);
}).
next(function (e) {
	print("end ["+e+"]");
});

1秒ずつまちながら 5 回ループする (0,1,2,3,4)

最後の値を次へ渡したいので条件をいれてる。end [4] と最後にでる。

わからないことを書くこと

ぼくはわからないことがあるとすぐ日記に書こうとする。「だれかおしえてくれないかなー」と思う。でもそれと同時に、この程度がわからないと思われるのは悔やしいと思う。なので日記を書いている途中で、調べに戻って、解決したりする。最初に「これがわからない」と書いてから、ins 要素を書くまではかなり必死に集中する (誰かが教えてもらうまえに「わかった!」と書きたい)。もちろん結局わからないこともあるけど、日記に書こうとすることで、回転の悪い頭を最大限回すことができる。ついでに「何がわからないか」を文章にすることで明確にできて、書きているうちに普通に解決してしまう場合もある。だから、「わからない」と書いたはいいけど、日記として残らず消えていった文章もある。

2007年 12月 02日

生姜

生姜の匂いを「冬を感じる優しいかおり」と表現しているのを見てなんかぐっときた。

Good Dog Happy Men - the GOLDENBELLCITY -嬉しくて悲しいこと-

3部作の完結のフルアルバムがでた。数日聴きこんでみたけど、「Groria Street から愛を込めて#3 」(原文ママ) が素晴らしい。「ただ生きるよりルール」

「Apple star storyS」 はヘッドフォンで聴くと面白い。ライブ音源もいいけどこれも好き。Most beautiful in the world にはASの歌詞がついてなくて、聴きとってテキストにしといたのだけど、何いってのかよくわかんなくてなんとなくで書いたりしたところがあった。でも答えあわせをしたら割とあってた (鍵カッコつけた部分まであってて笑った)。(「星空」を「この空」とまちがえてた (シャウトしててききとれない)。「たまにわからなくなるけど」を「たまにわからなくなるねと」とまちがえてた (なんで間違えたのかわからないけどw))

「そして列車は行く」はなんか長い部分を見ていろいろカッコいい。うまくいえない。曲としてめっちゃカッコいいのもそうだし、「今 拍手喝采とか涙よりもっと」とか、いちいちかっこいい。

「記憶と記録」は四人のゴブリン大いに踊るに収録されていた「微笑とメロディー」のリアレンジなんだけど、このアレンジがなんか想像の斜め上をいきまくってておもしろい。

でもって「黄金の鐘」なんだけど、最初の歌詞から大分歌詞が変わってて残念なところがあったりするけど、聴いてるとどうでもよくなってきた。これはたぶん聴きこむともっとじわじわきそうだなぁ。

ツインドラムがかっこいいからライブでききたいなぁ……

the GOLDENBELLCITY

MochiKit Deferred と jQuery Deferred の違い

(動いてはいるけど、ちょっと挙動が思ったとおりでない気がする (巨大なループのあと、次のプロセスへ進むのが遅い気がする) のでコードを考えなおしのために現在の実装をメモ書きします) なんか jQuery Deferred って書くと jQuery Core に Deferred システムがあるみたいにみえるけどちがうよちがうよ。でも内部的には animate あたりで必要だから持ってるんだとおもう……

チェインの根本的構造

MochiKit Deferred では子と親がはっきりわかれていて、子をつくるときには親を pause し、子が実行しおわったら親の pause を解除するようになっています (だと思うけど、実はあんまり使ったことなくてわからない)。これは、MochiKit の Deferred が Array でチェインを持って処理をしていて、子 (もまた Array でチェインをもっている) がかえされたとき、こうするのが一番だからだと思います。

jQuery Deferred では子も親もはっきりわかれておらず、子 Deferred が出現したら、現在の継続を子 Deferred の継続にし、親はもう過去の存在となるような実装にしています (親には戻らない)。そういうアレで pause がないです。

jQuery Deferred は一個の Deferred は一個のコールバックしか持ちません。処理のプロセス一つをパッケージングし、次のプロセス (を Deferred でパッケージしたもの=継続) を持っています。Deferred.prototype.next(fun) は fun を this のプロセスとし、さらに新しく Deferred をつくり、新しく Deferred を作り、そのプロセスを fun とし、それを this の継続として設定する関数です。

// global function next
next(function () {
	console.log(["chain", 1]);
}).
// Deferred.prototype.next
next(function () {
	console.log(["chain", 2]);
});

// 定義ずみの関数
/*
function next (fun) {
        // 新しく呼ばれることが約束された Deferred をつくる
	var d = new Deferred();
	setTimeout(function () { d.call() }, 0);
        // fun をその Deferred のプロセスとして設定し返す。   
	d.callback.ok = fun;
	return d;
}
*/

うえのコードは

// あとで呼ばれることが約束された Deferred を作成
d1 = next(function () {
	console.log(["chain", 1]);
});

// 次のプロセスをパッケージする Deferred を作成
d2 = $.deferred(); // (Deferred をエクスポートしてないので new Deferred() とはできません。
// プロセスを設定
d2.callback.ok = function () {
	console.log(["chain", 2]);
};

// d1 の継続を d2 に設定
d1._next = d2;

と同じです。

子 Deferred の例をだしてみます。

next(function () {
	console.log(["child", 1]);
	return next(function () {
		console.log(["child", 2]);
	});
}).
next(function () {
	console.log(["child", 3]);
});

このように Deferred をコールバックで返すと、コールバックを実行した Deferred は返された Deferred の継続に自分の継続をセットし、自分ではなにもしません。

next(function () {
	console.log(["child", 1]);
	ret = next(function () {
		console.log(["child", 2]);
	});
	ret._next = this._next;
	this.cancel();
}).
next(function () {
	console.log(["child", 3]);
});

これと全く一緒です。

実装では以下のようになっています。

call  : function (val) { return this._fire("ok", val); },
fail  : function (err) { return this._fire("ng", err); },

_fire : function (okng, value) {
	// if (typeof log == 'function') log("_fire called");
	var self = this;
	var next = "ok";
	try {
		value = self.callback[okng].call(self, value);
	} catch (e) {
		next  = "ng";
		value = e;
	}
	if (value instanceof Deferred) {
		value._next = self._next;
	} else {
		setTimeout(function () {
			if (self._next) self._next._fire(next, value);
		}, 0);
	}
}

_fire が実際にコールバックしている関数です (この関数は call/fail から間接的に呼びます)。コールバックの返り値が Deferred のインスタンスの場合は、それの _next を設定しているだけです。それ以外の場合は setTimeout を通して継続をよびだしています (setTimeout をつかっているのは、永遠とコールバックチェインが続くとスタックオーバーフローになるからです)。

エラーの処理

jQuery Deferred では一つしかプロセスをもっていないと書きましたが、実際のところエラーを処理するためのコールバックも持っています。とりあえず例をだすと (テストケースから)

next(function () { throw "Error"; }).
error(function (e) {
	expect("Errorback called", "Error", e);
	return e; // エラーのリカバリー
}).
next(function (e) {
	// next だけど、リカバリーされたので実行される。
	expect("Callback called", "Error", e);
	// また投げてみる。
	throw "Error2";
}).
next(function (e) {
        // エラーがリカバリーされていないのでよばれない。
	ng("Must not be called!!");
}).
error(function (e) {
        // エラー専用のチェインをたどりここまでくる。
	expect("Errorback called", "Error2", e);
});

コールバックで発生したエラーはエラー専用のチェインをとおります。また、エラーバックでエラーを処理し、値をなげなおすことで、後続の処理を続けることができます。

このエラー専用のチェインですが、単に throw をくりかえすだけのチェインです。Deferred は以下のように初期化されれ、デフォルトのコールバックを持っています。

init : function () {
	this.callback = {
		ok: function (x) { return x },
		ng: function (x) { throw  x }
	};
	this._next    = null;
},

デフォルトでは ng は常に throw をするため、前途の _fire の catch に捉えられ、継続の ng を実行するように伝えられます。エラーのチェインへの分岐は throw するかしないかなので、エラーバックで普通に return すればエラーのリカバリーになります。



なんかつかめそうでつかめない。どっかおかしいような気がする。頭悪いのがむかつく

あーわかった。わかった。next で呼ばれる Deferred を一個余計につくっていたせいだった。

http://coderepos.org/share/changeset/2287

で修正した。ついでに説明も修正した。テスト書いといてよかった……役にたった (テストも Deferred 自身で書かれているから、あきらかにおかしいときはテストの数があっているかどうかをみる)

2007年 12月 04日

Deferred による疑似マルチスレッド

Deferred をつかってマルチスレッドっぽいこともできます。

loop(10, function (n) {
	print(n);
	return wait(0.1);
});

loop(10, function (n) {
	print(String.fromCharCode(97+n));
	return wait(0.2);
});

このように書くと、0 から 9 までの数値と a から j までの文字がまざって出力されます。

例: 0 a 1 b 2 3 c 4 5 d 6 7 e 8 9 f g h i j

loop 関数は Deferred をかえすので、うえのふたつが終ったら実行する処理を書くなら、

parallel([
	loop(10, function (n) {
		print(n);
	}),
	loop(10, function (n) {
		print(String.fromCharCode(97+n));
	})
]).next(function () {
	print("End");
});

とか書けます (MochiKit Deferred でも書けるはずだけどめんどいからためしてない)。Deferred のおもしろいところは、めちゃくちゃ簡単で Greasemonkey スクリプトにコピペして使えるぐらいの長さのコードでこういうことができることだと思います。

2007年 12月 05日

JavaScript のコンストラクタ関数

new つけてもつけなくてもいいようにするにはどう書くのがベストか的なんだろう。Deferred ではこうしたけど

function Deferred () { return (this instanceof Deferred) ? this.init(this) : new Deferred() }
// prototype.init では this をかえしてる。
// でもコンストラクタは Object をかえした場合にしかその返り値を使わないので undefined でもべつにいい。

汎用的にするなら

function Foo () {
    if (this instanceof arguments.callee)
       this.init(this);
    else
       return new arguments.callee;
}

かな。ただ、これだと任意の数の引数がとれない (new は括弧をつけなくていいことからも解るように関数呼びだしではないので)。

function Foo () {
    if (this instanceof arguments.callee) {
       this.init.apply(this, arguments);
    } else {
       // new のエミュレート
       var f = function () {};
       f.prototype = arguments.callee.prototype;
       var o = new f;
       arguments.callee.apply(o, arguments);
       return o;
    }
}

どうみても素直に引数リストを書いたほうがよみやすくていい。(instanceof (がつかっている [[HasInstance]]) は [[Prototype]] をみる。new 以外に [[Prototype]] をセットする方法はない。)

てかはてなで

[[Prototype]]

[] [[Prototype]] [] <- リンクはされないけど括弧が消える。

を地で書くにはどうしたらいいんだ……

ちなみに global ( (function () { return this })() ) と、this をくらべるのはよくないことがある。

jQuery Deferred だと $.deferred = Deferred とやっているわけだけど、この場合 this は $ (jQuery) になってしまうのでだめ。

Deferred

jQuery Deferred とか言っていますがコアは全く jQuery に依存しないので (いい名前がおもいつかないから jQuery バインディングのほうのなまえでよんでる) http://svn.coderepos.org/share/lang/javascript/jquery-deferred/jquery-deferred.js の Deferred 関数と必要な関数をコピペしたら GM でもうごきます。setTimeout/clearTimeout にだけ依存してるのでその実装があるならどこでもうごくはず。

他の非同期なやつを Deferred 化するのは jQuery Deferred だと

function wait (n) {
	var d = new Deferred(), t = new Date();
	var id = setTimeout(function () {
		clearTimeout(id);
		d.call((new Date).getTime() - t.getTime());
	}, n * 1000)
	d.canceller   = function () { try { clearTimeout(id) } catch (e) {} };
	return d;
}

こんな感じになってます。Deferred#call がコールバック起動で、Deferred#fail がエラーバック起動です。

MochiKit のコードだと (機能がちょっと違いますが)

    /** @id MochiKit.Async.wait */
    wait: function (seconds, /* optional */value) {
        var d = new MochiKit.Async.Deferred();
        var m = MochiKit.Base;
        if (typeof(value) != 'undefined') {
            d.addCallback(function () { return value; });
        }
        var timeout = setTimeout(
            m.bind("callback", d),
            Math.floor(seconds * 1000));
        d.canceller = function () {
            try {
                clearTimeout(timeout);
            } catch (e) {
                // pass
            }
        };
        return d;
    },

引数 (value) をわたすためにチェインつかってるのがおもしろいすね。


ついでに jAutoPagerize でつかっているやつ。

function CachedResource (uri, convertfun, expire) {
	var d   = Deferred(); // new なしでいける。
	var key = uri;
	var v   = {};
	try { v = eval(GM_getValue(key)) || ({}) } catch (e) { log("parse error: may be uneval bug") }
	d.clear = function () {
		GM_setValue(key, "");
		return this;
	};
	if (v.time && v.time > (new Date).getTime() - expire) {
		log("Cache Hitted: " + key);
		setTimeout(function () { d.call(v.body); }, 10);
	} else {
		log("Cache expired; getting... " + key);
		GM_xmlhttpRequest({
			method  : "GET",
			url     : uri,
			onload  : function (req) { try {
				var res = convertfun(req.responseText);
				GM_setValue(key, uneval({time:(new Date).getTime(), body:res}));
				log(key, uneval({time:(new Date).getTime(), body:res}));
				log("Cached: " + key);
				d.call(res);
			} catch (e) { d.fail(e) } },
			onerror : function (e) {
				d.fail("HTTPError:"+e);
			}
		});
	}
	return d;
}
2007年 12月 06日

jQuery Deferred

名前がやっぱよくないよなぁ。General Deferred とかにすればいいのかなぁ (jQuery 部分は分離して Rakefile で一括生成)。

  • JSDeferred
  • General Deferred
  • jKuery Deferred
  • JSContinuation (Deferred って名前がウケ悪い説 でもおかしいからだめだな)

JSDeferred にしよう。作業かいし

http://svn.coderepos.org/share/lang/javascript/jsdeferred/trunk/

mini (簡易圧縮バージョン) と nodoc (コメント全削除) もコミットするようにした。rake すれば生成される。mini と nodoc は見た目の差の割にサイズがそんなに変わらない (タブインデントだし) ので nodoc だけでもいい気もする。

Rhino memo

なんか、Rhino 上で setTimeout エミュレートしてテストしようとおもったら、そもそも言語的な部分の非互換を踏んでだめすぎる……

$ rhino
js> a = undefined || 1
true <= expect 1
js> a
true
js> a = undefined || 0
js> uneval(a) // (undefined は表示されないっぽいので uneval)
undefined <= expect 0
js> undefined instanceof Object
js: "<stdin>", line 1: The undefined value has no properties. <= expect false

あと Rhino のバージョンってどうやってみるんだろ。apt-cache show rhino すると

Version: 1.6.R1-0.0ubuntu3

だけど、これってめっちゃ古くて実は上の問題は新しいのだと解決していたりするのかな

setTimeout のエミュレートはよくわからんけど spawn と sync つかってかいた。けど、べつに使わなくていいよなと今読みなおしておもった……

http://coderepos.org/share/browser/lang/javascript/jsdeferred/trunk/test-rhino.js?rev=2673#L94

最新にしたらいけた……sudo apt-get remove rhino

$ wget ftp://ftp.mozilla.org/pub/mozilla.org/js/rhino1_6R7.zip
$ unzip rhino1_6R7.zip
$ cp js.jar ~/bin
$ cd ~/bin
$ cat rhino
#!/bin/sh

if [ -z "$JAVA" ]; then
  if [ -n "$JAVA_HOME" ]; then
    JAVA="$JAVA_HOME/bin/java"
  else
    JAVA=/usr/bin/java
  fi
fi

"$JAVA" -jar ~/bin/js.jar "$@"
2007年 12月 07日

Rhino でテスト

いろつき!

ブラウザの機能使わないテストだと rake でテストできていいなぁ

どうやら

おれは、どうも、中身より、API のデザインのほうが気になるみたいだ。中身はもちろん、すごくおもしろいけど、中身がどうよくても、API がよくなければ使えない。そのうえで、中身、と、それと API をふくめた哲学が一体となって、美しいライブラリ/フレームワークになるんだなぁ。

これは別に比喩でもなんでもなくて、他のことに言いかえると意味が剥れてしまうようだ。中身より外見のほうが気になるってのはちがうし


そして、頭がわるいこともあって、できるだけシンプルなデータ構造と、できるだけシンプルな動作がすきだ。だから、そのために多少の高速性が犠牲になっても、べつにいいと思ってる。そうもいかないこともかなり多いけど、やっぱりそういうところをいじろうとすると、戸惑う。むずかしい。高速性より、理解のしやすさ、読みやすさ、がおれのなかでは、かなり優先順位が高い。綺麗なソースがすきだ。どうしてもそうだ。

あああ

もっとあたまがよければ、もっとよくいきれたのになぁ……

JS のドキュメンテーションツール

JSDoc Toolkit がよさそうなんだけど、どっちにしても Java Doc 形式のコメントが好きになれないので使う気がおきなかった……(ここでまた慣れるか、オレオレ文法でいくかで悩む。でも @return とか @param とかすごいダサく感じる……)

MochiKit は python の docutil (?) とかいうのをつかってるみたいだ。スクリプトのほうには id だけつけて、rst ? っていうのにドキュメントがまとまってる。よくわかんない。

あと MochiKit はスクリプトの圧縮に rhino をつかってるっぽい (custom_rhino.jar/js.jar) けど詳細がよくわからない。Rhino/Spidermonkey は JS 内部から JS トークナイザにアクセス (Ripper みたいに) できたらいいのに……Rhino のほうは内部メソッド叩いたらできるんかなぁ。


それとドキュメントをソースコードに書くべきかどうかがいまいち迷う。RDoc はソースコードにまぜて書くけど、見通しが悪くなるんだよなぁ。でも最低限の使いかたはコメントとして近くに書いておきたいし、挙動を変更したらすぐ書きかえたいから、近くにあるのは便利だ。

あとドキュメントに実装を簡単に見れるしくみが絶対必要だと思う。長い英語よむぐらいならソース見たほうが理解できるし、ソース見てからドキュメント読むとよめるようになるし……

Twisted

正直にいうとごくごく最近まで MochiKit Deferred の由来が Twisted (Pythonの非同期ライブラリ) からきていると知らなかった……
Python のマルチスレッドってどうなってるんだろう。threading/thread とかがヒットする。

Ruby のスレッドはなんか頭つかわなくても書けるなぁ。なんでだろう……あと Ruby で Deferred は必要か、っていうのが微妙に最近ひっかかる。なんで Ruby には Deferred がないんだろう (つまり、なんでなくてもいいやって思えるんだろう)

JS だとスレッドがなくて、しかもいちいちブラウザに処理をもどさないと固まってしまうから Deferred がすごい威力を発揮するけど、スレッドがあったときに、Deferred はどう活躍するんだろう。(Python にはスレッドがあるっぽいけど、なんで Deferred が必要になったんだろう)

Ruby だと非同期な HTTP GET をやるなら

require "open-uri" # net/http はめんどいから

t = Thread.start do
	open("http://example.com/") {|f|
		f.read
	}
end

p t.value

みたいになって、複数あつめてやるのをスレッドつかってかくと

require "open-uri"

t1 = Thread.start do
	open("http://example.com/") {|f|
		f.read
	}
end

t2 = Thread.start do
	open("http://example.com/") {|f|
		f.read
	}
end


[t1.value, t2.value].each do |i|
	p i.length
end

さらにつなげていこうとすると大変? そうでもない気がする。うーん

最初から非同期なやつだと (ぱっとでてこない)、めんどいかなぁ……

いやいやそもそも Deferred は非同期なやつをほげほげするやつなんだ。

Ruby だと非同期なメソッドがあんまりないから気にならないのかなぁ。

Greasemonkey スクリプトの構成

なんでこんなふうに書いてるの? って感があるのかもしれないから、いちおうかいとくよ!

(function () { // なんか GM ではいらなくなってるっぽいけど、一応かこう

// メインの処理
foobar...


// ユーティリティ関数たち
function $X () {
}


})();

って感じで書いてる。メインの処理、その GM で一番重要なところをできるだけ上に書きたい (ただし、うえから順に読んでも理解できるように)。なのでユーティリティ関数とかは関数式ではなく関数宣言で書く。宣言で書いた場合はあとに書いても前のほうで参照できる。

foo();

function foo () {
    foobar();

    function foobar () {
    }
}

// baz(); //=> これはできない

var baz = function () {
};

baz();

でも、これだと prototype への代入とかをするのをうしろに書けない。そういうときは、

with (F()) {
    var baz = new Foo();
}

function F () {
    function Foo () {
        return (this instanceof Foo) ? this.init() : new Foo();
    }
    Foo.prototype = {
        init : function () { }
    };

    var foo = {};
    foo.Foo = Foo;
    return foo;
}

とかやるとうまいこと分離できるぽい。

JSDeferred の jsdeferred.userscript.js は、コピペ用のコード ( http://svn.coderepos.org/share/lang/javascript/jsdeferred/trunk/jsdeferred.userscript.js ) を生成していて、これを最後にコピペして with をつかえば綺麗にかけるようにようにした。

with (D()) {
    next();
}

// コピペ
function D () {

}
2007年 12月 08日

Deferred チェインのときの setTimeout

http://coderepos.org/share/browser/lang/javascript/jsdeferred/trunk/jsdeferred.js?rev=2761#L119

の setTimeout について、スタックを消費するからこうしている、と書いたのは、next の問題で無駄な Deferred を生成していたせい ( http://subtech.g.hatena.ne.jp/cho45/20071202/1196571302 ) で、Stack over flow がでたことがあったからなんだけど、next の問題は解決したので、あらためて必要かどうか考えたらいらない気がした。

でもって http://coderepos.org/share/changeset/2817 はずしてみた。Safari はスタックサイズがかなりちっちゃくて、600?くらいの再帰でオーバーフローするからテストでは loop(1000 を実行してちゃんと戻ってくるかをテストしてる (loop は内部で next と call よんでる)。

この修正で、チェイン間ではブラウザへ処理がもどらなくなる。もどしたいなら wait(0) を return すればもどせる。

Stack over flow

Mac 10.4.11 Mem 2G

javascript:n=0;(function(){n++;arguments.callee();})();
javascript:alert(n);
Firefox 3.0b1
261503
Safari 3.0.4
500
Opera 9.24
3340
Thunderbird 2.0.0.9
1000

Fx の深さはなんなんだ……

Rhino だとインタプリタモードのときはいくらでもいける……

$ rhino -opt -1 -e 'n=0;(function(){n++;print(n);arguments.callee();})();'
#=> どこまでも
$ rhino -opt 0 -e 'n=0;(function(){n++;print(n);arguments.callee();})();'
2054
/home/cho45/bin/rhino: line 11: 31589 Segmentation fault      "$JAVA" -jar ~/bin/js.jar "$@"
exit 139

あふれると SEGV ってのはどうなんだ

Good Dog Happy Men - 新宿 TOWER RECORD インストアミニライブ

なんか想像以上によかった。ちょっとおかしいぐらい好きなことに打ち込んでる感がやっぱすばらしい。分野の違い、みたいな、うまくいえないけど、そういうのを感じた。なんとなく梅田もちおを想起した。

2007年 12月 09日


  • よりよい Ruby 用のドキュメント記法
    • doctest
  • よりよい JavaScript 用のドキュメント記法
    • ソースコードとの分離
    • doctest

syrup16g

なんか3月1日で終了らしいじゃないですか……光のはやさで wikipedia が更新されてて感動したけどそれはべつにどうでもいい。なんか、ざんねんだなぁほんとうに
GHOST PICTURES をそういえば買ってない。買うか

こう、アニソンきいてテンションあげる気分になれない

Last.fm weekly

http://f.hatena.ne.jp/cho45/20071209233148

ひきこもりすぎる。Top10 中半分以上がニコニコ関係だけど、Top2 (GDHM/バーガー) だけで一日11時間きいてることになってる。

2007年 12月 10日

ライブとか

実のところ新宿タワレコのミニライブ程度でさえ、行くのを直前まで迷ってた。ああいう近くで聴いたりするのはすごく楽しいんだけど、それと同時に、周りにいる人たちが嫌で嫌でしかたない。電車でも、普通に歩いていても、周りに人がいるのがたまらく嫌なことが多い。なぜなら、そういう、周りの人達の中に、すごく嫌な表現をする人がそこそこいて、すごく嫌な生きかたをしている人がそこそこいて、自分と、決定的に合わない人がかなり多くいることを感じるからで、そういうのは本当に、どうしよもない。物理的に近くにいれば、話声が聞こえてきてしまうし、視界に入ったりするしで、フィルタリングするにしても、一つの感覚だけが刺激されるわけじゃないから、難しい。

すごく嫌な人、自分にとっての嫌な人っていうのは、別に存在したっていいけれど (それは本当にどうしようもない)、絶対に、関わりたくないし、近くにいたくもない。外にでたらでたで、そこそこ気にしないでどうにかやれることが多いけど、ふとした拍子に思い出したりするし、そんなときはなすすべがないから、できるだけ外に出たくない。

>

にこにことか

ニコニコ動画とかにも、そういう嫌な空気を感じることがかなりあって、特に、ネタ系じゃない動画 (演奏してみたとか) はもうコメントを表示させて見ることなんてあんまりない。(Comment Heat Map for nicovideo のデータソースとしてだけ受信してる感じ) NG リストも常時最大ぎりぎりまで入れてる。

すごい嫌な表現をする人たち、例えば、自分を評価される場におかないで中傷だけする人達 (しかも自分ではそれが批評だと思っている) とかは、本当に、関わりたくない。むかつくと同時に、そういう人の多さ、居場所のなさを感じて、いろいろどうでもよくなってくる。どっちにしろ、自分がそういうことをしないようにしないといけない……
-->

2007年 12月 11日

Creative Commons Color

http://www.flickr.com/photos/joi/2093076116/

こういう配色っていいよなぁ……変に気取っていなくて……

あといまさらだけど Last.fm の audioscrobbler とあわせたロゴはすきだ

一日中コンピュータとむきあうこととか

別に、一日中コンピュータとむきあっているからといって、いつも同じことをしているわけではないのは、よほど古い人でなければすぐ想像可能で、あたりまえに感じることだと思う。プログラミングしていたり、写真現像していたり、ニコニコ動画見ていたり……

そんなのと同じように、プログラミングをするって一言で云っても、あっちいったりこっちいったりで、いつも同じようなことをしているわけじゃないのはごくごく簡単に想像できることだと思うんだけど、そうじゃない人もいるんだなぁと思った。

ActionScript とか JavaScript のプログラミングと C や D のプログラミングは全然違うし、JS に限定しても、ブラウザにすごく近い部分のプラグラミングと、言語を拡張するようなプログラミングとでは違うし、いくらでも細分化していくことができる (掘りさげて、あっちこっちいったりできる) 。もちろんこんなのプログラミングに限ったことじゃなく、写真だって被写体や画角の違い、撮影スタンスの違いでいくらでも広げることができるし、たぶん他の分野でも一緒だ (一見そうは思えないことだって多くて、たんにそれは自分がその分野について知らなすぎるだけなんだと思う)

>

洗濯機の向こう

むしろ今は、おれが行きたい。

2ch とか、ニコニコ動画とか、そういう人がいっぱい集るところは、ほんとうに、クズの最低な発言ばかり目立って、真面目なものほど全く面白くない。ただのネタスレにだけ存在価値がある。(どんどん、真面目なもの、本気なものはああいうところから消えていく。クズが集るまえのときにしか、そういうのは有効じゃない)

Good Dog Happy Men のスレは本当にクソだらけで微塵も面白くないと、久しぶりに読んで思った。ああいう、最低の表現をするやつらと、ライブなんかで同じ空間にいるとかは、腹立たしくてならない。「キモいやつらがいっぱいいた」とか、お前は何しにいっているんだという感じだ。そんなことを平然と、匿名でありつつも、キーボードでうちこみ、ポストする、という感覚や、その自分への自信、みたなのは、かえって羨しい。

というのをどっかに婉曲して書こうと思ったけど、一番いいたいことはうまく書けず、自分がそういうことを全くしていないかというとそうは絶対言いきれず、なんやかんや全部嫌になる。
-->

2007年 12月 10日

Trac で特定のコミッタの timeline フィード

http://mk-colors.org/scrap/2007/12/075208 みたいにあるとおり標準でそのまんまなのはできないっぽい。

けど http://dev.ariel-networks.com/column/tech/tracreport-tips/ よんでて、あーそっかーとおもったので report つかってフィード生成してみた。

SELECT
    "../changeset/" || rev AS ticket,
    rev || ": " || message AS summary,
    time AS _changetime,
    time AS created,
    author AS _reporter,
    message AS _description
    FROM revision WHERE author = '$AUTHOR' ORDER BY rev+0 DESC LIMIT 50;

こんなん。ticket がフィードのリンクにつかわれるみたい。ticket/#{ticket} にリンクされるので相対パスつかって changeset にしてる。詳細は TracReports にいろいろ書いてあった。

2007年 12月 11日

JSDeferred

そういえば、あらかじめデータは取得しておきたいけど、表示自体は遅延したい、みたいな場合 (ホバーツールチップみたいなやつ) にもめっさつかえるなぁねむい。

var d = null;

anElement.addEventListener("mouseover", function (e) {
    if (d) d.cancel();
    // http.get はおこなわれるが、少なくとも 1 秒遅延してから表示する
    d = parallel({
        wait:  wait(1),
        value: http.get("foobar")
    }).next(function (o) {
        show(e.pageX, e.pageY, o.value); // show はどっかで定義
    });
}, false);

anElement.addEventListener("mouseout", function (e) {
    if (d) d.cancel();
}, false);

これだとまだまずいけど (mouseover が発生しまくるから//http.get をキャッシュつきにラップすればスマートかも) wait(1) してからロードしにいくみたいにするより、これだと同時によみこむから待ち時間がへる (その変わりリクエストが必ずとんでサーバに負荷かかる)

2007年 12月 12日

JavaScript で Blosxom, Rhino

http://svn.coderepos.org/share/lang/javascript/blosxom.rhino/

Java との連動が結構たのしい。Java に足りない部分とかめんどうくさい部分と、JS にないシステムの部分とかをうまくくみあわせられてたのしい。

Java がよくわかんなくて文字化けしていたんだけど、結局 js.jar を叩くときの java コマンドに -Dfile.encoding=UTF-8 いれてうまくいった。ただこれって、プログラム側から設定しても反映されない? っぽくてよくわからない……

本体は完全に Rhino に依存してるけど、テンプレートエンジンは依存せずに書いてある

JS のテンプレートエンジンなんて腐るほどあるけど、自分で書いてみるのはやっぱ面白い。今回は new Function("stash", templatecode") みたいにして、ハッシュをわたすとテンプレートをプロセスする関数を動的に生成してみてる (toSource すればコンパイルされた結果をキャッシュできる)。new Function による eval はなんかなんともいえない楽しさがあるなぁと思った。

JS 1.6 相当の関数 (filter とか) ってほぼ必須だよなぁと思った……ないと書けない。

toSource と uneval の出力からわかる Object と Primitive

ためしてみるとすぐわかる違い。前提として、JavaScript では「全てオブジェクトというわけではない」ことを覚えておく必要があります (Ruby との違い)。

uneval("foo");
//=> "\"foo\""

"foo".toSource();
//=>  "(new String(\"foo\"))"

なぜこのような違いが生まれるか、というと 11.2.1 プロパティアクセス演算子 (Property Accessors) にある

生成規則 MemberExpression : MemberExpression [ Expression ] は次のように評価される:

  1. MemberExpression を評価。
  2. GetValue(Result(1)) を呼出す。
  3. Expression を評価。
  4. GetValue(Result(3)) を呼出す。
  5. ToObject(Result(2)) を呼出す。
  6. ToString(Result(4)) を呼出す。
  7. 基準オブジェクトが Result(5) でプロパティ名が Result(6) である Reference 型の値を返す。

の ToObject(Result(2)) がキモです。

JavaScript において

"foobar"

typeof "foobar" //=> "string"

は、typeof すればわかるように Primitive な String 型であって、String オブジェクトのインスタンス (Object 型) ではありません。プロパティアクセス演算子が使われると、そのつど String オブジェクトへ変換されます。

これは以下のようにすればすぐわかります。

String.prototype.returnThis = function () { return this };
typeof "foobar".returnThis(); //=> "object"

"foobar".returnThis() === "foobar".returnThis(); //=> false

レシーバは "foobar" にみえますが、上の結果と違っています。これはプロパティアクセス演算子の作用で ToObject された結果が this として渡されているからです。(ToObject は処理系の内部関数なので JS から直接はよべません)

ここでなんとなく気付くと思いますが、this は Object 型以外の型には絶対になりません。this を明示して渡せる call や apply でさえ this に対しては ToObject で変換がかかります。

そうなると、Object に変換されるまえの、Primitive な値がほしいときに (そんなケースあんまりありませんが)、ちょっと困るので、そういうときに valueOf() をつかいます。valueOf() って説明だけ読みとなにがしたいのがさっぱりわかりませんが、こいつを使ってやることで、本来のレシーバ (のようにみえる値) をとることができます。

"foobar".valueOf() //=> "foobar"

この valueOf() はどんなオブジェクトにも存在するので安心して本来のレシーバを取得することができます。(Primitive 値のラッパオブジェクトでは Primitive 値になるし、そうでなければ単に this をかえすだけです)

valueOf には Date オブジェクトみたいに this 以外をかえすのもあります。

JavaScript の型

前後しますが JavaScript には6個の型があります (処理系内部的/説明的には9個)。

  1. Undefined / undefined
  2. Null / null
  3. Boolean / true, false
  4. Number / 10, 0xff
  5. String / "foo", "fumino san love"
  6. Object / {foo: 123, bar: 456}

Object 型以外は Primitive であり、そう考えると Primitive vs Object の構造が想像できると思います。(リテラル undefined や null, 1, 2, "foo" とかは全部この型に対応しています) JavaScript における「オブジェクト」は Object 型の値のことで、Object 型以外は「プロパティ」や「メソッド」を持ったりはしていません。

プロパティアクセス演算子は Object 型へ必ず変換しますが、そのとき使われる ToObject は、undefined と null のときに TypeError をなげます。(この変換のおかげで Primitive 値の多くはオブジェクトのように扱うことができます)

割とよくみるであろう

TypeError: null has no properties
TypeError: undefined has no properties

は、この ToObject への変換時におきているものです (殆どないし全部)。もし JavaScript でも Ruby と同じように「全てがオブジェクト」であるならば、上のようなエラーは絶対に起きないはず (オブジェクトであれば no properties はありえない) ですし、Object に定義されているメソッドが null や undefined に対しても使えるはずです。

null.toString();
undefined.valueOf();

実行しなくてもわかるようにこのコードは TypeError がでます。JavaScript では「全てがオブジェクトというわけではない」ことは、この TypeError の背中が物語っています。

Tree Style Tab いい!

https://addons.mozilla.org/en-US/firefox/addon/5890 (SandBox にはいってる)

そろそろ Fx3 で縦おきタブデキナイカナーとおもってさまよってたら Tree Style Tab でできた……piroさん++

Mac のテーマだとタブの高さがちょっとたりなくてセレクトしたときに outline がはみだしてしまうので、Stylish で

@namespace url(http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul);

.tabbrowser-tab {
    height: 2.2em !important;
}

.tabbrowser-tab label {
    font-size: 90% !important;
}

こんなん書いた。

なんか Opera と同じようなレイアウトにしたら (Opera は左にタブ縦置きにしてる) Fx がはやくなったように感じるプラセボ

それにしてもツリーが思ったより便利><

>

2007年 12月 13日

..

人数が多いとそれだけ、嫌な人と遭遇しやすくなるんだから、ブログも日記も書いていない人がいっぱいいるところに、コミュニケーションを目的として行こうとなんて思えるはずがない……

id:cho45に嫌な人とマークされてるんじゃないかと思うと夜も眠れません><

http://b.hatena.ne.jp/ZIGOROu/20071213#bookmark-6783360

ちょw そんなわけない>< むしろ毎日会いたいw

殆ど知らない人いっぱいとあうのは絶対嫌だなぁというのを twitter の大規模なオフをやったという話を眺めながら思ったのでした……

事前に「あーこのひとはこういうひとかー」っていうのがわかってないとこわすぎる (知っていれば近づき/避けやすい)。そういうのは継続的な日記/ブログ (をどっちのスタンスで書いているか、とかも) がないとわからない……

要約すると、「ちんこちんこ言っても大丈夫なのかよくわからないのでめんどうくさい」

2007年 12月 12日

Windows 再インストール

たいして使ってないのに再インストール…… Windows Update でエラーでて (なんか証明書関係のエラーで、対策もひとおりしてみたんだけどだめだった。)

http://subtech.g.hatena.ne.jp/cho45/20070927/1190891651

  • Chipset Driver Windows 2000 用のやつ (from SC440 付属CD)
  • reboot
  • イーサネットコントローラ (ドライバの更新で CD を検索させる)
  • reboot
  • nVidia GeForce 6 系のドライバをインストール (via Internet)
  • reboot
  • WPCRSET 自動起動 ( Bus=0 Device=28 Function=0 Register=05h Data=00h )
  • Windows Update (再起動しまくり)
  • Avast インストール
  • US Keyboard http://subtech.g.hatena.ne.jp/cho45/20070928/1190965320
  • Firefox 3b1
  • Lhaplus
  • mayu
  • SKKIME http://subtech.g.hatena.ne.jp/cho45/20070929/1191020138
  • ~/fonts/* を %fonts% へコピー
  • foobar2000
    • Columns UI
    • ~/foobar.fcs からインポート
    • Last.fm インストール
Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\i8042prt\Parameters]
"LayerDriver JPN"="KBD101.DLL"
"OverrideKeyboardIdentifier"="PCAT_101KEY"
"OverrideKeyboardType"=dword:00000007
"OverrideKeyboardSubtype"=dword:00000000
"LayerDriver KOR"="KBD101A.DLL"
Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout]
"Scancode Map"=hex:00,00,00,00,00,00,00,00,03,00,00,00,1d,00,3a,00,00,00,00,00
2007年 12月 13日

やったーゆのの絵かいたよー

2007年 12月 14日

Haiku

gerry++

2007年 12月 15日

はてなハイクのお絵描き機能で fotolife の変わりに tumblr をつかう

fotolife は容量制限が厳しくて、落書きを大量に投稿する、というときちょっと不安 (制限に逹っしたとき、消さないといけないなぁという不安) があるので、tumblr を使うようにする userscript を書きました。(月別の容量制限とかならいいんだけどなぁ)

(イラスト投稿を確実にする GM より前に実行する必要があります)

といっても、tumblr はいまいち安定感 (いろんないみで) がないように思えるのでなんともいえない……

URL をうけとって保存してくれるサービス/そういうAPIがあるサービスなら簡単に対応できるんですが、そういうのあんまないっすね……

postDrawing がよばれないことが多々ある、そういうときはブックマークレットでよぶ

javascript:Hatena.Haiku.EntryForm.postDrawing("fotolife の該当画像の URL");

書きはじめてから一定時間おきに fotolife の feed を監視して投稿する、みたいなのをつくろうとおもったけど、二重投稿とか考えるのがめんどくてやめた……

2007年 12月 16日

はいく

はいく、おすすめ

2007年 12月 15日

Firefox3 の Greasemonkey, unsafeWindow 内の prototype がとれない

なぜかわからないけど unsafeWindow 中のオブジェクトの prototype がとれないっぽい……

unsafeWindow.Hatena.Haiku.EntryForm.prototype //=> undefined

でもって回避しようとして以下のようなコードを書いてみたけど

	function unsafeeval (code) {
		var d = new Deferred;
		unsafeWindow.___eval = arguments.callee;
		arguments.callee.callback = function (r) {
			delete unsafeWindow.___eval
			d.call(r);
		};
		unsafeWindow.location.href = "javascript:"+encodeURIComponent("___eval.callback("+code+")");
		return d;
	}

	unsafeeval("Hatena.Haiku.EntryForm.prototype").
	next(function (proto) {
		alert(proto.showDrawForm); // とれてる
		proto.showDrawForm = function () {
			alert("aaa"); // 実行されない orz
		};
		alert(proto.showDrawForm); // かきかえはできてる
	});

って感じになる。javascript:alert(Hatena.Haiku.EntryForm.prototype.showDrawForm) するとちゃんと設定された関数が表示されるんだけど、実行はされない (もとの関数はもちろんよばれない)。だれかたすけて>< これは Fx のバグ?

prototype 以外への書きかえはもちろんうごく……

Haiku のイラスト投稿を確実にする Greasemonkey script

postDrawing がたびたびよびだしされないので、fotolife を GM_xhr で監視して投稿するようにするスクリプトです。

流れは

  1. ページロード時に fotolife のフィードを取得 (ほんとはおえかきに切り替えしたときにしたいけど、prototype かきかえができない……)
  2. currentForm がセットされるのを監視 (Haiku! をおすとセットされる)
  3. セットされたら fotolife のフィードを監視開始
  4. ページロード時の状況と比較して、増えたものをハイクから投稿されたものとみなし、postDrawing をキック

tumblr に投稿しなおすスクリプトより後に実行する必要があります。

なかなか投稿できないなぁってときは API がエラーだしていたりするので http://f.hatena.ne.jp/rkatom/feed にアクセスして確認してみるとよいかもです

2007年 12月 16日

Haiku でイラストを投稿するとき、コメントも一緒にいれられるようにする

(他のスクリプトより先に読みこむ必要あり)

オリジナルの postDrawing を上書きして、イラスト投稿のときに、そのままポストではなくテキストとして URL を挿入する。


最初めんどくさがって

with (unsafeWindow) {
Hatena.Haiku.EntryForm.postDrawing = function (uri) {
	if (!uri) return;
	var form = Hatena.Haiku.EntryForm.currentForm;
	if (!form) return;
	form.textarea.value += uri;
	form.submit.disabled = false;
	form.showTextForm();
	// form.form.submit();
};
}

とかやってたんだけど、これだと他のユーザJSがこの関数を実行しようとしたとき (?) にセキュリティエラーがでてしまう。

javascript: によるロードとかいろいろためしたけどうまくかなくて、結局こうしてみたらうまくいった……

2007年 12月 17日

Haiku の Reply を全部展開する Greasemonkey

Reply がついたエントリや、あるエントリへの Reply の本文部分をクリックで全部展開してツリーにします。

親と子は同時に展開を開始しますが、二度目以降の展開は一応 1sec ウェイトを入れてます。

複数 reply のとき順がくずれると思うんですがあんまりそういうケースないのでなんもやってないです (テストケースがみつからなかったし、そんなのわざわざつくるのもアレ)

  • 体感ロードスピードをあげた (全体では遅くなるけど)
  • はてなスターを適用するように
  • いろいろ変更した
  • 同じページに展開エントリがある場合はそれを移動して展開

HTTP リクエストが一部の展開で劇的に減るはずです (キーワードページでの展開はだいたいリクエストなしでいけるかな)

二個以上の返信ついてる場合とかはてスタが多重ロードされますがめんどくさいので気がむいたら対応します。

あとたまに Node cannot be inserted がでるかもしれませんが安定して再現するページがみつからないので放置してます。

スター適用するとき一時的にエントリ1つを唯一子にもつ親をつくることで重複しないようにしました

Expand リンクをつけるようにした。

2007年 12月 19日

Firefox 3.0 b2

いれた。常用プロファイル続行

Tree Style Tab と Stylish は install.rdf のバージョン書きかえでうごく

Haiku のキャンバスリサイザ (縦だけ)

このスクリプトを script appendChild するようなブックマークレットかけばブックマークレットにもなるとおもう。図みたいなの書きたいときはデフォのキャンバスだとかなしいのでかいてみた。(書きはじめてからのリサイズはできません)


Greasemonkey からページ内コンテキストでJS実行するときのイディオム (こうするとシンタックスハイライトきかしたまま自由な感じに書ける)

location.href = "javascript:"+encodeURIComponent(uneval(function () {
...
}))+"()";

縮小されるときは fotolife の設定確認

オフィシャルで対応されたのでもう必要ありません。

2007年 12月 20日

Haiku のはてスタのリンク先を Haiku のユーザページにする GM

やっつけ

// ==UserScript==
// @name        Jump to haiku user page on clicking star
// @namespace   http://lowreal.net/
// @include     http://h.hatena.ne.jp/*
// ==/UserScript==

location.href = "javascript:"+encodeURIComponent(uneval(function () {
	Hatena.Star.User.prototype.userPage = function () {
		return "/" + this.name + "/";
	};
}))+"()";

Greasemonkey / prototype かきかえ / Fx3

b2 + GM 1208 でもだめだなぁ。

GM_* 系のをつかっていないなら、

location.href = "javascript:"+encodeURIComponent(uneval(function () {
body
}))+"()";

でかこえば使えるけど、めんどくさい

gerry++

なんでだろ……

2007年 12月 21日

1981s

にいってきた。yusukebe さんと抱きあえたのでよかった。Dan さんに自己紹介したとき JSDeferred がでてきてちょっとかんどうした。id:amachang++

2007年 12月 22日

ハッピーエンド

自分は物語にハッピーエンドを望んでいるけれど、ハッピーエンドで終わる物語が好きじゃない。

2007年 12月 23日

XUL/XPCOM のファイルのよみかき。

なんかすげーめんどくさいなぁ。Java 並のめんどくささ。しかも Java ほどセオリーっぽい書きかたがない…… (仕様変更がどうとか……)

実はラッパがあったりしないのかなぁ……

かるく書いてみたけど、こういうのが欲しい。ぜったい既にあると思うんだけど検索しにくくてみつからない……

function File () { this.initialize.apply(this, arguments) }
File.prototype = {
	initialize : function (path) {
		if (typeof path == "string") {
			this.file = Components.classes["@mozilla.org/file/local;1"]
			                      .createInstance(Components.interfaces.nsILocalFile);
			this.file.initWithPath(path);
		} else {
			this.file = path;
		}
		this.charset = "UTF-8";
	},

	read : function (cb) {
		if (!cb) cb = function (i) {
			var ret = [];
			var str = {};
			while (i.readString(4096, str) != 0) {
				ret.push(str.value);
			}
			return ret.join("");
		};
		var fistream = Components.classes["@mozilla.org/network/file-input-stream;1"]
		                         .createInstance(Components.interfaces.nsIFileInputStream);
		var cistream = Components.classes["@mozilla.org/intl/converter-input-stream;1"]
		                         .createInstance(Components.interfaces.nsIConverterInputStream);
		fistream.init(this.file, 0x01, 0444, 0);
		cistream.init(fistream, this.charset, 1024, Components.interfaces.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
		var ret = cb.call(this, cistream, fistream);
		cistream.close();
		fistream.close();
		return ret;
	},
	write : function (cb) {
		if (typeof cb == "string") {
			var _str = cb;
			cb = function (i) {
				i.writeString(_str);
				return this;
			};
		}
		var fostream = Components.classes["@mozilla.org/network/file-output-stream;1"]
		                         .createInstance(Components.interfaces.nsIFileOutputStream);
		var costream = Components.classes["@mozilla.org/intl/converter-output-stream;1"]
		                         .createInstance(Components.interfaces.nsIConverterOutputStream);
		fostream.init(this.file, 0x02 | 0x08 | 0x20, 0664, 0); // write, create, truncate
		costream.init(fostream, this.charset, 4096, 0x0000);
		var ret = cb.call(this, costream, fostream);
		costream.close();
		fostream.close();
		return ret;
	}
};
File.TempFile = function (prefix, suffix) {
	var name = [prefix, Math.floor(Math.random() * 0xffffff).toString(16), suffix].join(".");
	var file = Components.classes["@mozilla.org/file/directory_service;1"]
	                     .getService(Components.interfaces.nsIProperties)
	                     .get("TmpD", Components.interfaces.nsIFile);
	file.append(name);
	file.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0664);

	Components.classes["@mozilla.org/uriloader/external-helper-app-service;1"]
	          .getService(Components.interfaces.nsPIExternalAppLauncher)
	          .deleteTemporaryFileOnExit(file);

	return new File(file);
}

var tf = File.TempFile("foobar", "txt");
alert(tf);
tf.write("foobar");
alert(tf.read());

Opera での with の挙動

var foo = { 
    bar : "bar"
};
(function () {
    with (foo) {
        alert("normal+"+bar);
        function baz () {
            alert("function def."+bar); // opera だと reference error
        }
        baz();

        (function () {
            alert("function exp."+bar); // <del>opera だと reference error</del>
        })();
    }
})();

Fx と Safari では大丈夫。これは Opera のバグっぽい? (Opera 9.24, 9.50 Beta 4591)

同じくスコープチェインをいじる try/catch は大丈夫だ。with だけか

(function () {
    try {
        throw "hello";
    } catch (foo) {
        alert(foo);
        (function () {
            alert(foo);
        })();
    }
})();

(Opera, Safari, Fx でちゃんとできる)

関数式のほうは勘違いでした。関数宣言のほうだけだめです……

Safari の XPath

./div/div のつもりで div/div って書くと INVALID っていわれる。ひどい……

textarea を好きなエディタで編集する userChrome.js

XPCOM あたりを触っていたのはこれを書くため……

コメント欄で教えてもらった IO オブジェクトを使うようにしたので Fx3 でしか動かないです。

It's All Text とか使ってたんですが、Fx3 に対応していないのと、なんかいろいろ挙動がいまいちだったので短く書きなおした感じです。

ちゃんと設定を読むようにしたよ。
http://coderepos.org/share/changeset/3529

最初に Ctrl-E したときにエディタを訊くよ。もしリセットしたかったら about:config をひらいて extensions.userchromejs.EditOnFavorite.editor を検索してリセットすればいいよ。

キーバインドも設定を読むようにしたいけど、ちょっとめんどうなのでまだ放置だよ

キーバインドも設定可能にしたよ。
http://coderepos.org/share/changeset/3531

extensions.userchromejs.EditOnFavorite.key に C-e とか C-; とか入れればそっちを使うはずだよ。

設定画面をつけたよ……

Tools -> userChrome.js -> EditOnFavorite で画面がひらくよ。OS X でしか確認してないけど prefwindow をつかっているからたぶん別の環境でも大丈夫だよ

2007年 12月 25日

拡張機能

必須拡張機能のうち、自分で書けそうなやつで userChrome.js にできそうなやつは自分で書いたほうがいいですね。バージョンアップで動かなくなったら自分で直せるし (拡張機能になってると直すのめんどい……)、ノウハウたまるし……

だんだんインストールしてる拡張が減っていきます。

コードのよみかた

last_char = s.charAt(s.length - 1)

何が解りにくいって、どの単語が変数でどの単語がプロパティでどの単語がメソッドで…という区別が付かない。

http://d.hatena.ne.jp/hama_shun/20071224/1198504421

区別がつかなくても読めはするはず? (むしろ、どれがプロパティで……どれがメソッドで……っていうのは定義とか考えるとめんどくさいよなぁ……)

このコードでまず重要なのは、s が何であるか、ということだけだから、そこから読めば疲れないんじゃないかなぁ。

  • last_char はこの行で代入されているので、この先を読むにあたっては、この行さえ理解できれば、この前でどんな使われかたをされていようが関係ないし、先を読むのに必要なだけなのでとりあえず無視できる。
  • charAt, length は、s のプロパティアクセスなのだから (ドット演算子があるから)、s が何かわかればそれのリファレンスを読めばなにかわかる。

このコードだけから推測すれば、charAt がある標準オブジェクトは String しかないので sString だと思われる (sString の s だとおもうし、last_char に代入してることからも、s は String だなぁというのが想像できる)


自分がこの行を読むときのプロセスは (かなり冗長にかくと)

  1. last_char に代入してるなぁ
  2. last_char って名前から右側でやってそうなことを想像
  3. → 最後の文字が代入されるはず?
  4. last_char という名前はいったん忘れる
  5. s.charAt(s.length - 1) を頭にいれる
    1. ドットでくぎる
    2. s ってなんだろ (前からさがす)
    3. (この場合は前に定義がないので) charAt をよんでるし s だから String か
    4. charAt は位置を引数にとって文字を返すメソッドか (String のリファレンスよむ)
    5. 引数が s.length - 1 か
      1. s.length は s の長さか (String のリファレンスよむ)
      2. 長さ - 1 だから最後の文字の位置か
    6. s.charAt(s.length - 1) は最後の文字を取得か
  6. last_char に代入か (もどってくる)
  7. 最後の文字を取得して last_char に代入か
  8. 「last_char は s の最後の文字」だけ覚えて次の行を読む……

脳内スタック多い人はもっと別の読みかたできそうだよあぁ……

userChrome.js で設定画面をつくる

XUL で UI つくりたいなぁってちょっと思ったんです。なんかいろいろやったんですがこうしたら一応できた。なんかもっと、スマートな方法がありそうだけど……

function openChromeWindow (xml, opts) {
	// create temporary content dir.
	var t = IO.getFile("Temp", "content" + Math.random() * 0xffff);
	t.createUnique(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0700);

	// write manifest
	var f = IO.getFile("PrefD", "extensions");
	f.append("{1280606b-2510-4fe0-97ef-9b5a22eafe64}"); // userchromejs
	f.append("chrome.manifest");
	var prev = read(f);
	write(f, "content userchromejs file://" + t.path + "/\n");

	// write chrome xul
	var c = t.clone();
	c.append("temp.xul");
	c.create(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0700);
	write(c, xml.toXMLString());

	// refresh chrome registry
	Components.classes["@mozilla.org/chrome/chrome-registry;1"]
	          .getService(Components.interfaces.nsIChromeRegistry)
	          .checkForNewChrome();

	// open
	window[opts.fun || "openDialog"]("chrome://userchromejs/content/temp.xul", opts.name || "temp", opts.opts || "chrome");

	// remove temp files and restore original
	t.remove(true);
	write(f, prev);

	// refresh chrome registry
	Components.classes["@mozilla.org/chrome/chrome-registry;1"]
	          .getService(Components.interfaces.nsIChromeRegistry)
	          .checkForNewChrome();


	function read (f) {
		var res = "", str, strm = IO.newInputStream(f, "text");
		while (str = strm.readString(4096)) res += str;
		strm.close();
		return res;
	}

	function write (f, str) {
		var strm  = IO.newOutputStream(f, "text");
		strm.writeString(str);
		strm.close();
	}
}

こんなふうにつかう

default xml namespace = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
openChromeWindow(
	<window>
		<script type="application/javascript">
			const prefs = Components.classes["@mozilla.org/preferences;1"]
			                        .getService(Components.interfaces.nsIPrefBranch);
			alert(prefs.getCharPref("browser.startup.homepage"));
		</script>
	</window>
);
  • 一つのウィンドウとして開きたい
  • chrome 特権を行使したい
    • chrome 特権を行使するには chrome: じゃないとだめらしい
    • chrome: は manifest かかないとだめらしい

nsIScriptableIO

nsIScriptableIO は XPCOM 直接使うよりは遙かにマシだけれど、なんかいまいちだよなぁ……さらにラッパを書きたくなるよ……


こう書きたい

var content = IO.openFile(f, "read text");
// 上と同じ
var content = IO.openFile(f, "read text", function (stream) {
    var res = [];
    while (str = strm.readString(4096)) res.push(str);
    return res.join("");
}); // 自動で close

IO.openFile(f, "write text", "content");
// or
IO.openFile(f, "write text", function (stream) {
    stream.writeString("content");
}); // 自動で close

なんであんなインターフェイスなんだろ……

E4X で processing-instruction をふくめて String に

E4X はデフォルトだと pi ノードを無視する。無視してほしくないときは

XML.ignoreProcessingInstructions = false;

する必要がある。でもって、これ true にしようが false にしようが

xml = <?xml-stylesheet href=""?>
      <window/>;

みたいなのは syntax エラーなので、こうする必要がある。

xml = <>
	<?xml-stylesheet href=""?>
	<window/>;
</>;
2007年 12月 26日

拡張機能

userChrome.js に対して拡張機能にまとめるメリットがいまいちわかってない……

  • 複数ファイル使ったりとかの場合はむしろ必須
  • 設定が Tools -> Add-ons からアクセスできる (という仕組みが用意されている)
  • Mozilla Add-ons に登録できる


デメリット

  • userChrome.js にくらべて作るのがめんどくさい
    • 一回 Rakefile 書けばすみそうだけど
  • 気軽に書きかえられない
    • 書きかえてすぐコミット、とかができない
      • インストールしたあとにチェックアウトディレクトリへ symlink しなおせばいいだろうけど、それもめんどくさい (これは自分はいいけど、他の人がコミットしずらくなる)
  • ↑とかぶるけど設定画面ちゃんと作らないと使えない


あと拡張機能の content とかを content.jar とかに圧縮してるけど、あれのメリットがよくわからない。書きかえにくくなって嫌だ……chrome.manifest も書きかえないといけないし……

Fx3b2 フルズームの座標ずれ

なんか小数点以下の扱いに問題ありそう (縮小時だけ)

ejs.js はやくなった

コンパイル時間はともかく、実行時間が replace による簡単な置換の2倍程度まではやくなった。

COUNT = 500;

var t = "aaaa<%=s.foo%>bbbbb<%=s.bar%>ccc";
var e = EJS(t);
var f = EJS(t, {useWith:true});
var m = {foo:"test", bar:"foobar"};
var b = [
	function compile () {
		EJS(t);
	},
	function processing () {
		e.run(m);
	},
	function processing_with_with () {
		f.run(m);
	},
	function replace () {
		t.replace(/<%=s\.(\w+)%>/, function (_,a) {
			return m[a];
		});
	}
];


for (var i = 0; i < b.length; i++) {
	var fun = b[i];
	print(fun.name);
	var res = 0;
	for (var j = 0; j < COUNT; j++) {
		var now = (new Date).getTime();
		fun();
		res += (new Date).getTime() - now;
	}
	print(res + "ms / " + (res/COUNT) + "ms");
};
Spidermonkey
compile
283ms / 0.566ms
processing
25ms / 0.05ms
processing_with_with
37ms / 0.074ms
replace
12ms / 0.024ms

Rhino
compile
5094ms / 10.188ms
processing
500ms / 1ms
processing_with_with
670ms / 1.34ms
replace
279ms / 0.558ms

ejs.js の高速化より Spidermonkey と Rhino の速度差のほうに驚いた

replace の正規表現に g がついてないから、実際は replace はもうすこし遅いですね

2007年 12月 27日

d2

おー、タイトルもその場編集できるー

「日記を書く」をクリックしたとき、タイトルの input 要素までスクロールしてほしい。

日記かいてない

ここ最近日記を書いていないということは、ここ最近何も考えていないということだと思う。考えようとするときは、文章にするし、文章にするときは、日記にする。日記をふりかえって、書いていないところがあるなら、そこは何も考えていないところだ。

なんだか、どうも、「浮き足立っている」感じがする。落ちつきがない。客観的じゃない。綺麗なことも考えてない。ぜんぜんだめだ。ぜんぜんだめだ、と書いて安心しちゃだめだ。

本当に嫌な人

からまれたら、どうするのがいいんだろう……実際のところ、ネットだから、リアルだから、という差はだんだんなくなっていくし (なぜならネットがリアルの延長にあるから)、誰もがネットを使いはじめると、だんだん、嫌な人、決定的に合わない人とも出会いやすく、からまれやすくなる。今のところ、mixi とか、そういう部分でしか目立たないけれど、増えていく。実際に、そういったところ以外でもいることはいる。(例えば nicovideo なんかでも感じることができる)

徹底的な無視、といっても、SPAM 行為と一緒で、どうしてもすりぬけてくるものがある。そういう人達を、確実にどうにかする方法は、今のところないように思える。からまれたら終わり。いじめと同じだ……

安全なところから、他人を凹ませて、外に出れなくして、喜ぶ人、というのが、一定数いる。なんらかのタイミングで、自分さえ、そうなるかもしれない。気付かないうちに、既になっているかもしれない。素晴しい人は死んでいく。未来を感じない。

一年

一年のまとめ、みたいなのをやろうと思っているけど、なんだか、結局やらないで終わりそうで、まずい。いろいろあったけど、不確定なことが多くて、どうしよもない。

jsm メモ

  • 謎な環境で eval される。
    • Component.classes とかはもちろんあるけど、IO はない。alert もない (めんどす)
  • Components.utils.import の第二引数を省略すると、現在の名前空間に import される (これどうやってるんだろ)
  • resource Protocol の setSubstitution に http: を指定して import しようとすると失敗する?
  • なんか instanceof がうまくいかない
    • 謎な環境なせいで prototype のオブジェクトが別になってる?

とりあえず File のユーティリティをちょこっと (名前空間とかまだちゃんと考えてないのでサンプル程度に) 書いてみた。なんかすぐ影響力のでかい人 (海外の) とかが別の作りそうで気がすすまない (無駄になる気がする)

Components.classes["@mozilla.org/network/io-service;1"]
          .getService(Components.interfaces.nsIIOService)
          .getProtocolHandler("resource")
          .QueryInterface(Components.interfaces.nsIResProtocolHandler)
          .setSubstitution("coderepos.org", IO.newURI("file:///Users/cho45/coderepos/platform/gecko/jsm/"));
          // .setSubstitution("coderepos.org", IO.newURI("http://svn.coderepos.org/share/platform/gecko/jsm/"));
Components.utils.import("resource://coderepos.org/file.jsm");

var file = IO.getFile("Temp", "test.txt")
File.write(file, "foobar");
alert(File.read(file)); //=> foobar

File.open("/tmp/hoge.txt", "write text", function (stream) {
    stream.writeString("foobarbaz");
});

これテストコードどうやって書けばいいんだ…… MozRepl ?

フォントサイズとか口調とか

啓蒙的な、主張が多い長文書いてる日記/ブログで、本文部分に font-size: 80% のスタイルがあたってると、そういうところになんで気を配らないんだろうと思うなぁ。

あと、何度も書いてるけど「~なんだが。」ってのは、ちゃんとした積み上げがない人が使うと本当にダサい……

どうでもいいけど↓の「jsm メモ」を、用語も何もしらない気持ちで読むとなんか笑ってしまう。

jsm 考えないといけないこと

  • どこにリソースほぞんするか
    • resource ディレクトリだと特権もってないユーザが起動したときこまる
    • profile のどっかなのかなぁやぱ
  • resource: でどこにわりあてるか
    • ドメイン (どこのドメイン?) + なんちゃら
  • すぐに使えるように、ダウンロードを自動でやるやつ (ないとめんどくさくて使えないよね……)
    • 安全じゃない
  • テスト方法
  • コンセプト
    • jslib みたいに完全なラッパにしない (nsIFile とか、nsIScriptableIO とかはできるかぎり活用する)
    • めんどくさいし、他の XPCOM のラッパを全部書かなくても十分つかえるから
  • とっかかりをどうするか
    • 管理する Add-on つくる ← 嫌 (ユーザにはどんなライブラリを使っているかなんて関係ないから)
    • 一関数にまとめてそれだけコピペ (どんぐらい短かくできる?)
2007年 12月 28日

可愛い女の子

可愛い女の子をいまいちイメージできなくなっている。リアルよりリアリティのあるのを想像したい。プログラミングは大事だけど、可愛い女の子をちゃんと想像できなくなるのはまずい。

ruby1.8.6

もうほんとどうしよもないところでハマったりするので Mac でも 1.8.6 を常用することにした……

sudo rm -rf /usr/lib/ruby/gems 
sudo port install ruby
exec zsh (パスとおしなおし)
wget http://rubyforge.org/frs/download.php/29548/rubygems-1.0.1.tgz
tar xzvf rubygems-1.0.1.tgz
cd rubygems-1.0.1
sudo ruby setup.rb
sudo gem install resh

BridgeSupport の WebKit のところでおわた……

/opt/local/bin/ruby install.rb config --build-universal=yes
(in /Users/cho45/project/rubycocoa/src)
install.rb: entering config phase...
create ext/rubycocoa/extconf.rb
create framework/GeneratedConfig.xcconfig
create framework/src/objc/Version.h
create tests/Makefile
---> framework
create /Users/cho45/project/rubycocoa/src/framework/src/objc/osx_ruby.h ...
create /Users/cho45/project/rubycocoa/src/framework/src/objc/osx_intern.h ...
BSROOT="/Users/cho45/project/rubycocoa/src/framework/bridge-support" CFLAGS="-arch ppc -arch i386 -isysroot /Developer/SDKs/MacOSX10.4u.sdk" /opt/local/bin/ruby build.rb
Generating BridgeSupport metadata for: WebKit ...
./gen_bridge_metadata.rb:1800:in `compile_and_execute_code': Can't compile C code... aborting (RuntimeError)
command was: gcc  /tmp/src-0-28704.m -o /tmp/bin-0-28704 -F"/System/Library/Frameworks" -framework WebKit -framework Foundation  -include /tmp/src-0-28704.h  2>/tmp/log-0-28704

/usr/bin/ld: /System/Library/Frameworks/WebKit.framework/WebKit load command 20 unknown cmd field
collect2: ld returned 1 exit status
	from ./gen_bridge_metadata.rb:1051:in `collect_types_encoding'
	from ./gen_bridge_metadata.rb:521:in `collect'
	from build.rb:101
	from build.rb:50:in `measure'
	from build.rb:101
	from build.rb:62:in `each'
	from build.rb:62
config failed
hook /Users/cho45/project/rubycocoa/src/framework/post-config.rb failed:
'system BSROOT="/Users/cho45/project/rubycocoa/src/framework/bridge-support" CFLAGS="-arch ppc -arch i386 -isysroot /Developer/SDKs/MacOSX10.4u.sdk" /opt/local/bin/ruby build.rb' failed
try 'ruby install.rb --help' for usage
rake aborted!
Command failed with status (1): [/opt/local/bin/ruby install.rb config --bu...]
/Users/cho45/project/rubycocoa/src/rakefile:26
(See full trace by running task with --trace)

misc/bridgesupport/build.rb で WebKit はずして継続してるけど、Chemr がビルドできなくなりそうだなぁ……どうしたらいいんだろ……Leopard じゃないとだめなのかなぁ……

2007年 12月 29日

canvas

AS3 と自分との相性がことごとく悪いので canvas でかるくおえかきツールみたいなのをつくってみたけど、うまく実装できないなぁ。undo したいから、直近の数パスは保存しておかないといけない。canvas は直接書いてしまうから (オブジェクトをおいていくわけじゃない)、自分で再描画をコントロールしないといけない。でもって、書きはじめてから生成されたパスを、mousemove ごとに毎回全部再描画すると、割とすぐに重くなって使えない。

toDataURL つかってスナップショットをとりながら描画するようにしてみたけど、なんかこのへんでつかれた。ボタンとか作るのめんどいし、あまりにもクロスブラウザじゃないすぎる……

わりとどうでもいいけど toDataURL って名前おかしくないのかな。Locater じゃないと思う。

なんか toDataURL のよびだしが二回目以降 Security Error になる……

JS: コンテナとしての Object のキーの列挙

常にこう書くことにした。

for (var k in obj) if (obj.hasOwnProperty(k)) {
    alert(obj[k]);
}

今までは

for (var k in obj) {
    if (!obj.hasOwnProperty(k)) continue;
    alert(obj[k]);
}

とか書いてたけど、! を書くのを忘れて、いったりきたりしてしまうのでめんどかった。

ちなみに

for (var k in obj) {
    if (obj.hasOwnProperty(k)) {
        alert(obj[k]);
    }
}

はインデントが増えるから嫌だ。

hasOwnProperty は長いけど、慣れれば (主に autocomplpop.vim のおかげで) 気にならない。

Good Dog Happy Men のあれ

新宿のときのやつをかばんからだした (いまさら)
Good Dog Happy Men - the GOLDENBELLCITY, mini-live at Shibuya Tower Record

2007年 12月 30日

写真

ひさしぶりに近所を散歩して写真を撮ってみたけれど、ろくな写真がとれない……

ヘッドフォンにみえるサムネイル

がヘッドフォンに見えるって id:mayuki さんに言われたので、ぼーっと眺めてみたら見えてきた。おもしろいなぁ

花は撮ってから現像するまで、一定のイメージがたもてる気がする。でも花の写真は工夫しないと、ほんとうにただの写真だよなぁ……

シクラメン

自分は白くて派手じゃないシクラメンがベロニカペルシャの次ぐらいに大好きなので、もっと撮りまくりたい。うつむいて、静かにしてる感じがすごくいい。でもって、よくみると艶容なのもすごくいい。シクラメン、っていう名前もいい。「つめたくてかわいくてきれい」だと思う。

無口

無口な女の子はそんなに好きではないけど、嫌いでもないなぁと考えながらコンビニの帰り道を歩いていたら、なんとなく、三人以上でいると良く喋るのだけれど、二人になると喋らなくなる女の子、というのが少しグっとくることに気付いた。

言語

ロシア語のフィードバック的なものがあったのだけれど、全く読めなくて、最初それがロシア語かどうかもわからなくて、訊いたりして (ありがとうございます)、Google の機械翻訳で英語へ変換 (日本語への翻訳はできない) してみたときの、なんとも言えない感覚、あぁ読めた……っていう感覚が、なんとなく面白い。

日本語の文章を、英語圏の人が読もうとしたら、自分がその最初に感じた、読めない絶望感や、歯痒さ、途方もない感じが、やはりあるんだろうなぁと思った。そういう意味で、英語だと、いくら読めないといっても、調べる手段 (その文字をうちこめる) があり、読もうと思えばどうにか読める、というのは、大切なんだなぁと感じた。

userscripts.org 更新するのめんどくさい

ふと

userscripts.org をコマンドラインから更新するためのツール user.js みたいなのをつくるとしたら、はたして JS on Rhino と rubygems だとどっちのほうがいいんだろう、とおもった。(gem のほうがいいとおもう)


そういえば、Opera は公式みたいなところに user.js 配布するところあるのかな

2007年 12月 31日

一年のまとめ

箸の使いかたが少し上手になりました。

s

過去の日記読みかえしていたら、すこし、撮りたい写真を思いだしてきた。最近かわいい女の子について想像していないのと、同じような原因で忘れてしまっているようだ。なにかと、学校いかなくなってから、幸せだからなぁ……

なんで、おれは、センスがないんだろう…… 人生、なにもかもをやりなおすか、むしろ、別の、美しくて、なにもないようなところへ、いきたい……

自分は、悪意のあるものを徹底的に排除したいので、そういうのが、継続的に続くようなものは、自動で無視できるようにしようとしてる。そういう、本来、独りでつぶやき、独りで解決するような、悪意のあるつっこみ、茶々、みたいなのは、とにかく消してしまってかまわないと思う (消してしまう、というのはクライアントサイドの話で)。批判ではないネガティブなものは、本当に、意味がない。

「簡単にコメント」できる、みたいなのは、必ずしも良いことではない。簡単なフィードバックは、必ずしも良いことではない。ただし、機械的にある程度フィルタリングできるならば、できるだけ簡単にフィードバックができてもいい。いらないものは、機械によって読まれ、捨てることができる。でも、批判を気取った中傷みたいなのは、機械での判定が難しくて、嫌だ。

ART-SCHOOL - ステートオブグレース

これ、めっちゃいいよなぁ……なんでいいんだろう。すこし混沌とした感じがするけど、そうでもない。

批判と悪意

批判は、読んだあとに、考えることが、たくさんある。反論であったり、納得であったり、いずれにしても、対象をよく考えなおすことができる。でも悪意はそうじゃない。単に、嫌な気持ちになるだけだ。

LOST IN THE AIR

なんかリミックスがどっかにあったような……って思って探してしまった……
Paradise Lost のボーナス CD だった…… (Tony Doogan mix) こっちのほうがすきかなぁ。遠くから響いてくる、遠近感が、おもしろい。

グラスゴー

別に行きたいわけじゃないけど「グラスゴー」って語感がすごく好きだ。

フェアであること

技術力というより、評価がすごくフェアであることに尊敬する……メインの言語が違うから、直接何がすごいか、っていうのを実感できていないけど (頭ではわかる、みたいな感じ)、そういう部分が、本当に実感して、すごいと思う。

初音ミク 廻り出すセカイ

http://www.nicovideo.jp/watch/sm1878349 (gomez)

これすごい好きだなぁ。すこし凛とした感じ、冬の朝とか、冬の学校の放課後の屋上みたいなイメージ。じわじわ

ID3 にアーティスト名が入ってなくて迷ったけど作曲者の名前を入れるようにした。(同名の海外アーティストがいるみたいけど)

ポップな Sigur Rós って感じ (それ Sigur Rós じゃない)

高音のミクの声って Sigur Rós のボーカルにちょっと似てると思う。似てねぇよって言われそうだけど w

はぁ……まじいい曲だ

修正前のバージョンもめっちゃすき

2007年 12月 30日

埋め込み Rakefile

rake が、あるファイルの、うめこまれた Rakefile を解釈する、みたいな機能をもってると便利だよなぁ

rake -f foo.user.js publish

とかできるようになるとうれしい。


と、まで書いたところで、Rakefile ってただの ruby スクリプトだから工夫したらできるよなと思ってやってみた。

ようは user.js でもあり ruby でもあるコードをかけばいい

// ; <<EOF # Embed Rakefile
// ==UserScript==
// @name        Vox Editing with WYSIWYG or HTML alternately
// @namespace   http://lowreal.net/
// @include     http://www.vox.com/compose*
// ==/UserScript==

ここに JS コード

/*
EOF
# ↑ ここまでヒアドキュメント

# ここに Ruby コード。
# ただし */ は書けないので正規表現リテラルかくときは注意しないといけない

desc "upload to userscripts.org"
task :release do
    foo...bar....
end

# ↓ JS のコメントアウトをとじる
# */

Ruby では // はコメントではなく正規表現リテラル。ヒアドキュメントで JS コードをスキップさせてる。

もちろん、このままだと DRY じゃなくてダサいので、rubygems とかに userscripts.org を操作するライブラリをあげて (rubyforge みたいな)、それを使うようにたらよさそう。(require "userjs/raketasks" みたいな)

でもこれ壮絶にキモいからやめたほうがいい…… (正気にもどった)

Rakefile にする必要も別にない。なにがやりたかったんだろう……

2007年 12月 31日

はてなキーワード

http://d.hatena.ne.jp/keyword/Sigur%20R%8f%ab%d1s にキーワード記法でリンクはれないね。(数値参照になってしまうから)

あと、その場記法だとキーワードリンクが生成されない気がするんだけど大丈夫なのかな。

2007年 12月 30日

XHR/GM_xhr でバイナリ (\0 をふくむ) はできない……

\0 があるとそこでとめられてしまう……

無駄になったコードこぺ

	function multipart(data) {
		var ret = [], boundary = createBoundary();
		for (var k in data) if (data.hasOwnProperty(k)) {
			var list = data[k];
			for (var i = 0; i < list.length; i++) {
				var obj = list[i];
				if (obj.filename) {
					ret.push(
						'--' + boundary,
						'Content-Disposition: file; name="'+k+'"; filename="'+obj.filename+'"',
						'Content-Type: '+obj.contentType,
						'',
						obj.content
					);
				} else {
					obj = String(obj);
					ret.push(
						'--' + boundary,
						'Content-Disposition: form-data; name="'+k+'"',
						'',
						obj
					);
				}
			}
		}
		ret.push('--' + boundary + '--', '');
		return {
			contentType : "multipart/form-data; boundary=" + boundary,
			data: ret.join("\r\n")
		};

		function createBoundary () {
			return "B"+Math.floor(0x1000000 + Math.random() * 0xffffff).toString(16);
		}
	}
2007年 12月 31日

みぎくりく

なんか右クリックすると Open Selection Links in Tabs が暴発することがかなりある…… たぶん右クリックメニューの挙動が変なんだろうけど、セレクションがないのにセレクションがあると勘違いするバグとの相乗効果でかなり困る。何がわるいんだろ……