たまに18歳未満の人や心臓の弱い人にはお勧めできない情報が含まれることもあるかもしれない、甘くなくて酸っぱくてしょっぱいチラシの裏。RSSによる簡単な更新情報を利用したりすると、ハッピーになるかも知れませんしそうでないかも知れません。
の動向はもえじら組ブログで。
宣伝。日経LinuxにてLinuxの基礎?を紹介する漫画「シス管系女子」を連載させていただいています。
以下の特設サイトにて、単行本まんがでわかるLinux シス管系女子の試し読みが可能!
MochiKit見てみた。
これも基本はやっぱりユニットテストに特化した感じかなあ。少なくともGUIのテストは意識してないか……
仕事でFirefoxの拡張機能をやるという事になったときに最初に須藤さんに「拡張機能のテスト用フレームワークってあるの?」みたいな事を聞かれて、それでMozUnitに辿り着いたんだけど、その時の僕にはまだ自動テストとかテスト駆動開発という物がどういうものかよく分かってなかった(今もまだよく分かってないかもだけど)。今思うと、その時僕が思ってた「自動テストって、こういう事をしなきゃいけないのかな?」というのは、開発者世界の常識的には相当ワガママな要求をイメージしていたようで、普通は「自動テスト」「ユニットテスト」というともっと低レベルの、あくまで部品単位の品質を高める物という認識でよかったみたいだ。それを知らずに僕はSeleniumのGUIアプリ用版みたいなのをイメージしてたから、「そんなの無理ッスよ……」と勝手に諦めムードになってた。とはいえ、その勘違いが無ければここまで意地になってUxUに手を入れまくる事もなかっただろうしなあ。
19日のShibuya.js in KyotoでUxUの事を話そうと思ってとりあえずその前に他のツールの現状を調べとこうと思ってUxUの元になったMozLabを見てみたら、ライセンスがMPL/GPL/LGPLのトリプルライセンスになってた。フォーク前のMozLabはGPLだけだったのでUxUもGPLなんだけど、こういう場合ってUxUもトリプルライセンスにできたりするんだろうか、それともあくまでフォーク時点でのライセンスに従う事になるんだろうか。
とりあえず中身見てみたけど、スタックトレースをマトモに辿れないっぽいとことかその辺はあまり変わってなかった。先方はMozReplの開発の方に注力してるってことみたいだなあ。対するUxUはサーバソケットの方はほとんど放置(僕が触れないので)でGUIのテストランナーの方に注力してる。まだ返信できてないけどこないだ会社の代表アドレス宛にMozLab作者の人から「英語版ドキュメント無いの?」的メールが届いてたので、このあたりの事を話してマージの方向を目指してみるべきだろうか?
そういう事であれば確かにおっしゃる事はごもっともです。適用対象がすべてのWebページとなっていたのは、僕の記憶する限りでは改変元の物がそうなっていたのを手を加えずにいたからだと思いますが、そこをそのままにしておくのは確かに思慮不足でした。基本的に自分は「とりあえず自分がイメージしていた所まで辿り着いたらすぐ公開」をポリシーにしていますし、少なくとも趣味レベルや実験レベルでやっている事については、自分が気付いていない・当初の想定になかった問題は突き詰めると人に指摘されてから直せばよいと考えていますので、思慮不足である場合も少なくないです。ある時点(特に修正のサイクルが動き出す前のような時点)を切り取って「バカかおめーは」と言われれば、「その時点での自分は確かにバカでしたごめんなさい」と謝って修正するしかないです。
Jintrick氏がやり玉に挙げているスクリプトを僕が何故修正もせずに放置しているのかというと、本家配布元が変更を取り込んで開発を継続されたため、自分の作った物の役割は終わった、自分がこれをメンテナンスし続ける必要はない、後の事は先方が責任を持ってくれることだ、と考えたからです。「もう古いから本家の新しい物を使うように」という誘導が無くてこれが最新最終版ととられかねないような状態で置いておくのがよくない、と言われたら、それについても「誘導忘れてました放置してましたごめんなさい」と謝るしかないわけですけれども。
とはいえ件のコードの品質の低さや、品質が低いまま放置している事というのは、以下に詳しく述べますが自分としては一応理由があっての事で、僕のコードがいついかなる場合でも低品質で僕の姿勢が総じて宜しくないという風に思われるのは心外だとも思っています。
自分はGreasemonkeyスクリプトやuserChrome.js用のコードなどについては、品質が低いまま公開してもさほど問題ないと考えています。こういった、コードがむき出しで、インストールされたスクリプトの自動更新機能も持たない、スクリプト作者が後々のサポートができないタイプの拡張機能は、自助努力で問題を解決できる人、あるいはどんなトラブルが起こっても自己責任と納得できる人だけが使うべきだというのが自分の考えです。僕はやっつけ仕事で自分の必要最小限の物だけ書いたから、使いたい人は使ってくれて構わないけど、後はどうなっても知らんよ、というのがGreasemonkeyスクリプトに対する自分のスタンスです。ましてや、僕の加えた変更が本家に完全にマージされて、派生版が派生版としての存在意義を失い、本家の開発がきちんと継続されているのだから、役目を終えた古い派生版に文句を言われても、僕としては「知らんがな。開発を継続してる本家に言うてくれ。」というのが正直な感想です。
しかし、普通の拡張機能については、それとは違う態度で自分は取り組んでいるつもりです。Firefoxの拡張機能は自動アップデートが可能で、インストールもアンインストールも簡単という、純粋なエンドユーザに「さあ使ってくれ」とでも言わんばかりの仕様で、必要ない部分はとことん隠蔽されていますから、その様式に則って物を作るならそれ相応の覚悟が必要だというのが自分の認識です。
例えばXUL/Migemoを派生版としてメンテナンスする中で、ネットワークを通じての辞書の自動インストール機能やユーザ辞書機能といった風な「上級ユーザ向けには明らかにどうでもいい機能」を積極的に加えていったのも、そういう考えがあったからです。件のコードのようにFirefoxをフリーズさせかねないような機能、最近のスマートロケーションバーでの検索への対応でも、のりさんやdrryさんにまで協力してもらって何度も検証を行った上で、常用で問題が起きない程度の速度が出るようにできた時点でやっと一般向けにリリースしました。またその上で、AMOに頼らず自動アップデートのための環境を自前でも整えて、修正をエンドユーザに迅速に提供できるようにも努めているつもりです。(修正が追いつかずに後回しになっている事も多々ありますが、最初から修正する気がないのとは違うと自分では考えています。まあ、それを指して、結果的に不幸を垂れ流してるからダメだと言わたら、「そうですね」としか言えませんが。)
こういう、相手によって力の振り分け加減を変える姿勢を、不誠実だと言われてしまえば返す言葉はありませんが、自分は現時点では、これを「今自分ができる中で一番マシな形」と考えています。
まーとりあえず言える事は、Piroは自己弁護に必死だなと。
自分にはちょっと承伏できない理由でJintrick氏にDISられてるので、一応釈明しておきます。
――「一応」と書いておきながら、Jintrick氏に「バカじゃねーの」みたいに煽られたような気がして感情的になってクドクド書き過ぎてしまったので、最初に例だけ示しておきます。
<?xml version="1.0"?>
<html xml:lang="ja">
<head>
<title>テスト</title>
</head>
<body onload="init()">
<script type="application/x-javascript">
function init()
{
var ul = document.getElementById('indicator');
document.addEventListener('keypress', function(aEvent) {
var li = document.createElement('li');
li.appendChild(
document.createTextNode(
[
aEvent.type,
aEvent.keyCode,
String.fromCharCode(aEvent.charCode) +'('+aEvent.charCode+')',
aEvent.target,
aEvent.target.localName,
(new Date()).getTime()
].join(' : ')
)
);
ul.insertBefore(li, ul.firstChild);
}, false);
}
</script>
<textarea rows="5" cols="50">ここに文字を入力すると、イベントの詳細を表示します。</textarea>
<ul id="indicator" style="height: 15em; overflow: auto;">
</ul>
</body>
</html>
これが正常に動作しなくなるというただそれだけの理由で、僕はJintrick氏の勧める方法(上位のDOMノードをゴソッとDOMツリーから切り離して、ツリーに対する処理を行い、最後に再挿入することで、パフォーマンスを向上する)を全面的には採用できません。
以下、長々とその説明。
表題の通り、XUL/Migemo 0.10.5からロケーションバーでNOT検索を可能にしました。「mozilla -firefox」という風に入力すると、「Mozillaという単語は含むがFirefoxという単語は含まない」候補だけがヒットするようになります。当然Migemo検索との併用も可能。いらん候補が大量にヒットするのがウゼーと常々思っていたので、バグ修正のついでにサクッと実装してみました。
残念ながら、履歴とブックマークの管理、履歴サイドバー、ブックマークサイドバーでの検索については非対応です。これらの検索機能はPlacesのクエリ機能に依存していて、そのクエリ機能にNOT検索の機能がないためです。クエリにNOT検索の機能が付いたら対応できるかも。
ということでXUL/Migemo 0.10.0やっとリリース。
スクリーンショットを見ると分かるとおり、なにげにAND検索にも対応してます。仕掛けは単純といえば単純で、入力された文字列をスペースで区切ってそれぞれについて正規表現を生成した後に、それらの順列組み合わせを全展開した正規表現をさらに生成する(これを使ってマッチングするので、各単語の順番が入れ替わってもマッチする)という、ものすんごい力業。単語数が増えると組み合わせの数が爆発的に増えて正規表現がクソ長くなってマッチングがクソ重くなるので、実用的な速度が出るのはだいたい3語くらいまでが限界だと思います……
ちなみに順列組み合わせの展開には無駄にMozStorageを使ってます。JavaScriptで一体どーいうアルゴリズムでやりゃぁいいのかちっとも分からんかったのでググってみたら、順列組み合わせの総数を求める方法ばっかり引っかかる中で一つだけSQLの自己結合を使った解き方が見つかったので、それをそのまま使わしてもらいました。pIXMigemoTextUtilsのgetANDFindRegExpFromTermsというメソッドがそれなので、興味ある人は見てみてください。
しかしまあ、今回のこれはFirefox 3 HacksのためにPlacesのことを詳しく調べてたからやっと実現できたようなもんで、つまりFirefox 3 Hacksを読めばこんなことは楽勝でできるようになるかもねということで、皆さんゼヒ買って下さい、と宣伝しておきます。オライリーから8月発売予定です(再掲)。
5日追記。ページ内検索では考慮しなくてもよかった問題が表面化してフリーズする(全角スペース1文字だけにヒットした場合に無限ループに陥ってしまう)という現象が起こってしまっていて焦った。対策を入れて早速更新した。
前者は「ねんどろいど」等で有名なグッドスマイルカンパニーのブログ、後者はアイマスの双海亜美・真美役の下田麻美さんのブログ。まさかこんな所でFirefoxを見かける日が来るとは思わなかった。
どうでもいいけど、再販分のねんどろミク早くこないかなー……クオリティ落ちてないといいんだけど。
places.sqliteが数十MBを超えているのりさんやdrryさんの環境では分単位で固まってしまって使い物にならん、ということだったので、お二人に協力してもらって各段階での処理の所要時間を調べてみた。
そしたらどうも、Placesデータベースから文字列をぶっこ抜いて正規表現でマッチングしてるところがものすごく重いらしいということが判明した。ログによると500万文字ある文字列に対してマッチングをかけようとしてたんだから、そりゃあ固まるわ、と。
固まる問題だけでもとりあえず何とかしよう、ということで数千件単位で文字列を取り出し→マッチング→取り出し→マッチング……という風に分割処理するようにしてみたところ、とりあえず固まる問題は何とかなったんだけど、でも検索結果が出るまで延々待ち続けないといけないのは相変わらずで。
と、そこでやっと気づいたんだけど、べつに正規表現でのマッチングとポップアップの内容の更新とを完全に分けて実行する必要はないんですよね。ちょっとずつマッチングしてちょっとずつ検索結果を取得してちょっとずつ結果のリストを更新していけば、全体ではものすごく時間がかかるようであっても、とりあえず最初の方の結果だけは見えるからストレスにはならない。必要な数だけ結果を取り出せたらそこで処理を打ち切ってしまえばいいんだし。
というわけであちこち書き直してみた結果、最初の実装に比べるとびっくりするほど快適に動くようになった。スレッド使ってなくてもそんなに重くない。のりさんにも「これなら常用できそう」と言ってもらえたし。
最終的にやってることは同じなんだけど、やり方を変えるだけでこんなにも体感速度に違いが出るものなんだなあ、ということをこれ以上ないほど実感した日でした。
それはそうと、途中の段階で分割処理を行うようにしたときのログを見てて気がついたんだけど、SQLite(というか RDBMS)ってすごいね。テストしてもらったのりさんの環境の場合、スマートロケーションバーの検索対象になる物だけでも46000件近く、そうじゃない物も含めればきっともっと大量のレコードがあるのに、「並べ替え後の順番で任意の箇所を取り出す」のに1秒もかからないというのには驚いた。今までちゃんとしたデータベースを触ったことがなかったから、こんなの未知の世界だ。世界規模のデータベースと世界規模の処理環境に憧れてグーグルを目指す人の気持ちが、少しは分かったような気がする。
こないだから少しずつ取り組んでる。
当初は皆目見当も付かなかったけど、Firefox 3 Hacksを書くために調べた知識が早速役に立って、Places APIを使ってる「履歴とブックマークの管理」と「ブックマーク」「履歴」の各サイドバーについてはワリとあっさり実装できた。
ロケーションバーについては残念ながら普通のAPIを使っておらず、オートコンプリートの実装の中でガチガチに書かれてて、まともにやっても手出しできない。OR検索さえできればMigemoが使えるのに。ということで、まず最初は、オートコンプリートのコントローラに複数の単語を順番に渡して結果のリストを生成させてそれを最後にまとめる、という事をやってみた。これは結構イイ線いったんじゃないかと思ったんだけど、履歴の件数が増えたりヒットした単語数が増えたりするとえらい事になってしまって、実用的な速度は出なかった。
そこで諦めて腹をくくって、無い知恵絞ってSQL文書いて、なるべく効率よく処理するようにしてみた。これで速度はだいぶ上がって、3文字以上入力した先あたりならかなりサクサク動くようにはなったんだけど、1文字2文字程度しか入力していないとやっぱりズシッと重い感じがある。
XPCOMのスレッドを作る機能を使ってみた所、Firefoxが落ちたし。
組長が書いている本に僕も書いてます、っていうかやっと今日書き上がりました。ここのところ全然寝れてなかったけど、これでやっとゆっくり寝れる。
僕の担当パートは例によってアドオンがらみで、FUELとPlacesとJavaScriptコードモジュールとMcCoyあたりについて出せる物をすべて出し尽くしました。というか出せる物以上を書かないといけなかったのでFirefox 3のコードを追いかけて調べながら書きました。ATOK X3買ったのもこれのため。最終的に書いた物はサンプルのソースコードも含めてテキストファイルで360KBくらい? UTF-8だから何文字とかちょっとわかんない……
書いた内容はどれもまあソースコードを順番に読んでいけば分かる事っちゃ分かる事ばかりなんですが、まとめのようなものという事でどうか許してください。オライリーから8月発売予定です。