Category Archives: Uncategorized

ディスプレイをDell P2716Qに置き換えた

Apple LED Cinema Display 27インチは売り先が決まりそうなので、さっそくディスプレイを買い換えました。新しいMacBookにリプレースすると、Cinema Displayへの接続がとりあえずはできない(そのうちできるかもしれないけど)ので、HDMIのあるものに切り替える必要があります。以前のブログ記事のように、BenQの24インチもありますが、もう少しクオリティたかそうなものが欲しいのと、せっかく新しいMacBookなので、4Kにしようと思い、Dell P2715Qに変えました。

しかしながら、まだ新しいMacBookは到着していないので、本体はMacBook Air 2012年モデルのままです。Mini Display Portから直接つないでみましたが、もちろん、つないでほぼ即座に使えました(最初に入力元の切り替えだけ必要)。

IMG_0381

大きさ感はCinema Displayとさほど変わりません。もちろん、筐体のゴージャスさは大きく差がありますが、まあ、それは仕方ないでしょう。MacからはUSBケーブル1本で、ディスプレイ側に接続し、そこから4つのUSBケーブルを接続できます。USBのハブの出力先は1本増えたのは嬉しいところ。ただし、MacBook Airへの電源供給がなくなったので、ACアダプタを自宅でもしばらく使うことになります。

システム環境設定のディスプレイで見ると、本体が4K対応ではないので、2560×1440しか出ません。Cinema Displayだとそれが最大の解像度だったのでくっきり見えていましたが、Dell P2715Qだと、若干「解像度落としてます感」がありますね。まあ、でも気になりません。画質もBeQの24インチより色が自然な感じです。IPSだからというのもあるかもしれません。まあ、3倍くらい高いから当たり前といえば当たり前かもしれません。「プリセットモード」ってのがあるのですね。けっこう色調が変わりますが、とりあえずスタンダードです。

shot0319

システム環境設定の「サウンド」の出力を見ると、DELL P2715Qと見えているのでおや?と思ったのですが、単に項目として出るだけですね。サウンドがないのはもともと知っていました。下手なスピーカーをつけるより、正しい設計だと思います。そういえば、ラインアウトがあるので、つないだら何か出てくるのだと思います。

shot0318

大画面が2枚欲しいと言いながら、実のところ、クオリティ差が大きいこともあって、結局1枚しか使わない状態になりました。ただし、MacBookが来たら、Retinaだし、トラックパッドも新しくなります。ということで、多分、Dellのディスプレイの前にMacBookを置くパターンで作業するでしょうね。ということで、BenQ 24インチはまたまた、使う機会が減ったままです。実は、今ところ、Apple TVとつないで、大画面ラジオ(意味ない〜笑)にしか使っていない状態です。まあ、でも、たまに画面が欲しくなるときもあるだろうから、AirPlayでスタンバイのままで行くでしょう。

などと書きながら考えて、こういうセッティングにしてみました。右側のBenQ 24インチの後ろに、PromiseのPegasus R4とMac mini Serverがあります。なんとなく、スタンドの位置は夜になって悩む気がしますが、MacBookが来るまでの2、3週間はこの体制かなと思いっています。右の方の机は、もちろん片付けます(笑)。

IMG_0382

Yosemiteのウインドウの緑ボタンは最大化でなくフルスクリーン

Yosemiteのウインドウのタイトルバーにある左側のボタンがすっかりデザインが変わりましたが、もっと重要な違いがあります。緑のボタンをクリックすると、今までは最大化されましたが、Yosemiteではフルスクリーンモードになります。

スクリーンショット 2014-10-17 17.49.05

一方、タイトルバーをダブルクリックするか、あるいはoptionキーを押しながら緑のボタンをクリックすることで、従来の「ウインドウ最大化」と戻しができます。ただし、Chromeではタイトルバーをダブルクリックでは最大化されないので、アプリケーションの実装によりできない場合もあるかも。

緑のボタンを押してフルスクリーンにしてしまうと、メニューはでなくなります。また、タイトルバーの右端にあったフルスクリーンから戻すボタンもなくなってしまって一瞬慌てます

shot1110-1

元に戻すには、ポインタを画面上部に移動させます。すると、メニューも出ますし、緑色のボタンも出てきます。再度緑のボタンを押せば、元に戻ります。他には、「フルスクリーンを解除」のメニュー項目を探すのもいいでしょう。さらに、トラックパッドであれば、3本指スライドで、別のアプリケーションに移動するという方法もあります。もちろん、この方法は、フルスクリーンのままに、別の画面に切り替わります。

shot1111-1

ちなみにMavericksではこうでした。フルスクリーンにしたら、ウインドウの右側に戻すボタン領域が作られていましたが、Yosemiteではそれがなくなりました。

スクリーンショット 2014-07-28 2.50.37

 

[IM]ContributorとSpecial Thanksの定義

ReadmeなどにINTER-MediatorのContributorとSpecial Thanksの項目があって、ともかく英語で書いてありますが、この区分をいちおうきちんと定義しておきます。もちろん、状況に応じてルールの増減はあります。

Contributor

  • コア部分に関連するソースコードをコミットあるいは提供した
  • レポジトリにまとまったサンプルを提供した
  • 開発進行において重要な決定を下し、それを遂行した
  • Webサイトを主体的に編集した。あるいはWebサイトにまとまったページを作成した
  • 貢献順。たとえば、コードの行数など。判断はとりあえず新居が行う

Special Thanks

  • バグレポートを具体的にコミュニティに公開した
  • イベントやサイト運用などのコミュニティ活動を支えた
  • 順番は姓のアルファベット順、Contributorになればこちらのリストからは落とす
  • 通常は氏名のみ、つまり組織名は書かないが、希望があれば書きますよ

こんなところかと思いますが、ご意見ありますでしょうか?

[IM]コンテキストの共有化とPusherの利用

INTER-Mediatorでは、「コンテキスト」は、データベースに対するデータの出入り口的なイメージのものであり、検索条件などでの意味づけされたデータソースを意味します。その「共有化」とは、同一エンティティが複数のページ上のオブジェクトに展開されているとき、1つのエンティティを変更すると、その結果が他のオブジェクトにも反映される仕組みと定義します。Ver.4.4までに、単一ページ内のコンテキストの共有化が実現しています。つまり、あるページ上に、同一フィールドとバインドした要素があるとすると、一方を変更すると、もう一方は自動的に更新します。この動作を実現するためのプログラミングは必要なく、バインドの設定(ターゲット指定の付与)だけで可能です。

Ver.4.5に向けて、コンテキストの共有化をマルチクライアントで実現する仕組みを開発しており、概ね動くところまできました。つまり、同一のページを複数のクライアントで参照しているとき、誰かがデータを変更すると、その結果は他のユーザのページにも反映されるという動作が典型的です。従って、1つのフィールドを単一の要素にバインドしている場合でも、マルチユーザつまり複数のブラウザで同一のエンティティをバインドしているという点で「共有化」されていると言えるわけです。

コンテキストの共有化を実現するために、ページファイル上でのターゲット指定や、定義ファイルでのコンテキスト定義以外に何をしなければならないかをこの文書にまとめておきます。単一ページ内のコンテキストの共有化は特別な仕掛けは不要です。しかしながら、マルチクライアントでのコンテキストの共有化では、WebRTCを利用したPusherというサービスを利用することにしました。試用程度なら無償ですが、実運用には有償となってしまうものの、開発の効率化のために利用することにしました。

Pusherアカウントの取得とアプリケーション登録

Pusherのサイトでアカウントを取得します。Pusherでは「App」という単位で管理ができるので、たとえばINTER-Mediatorで作る1つのソリューションを、1つのPusherのAppとして登録するという方法もありますし、複数のソリューションで共有してもいいかもしれません。いずれにしても、アカウントを作成し、New Appというボタンなどで新たに1つのAppを作成します。ページ上に表示されるapp_id、key、secretの3つの情報がこの後に必要となります。

Pusherのサーバプログラムのインストール

PusherのサーバモジュールはPHP版を利用します。こちらのレポジトリをダウンロードし、そこから得られるlibディレクトリにあるPusher.phpという1つのファイルだけをサーバにインストールします。他は使用しません。ファイルはPHPの設定ファイル(php.iniが代表的)で、include_pathの設定で参照できるディレクトリにあればかまいません。もっとも安直な方法は、INTER-Mediatorフォルダに入れて、サーバにコピーしておくことです。もし、設定が以下のようなものであれば、例えば/usr/lib/phpディレクトリにPusher.phpをコピーしておけば良いでしょう。

include_path = ".:/usr/lib/php/pear:/usr/lib/php"

ページファイルへの追加

Pusherのクライアントソフトウエアを、ページファイルで組み込む必要があります。たとえば、以下のように、ヘッダ部で定義ファイル(include_MySQL.php)の読み込みの前に読み込みます。この方法だと、Pusherのサイトから直接取り出すので、ファイルを自分のサーバにコピーする必要はありません。ソースはこの通りコピペで大丈夫ですが、Pusherのバージョンが変わった時などはそれに合わせてください。

<html>
<head>
    :
    <script src="http://js.pusher.com/2.2/pusher.min.js" type="text/javascript"></script>
    <script type="text/javascript" src="include_MySQL.php"></script>
</head>

定義ファイルあるいはparams.phpへの追加

Pusherで定義したAppに関する指定は、定義ファイルのオプション部あるいはparams.phpで指定をします。原則的にはどちらか一方で定義をしてください。両方指定すると、定義ファイルの方が優先されます。定義ファイルでは、pusherをキーにした配列を定義し、さらにPusherのAppで示された3つの値を配列の各要素の値とします。以下は、定義ファイルでの定義例です。

IM_Entry(
    array( 
              /* コンテキストの定義 */ 
       ),
    array(
        :
        'pusher' => array(
            'app_id' => '1234',
            'key' => '9876543210',
            'secret' => '9876543210',
        ),
    ),
    array('db-class' => 'PDO'),
    false
);

params.phpファイルに記述するときには、以下のように、$pusherParameters変数に同様な配列として定義をします。

$pusherParameters = array(
 'app_id' => '1234',
 'key' => '9876543210',
 'secret' => '9876543210',
);

上記のいずれかがあると、マルチクライアントのコンテキストの共有化がオンになります。定義ファイルあるいはparams.phpの指定の有無だけで、共有化の利用/不使用が決まります。指定がないと一切何も行いません。指定があるのに、Pusherのサーバあるいはクライアントソフトウエアが利用できない状態になると、なんらかのエラーが発生します。

現状での制約

レコードの追加においては、そのコンテキストの検索条件を加味して、検索条件に合わないレコードの追加は行いません。しかしながら、別のクライアントで作成したレコードが当初はコンテキストに合わないものの、フィールドの値を変更してコンテキストの検索条件に合うようになっても、現状ではそのレコードが見えるようにはなりません。

さらに、コンテキストのソート条件は現状では加味されておらず、一連の表示リストのサイトに常に追加されます。

[IM]コンテキストに対応したモデルの実装

以前に「コンテキストの内部実装」という記事を書きましたが、コンテキストというか、正確には、コンテキストに対応したモデルの実装について、書いておきます。内部のソースを読んでいない人にはなんのことかさっぱり分からないと思います。

この仕組みを実装しているのは、INTER-Mediator-Context.jsファイルにあるIMLibContextクラスです。そこにあるいくつかのプロパティのデータ構造は、コードを読む場合や改造では絶対に必要な知識なので、一度まとめておこうと思っていました。

以下、「recKey」は、レコードを特定する文字列で、「キーフィールド=その値」という文字列です。たとえば、”id=3″のような文字列に相当します。そして、以下の「key」はすべてフィールド名の文字列が入ります。「portal」はFileMaker Serverを使う場合に、定義ファイルで’portal’=>trueにしている場合の、関連レコードに対応する外部キーの値です。FMS以外ではportal引数は渡されません。以下、portalが有る場合とない場合のデータ形式を記述します。

まず、IMLibContextクラスのプロパティstoreには、実際のフィールドのデータを記録します。store自体がオブジェクトで、以下のようにアクセスすることで、フィールドの値Valueにアクセス可能です。

this.store[recKey][key]→Value
this.store[recKey][key][portal]→Value

次に、プロパティbindingです。これは、データベースのフィールドが、どの要素に結びついているのかを記録するオブジェクトです。データベースから、バインドしているノードを求めるために用意しています。右辺は、オブジェクトの配列になっています。IdValueはバインドしたノードのid属性値です。Targetは、そこでのターゲット指定です。なお、Target指定は “” の場合もありますが、そのときにはTargetの値は “_im_no_target” という文字列にしています。

this.binding[recKey][field]→[{id: IdValue, target: Target}, ...]
this.binding[recKey][field][portal]→[{id: IdValue, target:Target}, ...]

次はcontextInfoプロパティです。こちらは、バインドしたノードから、データベースのどのレコードの、どのフィールドなのかを求めるためのものです。要するに逆テーブルです。thisと、.contextは同じものですが、thisが使えない状況を考慮してプロパティを作ってあります。

this.contextInfo[nodeId][target].context→コンテキスト自身
this.contextInfo[nodeId][target].record→recKeyの値
this.contextInfo[nodeId][target].field→keyの値
this.contextInfo[nodeId][target].portal→portalの値

これらの3つが主要なデータ構造となります。

FileMaker 13で、XMLおよびXSLTによる出力

久しぶりにタイトルのような事をやりました。この記事のハイライトは、変数でXSLTファイルの位置を指定できるようになったものの、エラーが出るという事象に遭遇しますが、その対処方法が分かったということです。

XML出力は、FileMaker 5くらいからありますし、出力するXMLデータにXSLTを適用して、テキストやらHTMLやらを生成することができるので、ちまちまと文字列処理を書かなくてもいいので便利です。XSLTの習得が大変という話もありますが、今時この種の情報は「基本知識」でしょうから、勉強すればいいのです。私自身は幸いにも、今はなくなってしまったXSLTでのWeb公開の時代に、かなり勉強していたし実稼働させたソリューションもあったので、自分的にはXSLTはOKです。この記事では、XMLやXSLTあるいはそれらを利用するFileMakerの機能については詳細には説明しませんので、必要な方は予習をしてください。

現実にXML/XSLTを使うとき、当然ながらXMLはテーブルを出力するときのフォーマットなので、テーブルから生成されることになります。一方、XSLTはどうでしょうか? 確実は方法は、Webサーバ等に配置して、URLで指定することですが、データベースファイルと別の管理対象ができて不便です。そこで、XSLTのテキスト自体をテーブルのフィールドにテキストとして保存しておくことで、データベースと一体化して管理ができて便利です。ただし、そのXSLTのテキストを利用するときにはファイルにしなければなりません。現実にはスクリプトを組むとして、1フィールド、1レコードだけのタブ区切りで出力すれば、余計な “” などは含まれません。ただし、その1フィールドに、改行が入っていると、コード番号12のものに置き換えられます。後から変更するのは面倒なので、XSLTのテキストから改行を除去する計算式を設定した計算フィールドをエクスポートすればいいのです。もちろん、XSLT内では改行の有無で動作が変わらないにしなければなりません。

さて、そこで、このXSLTファイルをどこに保存するのかということですが、WindowsでもMacで稼働できるようするには、テンポラリフォルダがいいのではないでしょうかということで、次のようなスクリプトで変数にパスを入れることにしました。順当な方法かと思います。

スクリーンショット 2014-06-26 10.47.20

この変数$templateJの結果を利用して、XSLTのテキストをエクスポートします。前に説明したように、スクリプトで、1レコードのみを対象レコードとして、改行を省いたテキストのフィールドだけをタブ区切りで出力します。出力ファイルに、変数$templateJを指定します。

ここで、XSLTによる変換をスクリプトのどこかで組み込むとします。スクリプトステップの「レコードのエクスポート」で、「出力ファイルの指定」を行い、OKボタンを押すと、ファイルタイプが「XML」の場合はさらに次のダイアログボックスが表示されます。ここで「XSLスタイルシートを使用」を選択し、ファイルを指定するわけですが、「ファイル」だとダイアログボックスが出て来て、特定のファイルの指定が必要です。Get ( テンポラリパス ) は一定のパスではない模様ですし、Win/Macでパスは違います。なので、「計算」を選択して、前の変数$templateJを指定して、実際に動かしてみます。ボタンと計算式の文字列が重なっているところにFileMaker社のこの機能への姿勢が見て取れます。

スクリーンショット 2014-06-26 10.46.40

すると、XMLのエクスポートをするときに、次のようなエラーが出ます。SAX(XMLのパーサ)のエラーがそのまま見えていて意味が分かりにくいですが、ようするにファイルが見つからないということです。Windowsでは、実際に見つからなかったパスも見えています。

スクリーンショット 2014-06-26 10.49.33

変数$templateJで出力し、その直後に変数$templateJでファイル参照して見つからない。ようするにバグなのですが、バグで使えません、以上ということでは前に進みません。バグは直らない可能性もあるからです。

そこで、変数$templateJの内容を、MacとWindowsで調べ見ました。Macだと、「/Macintosh HD/var/tmp/….」みたいになっています。Windowsだと、「/C:/Users/msyk/….」となっています。まず、Macは、明らかにパスの最初のコンポーネントを取り去れば、存在可能なUNIXパスになります。Windowsは…ともかく、まず、XSLTのテキストをエクスポートした後、以下のような「変数を設定」スクリプトステップを追加して、最初のコンポーネントを省いてみました。

スクリーンショット 2014-06-26 10.46.58

Macでは、予想通り、それでエラーなく動きました。一方、Windowsは別の対策をしないといけないかと思ったのですが、なんと、ちゃんと動きました。UNIXみたいなパスの与え方でどうやら動くようです。

XSLTのTipsを少し書いておきましょう。関連レコードのフィールドは、TOさえあれば出力できると思っていたら、ポータルに展開しないと出力されません。ポータルがない場合は、ちゃんと警告メッセージを出して、最初のレコードの値だけが出力されると言われます。ということで、ポータル作成はさぼれません。

関連レコードのデータは、たとえば2つのフィールドがあるとして、関連レコードが3つあると、次のように出力します。このノードの上位ノードのタグはROWになります。

<COL><DATA>1</DATA><DATA>2</DATA><DATA>3</DATA></COL>
<COL><DATA>abc</DATA><DATA>def</DATA><DATA>ghi</DATA></COL>

上記の2つのフィールドの番号を1、2とします。ROWタグがカレントノードのとき、上記のデータを展開するのにfor-eachを使うのですが、同じポータルにある関連レコードがいくつかるとき、for-eachをそのうち1つのフィールドに対して行います。次のような感じです。ネームスペースの略号は、xsl、fmrとしています。

<xsl:for-each select="fmr:COL[1]/fmr:DATA">
    <div>
        <xsl:value-of select="." />
        <xsl:value-of select="../../fmr:COL[2]/fmr:DATA[position()]" />
    </div>
</xsl:for-each>

最初のfor-eachは普通にDATAタグが複数あるので、それを1つ1つ取り出します。3行目の「.」によって、1つ目のフィールドの現在のDATAのテキストを取り出すので、「1」「2」「3」という値が順次取り出されます。2つ目のフィールドは、4行目にあるように、XPATHの記述で、カレントノードからROWまで「../..」でさかのぼり、そこから、COL、DATA集合へと下ります。そして「position()」というのは関数です。for-eachでループしているときに、何番目なのかを示す値を返します。これで、「abc」「def」「ghi」という文字列が順次得られます。

最後に大サービスで(笑)、FileMakerのXML出力向け(ただし、FMRXMLRESULTスキーマ)の汎用的なテンプレートを書いておきましょう。コピペして、あとはデータの順序に合わせてFMPXMLRESULTやROWタグ要素に対応するテンプレートにHTML等で出力テンプレートを書くだけです。

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xhtml="http://www.w3.org/1999/xhtml"
    xmlns:fmr="http://www.filemaker.com/fmpxmlresult"
    exclude-result-prefixes="xhtml fmr">
<xsl:output encoding="UTF-8" method="xml" indent="yes"
   omit-xml-declaration="yes"/>

<xsl:template match="fmr:ERRORCODE | fmr:PRODUCT | fmr:METADATA">
</xsl:template>

<xsl:template match="fmr:FMPXMLRESULT">
    <html><body><table>
       <tr><th>Name</th><th>Activity</th></tr>
       <xsl:apply-templates />
    </table></body></html>
</xsl:template>

<xsl:template match="fmr:ROW">
    <tr>
        <td><xsl:value-of select="fmr:COL[3]/fmr:DATA[position()]" /></td>
        <td>
            <table>
                <xsl:for-each select="fmr:COL[1]/fmr:DATA">
                   <tr>
                       <td><xsl:value-of select="." /></td>
                       <td><xsl:value-of select="../../fmr:COL[2]/fmr:DATA[position()]" /></td>
                   </tr>
                </xsl:for-each>
             </table>
         </td>
    </tr>
</xsl:template>

ノートをつけてみた

コンピュータ使いにとって、メモにはこだわりがあるのが普通だろう。情報機器を常日頃から使いこなしているのなら、スマートにメモを取るなんてことは当然のことだ。…といいたいところではあるが、実際にはどうだろう? あれこれ試しては新しいサービスやソフトに乗り換えてみたり、戻ってみたりと試行錯誤する日々ではないだろうか?

そんな中、STAP細胞の真偽を巡って「ノート」という存在が明らかになった。そういえば、大学のときも化学系の連中はノートを使っていたような記憶があるが、私は電気系であり、あまり実験ノート的な縛りはなかった記憶がある。工学系はやはり再現性が最も基本だから、ノートをエビデンスとして使うということより重要なことがあるのだが、それはさておき、ふと思って日々の仕事の内容を「ノート」を付けることでどうなるかを見てみた。ただ、1冊は以前からずっと使っているのだが、案件用に1冊追加し、それまでのノートはそれ以外の用途と2冊を使う事にした。それまでの記録の付け方は後に説明しよう。

さて、5月の1ヶ月間でどのくらいのページになったかと言えば、案件用23ページ、その他9ページとなった。もちろん、ノートにすべてを書いているわけでなく、Macに向かって打ち込む以外の「記述」をすべてノートでやってみた結果である。とりとめのないメモや、ざっくりとした図や表などをノートに書いて行った結果である。

スクリーンショット 2014-06-12 16.17.58

それまでどうしていたかと言うと、まず、案件ごとのメモは、きわめてシンプルに、その案件のファイルがあるフォルダにテキストファイルで残していた。URLやアカウント、情報の断片など、とにかくばんばんとコピペする。

そして、まとまった情報は、EvernoteとFileMakerで作ったデータベースに保存する。当初はFileMakerだけだったのだが、iOSで共有するとなるとEvernoteの方が手軽である。特に、URLを入れればリンクになるとか、そういうのはFileMakerではできないわけではないが、はっきり言ってたんに面倒になるだけなので、現在は作る文書によって使い分けている。FileMakerはどちらかと言えば書庫的であり、EvernoteはWiki的に使っている。複数人が関わるプロジェクトではBacklogを使い、場合によってはRedmineに入ることもある。

さらに、「紙切れ」を用意している。最近は、日めくりの裏を永年愛用している。スタートレックやギターの日めくりを買っており、翌年はメモとして活躍するのである。

思い付いたとき、そこでテキストファイルが開いていれば書き込み、Evernoteが開いていれば書き込み、それも面倒なときにはまずは紙切れに書いておく。紙切れに書いたものは、一定期間後に電子的な手段にコピーするが、その一定期間を過ぎて不要になったものまではわざわざ入力はしないで捨ててしまう。どうでもいい情報は適当にスクリーニングされるということだ。この「一定期間」を置くというのはなかなかみそで、メモ情報が爆発しないという利点もあると考える。もちろん、面倒を避けているという消極的な意味もあるが、短期間で情報価値がなくなるものは、長期間後に復活する可能性は極めて低いと言っていだろう。

ノートにして不便な事は、1つの案件ベースでのトレースがしづらくなるということだ。そうやってノートを分けるということをすると、きっと今度はノートだらけになるのだろう。案件事にテキストファイルを作っている理由は、トレースがしやすいからでもあるし、何年か後に開くことを考えての事だ。

一方、ノートを書くという習慣は、考えたことに対して自己評価をする機会が与えられる感じがする。ガシガシと打ち込んでしまうとそれで終わってしまうのだが、手で文字を書くという時間の幅が考える余地を生み出すように思える。それはそれで悪い事ではない。

さて、これからどうしようか? やはり全面的にノートにするより、今までの方法にじわじわ戻すつもりである。コンピュータ使いとしては「ノートは不要」と言いたいところだが、ノートにはノートのいいところもある。iPadでJot!で手書きしていた時期もあるものの、やはりノートの方が疲れない気がする。だけど、ノートで全て行うのは、むしろきちんと整理ができない。結局のところは使い分けということになるのだろう。そして、日々の記録方法を改善することも仕事のクオリティを高めることになるのじゃないかと改めて感じる。

[IM]JavaScriptコンポーネントのプラグイン

以前から、HTMLエディタのtinyMCE、コードエディタのCodeMirrorや独自作成したファイルアップロードコンポーネントを使えるようにしていたのですが、なんとか「プラグイン」的に使える状態になったので、一度ドキュメントを作成します。JavaScriptで作ったコンポーネントに、データベースにあるフィールドの値を表示し、修正するとそれが書き戻される仕組みを提供します。ただし、コンポーネントごとに、初期化の方法は違うので、その部分を吸収するプラグインを作らないといけません。

JavaScriptコンポーネントの使い方

まず、JavaScriptのコンポーネントを使いたい場合には、次のように、data-im-widget属性にキーワードを書きます。プラグインができていればこれだけです。

<div data-im="testtable@text1" data-im-widget="tinymce"></div>

ここで、tinyMCEを使うにはプラグインが必要ですが、これについては、すでにINTER-Mediatorの中にあります。Samples/Sample_webpage/tinymce_im.jsがそれなので、たとえば、ページファイルのヘッダ部に、次のような記述を行ってtinyMCE自身の読み込みと、プラグインの読み込みを行っておきます。もちろん、パスは適切なものを指定してください。

<script type="text/javascript" src="tinymce/js/tinymce/tinymce.min.js"></script>
<script type="text/javascript" src="tinymce_im.js"></script>

Ver.4.4現在、tinyMCE、CodeMirror、それから独自に作ったファイルアップロードコンポーネント(Samples/Sample_webpage/fileupload_MySQL.htmlがサンプル)が利用可能です。

JavaScriptコンポーネントプラグインの作り方

プラグイン(前記のtinymce_im.jsに相当)は、JavaScriptで記述します。もちろん、tinymce_im.jsもサンプルとして参照する必要があるでしょう。

プラグインのファイルでは、IMParts_Catalog変数のオブジェクトに、プラグインのオブジェクトを追加します。このときのキーが、data-im-widget属性に指定するキーワードとなります。以下はその基本構造です。

IMParts_Catalog["tinymce"] = {
    instanciate: function (parentNode) { },
    ids: [],
    finish: function (update) { }
}

右辺のオブジェクトは、instanciateとfinishという2つのメソッドを持つ事が重要です。INTER-Mediatorは、ページ合成時に、im-data-widget属性があるノードを見つけると、そのノードを引数にとって、instanciateメソッドを呼び出します。

一方、ページ合成の最終段階、つまり、DOMオブジェクトが確定してページ上に存在する状態になった後に、finishメソッドが呼び出されます。結果的に、im-data-widget属性が設定された要素×レコード数の回数instanciateメソッドが呼び出され、最後に1回finishが呼び出されます。

プラグインの作業として必要なこと

この2つのメソッドが行うことは、コンポーネントに対するゲッタおよびセッタメソッドをそれぞれ展開したコンポーネントに対して設定することです。また、対応コンポーネントのid属性値を得るメソッドも実装します。たとえば、instanciateメソッドに記述するとしたら、次のようになります。instanciateメソッドを呼び出されたときの引数parentNodeあるいはコンポーネントのルートの要素に対して、以下の決められた名称のメソッドを実装します。メソッドの中身はtinyMCEの場合の例です。

parentNode._im_getComponentId = function () { // data-im-widgetのある要素に設定
    var theId = newId;
    return theId;
};
parentNode._im_setValue = function (str) { // data-im-widgetのある要素に設定
    var targetNode = newNode;
    targetNode.innerHTML = str;
};
targetNode._im_getValue = (function () { // コンポーネントのルートの要素に設定
    var thisId = targetId;
    return function () {
        return tinymce.EditorManager.get(thisId).getContent();
    }
})();

instanciateメソッドでの作業

通常、JavaScriptのコンポーネントは、特定の要素にidやclass値を適当に与えて、その要素の中に必要なオブジェクトを詰め込むといった動作をします。つまり、起点となる要素を用意しておき、そこに必要なオブジェクトを追加します。tinyMCEだと、手軽な作り方はTEXTAREAタグ要素を用意することですが、ページファイル上に記述した要素がどんな種類のタグ要素でもいいように、data-im-widget属性がある要素の子要素にTEXTAREAタグ要素を作り、その要素をtinyMCEで初期化するようにしています。

そのTEXTAREA要素のid属性は、適当に付けます。targetNodeで参照されるリピーター内の要素は、すでにid属性が設定されているので、そのid値に適当な文字を追加すれば、一意なid属性になります。_im_getComponentIdメソッドは、ここでのTEXTAREA要素に付けたidを返します。

なお、instanticateメソッド中は、まだ、リピーターはエンクロージャーに挿入されておらず、documentからたどれない状態になっています。その場合、初期化をしてもうまく動作しないと思われます。従って、instanciateメソッドでは、元になるTEXTAREA要素を作り、id番号を振り、そのid番号をidsプロパティの配列に追加して、必須のメソッドを定義するところまでしかできないのが一般的かと思います。idsプロパティはなくてもいいのですが、この後のfinalizeメソッドでそれぞれの要素を初期化するために、初期化すべき要素を後から特定できるようにするために、instanciateで作成した要素のidを残します。

instanciateメソッドの段階で実際に利用されるのは、_im_getComponentIdメソッドと_im_setValueメソッドなので、_im_getValueメソッドは実際には設定する必要はありません。_im_setValueメソッドについては、JavaScriptコンポーネントが初期化前であることを考慮して、機能する前の状態での値設定が可能なプログラムを記述する必要があります。

finalizeメソッドでの作業

この段階では、全ての要素がdocument配下にいるので、JavaScriptコンポーネントの初期化を実際に行います。なお、初期化した結果、ゲッタやセッタの動作を変えたい場合は、設定をしなおします。JavaScriptのコンポーネント内で修正した結果をデータベースに書き戻すには、_im_getValueメソッドを、初期化が終わった後の状態でのゲッタとして動作するように設定をする必要があります。単にデータベースに書き戻すだけでいいのなら、ゲッタの設定のみでかまいません。以下は、tinyMCEの例で、idsプロパティにコンポーネントのid属性値が配列として残されています。1つ1つの要素に対して、_im_getValueメソッドを追加しています。

 for (var i = 0; i < this.ids.length; i++) {
     var targetNode = document.getElementById(this.ids[i]);
     var targetId = this.ids[i];
     if (targetNode) {
         targetNode._im_getValue = (function () {
             var thisId = targetId;
             return function () {
                 return tinymce.EditorManager.get(thisId).getContent();
             }
         })();
     }
 }

tinyMCEのプラグインは、ページ上にあるすべてTEXTAREAをHTMLエディタにしてしまう動作で初期化するので、tinyMCE.initメソッドを呼び出すだけです。コンポーネントによっては、個別にオブジェクトをidsプロパティから取得したid値で参照して、それぞれに何らかのメソッドを適用しないといけないかもしれません。

結果的に、それぞれのJavaScriptコンポーネントごとにうまく初期化をしないといけませんが、場合によってはフレームワークの更新も必要になるかもしれません。

自分でJavaScriptコンポーネントを作る場合

自分で1からコンポーネントを作る場合は、以下のプラグインの骨格を作り、後は自由につくっていいでしょう。このクラスにメソッドを集めてもいいですし、他のファイルから参照してもかまいません。

IMParts_Catalog["myjscomponent"] = {
    instanciate: function (parentNode) { },
    ids: [],
    finish: function (update) { }
}

ブログを整理しました

会社員時代はブログは書いていなかったのですが、独立してしばらくしてから、だいたい2010年あたりからブログを書いていました。最初は、Mac OS X Server Snow LeopardのWikiを使っていたのですが、Lionへはうまく移行できたものの、その後に失敗(アカウントを消した)とか、Mountain Lionのときに変な場所に移行したとか、いろいろあって、2013年2月からはWord Pressで運用しています。

さらに、Mavericksに移行しようとして決定的な失敗をしてしまい(とほほ)。「過去のブログを見るだけ」のWebサーバとしても機能しなくなりました。FileMaker ServerをWebで動かしているのでどっちに転んでもやっぱり両方の用途に使うのはかなりしんどいです。ということで、日曜日に過去のブログをサルベージしました。PostgreSQLのデータベースからダンプして、手作業も入りながらのコピペで移行しました。INTER-Mediatorのブログは思考のプロセスを思い出すのに必要なこともあり、この関連記事は全部以降しました。他に、受けたとか、今でも意味があるというのはみんな移行しましたが、OS X Server関連はもういいかということで省略としました。

そんなわけで、過去の記事が突然、Twitter公開とかでよみがえってしまってすみませんでした。これで、ここ何年かの消えた記事が復活して一安心です。

FileMaker Server 13とOS X ServerのWeb

FileMaker Server 13と、OS X ServerのWebサービスの共存は基本的にはできません。となると、OS X ServerのWikiとかはあきらめるか、設定ファイルをあれこれということになりますが、ともかくいったんあきらめてFMS13を入れるといういう場合、80番と443番ポートが使われているのでインストールができないというメッセージに出くわします。

Webサービスを止めても、Wikiを止めてもまだそのメッセージが出ます。コマンドで落としてインストールしていたりしましたが、再起動したらやっぱりFMS側がだめになってどうしようもありません。徹底究明した結果、なんと、WebDAVが動いていました。ファイル共有でWebDAVを利用すると、Webサービスがオフでも、80番ポートを使ったhttpdが動いています。

では、WebDAVを全部オフにして再起動してみます。それでも、httpdは動いています。どうやら一度オンにすると、テコでも動くようです。そこで、すべての共有ポイントでWebDAVがオフになっていることを確認して、以下のコマンドを入れれば、おそらくすべてのプロセスが止まります。念のため再起動してもhttpdが動かないことも確認します。

sudo launchctl unload -w /System/Library/LaunchDaemons/org.apache.httpd.plist

httpdが動いているかどうかを確認するには、以下のコマンドを入れてください。このコマンドで80番や443番ポートをLISTENしているプロセスが見えるはずです。このコマンドで何も出てこなくなれば、OS X ServerのHTTPDのサービスはすべて止まった事になります。

sudo lsof -i | grep httpd

こうしてFMSをセットアップしますが、Web関連のフォルダが大きく変わります。/Library/FileMaker Server/HTTPServer以下に必要なファイルがあります。Webの公開フォルダはHTTPServer/htdocsにあります。ここにファイルを起きますが、httpdプロセスはfmserverアカウントで稼働していることに注意が必要です。_wwwではありません。

設定ファイルは、HTTPServer/conf/httpd.confがまず読み込まれます。設定を変更するには、まずこのファイルから確認しましょう。OS X Serverのよう「全部バーチャルホスト」的な設定ではなく、デフォルトのドキュメントエリアを使います。以下はその設定例です、ほとんど自分のメモみたいなもんです(笑)。赤字は追加記述です。.htaccess等を稼働させるには、AllowOverrideの指定が必要です。PHPはすでに動いていますが、既定のファイルはindex.htmlだけです。なので、DirectoryIndexの指定も行います。もちろん、必要に応じて設定は加えます。

<Directory "${HTTP_ROOT}/htdocs">
     Options All -Indexes -ExecCGI -Includes
     AllowOverride All
     Order allow,deny
     Allow from all
 </Directory>

DirectoryIndex index.php index.html

ここで、設定ファイルを変更したらapachectl gracefulと思いたいところですが、普通にこのコマンドを入れても、OS X ServerのApacheの状況を変えようとするだけで、FMSが起動しているhttpdには適用されません。FMSのhttpdのスタート、ストップ、そして設定の反映は、次のようなコマンドを打ち込みます。

sudo touch /Library/FileMaker\ Server/HTTPServer/start
sudo touch /Library/FileMaker\ Server/HTTPServer/stop
sudo touch /Library/FileMaker\ Server/HTTPServer/graceful

もちろん、フルパスでなくてもかまいません。これらのファイルの修正日を更新するのです。こうすると、/S/L/LaunchDaemonsにあるcom.filemaker.[start|stop|graceful].plistによるファイル修正の監視が行われていて、FMSのhttpdデーモンの処理を行います。これらのlaunchdファイルを見れば分かりますが、/Library/FileMaker Server/HTTPServer/bin/httpdctlというコマンドが用意されていて、このコマンドを経由して、httpdをコントロールするようです。

そういうわけで、設定ファイルを変えてはsudo touch gracefulとやればいいということです。日曜日はOS X ServerとFileMaker Serverのメンテで終わってしまった…。