ただ生きることよりルール
じわじわくる!!
じわじわくる!!
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 要素を書くまではかなり必死に集中する (誰かが教えてもらうまえに「わかった!」と書きたい)。もちろん結局わからないこともあるけど、日記に書こうとすることで、回転の悪い頭を最大限回すことができる。ついでに「何がわからないか」を文章にすることで明確にできて、書きているうちに普通に解決してしまう場合もある。だから、「わからない」と書いたはいいけど、日記として残らず消えていった文章もある。
生姜の匂いを「冬を感じる優しいかおり」と表現しているのを見てなんかぐっときた。
3部作の完結のフルアルバムがでた。数日聴きこんでみたけど、「Groria Street から愛を込めて#3 」(原文ママ) が素晴らしい。「ただ生きるよりルール」
「Apple star storyS」 はヘッドフォンで聴くと面白い。ライブ音源もいいけどこれも好き。Most beautiful in the world にはASの歌詞がついてなくて、聴きとってテキストにしといたのだけど、何いってのかよくわかんなくてなんとなくで書いたりしたところがあった。でも答えあわせをしたら割とあってた (鍵カッコつけた部分まであってて笑った)。(「星空」を「この空」とまちがえてた (シャウトしててききとれない)。「たまにわからなくなるけど」を「たまにわからなくなるねと」とまちがえてた (なんで間違えたのかわからないけどw))
「そして列車は行く」はなんか長い部分を見ていろいろカッコいい。うまくいえない。曲としてめっちゃカッコいいのもそうだし、「今 拍手喝采とか涙よりもっと」とか、いちいちかっこいい。
「記憶と記録」は四人のゴブリン大いに踊るに収録されていた「微笑とメロディー」のリアレンジなんだけど、このアレンジがなんか想像の斜め上をいきまくってておもしろい。
でもって「黄金の鐘」なんだけど、最初の歌詞から大分歌詞が変わってて残念なところがあったりするけど、聴いてるとどうでもよくなってきた。これはたぶん聴きこむともっとじわじわきそうだなぁ。
ツインドラムがかっこいいからライブでききたいなぁ……
(動いてはいるけど、ちょっと挙動が思ったとおりでない気がする (巨大なループのあと、次のプロセスへ進むのが遅い気がする) のでコードを考えなおしのために現在の実装をメモ書きします) なんか 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 自身で書かれているから、あきらかにおかしいときはテストの数があっているかどうかをみる)
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 スクリプトにコピペして使えるぐらいの長さのコードでこういうことができることだと思います。
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) になってしまうのでだめ。
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;
}
名前がやっぱよくないよなぁ。General Deferred とかにすればいいのかなぁ (jQuery 部分は分離して Rakefile で一括生成)。
JSDeferred にしよう。作業かいし
http://svn.coderepos.org/share/lang/javascript/jsdeferred/trunk/
mini (簡易圧縮バージョン) と nodoc (コメント全削除) もコミットするようにした。rake すれば生成される。mini と nodoc は見た目の差の割にサイズがそんなに変わらない (タブインデントだし) ので nodoc だけでもいい気もする。
なんか、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 "$@"
おれは、どうも、中身より、API のデザインのほうが気になるみたいだ。中身はもちろん、すごくおもしろいけど、中身がどうよくても、API がよくなければ使えない。そのうえで、中身、と、それと API をふくめた哲学が一体となって、美しいライブラリ/フレームワークになるんだなぁ。
これは別に比喩でもなんでもなくて、他のことに言いかえると意味が剥れてしまうようだ。中身より外見のほうが気になるってのはちがうし
そして、頭がわるいこともあって、できるだけシンプルなデータ構造と、できるだけシンプルな動作がすきだ。だから、そのために多少の高速性が犠牲になっても、べつにいいと思ってる。そうもいかないこともかなり多いけど、やっぱりそういうところをいじろうとすると、戸惑う。むずかしい。高速性より、理解のしやすさ、読みやすさ、がおれのなかでは、かなり優先順位が高い。綺麗なソースがすきだ。どうしてもそうだ。
もっとあたまがよければ、もっとよくいきれたのになぁ……
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 はソースコードにまぜて書くけど、見通しが悪くなるんだよなぁ。でも最低限の使いかたはコメントとして近くに書いておきたいし、挙動を変更したらすぐ書きかえたいから、近くにあるのは便利だ。
あとドキュメントに実装を簡単に見れるしくみが絶対必要だと思う。長い英語よむぐらいならソース見たほうが理解できるし、ソース見てからドキュメント読むとよめるようになるし……
正直にいうとごくごく最近まで 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 だと非同期なメソッドがあんまりないから気にならないのかなぁ。
なんでこんなふうに書いてるの? って感があるのかもしれないから、いちおうかいとくよ!
(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 () {
}
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 すればもどせる。
Mac 10.4.11 Mem 2G
javascript:n=0;(function(){n++;arguments.callee();})();
javascript:alert(n);
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 ってのはどうなんだ
なんか想像以上によかった。ちょっとおかしいぐらい好きなことに打ち込んでる感がやっぱすばらしい。分野の違い、みたいな、うまくいえないけど、そういうのを感じた。なんとなく梅田もちおを想起した。
なんか3月1日で終了らしいじゃないですか……光のはやさで wikipedia が更新されてて感動したけどそれはべつにどうでもいい。なんか、ざんねんだなぁほんとうに
GHOST PICTURES をそういえば買ってない。買うか
こう、アニソンきいてテンションあげる気分になれない
http://f.hatena.ne.jp/cho45/20071209233148
ひきこもりすぎる。Top10 中半分以上がニコニコ関係だけど、Top2 (GDHM/バーガー) だけで一日11時間きいてることになってる。
実のところ新宿タワレコのミニライブ程度でさえ、行くのを直前まで迷ってた。ああいう近くで聴いたりするのはすごく楽しいんだけど、それと同時に、周りにいる人たちが嫌で嫌でしかたない。電車でも、普通に歩いていても、周りに人がいるのがたまらく嫌なことが多い。なぜなら、そういう、周りの人達の中に、すごく嫌な表現をする人がそこそこいて、すごく嫌な生きかたをしている人がそこそこいて、自分と、決定的に合わない人がかなり多くいることを感じるからで、そういうのは本当に、どうしよもない。物理的に近くにいれば、話声が聞こえてきてしまうし、視界に入ったりするしで、フィルタリングするにしても、一つの感覚だけが刺激されるわけじゃないから、難しい。
すごく嫌な人、自分にとっての嫌な人っていうのは、別に存在したっていいけれど (それは本当にどうしようもない)、絶対に、関わりたくないし、近くにいたくもない。外にでたらでたで、そこそこ気にしないでどうにかやれることが多いけど、ふとした拍子に思い出したりするし、そんなときはなすすべがないから、できるだけ外に出たくない。
>
ニコニコ動画とかにも、そういう嫌な空気を感じることがかなりあって、特に、ネタ系じゃない動画 (演奏してみたとか) はもうコメントを表示させて見ることなんてあんまりない。(Comment Heat Map for nicovideo のデータソースとしてだけ受信してる感じ) NG リストも常時最大ぎりぎりまで入れてる。
すごい嫌な表現をする人たち、例えば、自分を評価される場におかないで中傷だけする人達 (しかも自分ではそれが批評だと思っている) とかは、本当に、関わりたくない。むかつくと同時に、そういう人の多さ、居場所のなさを感じて、いろいろどうでもよくなってくる。どっちにしろ、自分がそういうことをしないようにしないといけない……
-->
http://www.flickr.com/photos/joi/2093076116/
こういう配色っていいよなぁ……変に気取っていなくて……
あといまさらだけど Last.fm の audioscrobbler とあわせたロゴはすきだ
別に、一日中コンピュータとむきあっているからといって、いつも同じことをしているわけではないのは、よほど古い人でなければすぐ想像可能で、あたりまえに感じることだと思う。プログラミングしていたり、写真現像していたり、ニコニコ動画見ていたり……
そんなのと同じように、プログラミングをするって一言で云っても、あっちいったりこっちいったりで、いつも同じようなことをしているわけじゃないのはごくごく簡単に想像できることだと思うんだけど、そうじゃない人もいるんだなぁと思った。
ActionScript とか JavaScript のプログラミングと C や D のプログラミングは全然違うし、JS に限定しても、ブラウザにすごく近い部分のプラグラミングと、言語を拡張するようなプログラミングとでは違うし、いくらでも細分化していくことができる (掘りさげて、あっちこっちいったりできる) 。もちろんこんなのプログラミングに限ったことじゃなく、写真だって被写体や画角の違い、撮影スタンスの違いでいくらでも広げることができるし、たぶん他の分野でも一緒だ (一見そうは思えないことだって多くて、たんにそれは自分がその分野について知らなすぎるだけなんだと思う)
>
むしろ今は、おれが行きたい。
2ch とか、ニコニコ動画とか、そういう人がいっぱい集るところは、ほんとうに、クズの最低な発言ばかり目立って、真面目なものほど全く面白くない。ただのネタスレにだけ存在価値がある。(どんどん、真面目なもの、本気なものはああいうところから消えていく。クズが集るまえのときにしか、そういうのは有効じゃない)
Good Dog Happy Men のスレは本当にクソだらけで微塵も面白くないと、久しぶりに読んで思った。ああいう、最低の表現をするやつらと、ライブなんかで同じ空間にいるとかは、腹立たしくてならない。「キモいやつらがいっぱいいた」とか、お前は何しにいっているんだという感じだ。そんなことを平然と、匿名でありつつも、キーボードでうちこみ、ポストする、という感覚や、その自分への自信、みたなのは、かえって羨しい。
というのをどっかに婉曲して書こうと思ったけど、一番いいたいことはうまく書けず、自分がそういうことを全くしていないかというとそうは絶対言いきれず、なんやかんや全部嫌になる。
-->
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 にいろいろ書いてあった。
そういえば、あらかじめデータは取得しておきたいけど、表示自体は遅延したい、みたいな場合 (ホバーツールチップみたいなやつ) にもめっさつかえるなぁねむい。
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) してからロードしにいくみたいにするより、これだと同時によみこむから待ち時間がへる (その変わりリクエストが必ずとんでサーバに負荷かかる)
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 とか) ってほぼ必須だよなぁと思った……ないと書けない。
ためしてみるとすぐわかる違い。前提として、JavaScript では「全てオブジェクトというわけではない」ことを覚えておく必要があります (Ruby との違い)。
uneval("foo");
//=> "\"foo\""
"foo".toSource();
//=> "(new String(\"foo\"))"なぜこのような違いが生まれるか、というと 11.2.1 プロパティアクセス演算子 (Property Accessors) にある
生成規則 MemberExpression : MemberExpression [ Expression ] は次のように評価される:
- MemberExpression を評価。
- GetValue(Result(1)) を呼出す。
- Expression を評価。
- GetValue(Result(3)) を呼出す。
- ToObject(Result(2)) を呼出す。
- ToString(Result(4)) を呼出す。
- 基準オブジェクトが 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 には6個の型があります (処理系内部的/説明的には9個)。
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 の背中が物語っています。
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 がはやくなったように感じるプラセボ
それにしてもツリーが思ったより便利><
>
人数が多いとそれだけ、嫌な人と遭遇しやすくなるんだから、ブログも日記も書いていない人がいっぱいいるところに、コミュニケーションを目的として行こうとなんて思えるはずがない……
id:cho45に嫌な人とマークされてるんじゃないかと思うと夜も眠れません><
ちょw そんなわけない>< むしろ毎日会いたいw
殆ど知らない人いっぱいとあうのは絶対嫌だなぁというのを twitter の大規模なオフをやったという話を眺めながら思ったのでした……
事前に「あーこのひとはこういうひとかー」っていうのがわかってないとこわすぎる (知っていれば近づき/避けやすい)。そういうのは継続的な日記/ブログ (をどっちのスタンスで書いているか、とかも) がないとわからない……
要約すると、「ちんこちんこ言っても大丈夫なのかよくわからないのでめんどうくさい」
たいして使ってないのに再インストール…… Windows Update でエラーでて (なんか証明書関係のエラーで、対策もひとおりしてみたんだけどだめだった。)
http://subtech.g.hatena.ne.jp/cho45/20070927/1190891651
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
fotolife は容量制限が厳しくて、落書きを大量に投稿する、というときちょっと不安 (制限に逹っしたとき、消さないといけないなぁという不安) があるので、tumblr を使うようにする userscript を書きました。(月別の容量制限とかならいいんだけどなぁ)
(イラスト投稿を確実にする GM より前に実行する必要があります)
といっても、tumblr はいまいち安定感 (いろんないみで) がないように思えるのでなんともいえない……
URL をうけとって保存してくれるサービス/そういうAPIがあるサービスなら簡単に対応できるんですが、そういうのあんまないっすね……
postDrawing がよばれないことが多々ある、そういうときはブックマークレットでよぶ
javascript:Hatena.Haiku.EntryForm.postDrawing("fotolife の該当画像の URL");
書きはじめてから一定時間おきに fotolife の feed を監視して投稿する、みたいなのをつくろうとおもったけど、二重投稿とか考えるのがめんどくてやめた……
なぜかわからないけど 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 以外への書きかえはもちろんうごく……
postDrawing がたびたびよびだしされないので、fotolife を GM_xhr で監視して投稿するようにするスクリプトです。
流れは
tumblr に投稿しなおすスクリプトより後に実行する必要があります。
なかなか投稿できないなぁってときは API がエラーだしていたりするので http://f.hatena.ne.jp/rkatom/feed にアクセスして確認してみるとよいかもです
(他のスクリプトより先に読みこむ必要あり)
オリジナルの 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: によるロードとかいろいろためしたけどうまくかなくて、結局こうしてみたらうまくいった……
Reply がついたエントリや、あるエントリへの Reply の本文部分をクリックで全部展開してツリーにします。
親と子は同時に展開を開始しますが、二度目以降の展開は一応 1sec ウェイトを入れてます。
複数 reply のとき順がくずれると思うんですがあんまりそういうケースないのでなんもやってないです (テストケースがみつからなかったし、そんなのわざわざつくるのもアレ)
HTTP リクエストが一部の展開で劇的に減るはずです (キーワードページでの展開はだいたいリクエストなしでいけるかな)
二個以上の返信ついてる場合とかはてスタが多重ロードされますがめんどくさいので気がむいたら対応します。
あとたまに Node cannot be inserted がでるかもしれませんが安定して再現するページがみつからないので放置してます。
スター適用するとき一時的にエントリ1つを唯一子にもつ親をつくることで重複しないようにしました
Expand リンクをつけるようにした。
いれた。常用プロファイル続行
Tree Style Tab と Stylish は install.rdf のバージョン書きかえでうごく
このスクリプトを script appendChild するようなブックマークレットかけばブックマークレットにもなるとおもう。図みたいなの書きたいときはデフォのキャンバスだとかなしいのでかいてみた。(書きはじめてからのリサイズはできません)
Greasemonkey からページ内コンテキストでJS実行するときのイディオム (こうするとシンタックスハイライトきかしたまま自由な感じに書ける)
location.href = "javascript:"+encodeURIComponent(uneval(function () {
...
}))+"()";
縮小されるときは fotolife の設定確認
オフィシャルで対応されたのでもう必要ありません。
やっつけ
// ==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 + "/";
};
}))+"()";
b2 + GM 1208 でもだめだなぁ。
GM_* 系のをつかっていないなら、
location.href = "javascript:"+encodeURIComponent(uneval(function () {
body
}))+"()";でかこえば使えるけど、めんどくさい
なんでだろ……
にいってきた。yusukebe さんと抱きあえたのでよかった。Dan さんに自己紹介したとき JSDeferred がでてきてちょっとかんどうした。id:amachang++
自分は物語にハッピーエンドを望んでいるけれど、ハッピーエンドで終わる物語が好きじゃない。
なんかすげーめんどくさいなぁ。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());
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 でちゃんとできる)
関数式のほうは勘違いでした。関数宣言のほうだけだめです……
./div/div のつもりで div/div って書くと INVALID っていわれる。ひどい……
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 をつかっているからたぶん別の環境でも大丈夫だよ
必須拡張機能のうち、自分で書けそうなやつで userChrome.js にできそうなやつは自分で書いたほうがいいですね。バージョンアップで動かなくなったら自分で直せるし (拡張機能になってると直すのめんどい……)、ノウハウたまるし……
だんだんインストールしてる拡張が減っていきます。
last_char = s.charAt(s.length - 1)何が解りにくいって、どの単語が変数でどの単語がプロパティでどの単語がメソッドで…という区別が付かない。
区別がつかなくても読めはするはず? (むしろ、どれがプロパティで……どれがメソッドで……っていうのは定義とか考えるとめんどくさいよなぁ……)
このコードでまず重要なのは、s が何であるか、ということだけだから、そこから読めば疲れないんじゃないかなぁ。
last_char はこの行で代入されているので、この先を読むにあたっては、この行さえ理解できれば、この前でどんな使われかたをされていようが関係ないし、先を読むのに必要なだけなのでとりあえず無視できる。charAt, length は、s のプロパティアクセスなのだから (ドット演算子があるから)、s が何かわかればそれのリファレンスを読めばなにかわかる。このコードだけから推測すれば、charAt がある標準オブジェクトは String しかないので s は String だと思われる (s は String の s だとおもうし、last_char に代入してることからも、s は String だなぁというのが想像できる)
自分がこの行を読むときのプロセスは (かなり冗長にかくと)
脳内スタック多い人はもっと別の読みかたできそうだよあぁ……
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>
);
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 はデフォルトだと pi ノードを無視する。無視してほしくないときは
XML.ignoreProcessingInstructions = false;
する必要がある。でもって、これ true にしようが false にしようが
xml = <?xml-stylesheet href=""?>
<window/>;みたいなのは syntax エラーなので、こうする必要がある。
xml = <> <?xml-stylesheet href=""?> <window/>; </>;
userChrome.js に対して拡張機能にまとめるメリットがいまいちわかってない……
デメリット
あと拡張機能の content とかを content.jar とかに圧縮してるけど、あれのメリットがよくわからない。書きかえにくくなって嫌だ……chrome.manifest も書きかえないといけないし……
なんか小数点以下の扱いに問題ありそう (縮小時だけ)
コンパイル時間はともかく、実行時間が 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 はもうすこし遅いですね
おー、タイトルもその場編集できるー
「日記を書く」をクリックしたとき、タイトルの input 要素までスクロールしてほしい。
ここ最近日記を書いていないということは、ここ最近何も考えていないということだと思う。考えようとするときは、文章にするし、文章にするときは、日記にする。日記をふりかえって、書いていないところがあるなら、そこは何も考えていないところだ。
なんだか、どうも、「浮き足立っている」感じがする。落ちつきがない。客観的じゃない。綺麗なことも考えてない。ぜんぜんだめだ。ぜんぜんだめだ、と書いて安心しちゃだめだ。
からまれたら、どうするのがいいんだろう……実際のところ、ネットだから、リアルだから、という差はだんだんなくなっていくし (なぜならネットがリアルの延長にあるから)、誰もがネットを使いはじめると、だんだん、嫌な人、決定的に合わない人とも出会いやすく、からまれやすくなる。今のところ、mixi とか、そういう部分でしか目立たないけれど、増えていく。実際に、そういったところ以外でもいることはいる。(例えば nicovideo なんかでも感じることができる)
徹底的な無視、といっても、SPAM 行為と一緒で、どうしてもすりぬけてくるものがある。そういう人達を、確実にどうにかする方法は、今のところないように思える。からまれたら終わり。いじめと同じだ……
安全なところから、他人を凹ませて、外に出れなくして、喜ぶ人、というのが、一定数いる。なんらかのタイミングで、自分さえ、そうなるかもしれない。気付かないうちに、既になっているかもしれない。素晴しい人は死んでいく。未来を感じない。
一年のまとめ、みたいなのをやろうと思っているけど、なんだか、結局やらないで終わりそうで、まずい。いろいろあったけど、不確定なことが多くて、どうしよもない。
とりあえず 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 メモ」を、用語も何もしらない気持ちで読むとなんか笑ってしまう。
可愛い女の子をいまいちイメージできなくなっている。リアルよりリアリティのあるのを想像したい。プログラミングは大事だけど、可愛い女の子をちゃんと想像できなくなるのはまずい。
もうほんとどうしよもないところでハマったりするので 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
/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 じゃないとだめなのかなぁ……
AS3 と自分との相性がことごとく悪いので canvas でかるくおえかきツールみたいなのをつくってみたけど、うまく実装できないなぁ。undo したいから、直近の数パスは保存しておかないといけない。canvas は直接書いてしまうから (オブジェクトをおいていくわけじゃない)、自分で再描画をコントロールしないといけない。でもって、書きはじめてから生成されたパスを、mousemove ごとに毎回全部再描画すると、割とすぐに重くなって使えない。
toDataURL つかってスナップショットをとりながら描画するようにしてみたけど、なんかこのへんでつかれた。ボタンとか作るのめんどいし、あまりにもクロスブラウザじゃないすぎる……
わりとどうでもいいけど toDataURL って名前おかしくないのかな。Locater じゃないと思う。
なんか toDataURL のよびだしが二回目以降 Security Error になる……
常にこう書くことにした。
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 のおかげで) 気にならない。
ひさしぶりに近所を散歩して写真を撮ってみたけれど、ろくな写真がとれない……
自分は白くて派手じゃないシクラメンがベロニカペルシャの次ぐらいに大好きなので、もっと撮りまくりたい。うつむいて、静かにしてる感じがすごくいい。でもって、よくみると艶容なのもすごくいい。シクラメン、っていう名前もいい。「つめたくてかわいくてきれい」だと思う。
無口な女の子はそんなに好きではないけど、嫌いでもないなぁと考えながらコンビニの帰り道を歩いていたら、なんとなく、三人以上でいると良く喋るのだけれど、二人になると喋らなくなる女の子、というのが少しグっとくることに気付いた。
ロシア語のフィードバック的なものがあったのだけれど、全く読めなくて、最初それがロシア語かどうかもわからなくて、訊いたりして (ありがとうございます)、Google の機械翻訳で英語へ変換 (日本語への翻訳はできない) してみたときの、なんとも言えない感覚、あぁ読めた……っていう感覚が、なんとなく面白い。
日本語の文章を、英語圏の人が読もうとしたら、自分がその最初に感じた、読めない絶望感や、歯痒さ、途方もない感じが、やはりあるんだろうなぁと思った。そういう意味で、英語だと、いくら読めないといっても、調べる手段 (その文字をうちこめる) があり、読もうと思えばどうにか読める、というのは、大切なんだなぁと感じた。
userscripts.org をコマンドラインから更新するためのツール user.js みたいなのをつくるとしたら、はたして JS on Rhino と rubygems だとどっちのほうがいいんだろう、とおもった。(gem のほうがいいとおもう)
そういえば、Opera は公式みたいなところに user.js 配布するところあるのかな
箸の使いかたが少し上手になりました。
過去の日記読みかえしていたら、すこし、撮りたい写真を思いだしてきた。最近かわいい女の子について想像していないのと、同じような原因で忘れてしまっているようだ。なにかと、学校いかなくなってから、幸せだからなぁ……
なんで、おれは、センスがないんだろう…… 人生、なにもかもをやりなおすか、むしろ、別の、美しくて、なにもないようなところへ、いきたい……
自分は、悪意のあるものを徹底的に排除したいので、そういうのが、継続的に続くようなものは、自動で無視できるようにしようとしてる。そういう、本来、独りでつぶやき、独りで解決するような、悪意のあるつっこみ、茶々、みたいなのは、とにかく消してしまってかまわないと思う (消してしまう、というのはクライアントサイドの話で)。批判ではないネガティブなものは、本当に、意味がない。
「簡単にコメント」できる、みたいなのは、必ずしも良いことではない。簡単なフィードバックは、必ずしも良いことではない。ただし、機械的にある程度フィルタリングできるならば、できるだけ簡単にフィードバックができてもいい。いらないものは、機械によって読まれ、捨てることができる。でも、批判を気取った中傷みたいなのは、機械での判定が難しくて、嫌だ。
これ、めっちゃいいよなぁ……なんでいいんだろう。すこし混沌とした感じがするけど、そうでもない。
批判は、読んだあとに、考えることが、たくさんある。反論であったり、納得であったり、いずれにしても、対象をよく考えなおすことができる。でも悪意はそうじゃない。単に、嫌な気持ちになるだけだ。
なんかリミックスがどっかにあったような……って思って探してしまった……
Paradise Lost のボーナス CD だった…… (Tony Doogan mix) こっちのほうがすきかなぁ。遠くから響いてくる、遠近感が、おもしろい。
別に行きたいわけじゃないけど「グラスゴー」って語感がすごく好きだ。
技術力というより、評価がすごくフェアであることに尊敬する……メインの言語が違うから、直接何がすごいか、っていうのを実感できていないけど (頭ではわかる、みたいな感じ)、そういう部分が、本当に実感して、すごいと思う。
http://www.nicovideo.jp/watch/sm1878349 (gomez)
これすごい好きだなぁ。すこし凛とした感じ、冬の朝とか、冬の学校の放課後の屋上みたいなイメージ。じわじわ
ID3 にアーティスト名が入ってなくて迷ったけど作曲者の名前を入れるようにした。(同名の海外アーティストがいるみたいけど)
ポップな Sigur Rós って感じ (それ Sigur Rós じゃない)
高音のミクの声って Sigur Rós のボーカルにちょっと似てると思う。似てねぇよって言われそうだけど w
はぁ……まじいい曲だ
修正前のバージョンもめっちゃすき
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 にする必要も別にない。なにがやりたかったんだろう……
http://d.hatena.ne.jp/keyword/Sigur%20R%8f%ab%d1s にキーワード記法でリンクはれないね。(数値参照になってしまうから)
あと、その場記法だとキーワードリンクが生成されない気がするんだけど大丈夫なのかな。
\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);
}
}
なんか右クリックすると Open Selection Links in Tabs が暴発することがかなりある…… たぶん右クリックメニューの挙動が変なんだろうけど、セレクションがないのにセレクションがあると勘違いするバグとの相乗効果でかなり困る。何がわるいんだろ……