たまに18歳未満の人や心臓の弱い人にはお勧めできない情報が含まれることもあるかもしれない、甘くなくて酸っぱくてしょっぱいチラシの裏。RSSによる簡単な更新情報を利用したりすると、ハッピーになるかも知れませんしそうでないかも知れません。
の動向はもえじら組ブログで。
宣伝。日経LinuxにてLinuxの基礎?を紹介する漫画「シス管系女子」を連載させていただいています。 以下の特設サイトにて、単行本まんがでわかるLinux シス管系女子の試し読みが可能!
There is the English version of this article.
2ペインブックマークをFirefox 57以降に対応して欲しいという要望を頂くのですが、残念ながら結論を先に言えば、僕の手による2ペインブックマークのWebExtensions移植はまず行われないと思って頂く他ありません。同様に、他にもいくつかのアドオンについて僕の手による移植は期待できない状況です。
以下、2ペインブックマークの場合を例にとって、何故僕の手による移植が期待できないかを説明します。
Firefoxの内部に食い込む従来型アドオンでは、そのような仕組みならではの特徴として、「Firefox本体が使っている仕組みを(APIとして整備されていないものでも)勝手に流用できる」というメリットがありました。
2ペインブックマークは元々、その特徴を最大限に活用して開発されたアドオンでした。 実際、Firefox本体のブックマークツリーのためのコードをほぼそのまま流用し、そこに「フォルダだけ表示するための絞り込み」と「選択されたフォルダの中身だけを表示するための絞り込み」という一手間を加えることによって、それ以外の事をまったくしなくても最小限の労力で実現できる、という背景があったことから成立していました。 というか、「簡単にできるのならやってみよう」というのが動機で作り始めたと言っても過言ではないです。
他方、WebExtensionsではそのような事はできません。ブックマークの列挙、表示、ドラッグ&ドロップ時の動作(ブックマークのツリー上に何かがドラッグ&ドロップされた時の対応も含む)、右クリックされた時のメニューそのもの、その中身となる各種のコマンド、などなど、ブックマークに関わるすべてをゼロから作り上げなくてはなりません。 つまり、実質的には「ブックマークパネルを再実装する」という事になります。これは大変な労力です。
(ちなみに、そういうわけなので、既にWebExtensions移植済みのツリー型タブのバージョン2.0以降も、Firefoxのタブバーに等しい物を、そこで表示されるコンテキストメニューやそれに関わるAPIも含めて、ひたすら愚直に再実装しているという事になります。
上述したとおり、2ペインブックマークは「簡単にできるのならやろう」という動機で始めたと言っていいプロジェクトです。 簡単にはできない事が明白である以上、最大の動機がそこにはありません。 それでもなお僕がアドオンのWebExtensions版を開発するとしたら、それ以外の動機が必要です。
そもそも漫画の作業のためにプライベートの時間をあまり割けない状況下で、それを押してでもやる動機が無い以上、僕の手による移植が行われることはまず期待できない、というのが現状での結論ということになります。
今の所、僕が手がけたアドオンの中でまだWebExtensionsになっていないもののうち、自分自身が強く依存していた物は、以下の通りです。
すみませんが、これら以外の物については、必要としていて作る動機がある方に後継版開発の希望を託したいと思っています。
Firefox 57で従来型のアドオンが使えなくなるという事で進めているアドオンのWebExtensions移行作業ですが、ツリー型タブ、マルチプルタブハンドラに続いて、テキストリンクもWebExtensionsに移行しました。移行後の最初のバージョンは6.0.0で、そこから若干の修正を施した最新版は6.0.1となっています。
テキストリンクは、テストケースの各種の例のようにWebページ中に普通のテキストとして書かれたURI文字列を、ダブルクリックするだけでリンクのように読み込めるようにするという物です。最盛期には10万を超えるユーザーに使われていた事もあった、僕がMozilla Add-onsに登録していたアドオンの中では統計上最もユーザー数の多「かった」アドオンです。
個人的にもこれが無いとイラッとする場面が結構あって地味に依存度が高かったので、いずれWebExtensions移行はするつもりでいたのですが、先月末にMozilla Corporationのアドオンコミュニティマネージャーの方(昨年のMozLondonにアテンドしてくださった方)から「そろそろFirefox 57リリースが近付いてるけど、テキストリンクの移行はどんな感じ?(大意)」というメールを頂いてしまい、顔を合わせた事のある人から直々にせっつかれてはやらないわけにはいくまい……と、予定を繰り上げて移行に着手したのでした。
メールをもらってからリリースまでに要したのがちょうど1週間で、これまでの2例の難航度合いに比べるとびっくりするぐらいあっさり完了した感があります。数を重ねてきてだんだん「WebExtensionsのやり方」に慣れてきたということでしょうか。
実を言うと、テキストリンクは1年ちょっと前にWebExtensions移行に挑戦してみた事があったのですが、その時は途中ですっかり投げ出してしまっていたのでした。今回は、この時の成果物をまるっきり無視しての再挑戦での成功と相成りました。
1回挫折した物が仕切り直して成功したという典型的な例なので、ここでは「何故前回は失敗し、今回は成功したか」という観点から語ってみようと思います。
過去の挑戦時の方針は、端的に言えば「最低限の手直しでの移行」ということになります。
テキストリンクは初版が2004年という非常に歴史の古いアドオンで、Firefoxの仕様変更に対し、その都度手直しでの追従を繰り返してきました。最初のバージョンからバージョン4までの間、テキストリンクはすべての処理が特権領域内で完結する仕様でした。バージョン5でのe10s(マルチプロセス)への対応にあたって、DOM RangeなどのWebページの生のDOMに触らないといけない「コンテントプロセス側で実行しなくてはならない処理」を分割するという変更を行いましたが、本質的な設計はずっと変化していなかったと言えます。
その延長線上にあったこの時の進め方は、WebExtensions化の作業用にブランチを切って、元のコードを「バックグラウンドスクリプト用」や「コンテントスクリプト用」といったフォルダに移動し、XPCOMやXULに依存していた部分を除去していく形でそれぞれのソースの中身を破壊的に変更していく、というものでした。
旧版テキストリンクは、選択範囲(※カーソルも選択範囲の一種なのです)からのURI検出や、ユーザーの操作からタブで開くかウィンドウで開くかといった判断を行う部分など、主要な処理のほとんどがコンテントプロセス側で動作する設計でした。chromeプロセス側は、コンテントプロセスからの指示に従って実際にタブやウィンドウを開くだけという感じです。
また、それとは別にコンテキストメニュー周りの実装がchromeプロセス側にあり、こちらはユーザーがコンテキストメニューを開いたタイミングで処理を開始して、コンテントプロセスに処理を依頼してはその結果を受け取って……という事を繰り返すようになっていました。
これをそっくりそのままWebExtensionsに持っていこうとすると、主要な処理はすべてコンテントスクリプトに移植することになります。しかし、WebExtensionsではコンテントスクリプトでできる事の範囲が大きく制限されています。そこで「コンテントスクリプトではこの機能が動かないのでバックグラウンドスクリプトに移す」という事をその都度やっていると、キリが無い上に、場当たり的な切り貼りの繰り返しでコードはどんどんカオスになっていきます。
また、従来のアドオンでの「コンテントプロセスで動作するスクリプト」とWebExtensionsの「コンテントスクリプト」には大きな違いがあります。それは、従来のコンテントプロセス用スクリプトは「1つのプロセスにつき1つのインスタンスが作られる」のに対し、コンテントスクリプトはタブ内のフレームの数だけインスタンスが作られるという点です。プロセスの数だけインスタンスが増えるという時点でいかがな物かという感じですが、フレームの数だけ増えるとなると、さすがに主要な機能をそこで動かすのは非効率的です。
このほか、コンテキストメニュー項目の動的な更新についての知見がなかったために、選択範囲からのURI文字列の検出結果を受けてメニュー項目を制御するやり方が分からなかった事や、XPCOMとXULがあることを前提として書かれたコードを総点検してXPCOMフリーに書き直すにあたって、代替手段が見つからなかった処理がいくつかあった(WebExtensionsでも最新のWeb技術でも機能が提供されていない部分があった)事など、数々の困難に嫌気がさし、また「シス管系女子」の連載の〆切が迫っていた事も相まって、道半ばで移行作業を放棄してしまったのでした。
TSTの移行に際しての振り返りで「直接Firefoxの中身をいじくり回していたレガシーなアドオンを『若干手直ししてFirefox 57でも使えるようにする』ということは不可能」と書きましたが、この時の失敗はまさにこれが原因であったと総括できます。例えて言うなら、従来バージョンから持ち越した既存の実装という大荷物を背負って道を歩いていて、道のど真ん中にある車止めに荷物が引っかかってしまい先に進めず、「こんなもんどけてやる!」とばかりに軽く考えて邪魔な車止めを取り除こうとして、でも地面にしっかりコンクリートで固定されていて蹴っても叩いても動きやしなくて、その埒の明かなさと背負っている荷物の重みとのダブルパンチで心が折れてしまった……という感じでしょうか。
今回の再挑戦では、TSTやMTHのWebExtensions移行で成功をもたらした「旧版の動作をリファレンスとして、同等のユーザー体験をもたらす新しいWebExtensionsベースのアドオンを新規に開発する(つもりで臨む)」というやり方を取りました。具体的には以下の順で作業を進めました。
この説明にも表れている通り、今バージョンのほとんどのコードはスクラッチで書いた物で、旧版からコードを引き継いだのは「文字列の中からURIらしき部分を検出する」部分だけです。以下、一般的な話は省略してテキストリンクに固有の事情だった部分に絞って詳しく述べます。
URI文字列を検出するにあたっては、window.getSelection()
で取得できるRangeのtoString()
の結果ではなく、「ページ中で目に見えているとおりのテキスト」を対象にマッチングを行わなくてはいけません。というのも、RangeのtoString()
はその範囲にあるテキストノードの内容を単純に連結した結果を返す物なので、親要素が非表示であるテキストノードがある場合や、CSSのdisplay:block
などで見た目上改行されているだけの部分がある場合に、「見た目上は改行されているように見えるのにデータ上は改行が存在しないので、複数の行が連結されて見える(そのためURI文字列の検出結果がおかしくなる)」という事が起こるからです。
旧版では、Webページをプレーンテキスト形式で保存する場面や、ThunderbirdでHTMLメールとして編集された本文からプレーンテキストの本文を生成する場面などで使われるnsDocumentEncoderというXPCOMコンポーネント(@mozilla.org/layout/documentEncoder;1?type=text/plain
)を使ってこれを一発で行えていたのですが、WebExtensionsでは当然使えません。相当する機能を提供して欲しいというbugはずいぶん前に立てたのですが、今に至るまで具体的な実装はまだなされていないままなので、諦めて自力で実装してみました。
詳しい事は当該処理のソースを見てもらうのが一番早いのですが、簡単にいうと、DOM2 TraversalのTreeWalkerを使って泥臭い事をやっています。TreeWalkerはnextNode()
とpreviousNode()
を使うとDOMツリー上の全ノードをツリー構造を無視して文書順で参照するイテレータとして使えるので、CSSのセレクタやXPathでは条件にできない生のDOMの情報を条件とした絞り込みを行っています。具体的には、まずNodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT
でざっくりテキストノードと要素ノードに絞り込んで、さらにそのノードの祖先に非表示の要素ノードがないかをwindow.getComputedStyle()
で順にチェックして、確かに可視状態だと確認できたノードだけを取り出しています。その後、テキストノードであればnodeVaue
を、要素ノードでdisplay:inline
以外の物があれば適宜改行文字を「表示されているテキスト」として取り出しています。
以上のようなやり方で、一応実用に耐える精度で「見た目通りのテキストを抽出する」を実現できたのですが、想像の及んでいなかったエッジケースなどで想定外の結果になる可能性は依然としてありそうな気がしています。nsDocumentEncoder相当の機能が実現されるまでは、まだまだ悩みは尽きない感じです。
与えられた文字列からURIを検出する処理は、今回の移行で唯一、旧バージョンからほとんどそのままコードを引き継いだ箇所です。
この処理は、データ量にして最終的に完成したWebExtensions版テキストリンクの全体の1/3を占める巨大なモジュールなのですが、やっている事は至って単純で、「相対パスも許容するのか?」「全角英数字も許容するのか?」等の条件に基づいてURIらしき文字列にマッチする正規表現を組み立てるだけの物です。相対パスを絶対パスに解決する部分などでXPCOMコンポーネントの機能を使っている部分はありましたが、全体の中ではそういった箇所はごく一部に限られており、ほとんどは単純な文字列処理だけで構成されていました。
また、元々自動テストを容易にするためにモジュール間の結合を弱めていた結果、機能を使うのに必要なパラメータはほとんどすべて外部から与えられるようになっており、旧テキストリンクの実装の中ではここだけ突出して浮いているようにも感じられるほどでした。
そういう事情があったため、このモジュールについてはほとんど苦労する事なくほぼそのままの形でWebExtensions版に組み込む事ができました。
旧版テキストリンクでコンテントプロセス側に大部分の処理があったのは、「URI文字列として検出した部分を新しい選択範囲にする」という挙動を実現したかったからでした。これをやるには、Rangeを対象に文字列を検索してヒット箇所をRangeで返すというAPIが不可欠です。
旧版ではnsFindというXPCOMコンポーネント(@mozilla.org/embedcomp/rangefind;1
)を使ってこれを実現していましたが、当然ですがこれはWebExtensionsでは使えません。また、W3Cで提案されていたらしいRangeFinderというAPIが実装されていればそれで代替できたのですが、こちらは残念ながら未実装です。という具合で代わりの手段がなかったという事が、過去の移行失敗時に移行を断念した理由の1つでもありました。
幸い、最近になってWebExtensionsにbrowser.find
というAPIが追加され、Firefox 57ではRangeFinder的な事ができるようになっています。なので今回はこれを使ってみる事にしました。
RangeFinderを使う時にネックになるのが、DOM Rangeの取り扱いです。コンテントスクリプトとバックグラウンドスクリプトの間ではJSON文字列に変換できるデータしか交換できないのですが、browser.find
はコンテントスクリプトでは動作しないためバックグラウンドスクリプトで呼び出す必要があり、しかし選択範囲の操作はコンテントスクリプト側でやらなくてはならない……ということで、どうやってDOM Rangeの情報を双方の間で受け渡すかが問題となります。
この事について何かヒントはないかとbrowser.find.find()
の説明を読み進めてみた所、まさにこの通りの事をやる例が載っていました。このAPIはrangeData
という形式で検索結果のRangeをシリアライズして返すようになっており、その情報に基づいてコンテントスクリプト側でRangeを組み立てれば良いようです。DOM Rangeをシリアライズして受け渡す事自体は容易に考えつくものの、どういう考え方でシリアライズするかという事についてはいろいろな考え方が可能であったため、自分で考えていたらそれだけでまた時間がかかってしまっていたでしょう。「既に動いている実装があるのなら、それとフォーマットを揃える」という具合に考える手間を省けたのは助かりました。
ただ、実際にbrowser.find.find()
を使ってみるとメチャクチャ遅いです。それもそのはず、このAPIは検索対象の範囲をRangeで絞り込む事ができなくて、実行すると必ずページ全体を対象に検索し、しかもすべてのヒット箇所を列挙してくるのです。検出対象のURIの数が増えれば増えるほど実行回数が増え、ページが長くなればなるほど1回あたりの処理時間が増えるという感じで、テストケースのページ全体からURIとしてマッチした箇所をRandeで取り出すのにトータルで10秒とかそのくらいかかってしまいました。なので最終的には、バージョン6.0.1の時点では「選択範囲が変化したらまずbrowser.find.find()
無しでURI文字列の検出だけを行い、それらを開くとかコピーするとかの操作が行われた時点で初めてbrowser.find.find()
を実行してRangeを取り出す」という風にして、日常的な操作であるテキストの範囲選択とコンテキストメニューの操作に悪影響が出ないようにしています。
Firefoxの各種メニューに項目を追加するためのAPIであるbrowser.menus
(browser.contextMenus
)では、menus.ContextType
のいずれかを伴って定義したメニュー項目については、その指定にマッチする場面でのみ表示されるようになります。その中にselection
というコンテキストもあり、テキストリンクの「選択範囲内のURIを待て馬手開く」系の機能はそのようにして登録しています。
しかし、ここに1つ問題があります。このコンテキストでは「テキストを範囲選択しているかどうか」しか考慮されず、「その中にどういう内容が含まれているか」までを判断材料とする事ができないのです。
テキストリンクは選択範囲のURI文字列を開く物ですから、選択範囲にURIらしき文字列が無い時にまでメニュー項目が表示されるのは混乱の元です。そこで旧版ではコンテキストメニューが開かれる瞬間に発火するpopupshowing
イベントを検知してメニュー項目の表示・非表示を切り替えていたのですが(これ自体はXULで作られたアドオンの一般的な作法です)、他方、WebExtensionsのbrowser.menus
で監視できるイベントには「メニューが開かれた時」に発火されるイベントがありません。これじゃあ動的にメニューの表示・非表示を切り替えられないじゃないか!ということで、これも過去の移行失敗時の躓きポイントの1つとなっていました。
現時点に至るまでpopupshowing
を代替できるイベント型はまだ実装されていないままなのですが、この回避策はTSTやMTHのWebExtensions移行を進める中で知らず知らずのうちに気が付いていました。要するに、「コンテキストメニューが表示されようとしているその時にメニューを更新する」のではなく、「コンテキストメニューの内容に影響を与える変化が起こったまさにその時に先行してメニュー項目を変化させておく(メニューが開かれる時には、既に定義済みのメニュー項目が表示されるだけになる)」という事なのです。その後実際にコンテキストメニューが開かれなければこの時の処理はまるっきり無駄になってしまいますが、これ以外に方法がない以上は仕方ありません。
WebExtensions版テキストリンクでもこの方針に則って、「selectionchange
イベントをコンテントスクリプトで監視し、変化があったらその時点で選択範囲からのURI文字列の検出を開始する指示をバックグラウンドスクリプトに送る」→「バックグラウンドスクリプトでコンテキストメニューの内容を更新する」という事を行うようにしました。バージョン6.0.0の時点では前述のbrowser.find.find()
がメチャクチャ遅いという問題に引きずられて、範囲選択から数秒待たないとコンテキストメニューの内容が更新されないという状況でしたが、バージョン6.0.1で範囲選択時のURI検出にはbrowser.find.find()
をバイパスした簡易的な処理を使うようにした結果、概ね一瞬でメニューを更新できるようになり、実用上ほとんどの場合では「しばらくお待ち下さい」的なメッセージを目にする事はなくなりました。
この件を通じて、コンテキストメニューでAPIで用意されているコンテキスト以上にきめ細かい判断を行いたい場合に、WebExtensionsでのベストプラクティスはレガシーなXULアドオンでのベストプラクティスとはまったく異なるのだ、という事をまざまざと思い知らされたのでした。
旧版テキストリンクでは、<textarea>
などのテキスト入力欄についてもXPCOMコンポーネントの機能を経由して内部的なDOMツリーに触っていました。これは、上記の「検出したURIの箇所を新しい選択範囲にする」という挙動を実現したかったからです。しかしWebExtensionsではその方法が使えず、テキスト入力欄内部のDOMツリーには触れません。
じゃあどうすればいいのかという話なのですが、これについては「無理なものは無理」という事で、テキスト入力欄の選択範囲はその要素ノードのselectionStart
/selectionEnd
/setSelectionRange()
を介して触れる範囲以上の事はしない事にしました。
移行に失敗した時の考え方だと、こういう時も何か対策はないかと手を尽くして、それでも機能が見つからなくて仕方なくBugを立ててそれが解決されるのを待つ、という事になっていたでしょうが、今回は「完全でなくても今できる範囲でできる事だけをする」という方針だったため、この点はリリースをブロックする要因にはなりませんでした。
はじめからやり直したい症候群や、それに類する言葉を見かける事があります。プログラミングの世界においても、メジャー製品の大規模アップデートで「ここらで一区切り付けて、最初から作り直してもっとスッキリした設計にしよう」みたいな事をやろうとして、収拾がつかなくなり失敗に終わってしまい、最終的に旧版からの小規模な修正のみに留めるしかなかった……みたいな事はたまにあります。そういった事例をいくつか見聞きして、また自分自身もそういった無謀な挑戦をしようとして挫折するという経験を何度かした結果、「スクラップ&ビルドですべてが上手くいくようになるというのは甘い幻想で、実際には地道な改良をコツコツ続けていくしか無い」という教訓が、自分の中である種の呪いのように刻み込まれていました。
しかし実際には、その「教訓」に従って進めようとした前回の移行は失敗に終わり、大部分でスクラッチに近いレベルでの作り直しとなった今回の移行の方が成功するという皮肉な結果となりました。ただし、今回スクラッチせず引き継いだ部分まで作り直していたら、この移行は再び失敗に終わっていた事でしょう。
今まさに自分が直面している問題がどちらのケースなのか、を適切に見極めるのは難しい事です。考える事を放棄して当て推量で雑な判断をすれば、痛い目を見ることになるのは自分自身です。確実な成功に繋げるためには、そこで使おうとしている・使わなければならない技術の特性と限界、現行技術とのギャップの大きさ、取り組んでいる問題の複雑さなど、様々な要因を考慮に入れた総合的な判断を、プログラム全体やモジュール単位で下す必要がある、という当たり前といえば当たり前の事を、自分は今回の移行を通じて実感した次第です。
去る2017年10月22日、東京・秋葉原UDXにて開催された技術同人誌オンリーイベント技術書典3に、企業サークル「シス管系女子会」として参加してきました。
シス管系女子の草の根的な営業活動とファンサービス、あと〆切を設けることで何か新作を作るモチベーションにするという目的での参加でしたが、結果のほどを記しておこうと思います。なお、技術書典、技術書典2の結果は過去記事をご参照下さい。
今回の数字は以下の通りでした。
ポスター等は前回の使い回しなので、今回新たにかかった費用はイベント参加費(企業扱い)と新刊コピー本の費用くらいです。
当日は台風直撃かつ衆議院議員選挙とも重なるという、前回・前々回を上回る悪条件でしたが、主催者発表によると来場者数は2700人ほどだったとのことで、来場者数に対するムックの販売実績としては前回を上回る比率となったと言えます。
前回の技術書典2では積極的に声かけを行い、サンプル代わりのリーフレットをチラシのように積極的にばらまいていましたが、今回はそこまでの積極的な声かけはせず、スペース前で足を止めて下さった方に「よかったらこちら無料なのでどうぞお持ち帰り下さい」と勧める程度に留めました。これは、リーフレットを増産していなかったためばらまいていると足りなくなると思ったのと、技術書典2までに参加した人にまた配ってもウザイだけだろうと思ったのとが理由です。
新刊が間に合うかどうかすら危うかったので事前のアピールをほとんどしておらず、会場内でもほとんどずっと座ったままだったので、数字は前回からかなり後退するのではと考えていたのですが、商業出版物と新刊の頒布数的には全然そんなことありませんでした(コピー本に至っては昼過ぎになくなってしまいました)。 近くにキンコーズがあるので追加で刷ってこようかとも思ったのですが、宣伝活動と考えたときにこれ以上お金をかける意味があるのかよく分からなくなってしまったため、そのまま増産無しで閉会まで居座っておりました。
今回、技術書典3というイベント自体の新たな試みとして「立ち読み専用スペース」「戦利品確認用スペース」という物が用意されており(自分は行かずじまい)、サークル参加者は見本誌とは別に本を立ち読み用に提出することでそちらにも置いてもらえるようになっていました。
どれくらい効果があるのか?については未知数の状態でとりあえず提出してみましたが、会場内でスペースまで足を運んで頂いて本をお買い上げ下さった方の中に、「上の立ち読みスペースで読んで気になったので」とおっしゃって下さった方がいらしたので、まったく効果無しということはないようです。
今回のイベント参加に当たり、元々はシス管系女子BEGINSの0.3話として新作を用意しようと思っていたのですが、
ということで、突貫作業でWSLの紹介の特別編を制作し、新刊としてリリースしました。 元々、イベントが終わったら公開するつもりだったのですが、昼過ぎの時点で頒布物の在庫が無くなりそうということが見えてきたため、早々に会場内からTwitterにも投稿しました。
ただいま技術書典3参加中❢ 新作特別編の無料コピー本では、なんとあたしがWindowsでLinuxコマンドを使っちゃう⁉「まんがでわかるWindows Subsystem for Linux シス管系女子」全編をここで公開しちゃいます✨ pic.twitter.com/x8pFX3uW0o
- 利奈みんとbot/マンガでLinux! (@sysadgirl_mint) 2017年10月22日
「まんがでわかるWindows Subsystem for Linux シス管系女子」の続き❗ これでWindowsユーザーのあなたも本編中の便利テクニックを活用できちゃう⁉ (※技術的に不正確な部分があったのを訂正しました💦) pic.twitter.com/bU7CQf3KM9
- 利奈みんとbot/マンガでLinux! (@sysadgirl_mint) 2017年10月22日
コピー本として頒布したバージョンと最初に公開したバージョンでは、最後のページでWSLのことを「準仮想化」と表現していたのですが、Twitter上でご指摘を受け、冷静に考えると間に挟まるレイヤーが薄いという点では準仮想化に似ているけれども仮想マシンがいるわけではないのだから「仮想化」と言うのは間違いだったと思い至り、帰宅後に最終ページの内容を大幅に更新してTwitterに再投稿しました。 結果として、前半4ページ分と後半4ページ分のそれぞれのツイートのうち後半の方が多くRTされるというヘンテコな状況が発生してしまいましたが、それだけWSLと他の競合技術との違い・使い分けに皆さん関心があるということなのでしょう。
また、まったくの副作用として、この話を描くにあたって色々調べ直したことで自分自身のWSLへの理解が深まりました。一応Cygwin・MinGW(とMSYS/MSYS2)・PowerShell・仮想マシンとの違いは何となく分かっていたつもりではあったのですが、漫画にするにあたって「どういう絵にすればより適切な表現になるのか?」を考えたことで、今までよりもそれぞれの違いをより具体的に言い表せるようになったと思っています。技術発表や紹介記事はそれを読むだけよりも自分で書く方が勉強になる、ということを改めて実感しました。
例によってTogetterの当日のまとめ等も見てみたのですが、戦利品報告として写真を公開されている方の戦利品ラインナップを見ると「ものすごいディープな内容・商業誌では扱われていないような内容の技術同人誌」が主で、今回のコピー本が写り込んでいる物はほとんどありませんでした。シス管系女子のような「解説対象が枯れた技術で、且つ、ものすごく技術的に高度な事をやっているわけではない、初級者向け(中級者以上へのステップアップ用)の内容」というのは、やはり、技術書典というイベントに台風の中わざわざ足を運んで戦利品報告までするようなアグレッシブな方にとっては魅力的ではないということなのだと思います。
宣伝活動としては、直接会場でリーチできる層以外に、その外側・イベント外にも拡散されるような場を選ぶのが効率的なのですが、「シス管系女子」というコンテンツにとってのそういう場所は一体どこにあるのか、そもそも「ある」のかどうか、むしろ拡散されるに足るコンテンツとしての価値は本当にあるのか、まだ答えは見つかっていない感じです。
以上の通り、商業出版物の広報活動としては今回もあまりパッとしない結果に終わってしまいましたが、上記のような悪条件下にも関わらず多くの方が来場して下さり、また、シス管系女子会のスペースまでお越し下さり、暖かい声援の言葉をおかけ頂けました。普段Webではあまり感想・反応を見かけないため、このように直接「ちゃんと読まれている」ということを実感できる機会は自分にとって非常に大きな意義があり、他の何にも代えられない喜びです。お声がけ頂いた皆様、本当にありがとうございます。
今回、事前の準備を疎かにしていたため頒布物は無料のコピー本だけだったのですが、次回以降の参加に際してはファンサービス的な面にもっと注力し、グッズ類の制作にも手を広げていきたいと思っております。
ということで、技術書典3のご報告でした。
ツリー型タブのWebExtensions移行の後半作業と並行して進めてたマルチプルタブハンドラのWE移行ですが、こちらも一区切りとしてバージョン2.0をリリースしました。こちらはTSTほどには語る内容が無いので手短に。
マルチプルタブハンドラ(以下、MTH)は元々、「そこにあるFirefoxのタブを雑にドラッグして選択したらメニューが出てきて『で、この選択したタブをどうしたい?』と次のアクションを訊ねてくる」という、操作対象を起点とした操作、本来の意味での「オブジェクト指向」らしい操作というコンセプトに基づくアドオンでした。そのコンセプトを具現化するために、レガシー版ではタブの上でのクリックやドラッグどいった操作をハンドルし、時にFirefox本体の挙動をキャンセルして、「タブをドラッグして選択」という挙動を実現していました。
ところが、WebExtensionsではFirefoxのタブの上での生のイベントをハンドルすることが許されていません。そういうAPIが欲しいという要望は挙がっていましたが、WebExtensions APIのコンセプトに反するということでWONTFIXになっています。よって今後もそういう事ができるようにはならないでしょう。
ただ、WE版TSTは専用のサイドバーを提供していて、その中で発生するイベントを扱う事に関してであれば自分の裁量で好きなようにAPIを提供できます。 なので、WE版MTHは当初は「TSTに完全に依存したアドオン」として開発を始め、TSTにAPIを実装してはMTHでそれを使ってみるという形で両者の開発を並行して進めていたのでした(TSTのAPI整備とその動作検証のための体のいい実験台になってもらったとも言えます)。 その過程で、ツールバーボタンから開いたパネル内であればドラッグ操作でのタブの選択もできなくはないと思い立ったため、TST完全依存のアドオンではなく一応単体でもそれなりに機能するアドオンとしてリリースする方針に切り替えて不足部分を整備し、この度ようやくリリースに至った次第です。
そういう経緯なので、本来意図していたMTHのユーザー体験は、WE版においてはTSTとの併用時においてのみ実現されています。単体のWE版MTHはあくまで仮の姿で、TSTと併用した時にのみ真価が発揮されるとは、なんとも中二病くさい仕様ですね。
ところで、Firefoxにはずいぶん前から(具体的には8年前から)タブを複数選択する機能の実装提案がなされています。 この機能がいつまで経っても実装される様子がないので、渋々MTHを今までメンテナンスしてきた、という部分も実を言うとあるのですが、なんとここに来てそれなりの優先度で解決(実装)に向けて動き始めてきたようです。 もっと早くやってくれていれば、MTHはWE版を開発せずそのまま開発終了にできたかもしれなかったのに……
ともあれ、将来のどこかの時点でMTHがお役御免となるのなら、それに越したことはありません。 その日が来るまでの間は、できる限りメンテナンスを続けていこうと思っています。
以上、MTHのWE版リリースの裏事情でした。
Here is the English version of this article. このエントリはQiitaとのクロスポストです。
2017年の8月下旬に思い立って、ツリー型タブのWebExtensions版を作り始め、去る9月26日にバージョン2.0としてリリースしました。
重い腰を上げて取り組む気になれたのは、必須と目していたAPIが一通り実装されてきて、Firefox 57でようやく技術的に作れる目処が立ってきたからでした。 関係者の皆さんの尽力に改めて感謝の意を表明します。
やっている事自体はそう難しい話ではなく、技術的に目新しいトピックは無いのですが、主に歴史的資料としてレガシーなアドオンの移行の一事例の記録を残しておこうと思います。
I started to develop WebExtensions-based version of the Tree Style Tab at late August 2017, and released as the version 2.0 at 26th November.
The largest reason why I did it is: many numbers of new WebExteisons APIs I required are landed to Firefox 57. Thank you developers for their great effort.
There is no technical novelty topics, but I wrote this as a historical document: a migration story of a very legacy addon.
手厚いサポートの恩恵をほとんど受けてないのでSoftbank MobileをやめてMVNOにしよう、ということで数ヶ月前から準備を進めてて、まずSIMロックのかかってない端末に機種変更した。そこそこ性能が良くてモバイルSuicaが使えること、を条件に検討した結果AQUOSブランドのSH-M03にした(既にこの次のモデルが出てたけど、次のモデルはコストダウンの方に舵を切った結果スペックが落ちてたので……)。
……んだけど、これが本体の内蔵ストレージがめっちゃ少なくて、この前に使ってた203SHは32GBあったのにこれは16GBだからアプリの自動更新が何度か降ってきたらもうそれだけでパンパン。microSDを外部ストレージとして使うようにはもちろんしてたんだけど、それでも全然追っつかない。Kindleのようにデータを自分の領域に保存するアプリはそもそも外部ストレージがいくらあっても使っちゃくれないし。
検索したら、Android 6以降だとSDカードを内部ストレージの追加領域にできるみたいな話が出てきたのでやってみた。結論としては、今まで外部ストレージだったmicroSDがそっくりそのまま内部ストレージになる感じになった。
以下、やったこと。
外部ストレージとしてしか認識されないmicroSDを強制的に内部ストレージにする。(前の手順で内部ストレージとしてフォーマットできてるなら、多分この手順は不要)
Path
にC:\Users\(ユーザー名)\AppData\Local\Android\Sdk\platform-tools
を加える。adb shell
を実行してAndroid端末に接続する。
USBデバッグ接続を許可するかどうかの確認がAndroid端末の画面に出るので、許可する。
error: more than one device/emulator
というエラーメッセージが出て接続できない(自分の環境ではCintiq Companion Hybridが繋がっててこれにハマった)ので、関係無いAndroid端末は外しておく。adb shell
で無事端末に接続できたら、sm disk-list
を実行する。すると、以下のような感じで認識されてるmicroSDの識別子が表示される。
C:\Users\piro>adb shell
shell@SH-M03:/ $ sm list-disks
disk:179,64
shell@SH-M03:/ $
ここではdisk:179,64
がそれにあたる。
sm partition (microSDの識別子) private
を実行する。
shell@SH-M03:/ $ sm partition disk:179,64 private
shell@SH-M03:/ $
しばらく待たされて処理が完了する。
private
と指定するとmicroSDの領域全体が内部ストレージとして使えるようになるんだけど、文献によっては「全体を内部ストレージにするとおかしくなるのでmixed 50
のように指定すること」のように案内してたりする。が、自分の環境で試した限りではmixed
を指定しても期待したような効果を得られず、むしろprivate
にした方が想定通りの結果を得られた。この状態でファイルマネージャの類のアプリを起動してみると、以前は内部ストレージとSDカード(外部ストレージ)の2つが見えていたのが、内部ストレージが見えなくなってSDカードだけ表示されるようになっていた。 また、Android端末をPCに接続しても、microSDの分の領域だけが見えるようになっていた。
最初に退避しておいたmicroSDの中身を書き戻すというかマージすれば、移行作業は完了。逆に、microSDを切り離して元の状態に戻したい時は、設定→ストレージとUSB で内部ストレージの項目をタップして、右上のメニューボタンをタップして出てくるメニューから「データを移行」を選択すればいいんだと思う。やる前にmicroSDの中に保存されてるデータを消して内部ストレージに収まる状態にしておかないと、多分、失敗するか警告されて処理を実行できないんじゃないかなあ。
仏陀再誕 The REBIRTH of BUDDHA、神秘の法に続く、幸福の科学制作の映画のチケットを譲って頂いたので見てきました感想です。
総じて、実写にすることで違和感が引き立つというか粗が目立つというか、一線を張ってるプロの脚本家や声優や俳優ってやっぱすごいんだなあという事を逆説的に感じる結果となった次第でした。
宗教本体の教義がアップデートされるわけでは当然ないので、教義の説明部分は回数を重ねれば重ねるほど「あ、また同じ事を言ってるな」となっちゃうのは致し方ないんだけど、それにしても、以前に見た映画と同様に「言いたい事を言う」が優先されていて「伝わるように言う」がなおざりにされてるなあと思った。
例えば「メッセージ」(テッド・チャン「あなたの人生の物語」が原作の物)は「悲劇的な未来が既に決定されていても、それでも人はその選択をする、ということの尊さ」をストーリー内に織り込んでたし、「オデッセイ」(アンディ・ウィアー「火星の人」が原作の物)は「折れないこと、諦めないこと、ユーモアを忘れないこと、の大切さ」を主役の演技から演出からすべてを投じて描いてたし、「LEGOムービー」は「自由な発想を忘れないことの大事さ」を語りつつも「お堅いルールに自由な発想で立ち向かった主人公達が、さらに次元の違う自由さを目の当たりにする」という落とし方をしてたし。上手くやるやりようはいくらでもあると思うんですよ。
例えば、「地獄に堕ちる」とかの恐怖を語るんだったら徹底的にホラーに振り切って救いも何も無しに終わらせるとか。
例えば、修行の大切さを語るんだったら修行そのものにテーマを置くしんみりした作品にするとか。
例えば、退魔的なところにフォーカスを当てるんだったらエクソシストみたいなエンターテインメントに振り切るとか。
全部語ろうとするからシッチャカメッチャカになるんであって、1作で全部語ろうとしないで、それぞれ分けてちゃんと掘り下げなきゃ。
こっちの言いたい事を全部言いたいだけまくし立てても相手が聞いてくれるのは、相手が最初から好意を持ってくれている場合だけなんだよね。そう考えると、これはやっぱりまだまだ「身内」向けの物で、「外」に出す性質ものではないんだと思う。
トレイラー見てちょっと面白そうかなって思ってチケット譲ってもらったんだけど、実際見てみたら、見せ場だけ繋いで面白そうに見せるトレイラー編集の妙というか、あれはあれで大した技術だよねと再認識したというか……市井のレビューを見ても「宗教映画と知らずに見に行った。(僕の挙げてるようなツッコミの後)お金損した。」みたいに後悔してる物すらあって、なんというか、いたたまれない。身内向けなら身内向けと分かるように振り切る、外向けなら外向けでもっと外の人が見ても面白く作る、どっちつかずが一番罪作りだというのを実感する。単に不出来ならまだ仕方ないけど、「普通のセミナーを装ってて、誘われて行ってみたら宗教だった」みたいな狙ってやってるんなら、騙すのは駄目ですほんと。
対象視聴者でないにも関わらず「見たい」って言ってチケット譲って貰っておきながら(あまりに本編だけでは訳がわからなかったので補足情報を求めてパンフレットは買いました)、批評とも言えないようなくさすばかりの感想を公開するのって道義的にどうなん?というのはあると思うんですが、貰うだけ貰って何も言及しない方が問題かなと思って書いてみました。
NETFLIXで映像化されたやつを映画館で見てきた。「すげえええ~~これまさに『俺の見たかったBLAME!のアニメ』やああ~~」って大興奮だったんだけど、帰宅後原作を読み返したら意外と色々違ってた。「シドニアの騎士を経た後の弐瓶勉」感もミックスされて色々アップデートされたBLAME!と言った方が適切なようだ。パンフレットは売り切れで買えなかったので、以下パンフレットに書いてある話と違う的外れなこと言ってたらごめんなさい。
総じて、原作のぐにょぐにょした有機的イメージは抑えめで、メカはメカと分かりやすい描かれ方に統一されてるなあと思った。これはCG作画だからという制約による部分もあるのかもだけど。
とりあえず、この1作だけじゃなくもっといろんなエピソードをこのクオリティの映像で見せて頂きたい、そしてそれに浸りたい、なんならVRでこの超構造体に挟まれた階層都市内での生活を体験したい(絶対後悔するけど)、という「もっとこれくれぇぇぇええ!!」感を覚えた次第でした。
技術書典2で隣のスペースだったマンガでわかるWebデザインとかGitとかの湊川さんが第113回 PHP勉強会@東京で発表されるということでPHP勉強会の運営の方がご挨拶にこられていて、その時になんやかやでお声がけを頂いて発表の機会を頂く運びとなりました。じぶんPHP使ってないんですけど!?(ずっと以前に案件でPHPを使う物があったのでちょっとだけ触ったきり)と戸惑ったのですが会的には全然アリだとのことだったので、第114回 PHP勉強会@東京にて思いっきり漫画の話に振った内容でプレゼンをさせて頂きました。資料はSpeaker Deckで公開済みで、画像の解像度を落としたソースも公開してます。当日の様子の一端はTogetterのまとめをご覧頂くと伝わるかもしれません。
当初は20分の枠でお話を伺っていたのですが、ここは語っておきたいという内容を詰め込んでいるうちにどんどん分量が膨らんでしまい(実は会場で自己紹介が進行してる間にも何枚か足してました……)、第2セッションの枠が空いていたのをいい事に結局2枠分の時間を使わせて頂きました。時間に余裕が生まれた分、ちょっとゆとりを持って話せたと思うのですが、人前での発表自体が結構久しぶりだったので、大変緊張しました。
発表内容は見ての通り解説漫画の描き方の解説というメタな話ですが、前半部分のプロットやシナリオの話はテキストで解説を書く時や人に何かを紹介する時に共通して言える事のように思いますので、新人教育とかそういう場面で知見を生かして頂けたらなあと思っています(なので、Speaker Deckのスライドのカテゴリも図々しいことにEducationとしています)。
スライドに書いてないことで当日会場で話した事のうち、覚えてる話ではこんな話題があったような気がします。
あと、質問を受けたこと以外でこんな事も話したなあという話題。
自分の発表が終わった後は開放感からアルコールを飲んでしまったため、LTの方はほとんど頭に入っていませんでした。ごめんなさい。でもBlackfireというプロファイラ的な事のできるサービスがあるという事と、WAF(Web Application Firewall, アクセスのパターンを識別して攻撃っぽい物を見つけたら遮断する)が有効だという話はうっすら記憶に残っています。
久しぶりにたくさん喋ったので翌日は声がおかしくなっていたのが自分で分かりました。こういう発表の機会が無いと自分が思っていることを整理してまとめる事も無いため、今回はそのいい機会になったと思います。発表の機会を与えて下さった勉強会運営の皆様、会場までお越し下さった皆様、ありがとうございます!