現在の認証方式は、[IM]INTER-Mediatorの認証フレームワーク(2)に記載の通りですが、これのベースにOAuthを動作させたいと考えています。ということで、とりあえず、Googleをベースに考えてみました。ブログなどでよく見られる「Google対応」は、2.1、4.1、4.2の部分です。Googleで認証をした結果を取り出すという部分です。しかしながら、そこから後が長いですね。その認証で得られた情報を元に、アプリケーション自体の認証もしなければなりません。OpenIDのtoken_idをそのままクッキーに入れるといった実装も見られますが、実際の認証はすでに動作しているユーザー名とクレデンシャルを使った方法を利用します。Open IDのtoken_idがあれば、その署名の検証を行うことで、内容を信頼するようにしようかと考えています。一番、問題なのは8.4で、クレデンシャルの期限切れがあったときに、クレデンシャルを問い合わせるか、あるいは再生成して再設定するかを行うことになると思います。その時、token_idの中身を見て、ユーザー名を特定することで、確実に動作してくれないかと考えています。ご意見よろしくお願いします。
[IM] バリデーションをどう実装するのか?
バリデーションに関しての実装は、バリデーションの実装を再考するや、Facebookのメッセージにも書きましたが、なんとなく実装が見えてきた感じがするので、一度ドキュメントにしてみたいと思います。
まず、UIからDBまで線を引いて、チェックポイントがどれだけあるかというと、これだけあります。もちろん、もっと細かくできますが、要するに出入りの部分となるとこうなります。
- テキストフィールドなどのデータがあるUIコンポーネント
- 送信ボタン等、データはないけど、データ送信を指示するUI
- AJAXの出口(Adapter_DBServer.js)
- サーバー側の受け入れ(DB_Proxy.php)
- データベースエンジンのスキーマに定義する制約
現状では、定義ファイルのコンテキスト定義に含めるvalidationキーによる連想配列の配列を設定することで、原則として、1そしてPost Onlyモードでの2のバリデーションが機能します。
ここでまず、3は不要と考えます。言い換えれば、4があるなら3はいらないということになります。5はフレームワーク外のものです。その有無とフレームワークの動作をどの程度連携させるのかは難しいですが、ここでポイントは「5はなくてもアプリケーションとして要求を満たせる」使用にしておくということです。
ちなみに、2は、Post Onlyモードと、IM_Entry関数のオプション変数でtransactionキーをnoneにして「保存」ボタンを表示した時になります。ここで、1つ考えられることは、1と2は同時に満たすようにはすることはまずないということです。もし、やりたい場合、「保存」ボタンでは現状APIはありませんが、Post Onlyモードはデータベースアクセス前に呼び出すメソッドを実装して、そこに機能を組み込むことができます。ということは、1と2は排他的であると言えるのではないでしょうか。
そうなると、(1 or 2) (4) [5] がチェックポイントになります。[5]については、データベースのエラーの扱いに含まれることになりますので、(1 or 2) (4) のチェックポイントが残ります。
そういうわけで、次のような使用を考えてみました。
A. validationキーの設定により(1)の状況を必ず満たす
validationキーの設定のあるフィールドとバインドした編集可能なUIコンポーネントは、フォーカスが外れた時に必ずバリデーションを行います。編集中のページはもちろん、Post Onlyモードでもそうします。また、初期値が違っている場合は、そこを変更しようとしてフィールドにフォーカスしたあと、そのまま別のフィールドに移動する時にチェックします。つまり、初期値はチェックしないのに等しいでしょう。
B. post-validationキーにより、(1)をやめて(2)にする
コンテキストに、新規に用意したpost-validationキーの値がtrueなら、(1)の状況ではチェックはせず、(2)の状況のみ、validataionキーで定義した内容に基づきチェックを行います。validation/notifyの指定がないフィールドが1以上ある場合、それらのメッセージをまとめて1つのダイアログボックスで表示します。post-validationキーの値が文字列の場合、ダイアログボックスで表示する。つまり、すべてのエラーメッセージをノードに表示したとしても、通知のためのダイアログボックスを出す手法を用意しておきます。
C. server-validationキーにより、サーバー側のバリデーションを有効化する
コンテキストに、新規に用意したserver-validationキーの値がtrueなら、サーバー側でvalidataionキーで定義した内容に基づきチェックを行います。notifyについては無視して、エラーをクライアントに返します。このキーの指定により、クライアントとサーバーの両方でチェックすることになる。ただ、こちらはエラー取得後の動作が悩ましいですね。
D. 外部キーフィールドの参照整合性のチェックは、ruleに特殊な関数あるいは記述で指定
外部キーフィールドにテキストフィールドを仮に利用したとしたら、こういう設定が欲しいかもしれません。しかし、よく考えると、そういう場合、ポップアップメニューにすれば解決するとおもいます。SELECT文のIN演算子の右側が欲しいわけですから、結果的にデータを取り出すコンテキストとフィールド名の指定が必要です。ただし、データベース接続が増えることや、レコードの増減を反映させることなどを考えれば、この仕様は優先度低いかなと思っています。
E. 複数のフィールドにまたがる検証はvalidationキーの指定を工夫する
例えば、{field: “f1, f2”, rule: “value1 != ” and value2 != ” “, message:”?”} ように、validationキーの連想配列の指定を複数に拡張します。
キータイプごとの検証や、検索条件の適用はしないことにします。A.はほぼ実装できていますが、B、C、D、Eはまだです。この中で、優先順位的にはB-C-E-Dというところでしょうか。
さて、これらの使用でいかがでしょうか?
[IM] SQLの集計処理をサポート
INTER-Mediatorは宣言的な設定やあるいは動作上の状況から自動的にSQLステートメントを生成します。通常のリレーション取得はそれでもいいのですが、集計処理などでは、SQLのチューニングが必要になります。そこで、コンテキストにaggregation-select、aggregation-from、aggregation-group-byという3つのキーをサポートするようにしました。これらのキーがあると、viewキーはSQL生成では無視されます。また、読み込み処理のみをサポートするので、tableキー、keyキーは実質的に使われません。aggregation-select、aggregation-fromは両方とも指定する必要があります。これらのキーを設定すると、コンテキストからの読み込みに次のようなSQLを生成します。
SELECT [aggregation-selectの値] FROM [aggregation-fromの値] WHERE [query, relation, その他による検索条件] ORDER BY [sort, その他によるソート条件] GROUP BY [aggregation-group-byの値] LIMIT [recordsの値] START [オフセット値]
つまり、SELECT、FROM、GROUP BY句については、新たに導入したキーの値を利用します。aggregation-selectにSUM()などの集計関数による記述が使えるので、キーの名前にaggregationを含めています。もちろん、自動生成できないうなSQLの生成は集計だけに限りません。WHERE、ORDER BY、LIMIT、STARTはすでに組み込まれている様々な指定方法が反映されます。WHRE句は、コンテキスト定義のqueryだけでなく、relationキーによる関連レコードの検索、JavaScript上での追加条件の設定、ローカルコンテキストを利用した追加設定を利用できます、これらはすべてが実行されるSQLステートメントに反映されます。ORDER BY句も同様、コンテキストのsortだけでなく、JavaScriptやローカルコンテキストの指定も加わります。
なお、STARTについては、引き渡しは実装しましたが、現状では0でのみ利用してください。つまり、ページネーションは利用できないということです。パフォーマンスを考慮して、レコード数のカウントは、SQLの結果の数と同じにしてあるので、結果的に1ページ分しか出てこないでしょう。これは、後々改良をすることとします。
この機能によるパフォーマンス向上の効果を説明しましょう。例えば、大量の売り上げデータがあって、月ごとに集計したいとします。集計する方法は、SQLだけでなく、計算プロパティを使う方法ありますが、大量なので、処理を効率的にしたいため、データベース側で集計したいとします。aggregation-*キーがない場合には、月ごとの売り上げ集計結果が1レコードとなるようなビューを作成しておき、検索条件(例えば、年と月を指定)をビューに適用することになります。しかし、そのような動作だと、一旦ビューを構築するために全部のデータの集計を行うこともあり、一部のデータだけを使うという動作にならず、十分なパフォーマンスが得られません。しかし、aggregation-selectに「SUM(price)」のような記述が含まれていれば、WHERE句で対象月に絞り込んでクエリーを実施した上で集計されるので、全部のデータを取り出して処理をするということはなく、より最適化されたSQLが発行されます。
FROMを独立して指定できるようにしているので、ここに、「テーブル名 JOIN テーブル名 ON 条件」という記述によるテーブル結合もできます。aggregation-*キーはそのまま指定されるようになっていて、とりあえず、現状ではフィールド名のクォートなどはしていません。セキュリティ的に問題になる可能性もありますが、クライアントのユーザーによって改変できない内容なので、構築時に注意をしておけば基本的には問題ないでしょう。
サンプルは、Samples/Sample_Extensible/aggregation3.htmlです。サンプルの選択ページでは、「Aggregation Query」という列を作り、そこにサンプルページのリンクを作ってあります。
[IM]LDAP認証の実装がだいたいできてきました
INTER-Mediatorには、自分自身でユーザーテーブルを持つ認証(ビルトイン認証)が可能です。そして、データベースエンジンのユーザーによる認証(ネイティブ認証)もすでにサポートしています。次に取り組むのはやはりLDAPです。ただ、MySQLにはLDAP接続のプラグインがあり、そういう手法を使えば、ネイティブ認証の一環としてLDAP認証を実現することができます。しかし、通常とは異なるデータベース運用が必要になりますし、MySQLとPostgreSQLで動作に違いがあるとまた大変です。SQLiteはそういう統合はできません。LDAPについては、単に認証の確認だけだと、要するに認証バインドをするだけのことであり、PHPではさほど難しくはないので、データベースエンジンと独立してLDAP認証の仕組みを搭載しました。
LDAPサーバに対する設定
まず、LDAPサーバ情報は、params.phpファイルに、変数で記載する方法にしました。LDAPでの認証時は、ユーザーはユーザー名だけを与えるのではなく、ユーザーレコードのDN(Distinguished Name)を指定する必要があります。たとえば、OS X Serverで、ホスト名がhomeserver.msyk.netの場合、
uid=msyk,cn=users,dc=homeserver,dc=msyk,dc=net
というのがユーザーを特定するDNとなります。ここで、dc…以降は「検索ベース」、cn=usersは「コンテナ」とします。さらに、OS X Serverはuidという属性名でユーザー名を指定しますが、これもActive Directoryでは違うこともあって、結果的に上記のユーザー名「msyk」以外の部分をすべて、変数で与えて、DNを構成するようにしています。サーバーのURL、ポート番号も合わせて、結局、params.phpファイルに以下のように記載をすることにします。
$ldapServer = "ldap://homeserver.msyk.net"; $ldapPort = 389; $ldapBase = "dc=homeserver,dc=msyk,dc=net"; $ldapContainer = "cn=users"; $ldapAccountKey = "uid";
なお、$ldapServer変数に設定されている文字列の長さが0以上なら、LDAP認証を試みるように動作します。これらの変数部分を全部コメントにすると、LDAP認証に関しては何も行わず、以前の通りの動作になるようにしました。
PHPのLDAPライブラリの機能を使って認証するとしたら、その認証のためのバインドはサーバーからLDAPサーバーに送られます。ということは、クライアントからサーバーに対して、ユーザー名とパスワードを送り届けないといけません。これは、ネイティブ認証の仕組みを利用しますが、そのために、鍵ペアを生成して、params.phpファイルに記述します。以下の部分です。もちろん、最初から入っている鍵ではなく、コメントに書いている方法で自分が使用する鍵に置き換えてください。もちろん、クライアントに送られるのは、公開鍵です。
$generatedPrivateKey = <<<EOL -----BEGIN RSA PRIVATE KEY----- MIIBOwIBAAJBAKihibtt92M6A/z49CqNcWugBd3sPrW3HF8TtKANZd1EWQ/agZ65 : jU6zr1wG9awuXj8j5x37eFXnfD/p92GpteyHuIDpog== -----END RSA PRIVATE KEY----- EOL;
ネイティブ認証との混合動作
そして、LDAPアカウントでのログインは簡単にできました。ただし、1回の認証バインドに0.2〜0.3秒ほどかかります。同一のサブネットです。たとえば、フォームのサンプルだと、1ページの合成にデータベースアクセスを15回ほど行うので、5秒くらいのアクセス時間の増加になります。これは、ちょっと長いです。また、単に認証ができたとしても、グループ設定との連動等といった問題があります。
そこで、LDAPアカウントで認証が成功したら、ビルトイン認証で使うテーブル(authuserテーブル)に、そのLDAPのアカウントの情報をレコードとして追加することにしました。1回成功したら、ビルトイン認証テーブルにユーザーを追加し、パスワードもわかっているのでハッシュ化したパスワードを保存します。そのために、ビルトイン認証を行って失敗するとLDAP認証を行うという流れにしました。ビルトイン認証とLDAP認証は切り替えるのではなく、この順序で両方行います。
しかし、その追加したユーザーがいつまでも使えるのは問題で、タイムアウトさせないといけません。そこで、結果的にはビルトイン認証のテーブルにDateTime型のフィールド「limitdt」を追加する必要が発生しました。現在の実装では、そのフィールドの有無で落ちることはないようにしてありますが、LDAPを使う場合には追加したフィールドの定義がされていないといけません。
こうしてユーザーのレコードを作っておくと、グループへの登録ができます。ユーザー名で識別され、1度登録すると消されないので、主キー値は保持されるはずです。タイムアウトすると、LDAP認証を試みます。ただ、この部分、現在実装中で、うまくいったりいかなかったり、一進一退ですが、ある程度のところまで動くようになっています。ちなみに、MoodleもLDAP認証をサポートしますが、ログインを1度することで、ユーーザーレコードが作られる仕組みになっており、やはり同じような仕組みをINTER-Mediatorでも実装しています。
認証処理の流れ
初めて、LDAPアカウントでログインしようとするとき、ビルドイン認証のテーブルにはそのユーザーはありません。したがって、ビルトイン認証では失敗しますが、その後のLDAP認証で成功します。このとき、新たにビルトイン認証のテーブルに、そのユーザーのレコードを作りパスワードのハッシュと期限を記録します。クライアント側には認証のための情報が残されているので、この次の通信時からは、自動的にビルトイン認証が成功します。したがって、1画面作るのに20回の通信処理が必要でも、最初の1回だけがLDAP認証されます。
次の通信処理が、LDAP認証のタイムアウト以内の期間なら、ビルトイン認証が成功して終了します。そのとき、limitdtフィールドも現在の時刻に更新します。しばらくクライアントを利用しないなどでタイムアウトになると、ビルトイン認証は失敗しますが、引き続くLDAP認証が成功するように、クライアントでは、LDAP認証とネイティブ認証に必要な情報が残されています。そして、1度LDAP認証に成功すると、次回以降はまたネイティブ認証がタイムアウトまで成功します。
認証に必要な情報はクッキーに保存することもできるので、翌日にまた認証を継続させることもできます。
今現在、動作が怪しいのは、LDAP認証のパスワードを変えたときです。まず、この方法だと、LDAP認証のタイムアウトの時間が来るまでLDAPでの認証は行われないので、その期間は変更前のパスワードが通ります。これは、とりあえず、仕方ないことの1つとしておきます。そして、タイムアウトしてLDAP認証すると、当然ながら以前のパスワードでは認証が通らないので認証エラーとなり、ログインパネルが表示されます。ここで、新しくなったパスワードを入力すると、また同じように動作するというのが期待する動作です。このあたりの挙動が現状、今ひとつな感じです。
FileMakerはサポートせず
なお、LDAP認証は、PDOのみで、FileMaker Serverはサポートしません。どうしようかと思ったのですが、Admin Consoleでの設定で「外部サーバーアカウント」をクライアント認証で使えるようにしておけば、ネイティブ認証で事実上、Active Directory、Open Directoryは利用できます。LinuxのLDAPは使えないけど、FileMakerのクライアントで使えないで、Web側だけで使える仕組みまでのサポートは必要かどうか疑問ですので、FileMakerはINTER-Mediator組み込みのLDAP認証はサポートしないということにしたいと思います。
今現在、USB-C搭載の新しいMacBookはどう使うか?
USB-Cとどう過ごすのかということで、いくつかの記事をここに投稿しました。まず、分かりきった結論かもしれませんが、29WのApple純正のACアダプタが安定して利用するということです。12Wだと、電源供給の認識はしますが、ディスプレイアダプタが間に入ると、おそらくそのディスプレイアダプタやそこから接続されている機器に配給する電力が足りなくなるのだと思いますが、予想外なことが起こります。従って、ディスプレイアダプタを使うときには、29WのACアダプタを使うべきです。この容量のもので、USB出力のものはあるかもしれませんが、結局Apple純正品がいちばんコンパクトで持ち運びしやすいということになりますね。ただ、2mのUSB-C両端ケーブルはちょっと長いので、短いものが欲しくなります。
仮にiPadのアダプタが役に立つとしたら、外出時、それほどの時間は使わないけど、念のためアダプタを持っておきたいとか、ディスプレイアダプタを使わない場合ということに限られるかと思います。それでも、以前に書いたように場所によっては給電状態にならないのであれば、やはり持ち歩くだけ無駄なのかもしれません。そういうわけで、結局、確実に電源にするには、Apple純正のACアダプタということになります。
ディスプレイは、DELLの4Kの27インチでMac純正ではありませんし、HDMIでの接続です。外付けディスプレイの接続が安定しないのがちょっと困り者です。いちばん困るのは、「ディスプレイ」環境設定での設定が記録されていないのか、何かある時点の記録なのか、変更しても戻るということです。しかし、これは、毎回そうでもないです。シャットダウンしてもそうなるときは続けてなるのだけど、なぜか突然、「直前と同じ状態」になったりします。
そして、ディスプレイがフリーズすることが稀にありあす。ディスプレイの電源ボタンを長押ししても、電源が消えず、画面も真っ暗なので、ディスプレイの電源の抜き差しが必要です。ディスプレイアダプタがフリーズしたかのようなときもあります。DELLのディスプレイはスリープと認識しますが、ディスプレイアダプタのすべてのコネクタを抜いて、挿し直すと直ります。その間、Mac側の操作で復活はどうやっても出来ない状態になります。これらは、純正のACアダプタを使っていてもごくごく稀に発生します。もしかしたら、ディスプレイアダプタには常に電源が入っているわけですから、コンピュータのリセットと連動していないということが原因の1つではないのだろうかと考えますが、それは単に推測です。
そういうわけで、Mini Display Portのアダプタが、次の期待ということになります。
[IM]バリデーションの実装を再考する
INTER-Mediatorではかなり以前にバリデーションの実装はしたものの、完全ではない状態だったのですが、このところ、手を入れるに従って、いろいろ不具合…というか、「考慮が薄い」ポイントが目立ち始めましたので、改めて、議論を進めたいと考えています。
まず、バリデーションは、「入力チェック」とも言われます。いちばん、根本的なことは何かというと、「正しくない値をデータベースに保持しないようにしたい」という要求があると考えています。「正しくない」の基準は、アプリケーションによって変わりますが、「NULLである」ということかもしれませんし、「正しいメールアドレスのフォーマットではない」ということかもしれません。その場合に、データベースに記録しないようにするということがあります。データベース絡みとなると、いろいろ複雑な問題が出てきますので、これを後回しにして、まずは、アプリケーション利用者レベルからの見方を考えてみます。
開発者や管理者がバリデーションを必要とし、実装しますが、Webアプリケーションフレームワークは、バリデーションに関連したユーザーインタフェースを構築し、ユーザーを惑わせない仕組みの提供が望まれます。そもそも、アプリケーションで、どようにバリデーションが絡み合うのか、5W1H的にまず考えます。
- When:正しくない値が入力されたとき
- What:開発者や管理者が望ましくないと考えるデータを検知する仕組み
- Where:入力可能なコンポーネント
- Who:ユーザーが生成すると考える
- Why:単純なミス、さまざまな誤認、テストあるいはインスペクション
- How:キータイプ、あるいはコピー&ペーストなどのユーザの操作
以上の分析からは、バリデーションの検知と通知が大きな目的であることが出てきます。しかし、一部に例外があって、フィールドの初期値がバリデーション違反という場合もあります。そのとき、上記のWhoは「システム」ということになってしまいます。この初期値が違反している問題は、厳密にはデータベースの定義が正しくないで終わってしまいますが、非常に複雑な事情が絡むので、後ほど議論します。
バリデーションの検知は、INTER-Mediatorではすでに実装しています。onchangeイベントが発生したときに、フィールド単位でのチェックを行います。フィールドをまたがった判定用にも、コールバックされるメソッドの定義があります。最近になって、初期値が違反しているときでもバリデーションが働くように、onblurイベントでも判定をするようにしました。これら、さまざまなニーズはあると思われますが、タイミングと仕様が確定していれば、対処できる範囲かと思います。
一方、バリデーション違反の通知は、さまざまなバリエーションが考えられます。そういうニーズも状況も多様な状況では、プログラムを組んで対処というのはもちろん柔軟な対応ができていい部分ですが、一定の範囲を宣言的な記述でまかなうことで、プログラムを書くことを減らす意図のあるINTER-Mediatorではなんとかしたかったところです。そこで、フィールド単位のバリデーションが違反したら、「ダイアログボックスを表示して促す」「近辺に赤字等でメッセージを出す」という仕組みを定義ファイルの設定だけで実現しました。そして、イベント発生時に違反が検知されれば、雇用な動作をして、フィールドからフォーカスがはずれないようにしました。
しかし、ここまででも、すでに議論のポイントはいくつもあります。
- バリデーションはいつ行うのか?
- キータイプごと?
- カット&ペーストするごと?
- データベース更新前?
- 複数のフィールドに対して「書き込み」ボタンがあれば、それを押したとき?
- ポストOnlyモードとデータベース更新時は動作を違う必要があるのか?
- 現状は、定義ファイルで指定可能なのはデータベース更新前のみ。
- 違反通知をどのように行うのか?
- 現在は、ダイアログボックスとページ上への文字の追加
- 新しいページを表示したい?
- 何が間違えたのかをもっと詳しく表示したい?
- バリデーションに違反したら、その後にどのような操作を期待するのか?あるいは期待されるのか?
- そのままでいいのか?
- どこまでロールバックするのか?
- どこまで既定値的な値を設定するのか?
- 違反したレコードは削除しなくていいのか?
- 違反してもレコードは作るのがいいのか?
- 現在は、そのままにしつつ、正しい値を入力しないとそのページの他の作業をできなくしている。
あらゆるバリエーションに対する答えを用意するのか、それとも、主要な手法以外はプログラミングをしてもらうのか、その辺りが議論のポイントになると思います。いずれにしても、問題を書き出すことは必要でしょう。
データベースエンジンには通常バリデーションの仕組みは含まているので、本来はそちらを使うべきという議論があるでしょう。SQL言語での定義時に記述するため、「難しいから敬遠している」という向きもあるかもしれません。一方、なぜ、フレームワークがバリデーションをサポートするかというと、データベース側でのバリデーション処理は、違反時の状況の取得や、そこからの適切なユーザーインタフェースの構築、さらにやり直しなどの処理の組み立てなど、単純ではないプログラミングを要求されます。また、その対処方法も、データベースごとに違う可能性もあるので、むしろ、フレームワークの内部でバリデーションをサポートした方が、動作上作りやすいということもあるわけです。データベース側のエラー検知は、レイヤーを上下するワークフローをうまく組み立てるようなプログラミングを必要としますし、その結果、アプリケーションサーバーとデータベースということなるソフトウエア間の連携ということも必要になります。結果として、データベースに頼らない方が、フレームワーク内部で完結するため複雑さの一部を回避でき、加えてデータベースごとの事情に左右されないというメリットを生みます。
その結果、データベースのスキーマ定義にバリデーションルールが入らないことになり、それによる大きな問題は、初期値がバリデーション違反という状況で、ユーザーの操作に入ることがあります。これをどこの段階で、不正とみなし、どのような方法で排除するか、これが定まらないと、実装が揺らぎます。
ということで、とりあえず、頭にあることを書き出しておいて、議論を進める手掛かりにしたいと思います。
USB-CのVGAアダプタ
新しいMacBookのための、「USB-C VGA Multiportアダプタ」が到着しました。「USB-C Digital AV Multiportアダプタ」については以前に書いた通り[こちら][こちら]です。VGAの方は、どんな風にOS側から見えるかを書いておきましょう。VGAなので「従来通り」です。なお、HDMIに接続しているDELL P2715QはVGA入力がありませんので、以前に購入したBenQ GL2450H、つまり、HD解像度の24インチのものに接続しました。「このMacについて」は次の通りです。
「システム情報」だと以下の通りです。USB-CのVGAアダプタが接続されていることがここで見えています。4K解像度だと、「このMacについて」と「システム情報」の解像度が2倍違うのですが、HDの解像度だと同一になっています。
システム環境設定のディスプレイは、Retinaではなくドット数を選択する方式が見えています。
あまりきれいな写真ではありませんが、HDMIのアダプタと、VGAのアダプタを並べて写真に撮ってみました。VGAの方も、USB、USB-Cがいずれもあるので、幅が広くなるのは仕方ないとして、なぜか、ケーブルも長いです。しかしながら、ディスプレイ端子の位置から、Macに差し込むコネクタまでの長さは同一です。ボックス部分が長方形になっている分、ケーブルが長くなっています。しかし、このVGAアダプタは、微妙な大きさですね。3端子ないとやっぱり不便だけど、かさばる感じがしますね。厚みは、VGAの方が少し多いです。
買ったばかりのMacBookのUSB-C事情
MacBookは5/17に到着、5/20に「USB-C Digital AV Multiportアダプタ」が到着、注文中の「USB-C VGA Multiportアダプタ」はまだ未着の段階です。DELLの4Kディスプレイで、Retina動作をすることを報告しました。これはある種の「予想外の動作」と言えるでしょう。しかしながら、使うに従って、USB-Cについて、いろいろ試行錯誤が必要になってきました。
まず、Nexus 7のACアダプタ(7Wか10Wだと思う)で、充電できることをFacebookにも書きましたが、場所によって充電できる場合とできない場合があることが判明しました。自宅だと、充電できます。しかし、移動先ではできたりできなかったりします。同一のアダプタ、同一のケーブル(USB-AとUSB-Cのケーブルを購入した)でやっているので、これはおそらくコンセントの段階での電圧の問題ではないかと思います。先日、「充電できる」と思っていたら、「充電できない」という状況に遭遇しました。とはいえ、1日程度はなんとかバッテリーは持ちました。
次にディスプレイアダプタ(USB-C Digital AV Multiportアダプタ)を装着すると、Nexus 7のACアダプタでは、100%充電はできないし、給電もできないことがわかりました。アダプタが電源を食うのか、USBの機材の関係なのか、ともかくNexusのアダプタ経由では充電や給電ができないのです。
しかし、なんと、iPadに付属のACアダプタ(12W)だと、ディスプレイアダプタを経由して、MacBookに給電/充電ができるのです。ということは、持ち歩きはiPadのアダプタでいいということになりますね。iPadは、Nexusのアダプタで使えばいいということで、「予想外の嬉しい組み合わせ」がもう1つ見つかりました。
代替のACアダプタ、つまり、軽いとか、安いのでいくつか買ってあっちこちにキープみたいなことができないかと考えるわけですが、USB出力があって、10Wを超える(つまり、1つのポートで20W)みたいな製品ってAmazonで調べたけど、見当たりませんでした。USB出力のACアダプタは、ほぼ、スマホタブレット向けで、出力が低いのです。20Wと書いてあっても2端子合計だったりするのが普通のようです。iPadのACアダプタは2200円なので、純正品が5800円に対して半額以下であり、大きさも小さいということもあり、ある意味、持ち歩き用としては、買い足してもいい範囲なんじゃないかと思います。
USB-Cのケーブルもまだまだ高いですし、USB-Cの反対側が高出力のACアダプタ向けのものなんてまだ見当たりません。ということで、新しいMacBookユーザが欲しいスペックのブツはどうやらまだまだのようです。要するに純正以外の選択肢が非常にない状態ということです。予測はしていましたが、とにかく乗り切らねば。Facebookでリンクを紹介しましたが、クラウドファンディングで募集しているHub+がまずは新しいパターンの製品ですね。mini Display 端子があるので、Apple純正のディスプレイをつなぐことができます。
ディスプレイアダプタが来て本格的に利用
新しいMacBookは日曜日に来ました。そして、今日水曜日に遅れてUSB-C Digital Multiport Adapterが到着し、やっと大画面ディスプレイと接続ができました。薄っぺらいもののちょっと大きなアダプタですが、3つのコネクタを横に並べるとしたら、やっぱりこのサイズになるでしょうか。USB-Cには本体付属のケーブルで、付属のACアダプタへ接続しています。ディスプレイとは、ディスプレイに付属のUSBケーブルと、購入したHDMIケーブルで接続をしています。
このMacについてを見てみると、ディスプレイフルの解像度で見えています。4Kということで、4000弱の横ドット数です。
ところが、「システム情報」を見てみると、1920×1080となっており、ディスプレイ自体のちょうど半分の解像度です。これは、Appleの27インチのCinema Displayの解像度(2560×1440)より低い解像度となります。Command+Shift+3で画面ショットを作成すると、3840×2160ドットなので、ディスプレイのフルの解像度を利用していることがわかります。
システム環境設定の「ディスプレイ」では、外付けディスプレイも、内蔵ディスプレイと同じように、ドット数ではなく、4段階の選択になっています。つまり、外付けのRetinaディスプレイとして扱っていると考えていいのではないでしょうか。
実は直前まで使っていたのはMacBook Airで、RetinaディスプレイのMacは今回購入したMacBookが初めてなんです。もちろん、美しいのは当然ですが、外付けディスプレイまで、Retinaの処理をしているのは知りませんでした。しかしながら、外付けディスプレイの表示結果は、内蔵ディスプレイに比べて「ちょっと大きい」感じがします。27インチのディスプレイの、従来の解像度よりも低い解像度だけに大きく見えるのは当然でしょう。内蔵ディスプレイの内容がやや小さいので、並べると外付け側が大きい感じが出ます。
しかし、最近、視力も落ち気味だけに、ちょうどいいかとも思っています。システム環境設定の「ディスプレイ」で「スペースを拡大」側のいちばん右にすると、さすがに小さすぎます。しかし、これは、もしかして、5Kだったら大きさ感が一致するのかもしれません。もしかして、それが理由で4KディスプレイをAppleは出さない(部品がなくてだせないとか?)のかもとも思ってしまいます。
Yosemiteでdocdiff
以前、2つの文書の比較結果をカラーリングで示せるdocdiffのことをMavericks向けに書きました。Yosemiteで同じようにすると動きませんでした。しかし、gemで簡単にインストールできるようです(松尾さんありがとう)。
sudo gem install docdiff
これで、/usr/bin/docdiffがコマンドとして機能するようになります。そのほかのライブラリファイル群は正しい場所に入っているということで、気にしないで行きます。
さて、svnで使うには、パラメータの組み換えが必要です。そこで、/usr/local/binにdocdiffを作ってそれを実行用にします。もちろん、viでもemacsでもご自由なエディタで編集してください。もし、/usr/local/binが作られていないのなら、mkdirコマンドで作ってください。
sudo nano /usr/local/bin/docdiff
中身はこのように書きます。
#/bin/sh
/usr/bin/docdiff --format=tty $6 $7
そして、もちろん、アクセス権を設定しておきます。
sudo chmod a+x /usr/local/bin/docdiff
こうすれば、以下のようにsvnコマンドを打ち込むときに、docdiffを使って比較を行います。最後のパラメータはファイル名です。
svn diff --diff-cmd=docdiff -r PREV _any_file_name_
もし、パス(echo $PATH で確認できます)が、/usr/local/binに通っていないとか、/usr/binより後にある場合には、上記のパラメータの1つを「–diff-cmd=/usr/local/bin/docdiff」のように指定します。
ということで、docdiffは便利です。