Home > Latest topics

Latest topics 近況報告

たまに18歳未満の人や心臓の弱い人にはお勧めできない情報が含まれることもあるかもしれない、甘くなくて酸っぱくてしょっぱいチラシの裏。RSSによる簡単な更新情報を利用したりすると、ハッピーになるかも知れませんしそうでないかも知れません。

萌えるふぉくす子さんだば子本制作プロジェクトの動向はもえじら組ブログで。

宣伝1。日経LinuxにてLinuxの基礎?を紹介する漫画「シス管系女子」を連載させていただいています。 以下の特設サイトにて、単行本まんがでわかるLinux シス管系女子の試し読みが可能! シス管系女子って何!? - 「シス管系女子」特設サイト

宣伝2。Firefox Hacks Rebooted発売中。本書の1/3を使って、再起動不要なアドオンの作り方のテクニックや非同期処理の効率のいい書き方などを解説しています。既刊のFirefox 3 Hacks拡張機能開発チュートリアルと併せてどうぞ。

Firefox Hacks Rebooted ―Mozillaテクノロジ徹底活用テクニック
浅井 智也 池田 譲治 小山田 昌史 五味渕 大賀 下田 洋志 寺田 真 松澤 太郎
オライリージャパン

Page 23/240: « 19 20 21 22 23 24 25 26 27 »

SubversionからGitに移行した - Nov 01, 2010

アドオンの開発にはずっと須藤さんに用意してもらったSubversionのリポジトリを使ってたんだけど、

  • インターネットに繋がらない状態でコミットできないのが辛い
  • 他の人からの変更を受け取りづらい(そんな事があればの話なんだけど)

と思っていて、Git(あるいは他の分散型バージョン管理システム)ならそれが解消されると期待してて、でもずっと移行できていなかった。

  • コマンドライン操作が嫌いなので、Subversionを使うのにWindowsではTortoiseSVNを、LinuxではRabbitVCS(旧称:NautilusSVN)を使ってるけど、GitではWindowsにはTortoiseGitがあってもLinuxでは相当する物が無いみたい。
  • バージョン管理システムを移行するとそれまでのコミットの履歴も全部なくなっちゃうんじゃないの?
  • git-svnっていうのを使うといいと聞いたけど、試しても空のディレクトリしかできないんですけど……

というのがその理由だった。でも

  • git-svnは時々動作がうまくいかない事があるみたいで、Windows上のmsysgitが特に高確率で失敗するだけで、VirtualPC上のUbuntu 10.04LTSのgit-svnだとそれほどでもなかった。
    • それで成功したケースだとコミット履歴が完全に引き継がれてた。なんだ、ちゃんと動けばちゃんとやってくれるんじゃん!!!
  • 最近、システムモニターの開発でGitをずっと使ってたから、まあLinux上ではコマンドラインでも別にいいかな……という気がしてきた。

という事で、思い切って移行してみる事にしました。具体的な手順はSourceForge.JP のプロジェクトを Subversion から Git へ移行するに従いました。

SubversionとGit

大まかに言うとこういう事だと僕は理解してる。

  • Subversionでは、中央に1つのリポジトリがあって、それを各人がチェックアウトしてワーキングコピーを作り、ワーキングコピーに対して行った変更をリポジトリにコミットする、という形で「バージョンの管理」と「成果の共有」を実現する。
  • Gitでは、リポジトリのコピーを誰でも簡単に手元に作る事ができて(Gitではこれをcloneと言う)、Subversionでワーキングコピーからリポジトリに変更点をコミットするのと同じように、Gitではリポジトリとリポジトリの間で変更点をコミットできる(Gitではこれをpushとかpullとか言う)。
    • どれか1つのリポジトリを「中央のリポジトリ」として運用すれば、Subversionでのバージョン管理と同じような運用もできる。
    • 手元にできるのは「履歴の情報を持たないワーキングコピー」ではなく「元のリポジトリを複製したリポジトリそのもの」なので、インターネットに繋がってない状態でもローカルのリポジトリに対してコミットできる。
    • Subversionではtrunkと呼ばれていた物は、Gitではmasterと呼ばれる。
  • git-svnは、以下のような事をする。
    • Subversionのリポジトリのコミット履歴を全部辿る。
    • ローカルに新しいGitリポジトリを作って、Subversionのコミット履歴に対応するコミットを順番にそのGitリポジトリにコミットする。
    • なので、git-svnでGitリポジトリ化したSubversionリポジトリは、元のリポジトリの変更履歴を完全に引き継いだ物になる。

やってみる

ツリー型タブSubversionリポジトリをgithub上の同名のリポジトリに移行する手順を振り返ってみる。

  1. Subversionのリポジトリをgit-svnでGitリポジトリに変換する。
    $ git svn clone --prefix svn/ -s https://www.cozmixng.org/repos/piro/treestyletab
    これでローカルにtreestyletabという名前のディレクトリができて、これがGitリポジトリになってる。コミットを1件1件取り込むので、コミット数が多いとメチャメチャ時間がかかるけど、黙って待つ。たまに失敗するので、そういう時はできたゴミディレクトリを消してもう一度やり直す。
  2. githubに「treestyletab」という名前でリポジトリを作る。(分かりやすくするためにSubversionの物と同じ名前にするといい。リポジトリ名は後でgithub上で好きなように変更できるので。)これで、読み書き両用のURLとして「git@github.com:piroor/treestyletab.git」みたいなのが使えるようになる。
  3. ローカルにできたtreestyletabのGitリポジトリの「元」として、githubのリポジトリを登録する。
    $ git remote add origin git@github.com:piroor/treestyletab.git
    これによって、「このリポジトリはgithubのリポジトリをcloneした物ですよ」「このリポジトリに行われた変更を元のリポジトリにpushする時は、githubにpushしますよ」ということになる。
  4. pushする。
    $ git push origin master
    これで、Subversionのリポジトリから持ってきたコミット履歴が全部github上のリポジトリに反映される。
  5. Subversionのtagsの内容をGitのtagに変換する。Subversionでtags以下に作ったタグはブランチとして取り込まれているので、これをGitのタグにしてやる。
    $ git branch -r
    これでブランチの一覧を見れるので、
    $ git checkout svn/tags/0.10.2010102501
    という風にしてブランチを切り替えて
    $ git tag 0.10.2010102501
    でタグを打って
    $ git push --tags origin
    でタグの情報をgithubのリポジトリにpushする。タグの数だけこの操作を繰り返す。
  6. Subversionのbranchesにブランチがある場合、Gitのbranchに変換する。Gitだとローカルにあるブランチをgit push origin ローカルリポジトリのブランチ名:リモートリポジトリのブランチ名でリモートリポジトリにpushできるんだけど、git−svnでcloneしたローカルリポジトリにあるブランチはそのままだとpushできない(不可視のブランチになってる?)ようなので、
    $ git checkout svn/my-branch
    でブランチを切り替えて
    $ git branch my-branch
    で普通のブランチとして切り直して
    $ git push origin my-branch:my-branch
    でgithubにpushする。

自分はアドオンの数自体20個以上あるし、それぞれアホみたいに何度もリリースしててタグの数がハンパないことになってるので、全部手動でやることを考えたら気が遠くなりました。なのでこういうスクリプトをRubyで書いてみました。

#!/usr/bin/ruby

SVN_REPOSITORY_PATH = "https://www.cozmixng.org/repos/piro/<%= src_project_name %>"
GIT_REPOSITORY_PATH = "git@github.com:piroor/<%= dest_project_name %>.git"

$LOAD_PATH.unshift(File.dirname(__FILE__))

require "fileutils"
require "erb"
require "shellwords"

def main
  ARGV.each do |arg|
    p "process #{arg}"
    args = arg.split(":")
    src_project_name = args[0]
    dest_project_name = args.size > 1 ? args[1] : args[0]
    svn_to_git(src_project_name, dest_project_name)
  end
end

def svn_to_git(src_project_name, dest_project_name)
  p "svn:#{src_project_name}, git:#{dest_project_name}"
  clone(src_project_name)
  push(src_project_name, dest_project_name)
  push_branches_and_tags(src_project_name)
rescue Exception
  p $!
end

def clone(src_project_name)
  result = run("git", "svn", "clone",
               "--prefix", "svn/",
               "-s", ERB.new(SVN_REPOSITORY_PATH).result(binding).chomp)
    p result.to_s
  raise Exception.new("clone of #{src_project_name}, #{result.to_s}") unless result.to_s.include?("Checked out HEAD:")
end

def push(src_project_name, dest_project_name)
  FileUtils.cd(src_project_name) do
    result = run("git", "remote", "add",
                 "origin", ERB.new(GIT_REPOSITORY_PATH).result(binding).chomp)
    p result.to_s
    result = run("git", "push", "origin", "master")
    p result.to_s
    raise Exception.new("push of #{src_project_name}, #{result.to_s}") unless result.to_s.include?("master -> master")
  end
end

def push_branches_and_tags(src_project_name)
  FileUtils.cd(src_project_name) do
    branches = run("git", "branch", "-r")
    branches = branches.to_s.split("\n")
    branches.each do |branch|
      next unless branch.include?("svn/")
      branch.strip!

      name = branch.split("svn/")[1]
      next if name == "trunk"

      if name.include?("tags/")
        tag = branch.split("tags/")[1]
        p run("git", "checkout", branch)
        p run("git", "tag", tag)
        p run("git", "push", "--tags", "origin")
      else
        p run("git", "checkout", branch)
        p run("git", "branch", name)
        p run("git", "push", "origin", "#{name}:#{name}")
      end
    end
  end
end

def run(*args)
  command_line = Shellwords.shelljoin(args)
  result = `#{command_line} 2>&1`
  result
end

main

ファイル名は svn-to-git.rb として、

$ ./svn-to-git.rb treestyletab

とやると、ここまでの手順のうちgithubのサイト上でリポジトリを作る所以外を全部自動でやってくれるという物です(ということは、スクリプトの実行前にあらかじめgithubのサイト上でリポジトリを作っておかないといけない)。これでなんとか全部のリポジトリをgithubに持ってくることができましたXUL/Migemoの辞書をSQLiteにしてみようとかそういうブランチを切ってた物が取り込めてなかったりsvn:externalsで参照してた物が入ってなかったり、Subversionに突っ込んでから1回もコミットしてないプロジェクトをまだgithubに持ってきてなかったり(必要あるの? 無いよね?)という課題は残っていますが。→ブランチの取り込み方が分かったので追記しました。→svn:externalsの移行は諦めてsubmoduleにすることにしました。TortoiseGitでメニューから「Submodule Add」を選んでリポジトリにgit@github.com:piroor/makexpi.gitを、パスにbuildscriptを指定する、という手順でだいたい同じような結果になるみたい。更新の時はTortoiseGitだと「Git Sync」から「Submodule Sync」しないといけないようだ。コマンドラインなら一発で更新できるようなんだけど……

今後はgit-svn駆け込み寺あたりを熟読して頑張っていきたいと思っております。あと、今後具体的にコードを提供してくれるような人がもしいれば、githubの方にpull requestっていうんですか?するようにしてもらえたら幸いです。

……というまとめエントリを書こうとしてもうちょっと調べ直してたら、git-svnでタグが自動で取り込まれないとかの問題を解消するラッパーのsvn2gitという物があるということを今更知りました。ギャフン!!!!!

……さらに後から気がついたけど、HTTPでアクセスできる公開のSubversionリポジトリをgithubに移行するだけならtagやbranchの変換も含めてgithubのWebインターフェース上の機能だけでサクッとできてしまうことが分かりました。ギャフンギャフン!!!!!!!!! 手順は以下の通りです。

  1. githubで新しいリポジトリを作る。
  2. 空のリポジトリができたら、最初に表示されてる説明の下の方にある「Subversionのリポジトリを取り込みたい? ここをクリック」というリンク(日本語のUIにしてる場合。英語でも多分似たような文言があると思う。)を辿る。
  3. インポート元のSubversionリポジトリのURLを入力する。
  4. githubのユーザ名( 「piroor <piro.outsider.reflex@gmail.com>」のような、githubのユーザ名と登録済みのメールアドレスの組み合わせ)を作者として入力する。
  5. しばらく待つ。

最初githubのUIを英語で使ってたのと、下までスクロールしてなかったから気がついてなかった。なんということでしょう。丸1日以上を無駄にしてしまいました。

Ubuntu 10.04LTSからUbuntu 10.10へのアップグレードとATOK X3 - Oct 26, 2010

仕事でRails 3.0とかRuby 1.9.2とかを使わないといけなくなったんだけど、Rails 3.0と併せて使うとお薦めと紹介されていたBundlerというやつをgemでインストールしようとしたらRubyGemsのバージョンが古くてダメだと言われてしまい、Ubuntu 10.10にアップグレードしたらいけると教えてもらったので、早速上げてみた。(10.04はLong Time Supportだからアップグレードの通知が来てなくて、10.10がリリースされていたことに気付いてなかった。)

  • 例によってUbuntu Japanese Wikiのアップグレード手順解説の通りに操作したらアップグレードできた。
  • Ubuntu 9.10→Ubuntu 10.04LTSの時は沢山エラーが出たけど今回は特にそういうことはなかった。
  • DropboxのクライアントもWineにインストールしたLimeChat 2もそのまま動いてくれた。
  • 既定のブラウザがFirefoxじゃなく自分でインストールしてたGoogle Chromeになっていたので、Firefoxの設定から既定のブラウザに設定し直す必要があった。
  • 多分Ubuntu 10.04LTSの頃からだと思うけど、Ubuntuマシン上のフォルダをSambaで共有しててそのフォルダの中に別のフォルダへのシンボリックリンクがある時に、別のマシンからその共有フォルダを覗いてシンボリックリンクを辿ろうとすると、権限がないから開けないみたいな事を言われるようになってた。Ubuntu 10.10でも変わっていなかった。
  • また例によってLet’s noteのくるくるスクロールができなくなってた。
    • Ubuntu 10.04LTSにアップグレードした時は設定ファイルを追加してやる必要があったけど、そのファイルは已然として存在している。gsynapticsもインストールされている。なのにシステム→設定→マウス の所を見ても設定がない!!
    • 検索したらgpointing-device-settingsというのを使うとできるとあったんだけど、パッケージは既にインストール済みになってる……と思ってよく読んだら、設定には システム→設定→Pointing devices を使うと書いてあった。こっちに移動してたのか。アイコンがタッチパッドじゃなくてマウスだったし、そもそもラベル文字列が翻訳されてなかったから、完全に見落としてた。
    • ここで「回転スクロールを有効にする」にチェックを入れたらまたくるくるスクロールできるようになった。

が、日本語入力の所で問題が起こった。

ATOK X3をUbuntu 10.10で動かした時に起こった問題とその対策

僕は以前からUbuntuでATOK X3を使ってた。アップグレード後も、特にインストールし直さなくてもATOKによる日本語入力はできるようだったが、どうも動作が怪しい。

  • gedit等のアプリケーションで日本語を入力すると、確定した瞬間にメニューバーにフォーカスが行ってしまう。(Altキーが入力されてしまうのか何なのか分からないけど、「ファイル」メニューが開かれてしまって入力中の内容が失われる。)
  • 変換候補のポップアップが、アプリケーションのウィンドウの左下に張り付いてしまう。
  • 最初に導入した時にiiimf-properties(iiim-properties)で設定した「ウィンドウ左下のツールチップ?を表示しない設定」+「変換キーでIMEのON/OFFをトグル」が効かなくなったみたい。
    • さらに悪いことに、ウィンドウ左下に出てくるツールチップが何故か真っ黒になる。

9.10→10.04LTSの時の手順でATOKを再インストールしてみよう……とする前に、念のため「Ubuntu 10.10 ATOK」で検索してみたら、Ubuntu日本語フォーラム / 10.10にATOKをインストールというのが出てきた。これによると、

  • Ubuntu 10.10ではdpkgの仕様が変更されて、そのままではATOK X3のdebパッケージをインストールできない。
  • この点に対処したdebパッケージがJustSystemのサポートサイトで既に公開されている。このページに、過去のパッチも適用した上でインストールする手順の解説も掲載されている。

という事だったので、早速やってみた。しかし、上記の「動作が怪しい」点は変化が無かった。

症状をキーワードに検索してみたけど類似の例が見つからなかったのでお手上げということでtwitterでぼやいたら、いくやさんが情報を示して下さった紹介していただいたエントリによると、「immoduleの設定がおかしい」のが原因……らしい。

いくやさんのエントリには /usr/lib/gtk-2.0/2.10.0/immodule-files.d/libgtk2.0-0.immodules を編集するように書いてあるけど、何故か僕の環境だとこの位置にファイルが無くて /usr/lib/gtk-2.0/2.10.0/gtk.immodules にそれらしきファイルがあった。sudo vi /usr/lib/gtk-2.0/2.10.0/gtk.immodulesで開いて、こちらはいくやさんのエントリと同じように

"/usr/lib/gtk-2.0/immodules/im-iiim.so"
"iiim" "Internet/Intranet Input Method" "iiimgcf" "/usr/share/locale" ""

と追記し( /usr/lib/gtk-2.0/immodules/im-iiim.so の位置にファイルがあることはちゃんと確認した)、ログアウトしてログインし直したら、「入力を確定するとメニューバーにフォーカスしてしまう」「変換候補のポップアップがウィンドウの左下に張り付いてしまう」問題は解消された。

ただ、上記のリンク先にある修正版のATOK(用のIIIMF)のパッチにはiiimf-properties(iiim-properties)のパッケージは含まれていなくて、tarからインストールするのはさすがに怖かったので、「ウィンドウ左下のツールチップ?を表示しない設定」+「変換キーでIMEのON/OFFをトグル」は諦めるしかないようだった。(「ウィンドウ左下のツールチップ?を表示しない設定」の方だけは、JustSystemのサポートサイトで公開されているIIIMFステータス非表示ツールというのを使うことでどうにかできるけど。)

ibus-mozc

ATOKの使用をあきらめかけた時に、せっかくだからとibus-mozc(Google日本語入力のエンジンのオープンソース版)を試してみることにした。

  • アップグレードで使ってるからか、10.10になった段階ではibus-mozcは入っていなかった。
  • 日本語環境セットアップ・ヘルパを起動したらibus-mozcの項目があったので、そこにチェックを入れたらインストールできた。
  • 再起動してもどうやって有効にすればいいのか分からなかったけど、システム→システム管理→言語サポート で「キーボード入力に使うIMシステム」をiiimfからibusに切り替えたら、ibus-mozcが有効になった(ログアウト→ログイン してからだったかもしれない)。

ibusの設定は システム→設定→キーボード・インプットメソッド で変更できる。こちらは変換キーだけでのIMEのON/OFFトグルも簡単に設定できた。また、言語パネルを表示させた状態であればibus-mozcの設定を変更できて、ここからキーバインドをATOK風に変えることができた。

とりあえずちょっと触った感じでは日常的な利用には支障なさそうだと思った。ただ、僕はATOKに電子辞書を入れて変換候補の同音異義語の使い分けに使ってて、mozcにはそれがないようだったので、ATOKが使えるうちはATOKを使いたいなあと思った。

XBLの使用を避けたがるのは何故か - Oct 22, 2010

僕がアドオン開発でXBLの利用を避けることが多いのは、XBLを使ってると、他のアドオンやサードパーティ製のテーマと衝突した時ににっちもさっちもいかなくなってしまうことが多かった(という印象が強い)り、複数のバージョンのFirefoxに対応しようと思うとドツボにハマったりしたからだ。

例えばツリー型タブのようなアドオンを作る時に、「タブのDOMノードに、子タブの一覧を取得するためのchildTabsというプロパティを追加したいな」と思ったとする。思ったっていうか、タブブラウザ拡張でかつてツリー表示機能を実装した時には実際そうしてたんだけど。それをXBLでやるとこんな風になるだろう。

<binding id="tabbrowser-tab"
         extends="chrome://browser/content/tabbrowser.xml#tabbrowser-tab">
  <implementation>
    <property name="childTabs" readonly="true">
      <getter><![CDATA[
        ...
      ]]></getter>
    </property>
  </implementation>
</binding>

同時に、こういうCSSも書くことになる。

.tabbrowser-tab {
  -moz-binding: url("mybinding.xml#tabbrowser-tab");
}

XBLではextendsで他のバインディング定義を継承することができる。chrome://browser/content/tabbrowser.xml というのは、Firefox 3.6でタブブラウズ関係の機能を定義してるバインディングなので、これで「Firefox本来のタブの機能に加えて新しい機能を定義する」という事が簡単にできる。

が、これは同時に欠点でもある。XULの機能のかなりの部分はXBLで定義されているので、extendsを書き忘れるとマトモに動かなくなってしまうことが結構ある。だから、独自のバインディングを適用する時は、適用先の要素に既にバインディングが適用されているかどうかを調べて、現在適用されているバインディングのURIを独自のバインディングのextendsに書いておかないといけない。

そして、「元々適用されているバインディングのURI」は簡単には同定できない。Firefoxのバージョンによっても変わるし、WindowsかMac OS Xかによっても変わるし、サードパーティ製のテーマでバインディングが上書きされているかもしれないし、アドオンがバインディングを適用しているかもしれない。ひょっとしたらユーザがuserChrome.cssでバインディングの指定を変えているかもしれない。継承の順番は、自分のXBL→tabbrowser.xml→tabbox.xml→general.xml かもしれないし、自分のXBL→テーマのXBL→tabbrowser.xml→tabbox.xml→general.xml かもしれないし、自分のXBL→他のアドオンのXBL→テーマのXBL→tabbrowser.xml→tabbox.xml→general.xml かもしれない。「こう書いておけば大丈夫」という単一の継承元のURIは存在しないのだ。

さらにタチが悪いことに、XBLの定義ファイルの中に書かれたextendsは動的には書き換えられない。現在適用されているバインディングのURIをgetComputedStyle()で取得しても、それを後からXBLのextendsに指定するという事はできない。(ひょっとしたらdata: URLを使えばできるかもしれないけど、僕はそんなのやりたくないし見たくもない……)

だから、XBLを使うアドオン同士ではバインディングの優先権の取り合いになる。CSSは後から読み込まれたもの・セレクタの指定の詳細度が高いものほど優先的に適用されるから、後からインストールしたアドオンのせいでそれまで使っていたアドオンのバインディングが適用されなくなる、なんてこともしょっちゅうあった。タブブラウザのタブ要素なんて、激戦区中の激戦区と言っていいだろう。

そう考えると、ほんの2~3個のプロパティだとかメソッドだとかを追加するためだけにこれだけのリスクを負うのは到底割に合わない。それだったら、要素のDOMノードに直接プロパティを加えるのを諦めて、コントローラやサービスになるようなクラスを作ってそっちに必要な処理を集約させる方がずっと楽だ。(だからツリー型タブでは、前述の例のようなバインディングを使う代わりに、gBrowser.treeStyleTab.getChildTabs(aTab)で子タブの配列を得るように設計した。)

というのが、僕の出した結論だった。

そういう話なので、僕は、「何が何でもXBLを使うな」とまで言うつもりはない。前述のようなバインディングの適用の優先権争いが起こらない場所、例えば独自のXULRunnerアプリケーションだったり、独自のサイドバーパネルだったり……という部分でなら、XBLはいくらでも使っていいと思ってる。

例えば、派生の要素型がたくさんあるようなケースではXBLの継承が威力を発揮する。会社で一時期やってたXULRunnerアプリのプロジェクトでは、継承を多用することで結構工数を削減できた(と思う)。また、anonymous contentsの追加は(特に、既に存在しているDOMツリーのノードの親子関係の間に安全に割り込むような物は)、XBLでなければできないことだ。

ただ、XBLは、1つのウィンドウの中にいろんな人が好き勝手に書いたコードが同居する「Firefoxのアドオン」という分野とは、すこぶる相性が悪い。JavaScriptで書く物でもCSSで書く物でも「最初にやった者勝ち」な所はどこかしらあるけれども、XBLの場合はそれが顕著だし、「後から来た者が上手く隙間に入り込む」という風な余地が全然無い。だから僕は、XBLをなるべく避ける形でコードを書くように努めてるんだな。

未だにXBLを使うことを避けられない場面 - Oct 22, 2010

XBLはアドオン同士の衝突の原因になりやすい。だからXBLはあまり使わないように僕はしてる。

XBLを使うと、DOMノードにgetterやsetterになってるプロパティを定義したり、独自のメソッドを追加したりできる。でも、それらはJavaScriptのテクニックで代用できないこともない。JavaScriptのレベルで目的を達成するやり方として、僕は最近よく、こんな設計をしてる。

function MyController(aNode) {
  this._node = aNode;
  this.init();
}
MyController.prototype = {
  get property() {
    ...
  },
  set property(aVaule) {
    ...
  },
  method : function() {
    ...
  },
  init : function() {
    this._node.addEventListener('...', this, false);
    ...
  },
  destroy : function() {
    this._node.removeEventListener('...', this, false);
    ...
  },
  handleEvent : function(aEvent) {
    ...
  }
};

var node = document.createElement('box');
node.controller = new MyController(node);

かなりの部分はこういったやり方で目的を達成できると思う。ツリー型タブなんかもこれに近い実装になってる。

ただ、オートコンプリートのテキストボックスの挙動を変えるだとかの、本体で定義されている物を置き換える場面では、たまにこの方法だけでは不十分なことがある。例えば<textbox type="autocomplete" />な要素のmaxDropMarkerRows<panel type="autocomplete" />な要素のoverrideValueやなんかはreadonlyなプロパティとしてXBLで定義されてしまっているので、これらが返す値を変えたいと思うと結構厄介な事になる。

XBLを使わないでサクッと済ませようとすると、__defineGetter__()を使う方法がまずは思い浮かぶ。Firefox 3.0以降ではDOMノードに対して__defineGetter__()を使えるので、上記の例のコードのinit()あたりでそれを使ってやるという感じだ。実際、XUL/MigemoではoverrideValueで任意の値を返すためにそうしてる。

でも、この方法はできれば使わない方がいいのかもなと思ってる。そう思ったきっかけは、同じようなことをやるコードの自動テストを書いていた時。setUpとtearDownで毎回ウィンドウを開いたり閉じたりとやってると時間がかかってしょうがないからUxU組み込みのフレームにページを読み込ませて……という風にしてみたら、セキュリティの制限に引っかかってしまった。object.__defineGetter__(name, getter)objectgetterの属してる名前空間が違うと、Illegal valueとか言われてエラーになってしまった。それでTrunkでの__defineGetter__()の実装を見てみたら、この両者のコンパートメントが違う場合はゲッタの登録を拒否するような設計になってた。こういうセキュリティの制限を回避してreadonlyなプロパティの働きを置き換えようと思ったら、どうもやはり、XBLを使うしかないようだ。

そもそもなんでoverrideValueがreadonlyなんだよ、なんで書き換え可能なただのフィールドになってないんだよ、って思って来歴を調べてみたら、nsIAutoCompletePopupインターフェースのoverrideValue昔のオートコンプリートの実装におけるgetOverrideValue()メソッドがその祖先で、当時のコードには「こいつの働きを変えたかったらXBLでオーバーライドしろ」ってコメントが書いてあった。今のFirefoxのオートコンプリートの実装にはこのコメントがなかったので、なんでreadonlyになってるんだよという不満しか抱きようがなかった。getXXXとなってたメソッドをプロパティの形に置き換えるなら、確かにそれはreadonlyになるだろう。

でもどうせプロパティに変えたんだったらwritableにしたってよかったはず。ほんとに、何でこんな設計にするんだろう……

拡張機能の標準化の話について思うこと - Oct 20, 2010

かつてIE6が一番先進的なブラウザだった頃は、ブラウザに機能を加える物といったら、「ツールバー」か「コンテキストメニューの追加項目」くらいしかなかった気がする。そもそも、「ブラウザにツールバーを追加できますよ」だけでもずいぶんすごいことであったような気がする。僕がそれ以外を知らなかっただけかも知れないけど。(具体的に僕が「その頃」の代表的なブラウザとして今思い浮かべているのはIE6とNetscape Communicator 4.xです。)

その頃は、MicrosoftとかNetscapeとかがリリースしてるメジャーなブラウザの使い勝手に不満があっても、プログラミングの知識がないフツーの人は、我慢するか、既にある別のブラウザ(iCabとかOperaとか)を探すかしか無かった。そもそもこの時代、ちょっと前までブラウザは4000円とか9000円とかお金払って「買う物」であったから、基本的には「買った物をそのまま使うか、買わないか」という選択肢しかなかったとも言える。

それでも、腕に覚えのある人なら、コアであるレンダリングエンジンにはIEの物を流用して、それ以外のブラウザのUI自体を頑張って全部作り直すということは可能だったようだ。それで出てきたのがDonutだったりSleipnirだったりLunascapeだったりのいわゆるIEコンポーネントブラウザだった。メジャーなブラウザがリリース計画とか顧客とか組織とか色んな都合で足踏みしている間に、個人の開発者あるいは小規模な開発チームであるが故のフットワークの軽さによって、凡庸なメジャー製品では手に入らなかった「痒い所に手が届く使い勝手の良さ」を提供したことで、それらIEコンポーネントブラウザはパワーユーザの支持を得るに至ったのだろう。

IEを使うのなら、できる「機能拡張」はせいぜいツールバーの追加かコンテキストメニューの機能追加くらい。なぜなら、IEが開発者向けに開いていた「ブラウザの個々に機能を追加できますよ」というポイントが限られていたから。(あるいは、もっと色々できたのかもしれないけど、それくらいしかできないという印象が強かった。)それ以上の物が欲しかったら、そういう機能を提供するIEコンポーネントブラウザに乗り換えるしかない。それが、あの頃に取り得た現実的な選択肢の全てだったのだと思う。

僕にとっては、そういう「暗黒時代」はMozillaとの出会いで終わった。当時はまだMozilla Suite(Seamonkey)がメインラインで、バージョンはM16とか0.6とか言われてた頃だったか。当初はCSS2に一番真っ当に対応してたブラウザだったからという理由で使い始めたけど、使い続ける理由はいつの間にか、「一番痒い所に手が届くから」になっていた。

Ben Goodger氏が当時を振り返って語ったエントリにもあるけれど、Mozillaの設計上の特性からくる「拡張性の高さ」はホントにぶっ飛んでた。

Mozilla以前は、
「標準のUIに不満がある? Googleサジェストが使える検索ボックスが欲しい? じゃあ、このツールバーを追加して下さい。ほら、このツールバーの中でならもっと快適に過ごせますよ! Googleサジェストの結果もポップアップされますよ! まあ、このツールバーの世界から一歩でも外に出ると、また今まで通りの世界に逆戻りですけどね。」
「え、このボタンだけ切り離してウィンドウの下の方に置いておきたい? そんなことできるわけないでしょ。この素敵な便利機能は、このツールバーの世界から外には持ち出せませないんですよ。」
「え、専用のツールバーなんかいらないから、本来のアドレスバーから色んな検索エンジンでWeb検索できるようにしてくれって? そりゃ無理ですよ。このツールバーの枠の中の事ならどうとでもできるけど、枠の外は元々作られてた通りにしか動かないんだもの。」
こうだった。ツールバーという細長い箱の中、コンテキストメニューというメニューの中、そういう様式の中でないと何もできなかったっぽかった。

あるいは、こうだった。
「このブラウザに乗り換えたら、こんな便利な機能が使えますよ!」
「え、こっちのブラウザのこの機能が欲しいって? そんなこと言われても、それは別のソフトだし……正直、そんなもん知らんがな。」
「パソコン盗まれてソースコードが失なわれちゃいました! もうメンテナンスできません!」

でもMozillaではそうじゃなかった。
「標準のUIに不満がある? じゃあ、そこをピンポイントで解決しちゃえばいいよ。」
「ボタンはウィンドウの上じゃなくて下の方にあって欲しい? じゃあそうすればいいよ。ほら、ツールバーのボタンをウィンドウの下に移動できるようになった。」
「アドレスバーから色んな検索エンジンで検索できるようにしたい? じゃあそうすればいいよ。ほら、GoogleやAmazonの検索結果がアドレスバーの履歴と一緒に表示されるようになった。」
こうだ。実にシンプルだった。「イラッ」と来たまさにその点を、イメージしていた通りに、一番ストレスのない形で解決できる。ツールバーという細長い四角い枠の中であるとか、たった1人の作者の都合であるとかに、囲い込まれなくてよかった。使いたい機能を使いたいように組み合わせて使えた。

具体的な例をもっと挙げると、例えば、ツリー型タブマルチプルタブハンドラ情報化タブの併用みたいなことができるのかどうか、ってことなんですよ。

タブで開いてるページをツリー表示するポップアップを表示する拡張機能。うん、それは多分便利。
開いてるタブのリストを表示して、任意のアイテムを選択してまとめて操作するポップアップを表示する拡張機能。うん、それも多分便利。
開いてる全てのタブの内容をサムネイルで一覧表示するポップアップを表示する拡張機能。うん、それも多分便利。

で、それを1つにまとめて同時に使えるの? ツリー表示されていて、気が向いたらそれを複数個選択してまとめて閉じられて、それらには常時サムネイルが表示されてる、というソリューションは誰でも得られるの? エンドユーザでも? って事なんですよ。

「ツリー表示してサムネイルも表示して複数選択もできるUI、を提供する1つの拡張機能」があればいい? 「ツリー表示してサムネイルも表示して複数選択もできるUI、を持ったIEコンポーネントブラウザ」があればいい? そういう物がもしあるのならそれを使うのもいいだろうし、作れる能力があるのなら作って全然いいと思う。でも、そういう物が無かったらどうなのか? 誰も作っていなかったら? そして自分でそれを作る知識は無いというのなら? 

また、3つの機能を持った物くらいならともかく、要求事項が4つ5つと増えていったらどうなるか。条件が増えれば増えるほど、既製品で要求を完全に満たす物は見つけにくくなるだろう。妥協が増えてくるだろう。その逆に、個々の要求事項を満たす物を集めてきてそれで1つの物として使えるのなら、何も我慢しなくて済む。

だから僕は、Firefoxを捨てられないんだ。「Operaならあれもできるよ、これもできるよ」って言われても、「Chromeなら爆速だよ」って言われても、「ほうほう、ではこのポップアップパネルの下の端にこれこれこういうボタンを置いておきたいんだけど、そういうことはできるのかね? え、できない? ああそう……それじゃ日々の『イラッ』はなくならないなあ」と思ってしまうんだな。(だからFirefoxが好きなんですよ、っていうのが全く無いとは言い切れないけど、むしろ、他の物もそうだったらいいのに、でも残念ながらそうじゃないから諦めてFirefox使い続けるしかないのか、って思ってる所も結構ある。)

でも、時代は今また「用意された枠の中でならなんでもできますよ、でもそこからは一歩もはみ出せませんよ」の方向に戻ろうとしている。(いや、あの頃に比べたらずっと洗練されたAPIで、できることの幅も広がっているようなのだけれども。)何故なのか。

理由はたくさんあるようだけど、多分一番重要なのは、「みんな、そんなに自由でなくていい」って事なんだろうね。

頑固で融通の利かない馬鹿で順応性が低い僕にとっては、こうだ。「イラッと来たまさにその部分がピンポイントで解決されてくれないと、我慢ならない。ちょっとでも遠回りしないといけないのは、もう嫌。このツールバーの中でならそんな不満は起こりませんよ、なんて言われても、ツールバーなんていらんし。そんなん興味ない。今目の前にあるコイツがどうにかなってくれないと嫌なの。」でも、普通の人は僕なんかよりもっと頭が柔らかくて順応性が高いから、苦にならないんだろう。「こういうとこが不満で、なんとかして欲しいんだけど。え、代わりにこれを使わないといけないの? ふーん、まあ、いいけど。」で受け入れてしまえるのだろう。

(というか多分そもそも「こういうとこが不満で」なんて思わなくて、今ある物でだいたい満足できてしまうんだろう。思い入れも無ければ、一日中それと接するわけでもない、1日1回1時間くらいしかブラウザを操作しない、だからそんな深刻な不満を抱きようがないんじゃあないかな。頭が固いとか柔らかいとか以前に。)

(あと、これは、「普通の人」を揶揄する話ではない。そういう人達の方が環境の変化に柔軟に適応できる能力があるって事で、それは人として素晴らしいことだと僕は思う。こうやりたいと決めたやり方以外だとストレスを感じてしまうとか、そういうどうでもいいことにこだわってしまう性根というのは、人として問題があると思う。)

Jetpackがrebootされる前、まだJavaScriptのファイルいっこで完結してた頃、僕は「JetpackはGreasemonkeyやChromeの拡張機能とAPIのレベルで互換性を設けるべきだ」と強く思っていた。なので今回のOperaの「拡張機能を標準化しよう」っていう話に僕は賛成する。既に、ChromeとSafariの間では既にそういう状況になっていると聞いた気がする。大抵の人がそれで満足できる、ツールバーのボタンなり、Webページ内で自動実行されるスクリプトなり、そういう「どのブラウザでも共通して利用できそうな物」には、互換性があっていいと思う。僕だってひょっとしたら、ユーザになるかもしれないし。OperaやSafariをメインで使ってる人が作った拡張機能の恩恵に僕がFirefoxで与れる、そういうことがあり得るかも知れないし。

ただ、Firefoxと同じくらいになんでもできる環境になってくれない限りは、僕自身は軸足をChromeとかその後に出てくる物とかには移せないんじゃないかなー、と思ってる。些細な「イラッ」に目を瞑らずにストレートにそれを解消することができる、という居心地の良さに、僕はあまりにドップリと浸かりきってしまっているので。あまりに「自分を変えなくていい」事に慣れきってしまっているので。

Jetpack作った - Oct 11, 2010

今のFirefox用アドオンの開発にかかる手間を省いて、インストールやアンインストールの際にFirefoxを再起動しなくても済むようにする、Firefox 4向けの新しいアドオンの仕組みであるところのJetpack(サイトのトップページのスクリーンショット) 最初はGreasemonkeyとuserChrome.jsの合いの子みたいな感じでスタートしてたみたいですが、いつの間にかRebootedになって、SDKを使って開発するという形の物に変わってしまっていました。Rebootedになってからの情報はGomitaさんが色々と記事を書いて下さっています。

Rebooted前に僕もちょっとだけJetpack用にテキストリンククリップボード監視を書き直してみたりしたんですが、Rebootedになってからは全くフォローできていませんでした。

で、この度改めてちょっと本腰入れてJetpack作ってみようと思ったんです。

はい、できました。

(Jetpackの写真)

うん。どこから見てもJetpack。

(Jetpackの写真:裏側)

SDKベースになっても作るのは簡単でした。Jetpack素晴らしいですね。

そういうわけでリアルJetpackです。制作期間は大体1.5週間くらいでしょうか。夏コミの時にふぉくす子コスで手伝ってもらったhknさんがはやぶさで有名秋の『』さん会場で偶然遭遇したそうで、背負い物イイナー!ということで面白そうだから冬までには作ってみようと思っていたのですが、去る10月10日に開催された痛Gふぇすた2010にふぉくす子の参加要請があったため、それに合わせて突貫作業で作ってみました。

芯にペットボトルを使い、先端部分とノズル周りと背負うためのベルトさえ作れば簡単にできるんじゃね? と思ってやってみたんですが、リアル工作なんてものすげー久しぶりだったので少々苦労しました。ちゃんとした設計図を作らないまま現物合わせで切ったり貼ったりしたのであちこち微妙に歪んでいますが、遠目に見たら分からないので気にしないことにします。

制作は先端部分から取りかかりました。芯にしたのはペプシコーラのペットボトルで、口をノズル側にした(今回はやらないけど、いつかチャンスがあったらペットボトルロケット的なギミックを仕込んだバージョンを作る事を想定して、そのようにしています)ので先端側にはペットボトルの尻が来たわけですが、5角形というか星形というかそういう変な形をした尻だったので、先端の断面の形に切った厚紙5枚を組み合わせてガムテープでぐるぐる巻にして大まかな形を作った後、普通の紙粘土で覆って表面を丸っこくしました。

(Jetpackの写真:先端のアップ)

乾燥させて紙ヤスリで表面をなめらかにして色を塗ればそれで十分かなーと思ってたんですが、この紙粘土が乾燥してもメチャメチャ脆くて、塗装中も段ボールに先っぽをぶつけただけでボロッと崩れるとか、掃除機で表面の削りカスを吸い取ろうとしたら芯への食いつきが悪いせいで端の方からベリッとはがれるとか、こいつのせいで手間がだいぶ増した気がします。とにかくこんなに脆いんじゃそのまま使うとヤバイと思ったので、塗装した後で透明ニスを何回も重ね塗りして補強しておきました。ニスを塗る工程は当初は想定してませんでしたが、小さい頃に紙粘土工作をした後に必ずニスを塗らされたのはこういう事だったのだなあと、今更になって当時やった事の意味をを思い知らされました。

あと、形を出した後で思い出しましたが、確かハンズにこういう形の発泡スチロールの塊が売られていた気がしますので、最初からそれを使えばよかったなあと後悔しました。紙粘土は表面だけに使ったといっても、大きさが大きさだったので結局ここだけで500グラム以上になってたみたいですし。軽く作る工夫は大事です。

胴体は元のデザインにあるスリットを開けておいたボール紙をペットボトルに巻き付けただけです。 (Jetpackの写真:胴体のアップ)

ノズル部分は、戦闘機のベクタードスラストノズルみたいなデザインだと思い込んでいたためにその前提でプランを考えていたのですが、胴体のスリットを開口するために元のデザインを確認したら、全然違ってました。でも先すぼまりな形を継ぎ目無しに作るのはボール紙じゃキツいわと思ったので、元デザイン無視でやはりベクタードスラストっぽいデザインを意識した物にしてみました(配色もそれを意識してます)。 (Jetpackの写真:ノズルのアップ) あと、先端を紙粘土にしたことによってすごいトップヘビーになってしまったので、バランスを取るために、外からは見えませんがペットボトルの口の周りに紙粘土を重りとして巻いてあります。これで結局、全体で1kg以上はある感じの重たい装備になってしまいました。

胴体のボール紙の継ぎ目とか先端と胴体の間の所とかをごまかすために細切りのボール紙を巻いて、隙間をホットボンドで埋め、形としては完成しました。

着色は、スプレーで先端とノズルに色を付けた後、先端とノズルをマスキングして胴体のシルバーをスプレーで塗るつもりだったのですが、前述した通り紙粘土部分がメチャメチャ脆くて、これじゃマスキングテープで確実に表面がボロボロはがれるわと思ったので、先に先端(とノズル)だけニスでコーティングすることにしました。2時間以上乾燥→重ね塗り、で2~3重に塗ったので、結構頑丈になったと思います。あと、塗装は缶スプレーだけでいいかなと思ってましたが、実際やってみると赤色は結構下地のアラが目立ってしまいましたので、先にサーフェイサーで灰色一色にしてから赤や茶色を塗りました。胴体は、銀色の隠蔽力の高さに期待して特にそういう事はせず、ボール紙に銀色のスプレーを吹いてニスを塗っただけです。ニスが乾いた後で、ノズルがテカテカ光ってるのは変かなーと思ったので、最後に胴体をマスキングしてノズルの部分だけつや消しクリアーを吹いてあります。

左右の胴体の連結やベルトの固定方法については、当初は何も考えていなかったのですが、いい材料はないかと思ってホームセンターの商品を眺めていたら簡単に曲げられそうな穴あきの金属の板があったので、それを曲げて形を作って左右の部品をネジ留めしてからタッピングビスで胴体に固定することにしました。 (Jetpackの写真:連結部分のアップ)

ベルトは100円ショップで買った物を適当に切って使ってます。しかし実際に背負ってみるとベルトが肩に食い込んで痛かったので、そのうちクッション材(カバンの肩紐にあるようなやつ)を付けたいとは思っています。

表面がガタガタであまり見れたものではありませんが、大きな写真をFlickrに置いてありますふぉくす子が背負っている様子の写真はもえじらブログの方にあります

Firefox 4: jar jar jar - Oct 06, 2010

この間悩まされたばかりのomnijarの話である、Taras’ Blog » Blog Archive » Firefox 4: jar jar jarの勝手翻訳です。分からない所が多かったので創作的意訳が多めですが気にしません。


ファイルを開く処理というものは、システムコールのための小さなオーバーヘッドや、ディスクからのデータの先読みによる大きなオーバーヘッドがある、比較的重たい処理です。データの物理的な配置の状態やディスクの種類によっては、この処理は今時の高速なCPUに対して、複数の異なるファイルそれぞれの全ての断片を先読みするためにディスク上をヘッドが激しく行き来する間、長々と無駄に暇をもてあまさせる事にもなり得ます。

最適化その1:裸のファイルをより少なくする

約2年前、私(訳注:元エントリの著者のTaras Glek)はディスク上にある裸のファイルを収集してjarファイルに詰め込む作業を始めました(例:bug 508421)。また、コードのクリーンアップやmmapへの移行などを通じて、私達はjarファイルの読み込み処理の効率も可能な限り改善しました。そして最終的には、通常の起動時にディスクから読み込まれていた、アプリケーションを構成するデータファイルの全てが、jarファイルの中に格納されるようになりました。しかし残念ながら、私達は4つのjarファイル(toolkit、chrome、そして2つのロケール用jarファイル)に構成ファイルをまとめる所までしか至れませんでした−−何ともマヌケな事ですけれども。またXPCOMの制限により、多数の裸のファイルがまだ、Firefoxのアップデートや拡張機能のインストールの度にディスクから読み込まれる状態となっていました。

最適化その2:全てを統べる1つのjarファイル

最近、Michael Wuがomnijarという滅茶苦茶にヤバい物を解き放ち非常に影響範囲の大きな変更を導入しました。これはAndroid用パッケージ作成での必要に迫られて行われた非常に大きな取り組みです。今や、アプリケーション起動時に必要なデータは常に単一のファイルから読み込まれるようになりました。これはデータの位置の集約化、ファイル走査の手間の短縮、そして待ち時間の短縮に繋がります。複数のファイルを1つに小さくまとめる事の1つの利点としては、OSがディスクからデータを読み込む際に、大抵の場合はアプリケーションが要求したよりも大きな単位で、投機的にディスクからデータを読み込む事も挙げられます。これにより、隣接するファイルの読み込みがより自由に行えるようになります。残念ながら、Firefoxを実際に実行せずにファイルアクセスの順番を予測するための良い方法がなかったため、ここにはさらなる改善の余地があります。

最適化その3:jarファイル内でのファイル配置の最適化

さて、今や全てのデータが1つのファイルの中に置かれましたので、論理的な次のステップは、それらをより賢く格納する事でした。それを行うための唯一の方法は、Firefoxの起動時の処理を分析して、jarファイル内のファイル配置をその結果に基づいて並べ替える事です。残念な事に、jarファイル内の全ての項目を連続的に配置するにあたって、私達はまだ次善の策を取っています。これは、ZIP(jarファイルの実態はZIPファイルです)のインデックスが伝統的にファイルの終端に配置されている事に依っています。Wikipediaの記事にこれを図示した物があります。

先読みの利点を最大限に活かし、ディスクの走査を最小限にするためには、格納されたファイルのインデックスがZIPファイルの先頭に置かれているのが望ましいです。そのため、私は私達のZIPファイル内のデータの配置を、

<項目1><項目2>…<項目N><インデックス><インデックスの終端>

から

<最初に読み込まれる、最後の項目の位置のオフセット値><インデックス><インデックスの終端><項目1><項目2>…<項目N><インデックスの終端>

に変更しました。

ここで私がやったのは、<インデックスの終端>のオフセット値を常に4になるようにした(どうでもいい事に拘るZIPアーカイバはインデックスのオフセットがNULLだとフリーズしてしまう事があるので、これは0にすることはできません)だけです。その際、インデックスは常に前のインデックスの終端に続けて配置されなければならないという仕様を満たすために、私は最初の物と全く同じ2つ目の<インデックスの終端>を加えました。また、私は、過度に用心深いZIPアーカイバによって強制された、どれだけのデータを最初に先読みしておく事ができるかを示す数値を格納するための追加の余白も利用する事にしました。

これによって、最適化されていないomnijarに比べてディスクI/Oの2〜3倍の削減を実現しました。これは裸のファイルをomnijarにすることで20〜100倍以上の高速化が実現できた事の最大の要因です。

私がZIPの仕様を読んでガッカリしたのは、ZIPアーカイバの中にはZIPファイルが仕様が許容しているよりもずっと厳格な形式になっている事を期待している物があるということです。以前のバージョンのFirefoxや、Microsoft WindowsのZIPサポート(訳注:圧縮フォルダ)、WinRAR、UNIXのZIPアーカイバなどは、私の最適化されたjarファイルを受け付けてくれますが、7-Zipや壊れたアンチウィルスソフト(スキャン対象を無闇矢鱈に限定する事はセキュリティ上危険です)はこれらを開く事ができません

豆知識:これは、受け付けるZIPファイルの内容を選り好みするソフトウェアのせいで困らされた最初のケースではありません。例えば、Android標準のAPK読み込み処理は、Android用のパッケージが0バイトの大きさの項目を含んだZIPファイルである場合に、いちいちしつこくそれを警告してきます。これは、APK形式のファイルをWindowsにおける自己解凍形式のEXEファイルのように使う事ができないということです。Michael Wuはこの問題を解決するための独自の読み込み用ライブラリを書いている所です。

最適化その4:さらなるomnijar

omnijarは十分に素晴らしいとはまだ言えないということで、Michael Wuはさらに先に進んで拡張機能をomnijar化しました(訳注:アドオンがXPIのままで認識されるようになった事を述べたエントリ)。ほとんどの拡張機能はXPIから裸のファイルに展開される必要が無くなる事でしょう。これは、拡張機能の作者が上記のような最適化されたjar形式を、Firefoxの起動を高速化するために利用できるという事を意味します。

その他のjarファイルの最適化

起動処理の高速化用のキャッシュをjarに切り替える事によって、私達は最初の起動処理をさらに最適化できるようになることでしょう。私が最適化されたjarファイルに加えた先読み用の情報を実際に利用する事によって、jarファイルのI/Oを半減できる可能性もあります。

元記事に寄せられたコメント

Benによるコメント(2010-09-23 05:32pm)

2点だけ:

1つ目。あなたがどのように言おうと、これらの「最適化された」jarファイルはもはやZIPファイルではありません。仕様は非常に明確で、インデックスはファイルの末尾になくてはなりません。

あなたがやった事に間違った点はありませんが、しかし、それらのファイルをZIPであるかのように偽ろうとした上で、ZIPを扱うアプリケーションがそれらに対して文句を言わないようになる事を望むというのは、良い事ではありません。それよりもあなたは、最適化されたファイルの拡張子を変更することにして、最適化とその解除を手動で行うためのツールを提供した方がよいでしょう。

私は、例えば7-Zipは仕様に対して非常に厳格に設計されているがために、これらのファイル形式をサポートする事はあり得ないだろうと確信しています。

2つ目。私はFirefoxのコールドスタート(訳注:キャッシュ等にファイルが読み込まれていない状態からの起動)が(特に他のブラウザと比べて)遅いということを体感して、少し調べてみる事にしました。新規作成したプロファイルであってもまだ起動は遅かったです。私は、Firefoxは起動時に18個ものDLL(それらは全て、Firefox/Minefieldのインストール先ディレクトリに置かれています)を読み込んでいるという事に気がつきました。これは非常に良くない事で、ファイルの数の問題だけでなく、Windowsではセキュリティ対策ソフト(既定の状態であればWindows Defender、大抵の場合は何らかのアンチウィルスソフト)においての問題もあります。

私のマシン上では、ファイルのスキャンは1つあたりだいたい50ミリ秒を要していますが、この処理時間はファイルサイズには影響を受けません。Firefoxの場合、起動に数秒を要してしまいます。セキュリティ対策のソフトが大抵の場合は必要が生じた際の動的なスキャンの結果をキャッシュしていて、再起動されるか定義ファイルが更新されるまでの間は再スキャンが行われないために、この問題がウォームスタート(訳注:ファイルがキャッシュ等に読み込まれた状態からの起動)の場合には起こらないという事には注意して下さい。

いくつかの他のブラウザは、起動時にDLLを2つだけ読み込んでいて、他は必要が生じた時(動画の再生、WebGLを使う場合など)に動的に読み込んでいます。これはFirefoxの場合よりもずっといい具合に動作しているように思われます。

検索してみた所、私はLinuxについてのこの件に対するバグをいくつか見つけましたが、Windowsについてのバグは見つかりませんでした。それらが1つの大きなDLL(xul.dll)とそれ以外の小さなDLL(それらは無条件に読み込まれる)となっているので、全てを1つのファイルにまとめるのは理にかなっていると思います。

Taras Glekによるコメント(2010-09-24 09:06am)

Ben、あなたが注目した多数のDLLを提供している点についてはあなたの指摘は的を射ています。それについてのバグは https://bugzilla.mozilla.org/show_bug.cgi?id=561842 です。残念ながら、私達はこの作業をFirefox 4のリリースには間に合わせられませんので、後のリリース版で反映される事でしょう。

私はアンチウィルスソフトが起動時の処理に与える影響についても、より詳しい情報を得たいです。

ワークライフバランスの前提にある幸福観 - Oct 02, 2010

1つ前の話から一転してネガティブな話。

1つ前の話もそうだし、これらのエントリを見ても「うんうんそうだよなあ」とか「そうあるべきだよなあ」とか思うんだけど、これって何を以て「幸福」と考えるか次第で全然変わるんだよなあとも思う。

少なくとも今の僕は、メキシコの漁師とMBAホルダーのアメリカ人旅行者のジョークではメキシコの漁師の方に肩入れする。するんだけど、でも、このジョークで省略された事、「楽しい職場」の話で意図的に無視されている事についてちょっと考えてしまった。

メキシコの漁師も、楽しい職場で働く人も、「日々の収入はそんなに多くなくてもいい、自分が食って行ければそれで十分だ。だから毎日を楽しく暮らしたい。」という事だと思う。でもその前提には「毎日を楽しく暮らすためには、毎日働き続けなければならない」という事がある。もっと言うと、「今まで通りに働けなくなったら一気に幸せが失われる、そういうリスクを負わなくてはならない」という事だ。

例えば僕の場合、労働力を提供できなくなると、会社にはいられなくなるだろう。ブラック企業だろうがホワイト企業だろうが、労働力を提供することで対価を受け取るという形の働き方をしている限り、これは変わらない。交通事故で両腕を失ったら? 筋ジストロフィーとかそういう病気になったら? あるいはもっと単純に、歳を取って新しい物を覚えられなくなって受託開発でやっていけなくなってしまったら?

株の自動的な売買によって、自分は寝ててもどんどん金が増えていくとか、自分は意志決定だけすればよくてそれ以外の雑務は全部平社員に任せるとか、そういう「働かなくても金が手に入る」仕組みを構築する(「金持ち父さん」にはそういう話があったと思う)と、そういうリスクから解放される。逆に言うと、そういうリスクから解放されたければ、労働力を金に換える以外の方法で金を手に入れる手段を確立するしかない。黙々と手を動かしていればいいというような頭を使わない人間でいては、その域に達することはできない。大学で学ぶなり何なりして必死で高度な知識を身に付けないといけないかもしれないし、あるいは、持って生まれた頭の良さというものがないといけないのかもしれない。

そういう才能がない人は、前述のリスクを避けられない。才能を持って生まれることができなかった人、高度な知識を身に付けるための努力ができそうにない・そんなの無理だって言う人は、賭けに出る勇気もない人は、もう「諦める」しかない……だから「不労所得でウハウハなんて生活はどうせ自分には手に入らないのだから、スッパリ諦めて、せめて毎日を楽しく生きられるようにしよう。今と同じように働ける間くらいは。」という「身の程をわきまえた幸福観」が、ワークライフバランスとか楽しい(しかしそんなには儲からない)職場環境とかそういうものが支持される理由なのかな、と思った。

職場環境 - Oct 02, 2010

最近、僕は「自分って幸せだなあ」と思うことが多いです。このエントリでは、仕事の面におけるその理由を考えてみたいと思います。

さて、僕は今の職場環境が気に入っている。給与面で自分は不満を感じていないし、空気も好きだ。要するに幸せだと、自分の主観では思ってる。

須藤さん(現社長)は就活?の時にGoogleやはてなを見学して、ブースに区切られた上でヘッドホンまでしてるような環境を見て「こういう所では働きたくないなあ」と思ったらしい。

僕は最初はその話に正直ピンと来なかったんだけど、分からない事や知らない事で困った時に「教えて」と気軽に訊きあったり、変数名の付け方に困った時や機能の切り分け方・設計方針に迷った時に「どっちがイイと思います?」とアドバイスを求めたり、作業内容と全然関係無いどうでもいい話(本当にどうでもいい話)をしたり、というのが当たり前(会議の時だけそうするんじゃなくて、常時そう。だから栃木にオフィスを開設するにあたっても、テレビ会議のシステムを常時動かしっぱなしにしておいて、画面の向こうに向かって「ちょっと、池添さーん」と呼びかけられるようにしておこう、という風な話になった。)の今の職場環境に慣れてくると(東京に来てから結構長い間お客さんの所に半常駐だった時期があって、クリアコードの方にずっといるようになったのは途中からだった。半常駐だった所は個々人のブースが別れていたし、ヘッドホンしてる人もいて、どちらかというと前述のGoogleに近い感じだったんじゃないかなと思う)、須藤さんの言っていたことがどういう事だったのかが、なんとなくこういう事なのかなあ、という感じで分かってきたような気がする。

端的に言うと、今の自分が「個々人の席がブースで区切られてて、ヘッドホンで耳を塞いでる人もいたりして」という環境に放り込まれて「仕事をしろ」と言われた時に、やっていける自信がない。精神的負荷で潰れるとかじゃなくて(それもあるかもしれないけど)、自分にはそれでは何もできないんじゃないかって思う。IP unreachableな環境に置かれた時に、GoogleもWikipediaもMDNMXRも何も無い環境では右も左も分からないよ!という風な感じで。

須藤さんや池添さんはよく、「自分達は間違いをどうしても犯してしまう残念な人達なんだから、間違いが起こったり、一人ではうまく行かなかったりする前提でいた方がいい」という感じの事を言っている。だから、リポジトリへのコミットの単位は短くするし、自動テストも書く。1人だと煮詰まるから、些細な事でも相談する。2人でも煮詰まるから、相談してる人同士の横から割り込んで意見を言ったり言われたりもする。僕はずっと、そういう環境で自分の残念な部分を他の人に大いに補ってもらいながら作業していて、そのおかげで自分の能力以上の成果(=会社にとっての売り上げ)が出てきたと思っているから、今更1人でやれと言われても心細くて仕方がない。

Googleのような職場環境は「他人に頼るより自分でやった方が早い」とか「他人と関わらずに1人でやった方が能率が上がる」とかそういうタイプの人でなければ、少なくとも、自分がそういうタイプだと自信を持っている人でなければ生きていけない環境なんじゃないのかなーと思う。学者タイプとか研究者タイプとか。誰にも邪魔されずに作業することで最高のパフォーマンスを発揮して素晴らしい製品を生み出す、という人のための環境なんじゃないのかと思う。

翻って自分は、残念な人間だ。物覚えは悪いし知らないことだらけだし頭の回転も遅いし発想力もない。だから独創的な製品を生み出すことはできないと思う。できるのは、自分の中から湧き出てくる物でお金を儲けることではなく、自分が知ってる複数の世界の間の非対称性を埋めることで労働の対価を得る事だけだと思ってる。

この辺の話を見ても、僕は(この1点だけを見たら)elm200氏よりも小飼弾氏の話の方にシンパシーを感じる。

自分が今いる環境に順応した結果としてそう思うようになって、自分が今いる環境に対して問答無用で快感を感じるように自分の精神構造が自己調整された結果だ、という事も考えられるんだけど、とりあえず今は、「自分は元々そういう性質の人間だった」「それにピッタリ上手くハマる環境に収まることができた」という事だと考えておこうと思う。そう考えていた方が自分の主観的には幸せでいられるので。

あ。僕がこう思ってるからって、弊社の他の人がどう思ってるかは分かりませんよ。当たり前ですけど。

あと、このエントリの主題は僕1人のトピックとしては「僕は今いる環境が好きです、Googleはイヤです」だけど、一般化すると「人は自分に合った環境にいることが幸せなのだ、世間で素晴らしいとされている環境が誰にとってもフィットするというわけではないのだ」という話だと僕は思っております。

デフォルメが下手なのは、見る目が無いって事なんだよね、何事に対しても。 - Oct 02, 2010

ちびキャラっていうんですか? なんて言うのが妥当なんだろう、まあ、デフォルメされたキャラクターのこと。

4コママンガとか描く時って、コマが小さいじゃないすか。だからリアルな頭身のキャラクターだと描きにくい。デフォルメされたキャラクターにせざるを得なくなる。商品のPOPに描く時もそんな感じ。だけどそういう時の自分の絵が嫌いで嫌いで仕方ない。そういう時のデフォルメされたキャラクターをかわいらしく描ける人が羨ましくて仕方がない。昔から。

この2つを見て瞬間的に、R-Styleの方には嫌悪感を覚えた。ねんぷちの方は素直に「可愛いなあ」と思うのに。それは何故なんだろう、という事を考えたんだけど、なんとなく上記の話による同族嫌悪なんじゃないかなあと思った。

R-Styleの商品写真の唯(センターで黒いタイツはいてるキャラ)の脚がエロいと思うんですよ。僕がデフォルメされたキャラクターを描こうとしてもやっぱり脚をエロく描いてしまうと思うんですよ。エロい脚を描こうと思うとこのくらいの頭身が限界になるんじゃないかと思う。少なくとも僕の表現力ではそう。これ以上頭身が下がった状態で、僕にできる表現で脚をエロくすると、多分すごく変になる。だから頭身をこれ以上下げられない。

じゃあエロくしなきゃイイじゃん、って話ですよ。特定の特徴を強調してそれ以外の情報を省くのが「デフォルメ」なんだから、「かわいさ」を強調したいならそれ以外は省けばいいわけですよ。理屈ではそう。でも僕にはそれができないのですよ。

「かわいいもの」を描かなければいけないのに、「かわいさ」以外の要素をそぎ落とさなければならないのに、エロいものへの欲求を捨てることができない。その結果、「かわいい」以外の余計な物である「エロい」の臭いをプンプン漂わせたイヤな絵になってしまう。デフォルメの過程で「可愛い」以外のディティールを省こうとしてそこに「エロさ」が残ってしまったから、「かわいい」だけでなく「エロい」まで無駄に強調されてしまう。なんとグロテスクなんだろう。僕は僕が描いたデフォルメ絵を見るとそう感じずにはいられない。

思えば僕は昔から、余計な物を省くのが苦手だった。特徴を抜き出してそれ以外のディティールを省くのがコツである所の「似顔絵」というジャンルも、陰影を強調して影の中のディティールを真っ黒に塗りつぶしてしまうような絵も、昔から僕にはできていなかった。

絵以外でもそうだ。部屋の中には「今は使ってないけど、いつか使うかもしれないし……」という物がどんどん増えていくし、プログラムを作ればあれもこれもと詰め込みたがるし、味噌汁を作ればあれもこれもと野菜をブチ込みたがる。取捨選択ができないんだ。何が大事で何が大事でないのかが分からないんだ。物事の要点がどこにあるかが分かってないんだ。審美眼のない、焦点がぼやけた、とてもつまらない人間だと自分で思う。

センスが無いんだよね。一言で言うと。

僕がアサノさんのことを「すげえなあ」と思うのも、このへんが大きな理由なんじゃないかなと思う。

Page 23/240: « 19 20 21 22 23 24 25 26 27 »

Powered by blosxom 2.0 + starter kit
Home

カテゴリ一覧

過去の記事

1999.2~2005.8

最近のつぶやき

オススメ

Mozilla Firefox ブラウザ無料ダウンロード