hello, onedrive

OneDrive にも対応するようにした。OneDrive というのはかつては SkyDrive とよばれていた、Microsoft が提供するオンラインストレージだ。

そのためにドキュメントをいろいろ参照するわけなのだけど、まあいつもの MSDN クオリティというか、量自体は豊富なんだけど痒いところに手が届かない感じがしてあんまり使いやすくない。

あと、OAuth での認可を受けるためのエンドポイントのドメインが login.live.com なのに OneDrive(というか Live Connect)の API は apis.live.net だったりちぐはぐなのがなんか全体的にこう……なんと言ったらいいのか MS らしいですね!

かつて apple の親分だったおじさんが MS を評して曰く、「彼らはセンスが足りないんじゃない。『ない』んだ」とかなんとか、と聞いたことがあるけれど、もしかしたら、まったくもって、その通りなのかもしれない。

mkdir -p

[cci]$ mkdir -p foo/bar/baz[/cci] とすると、パスを構成する各ディレクトリがなかったら、自動的に作ってくれるという賢い動作をしてくれるじゃないですか。

オンラインストレージの API でそういう動作をしてくれるかという話。

dropbox は、まさにそういう動作をする。というより、それ以外の動作(存在しないパスが指定されたらエラーにする的な)を指定できない。ファイルをアップロードする REST エンドポイントの構造は
[cci]https://api-content.dropbox.com/[VERSION]/files_put/[ROOT IDENTIFIER]/[PATH][/cci]
というものだ。VERSION は現在は [cci]1[/cci]、ROOT IDENTIFIER はユーザーに割り当てられた空間のどこをルートにするかという指定で、[cci]dropbox[/cci] は空間全体のルートを表し、[cci]sandbox[/cci] は登録したアプリケーションごとの専用のディレクトリを表す。

実際には、[cci]sandbox/foo.txt[/cci] は 例えば単に [cci]dropbox/app/akahukuplus/foo.txt[/cci] と同じ場所を示す。sandbox を指定している限り、誤っておかしなディレクトリのファイルを読み書きしてしまうことはないというシンプルだけど確かに効果のあるからくりだ。

そして、PATH で目的のファイルのパスを指定する。つまりエンドポイント URL に対象となるパスの、その階層構造も含まれている。

一方で、Google Drive はどうかというと、そもそも階層構造の中の特定の位置を文字列で示すという概念がない(気がする)。[cci]/foo/bar/baz.txt[/cci] というパスの baz.txt の情報を得るには、ルート上のファイルの中で [cci]foo[/cci] を検索し、そのディレクトリの下にある [cci]bar[/cci] を検索し…という処理を再帰的に行う必要があり、そのつど REST のネットワークアクセスが発生する。非常に、恐ろしく無駄だ。なぜ、パス文字列という概念を google が導入しないのかはわからない。そういう環境なので、そもそも mkdir -p 的な動作を期待できない。

 * * *

というわけで、akahukuplus のバックエンドの gdrive ファイルシステムモジュールでは、例えば [cci]/dat/b/1234567890.jpg[/cci] というパスにファイルを保存したい際は mkdir オプションを指定できるようにした。この値が [cci]auto[/cci] で、かつ指定のパスが存在していなかった場合は mkdir -p 相当の動作をエミュレートしてから保存処理を再度実行する。

OAuth 2.0 in a browser extension

アプリケーションが OAuth 2.0 における認可を得る際の手順は、そのアプリケーションの性格によっていくつかの系統に分かれる。このあたりは google のドキュメントなどにまとまっているのだが、つまり

  • Web サーバが主体になる場合
  • ネイティブアプリケーションが主体になる場合
  • ブラウザが主体になる場合

と大別される。いずれにしても、基本的には

  1. 認可を得るための一時的なコードを得るための最初のリクエスト(これは正確には認可を得るためのページを web ブラウザで開くだけの処理だ。認可を得るかどうかはそのページを見ているユーザが判断する)
  2. そのコードをアクセストークンへ交換するための 2 度目のリクエスト
  3. 得たアクセストークンが正しいものであるかの確認のリクエスト(これは認可を得るための必須の処理ではないけれど、普通は行う)

を順に行うという流れに従うのだが、何が主体になるかで微妙なところが微妙に違う。具体的には、一時的なコードを得るための経路や、アプリケーションごとに割り当てられるクライアント ID、クライアントシークレットの扱いなどだ。

  • Web サーバが主体になる場合、リクエスト 1 の際にリダイレクト URL を指定する。この URL として、Web サーバの管理が及ぶ適当なものを与える。アプリケーションを利用するユーザが承認すると、ユーザが見ているブラウザのページは自動的にリダイレクト URL に転送される。このとき、URL に追加されているクエリ文字列に一時コードが含まれているので、Web サーバはそれを得ることができる。
  • ネイティブアプリケーションが主体になる場合、Web サーバのようには行かないので、2 つの特殊なリダイレクト URL のどちらかを使用する。[cci]urn:ietf:wg:oauth:2.0:oob[/cci] を指定した場合は、何やら呪文のようなアドレスだが、つまりリクエスト 1 の時点で単にページ上に一時コードを表示して一旦終了ということだ。これをユーザが手作業でアプリケーションにコピペする。[cci]http://localhost[/cci] を指定した場合は、あらかじめネイティブアプリケーションがローカルマシンの適当なポートをリスンしておき、その経路を通して一時コードを得る。
  • ブラウザが主体になる場合は特殊で、一時コードをすっ飛ばしていきなりアクセストークンを得ることができてしまう。ただしこれで得たアクセストークンは非常に短い有効期間しか持っていない。

と、ここまでは、上のドキュメントに書いてあることそのままなので、いいのである。問題は、ブラウザに組み込まれるエクステンションの場合はどのシナリオを選択すればいいの? ということだ。

エクステンションは単なるブラウザ上のスクリプトよりも多くの機能を持っているので、ブラウザだからといってブラウザ主体のシナリオのみ許されるわけではない。それどころか、とても興味深いことに、ブラウザのエクステンションは工夫次第によって 3 つのシナリオを全てを実装できてしまう。そして同時に、いずれの方式にも若干の気をつけるポイントも出てくる。どれを選択するべきなのか?

 * * *

Web サーバシナリオを選択した場合、適当な外部の Web サーバを用意し、リダイレクト URL を作る。エクステンションはリクエスト 1 によるアクセスにまつわるブラウザのページ遷移を監視し、リダイレクト URL に達した時点でクエリ文字列を得ればいい。これに嫌な点があるとすると、一時コードを含んだ URL が認可サーバからブラウザに来るパスの他にもう一度、ネットワークを流れてしまうということだ。そのためリダイレクト URL を SSL 経由にしたりする必要があるが、これはなかなかコストのかかる作業である。

ネイティブアプリケーションシナリオを選択した場合、外部 Web サーバは不要だ。ブラウザのリダイレクトを [cci]oob[/cci] にし、ページに一時コードが表示された時点でエクステンションからそれを読み取ればいい(このへんがちょっとハックでストレートじゃないのが気になるが)。一方で、これは Web サーバシナリオでも実質的に同じだが、クライアント ID とクライアントシークレットをエクステンションのパッケージに内包させなければならないのが気になる。全然シークレットでもなんでもなくなってしまうのである(これは、上のドキュメントにも書いてあることであるが、ネイティブアプリケーションシナリオにおいてはどうにもならない副作用だ)。

wasavi は dropbox のクライアント情報に関しては、エクステンションのパッケージ内に暗号化して含めるようにしている。これはプレーンな状態で含めようとしたら dropbox の審査で暗号化しろよ! と怒られたのでそうした経緯があるのだが、しかしまあ、ブラウザのエクステンションである。すなわち javascript コードがそのまま入ってるのである。コードを読めば、どう復号するのかはすぐわかっちゃうわけで、意味があるのかどうかはいまいちわからない。

最後のブラウザシナリオでは上に書いたような問題点は一見ない。アクセストークンを得るためにクライアントシークレットは不要だ(クライアント ID は必要なのでこのあたりの問題が根本的に解決するわけではない)。しかしこの形式で得たアクセストークンは前述したとおりすぐ切れる。wasavi では Google Drive との接続はこの方式を用いているのだが、だいたい 1 時間もするとすぐに再認可のページに飛ばされてしまう。これは使い勝手が良いとはちょっと言えない。

reborn: akahukuplus

この一ヶ月特に何も作っていなかったというのはつまり、引っ越ししたのでそもそもネットから遮断されていたということなのだが、その直前までは何をしていたのかといえば、wasavi に関してはほとんどコードをいじっていない。

いじっていたのは赤福プラスとよばれるブラウザ用拡張なのである。

かつてふたば☆ちゃんねる向けに IE のコンテキストメニューを拡張する赤福というツールを作った。赤福プラスはその Opera 版というわけだ。Opera 版は当時の Opera が搭載したばかりのユーザースクリプトの仕組に乗っかって動作し、コンテキストメニューにとどまらない様々な機能を持っていた。

その後、Chrome でも動くようにしたり、その過程でブラウザ拡張として構成しなおしたりしたのだが、さすがに建て増し続きだったし、また IE6 あたりでも動作するようにしていたので、例えば Selector API とか XPath とか続々とブラウザに搭載されていく新機能を使うわけにも行かず、中味はなかなかぐぬぬなコードになっていた。

今回、そんなわけで一から作り直してみようということである。残念ながら IE はサポート外となる。最近の IE 自身は、新しい赤福プラスを動作させるポテンシャルは十分あるのだけど、スクリプトベースの拡張の仕組みがないので。一方で、Presto Opera はサポートする。サポートするも何も、Opera 12 で開発してるので、未だにファーストクラスのブラウザだったりする。この他には Chrome と Blink Opera でテストする。気が向けば Firefox 版も作るかもしれない(気が向かないのは、Firefox には別の人が作った赤福がすでにあるからである)。

技術的な面に目を向けてみると、フロントエンドとバックエンドで全く違ういくつかのトピックがある。

まずフロントエンドからだが、赤福プラスというのはつまりふたばの画像掲示板の html を動的にちょっと書き換えるツールだ。ここではふたばの画像掲示板に DOMContentLoaded でスクリプトを引っ掛けて、ページの DOM をごにょごにょするのがフロントエンドの役割だ。

しかし、ふたばの画像掲示板が吐く html というのは、まああんまりそういう再利用はしやすくないのである。そこで、おそらく他のふたば用ツールはほとんどやっていないであろう手法を取る。ページを読み込んだらそれをスクレイピングし、一旦中間的な xml を構築する。さらにそれを XSLT プロセッサに与えて html に変換するのである。続きのレスを読んだりダイアログを出したりするときも必要なら XSL による変換が入るので、けっこう XSLT が大回転することになる。

これによってふたばの元々の html に振り回されるのはスクレイピング処理部だけになり、その他の部分は自分で完全に制御できる xml だけを見ればよくなる。また、ページ全体を制御できるのでよりダイナミックにページを構成することが可能になる。たとえばスティッキーなサムネイルとかバナー、固定ヘッダなどをなんでも導入できるようになる。

次にバックエンド。バックエンドとはつまり拡張の表に出てこない裏方の部分だが、実はこれは wasavi とちょっと関連する。wasavi もバックエンドを持っている。wasavi もまたいくつかのブラウザで動くため、各ブラウザの拡張の仕組みをある程度抽象化させた部分をもっているのだが、残念ながら完全ではなかった。また、wasavi というアプリケーションからも独立してるわけでもなかった。

これがずっと気にかかっていたので、今回を機にブラウザ拡張の抽象化層をきっちり作り、またアプリケーションからも完全に独立させたい。その抽象化層をベースにして赤福プラスのバックエンドを構築し、さらに wasavi にもバックポートする。なかなか遠大・壮大な計画なのである。

バックエンドに関してはもうひとつやることがある。オンラインストレージをアプリケーションから利用する際の承認において、dropbox はなんかなかなか OAuth 2.0 をサポートしなかった。ので、wasavi も jsOAuth というちょっと癖のあるライブラリを使って OAuth 1.0 で繋ぐしかなかったのである。しかし最近なのか結構前なのか知らないけど、いつの間にか OAuth 2.0 がサポートされていたのでそのへんの仕組みをごっそり書き直したい。当然この辺りも wasavi にバックポートされることになる。

赤福プラスにおいては、オンラインストレージは画像の保存・スレッドの保存時に利用することになる。画像のサムネイルから保存ボタンを押すとオンラインストレージの API を通して保存を行うのである。オンラインストレージ側の機能でローカルや複数デバイス間で同期することができる。

最近の状況はこんな感じです。

serif or sans-serif

文字の形は一般的に書体、フォント、タイプフェイスなどとよばれる。

欧文の場合、まず大きく分けて serif 体と sans-serif 体(と、その他)がある。見た目上の決定的な違いは、前者がいわゆるヒゲ付きで、後者がヒゲなしだということなのだが、1 文字 1 文字の見た目以上の違いがもっといろいろなところに現れる。

書籍などの印刷物なんかでは、だいたい本文のような長い段落の文章は serif で組む。serif のほうが読みやすいからである。対して、見出しのように目立ってなんぼの部分は sans-serif で組む。そのほうが目立つからである。とこのように、それぞれのデザインに用途の向き不向きがある。したがって普通は適材適所にそれぞれの特徴を活かした組版を行う。

翻ってコンピュータ上でのテキストの組版、とりわけ web ページのそれはどうなのかというと、残念ながら長い文章であっても serif が使われることは少ないように思える。特に日本語のページではそうである。これは一つ理由が考えられて、現在の一般的なディスプレイのピクセル密度では、serif 体はあんまり綺麗に表現できないのである。

個人的には、ディスプレイ上であっても長い文章は serif で読みたい。日本語の書体では serif / sans-serif は明朝体 / ゴシック体というものに対応する。しかしどうもゴシック体で組まれた文章は、クールでポップでかっこよくはあるのだけど、なんというか真摯さに欠ける。どんな高尚な内容の文章も、メイリオとかヒラギノ角でレンダリングしてしまうと、薄っぺらな C 調言葉にしか見えなくなってしまうのである。これは「おまえは何を言っているんだ」と言われそうだが、かなり本気でそう思っている。そんなわけで、もっと明朝体をゴリ押ししたい。ゴリ押ししていきたい。どうでもいいけど C 調とか我ながら発想が古いなあ。

さて、最近は特にモバイル機器を先頭に、ディスプレイの解像度はじわじわと上がりつつある。96ppi どころか、一気に 200 とか 300 とかの ppi に達しているものもある。これくらいの解像度があれば十分 serif も明朝体も綺麗に表示できる。ヘタしたら、アンチエイリアシングのような小細工すら必要ないかもしれない。この分だと、あと数年もすればほとんどのディスプレイが高解像度に置き換わるのではないか。そうするとつまり、ハードウェアの面では明朝体ゴリ押し計画に対する障壁はないことになる。

問題はソフトウェアの面なのである。

RDP 8.0 #2

いろいろ試してみると、[cci]ping[/cci] では効果がなかった。また、Windows7 ではローカルセキュリティポリシーの設定によって RDP 8.x かそれ未満を使うかを指定できるのだが、8.x を指定しなければ勝手にスリープは起こらなかった。やはり 8.x に問題があるようだ。

これはうちだけではなく普遍的な問題なのか、Windows7 向けの更新プログラムが現在は公開中断されているようだ。なんということでしょう。

MS さん早く直してください。

RDP 8.0

最近 Windows7 にもたらされた更新の中に、RDP、つまりリモートデスクトップで使用するプロトコルのバージョンを 8.0 に上げるというものがある。これは 7.1 に比べてデータの送信がずいぶん軽くなっているという触れ込みである。そいつは嬉しいじゃないか、ということでいれてみた。

確かに体感的に軽くなっているような気がしないでもない。などと書くと曖昧だけど、いや実際リモートで地デジなんかを見ると、従来はその時々の状態によってはコマ送りになったり音声がノイズまみれになったりすることもあったのがかなり軽減されたりしているので、実際効率は上がっているのだと思う。いいことだ。

しかしいいことばかりではないのだった。

ホスト側は 30 分、インタラクティブな操作を行わないと自動的にスリープするようにしているのである。従来は、その設定の状態でリモートデスクトップに接続した場合でも、それを通したリモート側の操作がホストのスリープを回避するアクションとして認識されていた。しかし RDP を 8.0 にすると無効になってしまう感じなのだ。リモートデスクトップを操作中に予告なく画面が固まり、あれ? ハングした? と思うとホストが眠りに入っている。なにこれもうやめてよね!

とりあえず、RDP 以外の手段でホストに定期的にちょっかいを出せば回避できる。たとえば WMP でホスト上のメディアファイルをずっと再生し続けるとか、あるいは単に [cci]ping -t[/cci] するとか。

MS さん早く直してください。

creating NTFS native symbolic link in cygwin

以前 cygwin 上で、Windows Vista 以降の NTFS ネイティブなシンボリックリンクを作るために逡巡したことがあって、一応できたのだが、それは諸々の環境を整えた上で最終的には [cci]cmd /c mklink[/cci] を呼ぶというものであった。

これだとメッセージが mklink のそれになってしまうし、コードページの不整合が起きる(つまり UTF-8 な端末で呼ぶとメッセージが文字化けする)というどうでもいいけどどうでもよくない不都合もある。それを置いても、やはり cygwin の中からコマンドプロンプトベースの実行ファイルを呼び出すのはなんともイケてない。なんとかならないか。

さて Windows 側のシステム環境変数 [cci]CYGWIN[/cci] に設定する値によって、cygwin の動作を制御することができるのだが(ドキュメント)、その中に winsymlinks という項目がある。これを [cci]nativestrict[/cci] という値にすることによって解決できた。ちなみにこの項目は [cci]lnk[/cci]、[cci]native[/cci]、[cci]nativestrict[/cci] の 3 つの値を割り当てることができるのだが、

  • lnk: シンボリックリンクとして Explorer が認識する .lnk ファイルを作成する
  • native: シンボリックリンクとして NTFS ネイティブなそれを作成する。作成が不可能な場合(NTFS じゃないとか、権限がないとか)は、lnk として振る舞う
  • nativestrict: native と同様に ネイティブなシンボリックリンクを作成するが、作成が不可能な場合はエラーを返す

というわけで、ナウい cygwin で NTFS ネイティブなシンボリックを作成するには

  1. Administrators グループに属する別のアカウントを作成する
  2. 普段使用するアカウントを Administrators グループから外し、Users に含めるようにする(これにより、UAC ダイアログでは単なる権限のエスカレーションの確認だけでなく、管理者アカウントのパスワードを入力を求められるようになるが、慣れるしかない)
  3. ローカルセキュリティポリシーを起動し、[cci]セキュリティの設定 -> ローカルポリシー -> ユーザー権利の割り当て[/cci] の中にある [cci]シンボリック リンクの作成[/cci] に普段使用するアカウント名を追加する
  4. システム環境変数 [cci]CYGWIN[/cci] に [cci]winsymlinks:nativestrict[/cci] を追加する

という手順になる。

hang on search?

issue #20 で、検索するとパターンによって無限ループになってタブを閉じるしかなくなるというのがある。特に [cci]|[/cci] とかが危険らしい。なるほどなかなかそんな雰囲気がしないでもない。

これは由々しき問題だ……ということですぐ直そうとしてみたのだけど、再現しない。ということでどういうパターンだと発生するのか聞いているところ。

home updated

wasavi のホームを更新してみたりした。といっても開発版のエクステンションは github に置くようにしたし、フォーラムのようなものは全然利用されないので除去した、つまり単に readme.md を表示するだけの特に存在理由のないページになっている。

まあきっといろいろと、そのうちに拡充していくんじゃないかな!(希望的観測)