2010年10月10日日曜日

ハードウェアをアクセスするサンプルコード3.2

dealWithDevice()
IOReturn dealWithDevice(io_service_t usbDeviceRef)
{
  変数宣言
  err = IOCreatePlugInInterfaceForService(..., ..., ..., ..., ...);
  エラー処理
  err = (*iodev)->QueryInterface(..., CFUUIDGetUUIDBytes(...), ...);
  IODestroyPlugInInterface(...);
  エラー処理
  err = (*dev)->GetIOUSBLibVersion(..., ..., ...);
  エラー処理
  出力
  return err;
}

dealWithDevice()ではIOCreatePlugInInterfaceForService()でプラグインを生成し、さらにQueryInterface()でDevice Interfaceを生成します。このDevice Interfaceを経由して装置とやり取りします。USBの場合はIOUSBLib.hにある関数を利用して、USBのInterfaceを開いて、目的の装置を確認して、必要な作業を行います。今回の場合はGetIOUSBLibVersion()を呼び出してバージョンを調べているだけです。

topに戻る

ハードウェアをアクセスするサンプルコード3.1

main()
int main (void)
{
  変数宣言
  err = IOMasterPort(..., ...);
  エラー処理
  matchingDictionary = IOServiceMatching(...);
  エラー処理
  err = IOServiceGetMatchingServices(..., ..., ...);
  matchingDictionary = 0;
  if ((usbDeviceRef = IOIteratorNext(...)))
  {
    err = dealWithDevice(usbDeviceRef);
    エラー処理
  } else {
    エラー処理
  }
  使用したオブジェクトの解放
}

ここではIOMasterPortでポートを開き、ポートにアクセスするためのオブジェクトとして先ほどのmasterPortを利用します。確実にメモリ領域を取得するために、この命令を最初に入れます。


次に、以下の一文でIO RegistryデータベースにUSBに関して問い合わせるためのオブジェクトを作ります。

matchingDictionary = IOServiceMatching(kIOUSBDeviceClassName);

AppleではこのオブジェクトをDictionaryと読んでいますが、問い合わせたい内容をこのDictionaryに追加して目的の装置やソフトウェアを見つけ出します。

問い合わせの内容を追加する作業は意外と面倒です。USBを例にすると、USBには装置を特定するために企業名を指すVender IDと装置を指すProduct IDがあります。それぞれのIDをCFNumberCreate()と言う関数でCore Foundationのオブジェクトに変換し、CFDictionaryAddValue()でDictionaryオブジェクトに追加し、不要になったCore FoundationのオブジェクトをCFRelease()で解放し、0を代入してカーネルが必要に応じてパージしても良いようにします。

このサンプルコードでは、USB全体をターゲットにしますので、最初の IOServiceMatching()だけでDictionaryオブジェクトの作成が終わり、すぐにIOServiceGetMatchingServices()を読んでUSBに関連するデータを取得します。

IOServiceGetMatchingServices()では三つ目の引数として&iteratorというオブジェクトに入れています。USBやPCI拡張カードでは同じ装置が何台も接続されているかもしれません。&iteratorオブジェクトは複数の装置がつながっている場合を想定したオブジェクトで、装置に関するデータをif文で一つずつ取り出して処理します。この処理をするのがここで書かれている二つ目の関数であるdealWithDevice()です。

topに戻る

ハードウェアをアクセスするサンプルコード3rd

サンプルコードの説明

main.cファイルに書かれている内容を紹介します。サンプルコードと見比べながらご覧ください。

#include 
 省略
#include 

#ifndef __DebugSettin__
 省略
#endif // __DebugSettin__

mach_port_t  masterPort = 0;

IOReturn dealWithDevice(io_service_t usbDeviceRef)
{
 省略
}

int main (void)
{
 省略
}

まず、#includeで宣言されているファイルはポートを開いたり、IOKitとやり取りするためのヘッダファイルです。CoreFoundationは基本的な文字列操作から始まり、Mac OS Xのさまざまな基礎データを扱うライブラリです。

次の#ifndef...#endifはデバッグ用のコンソールやシステム ログへの出力を切り替えるマクロです。

グローバル変数のmasterPortはポートを参照するオブジェクトです。

関数はdealWithDevice()main()の二つです。main()で作業の対象となるオブジェクト(USBのドライバ)を探し出し、dealWithDevice()で作業(USB バージョンの取得)をしています。今回はUSBのドライバを見つけ出してやり取りしていますが、通常はUSB装置やPCI拡張カードなどを探し出して、見つけた装置とやり取りします。

戻る

ハードウェアをアクセスするサンプルコード2nd

コンパイル手順
コンパイルにはXcodeを使います。古いものでも動作しますが、今回はXcode 3.2.2を使用しました。理由はたまたま手元にあるものがこのバージョンであったと言うだけです。zipファイルにはXcodeのプロジェクト ファイルも入っています。プロジェクト ファイルから作る場合のコンパイルの手順は以下の通りです。
  1. Xcodeを起動
  2. [ファイル]メニューから[新規プロジェクト...]を選択
  3. 左蘭から[Mac OS X]>[Application]を選択
  4. 右蘭から[Command Line Tool]を選択
  5. Typeは”C"のまま、[選択]ボタンを押下
  6. プロジェクトの保存場所、プロジェクト名を決定
  7. メインのウィンドウ右蘭から"main.c"を選択
  8. main.cファイルをダブルクリック
  9. main.cの内容をサンプルコードに入れ替え
  10. メイン ウィンドウ左蘭からプロジェクト名を選択
  11. プロジェクト名を右クリック
  12. [追加]>[既存のフレームワーク...]を選択
  13. リストから以下の二つを選択して追加ボタンを押下
    * CoreFoundation.framework
    * IOKit.framework
  14. [実行]メニューから[コンソール]を選択
  15. [ビルドと実行ボタン]を押下
以上で、コンソールの画面にUSBLibとUSBFamilyのバージョンが表示されます。
    USBLib    Version is 3.90
        stage is 80 non-released version is 00
    USBFamily Version is 4.02
        stage is 80 non-released version is 00

戻る

ハードウェアをアクセスするサンプルコード1st

Mac OS X ハードウェア アクセスの概要

Mac OS XではIO Registryと呼ばれるデータベースにハードウェアに関する情報やDevice Driverなどを保管しています。Windowsのデバイス マネージャに近いものと考えても良いでしょう。このIO RegistryをブラウズするツールとしてIORegistryExplorer.appというソフトウェアがあります。Mac OS Xに標準付属の開発環境Xcodeをインストールすると以下の場所にありますので、試しにブラウズしてみてください。


/Developer/Applications/Utilities/IORegistryExplorer.app

Mac OS XではDarwinカーネル内にあるI/O Kitがハードウェアに関連するリソースを管理しています。ハードウェアをアクセスするにはこのI/O Kitを通してやり取りしますが、Darwinカーネルのメモリ空間(カーネル空間)とアプリケーションのメモリ空間(ユーザ空間)は分離されて、相互のやり取りは限定されています。ユーザ空間にあるプログラムからカーネル空間のI/O Kitとやり取りするために、通常はDevice Interfaceを経由してやり取りします。Device Interfaceはユーザ空間側にあるライブラリまたはプラグインです。

Mac OS Xのユーザ空間側にあるプログラムからハードウェアにアクセスする一般的な手順は、まずIO Registryのデータベースに問い合わせてハードウェアを参照するオブジェクトを入手します。次に入手したオブジェクトを元にDevice Interfaceのプラグインを開いて、そのプラグインとI/O Kitを経由して目的の装置とやり取りをします。やり取りが終わるとオブジェクトなどを解放してプログラムを終了させます。

サンプルコードはTerminal用のアプリケーションで、USBを管理するソフトウェアであるUSBLibUSBFamilyのバージョンを表示します。この時に上記のIO RegistryデータベースにUSBの情報を問い合わせて、Device Interfaceを経由してそのバージョンを入手し表示しています。

戻る

ハードウェアをアクセスするサンプルコードtop

2年前に公開するつもりでコードの切れ端をかき集めて、そのままになっていたサンプルコードを見つけました(笑)

USBを例にして、Mac OS Xでハードウェアをアクセスする時の基本を紹介したコードです。知っている人には何を今さらというたわいないものですが、始めてMac OS Xでハードウェアをアクセスするプログラムを書く人にはヒントになると思います。

詳細はAppleの資料Accessing Hardware From ApplicationsFinding and Accessing Devicesを参照してください。昔と比べれば大幅に改善されて分かりやすい解説になっています。

サンプルコードはこちらからダウンロードしてください

目次

2010年9月10日金曜日

データベースと表形式

データベースではデータを表にして利用する場合が多いと思います。
この場合に、表計算ソフトなどのように入力したデータを枠の長さに合わせてクリップ処理したいと思う人も多いと思います。

表で入出力をするには<table>タグの中に<input>タグを入れる方法もあるのですが、以下の二つに理由でどうも私の好みに合いません(笑)
  • 上下左右に余白ができて場所を取りすぎる
  • HTML文またはJavaScript命令が長くなって読みにくくなる
<table>タグにJavaScriptのsetAttribute()でcontenteditableのスイッチを付けて直接編集できないかを試してみましたが、以下のようになって改行処理とスクロール処理が思うようにできません。

元の表が以下のような物とします。
    • 一つの英単語が長いと、その長さに合わせて枠が横に長くなります。
    • 枠に入りきらない英文または和文を入力すると、文章が改行されて枠が縦に長くなります。

    以下のCSS文を試してみましたが、思うような結果を得られませんでした。

    試したCSSの一覧。(命令にwebkitとあるのはwebkit独自の仕様で、この記事を書いた時点ではHTML5に採用されていません)

    width: 35px;
    -webkit-column-width: 35px;
    text-overflow: clip;
    white-space: nowrap;
    word-wrap: break-word
    word-wrap: normal;
    overflow: hidden;
    overflow-x: hidden;
    overflow-y: hidden;
    overflow-y: scroll;
    -webkit-user-modify: read-write-plaintext-only;
    -webkit-user-modify: read-write;

    今のところ、<table>タグの中に<input>タグを入れるか、<div> タグで四角を縦横に並べるしか方法が思い付きません。

    Safariのtransaction

    SafariのopenDatabase」の項目に引き続いて、以下のURLにあるSafariのデータベースの解説を見ていきたいと思います。

    Safari Client-Side Storage and Offline Applications Programming Guide: Introduction
    http://developer.apple.com/safari/library/documentation/iPhone/Conceptual/SafariJSDatabaseGuide/Introduction/Introduction.html

    Safariのデータベースで面倒なのが"Listing4-2 CreatingaSQLtable"にあるようなトランザクション処理の関数です。"Listing4-2 CreatingaSQLtable"にある最初のトランザクションは「SafariのopenDatabase」の項目にあるように他の関数に移し、すでにデータがある場合の処理は別にしたとして、データベースに初期データを入れる部分を抜き書きして、さらに初期データを一つだけにすると以下のようになります。

    function createTables()
    {
     db.transaction(
      function (transaction) {
       transaction.executeSql('insert into people 
        (name, shirt) VALUES ("Joe", "Green");',
        [], nullDataHandler, errorHandler);
      }
     );
    }
    

    関数内の最初の二行で、データベースのオブジェクト db のメソッドである transaction に関数を渡しています。渡した関数の引数がオブジェクトになっていて、そのオブジェクトのメソッドである executeSql でSQL命令を発効しています。
    これだけでもチョット面倒ですが、さらに面倒なことに executeSql メソッドの引数が四つあって、その内の二つが関数で、その二つの関数がくせ者です(苦笑)

    そのくせ者の前に注意しなくてはならないのが transaction です。 db.transaction とその後の transaction は別物です。 function(transaction)transaction.executeSqltransaction は同じ変数で、その名前は transaction である必要はなく、 myTransaction などの他の変数名でも動作します。ここで同じ名前を使用しなくてはならない理由が私には思い付かず、サンプルコードとしては誤解を招きやすい解説だと思います。私は実際のコードを書く場合でも、後から調べることを考えて別名にしています。

    閑話休題、もとの「くせ者」の話に戻しましょう。この二つの関数は一方通行で、行ったまま戻ってきませんし、引数を渡すこともできません。呼び出される関数の引数は二つのオブジェクトと決まっています。マウスなどのイベントを処理するメソッド addEventListener に近い感じです。また、話しを脱線させると・・・個人的な経験を元にした推測にしか過ぎませんが、おそらくトランザクション処理をするために非同期コールを組み込む必要が出てこのような面倒なことをしているのではないか?と思っています。

    さて、 executeSql メソッドの第一引数と第二引数はC言語の printf 関数のようなイメージで使用しますが、変数が多くなると高い確率で間違います・・・つまり、私は間違いました(笑)また、初期化に限らず似たような処理を繰り返し実行することは良くあります。そこで私は「SafariのopenDatabase」の項目にあるSQL文の書き方にもう少し手を加えた方法を利用しています。一つの参考としてご紹介します。

    function createTables()
    {
     var nameShirt = {    
      "Joe": "Green",
      "Mark": "Blue",
      "Phil": "Orange",
      "jdoe": "Purple"
     }
     db.transaction(
      function (trans) {
       for(var index in nameShirt) {
        var mySQL = 'insert into people (name, shirt) VALUES ("' +
         index +
         '", "' +
         nameShirt[index] +
         '");';
        trans.executeSql(mySQL, [], nullDataHandler, errorHandler);
       }
      }
     );
    }
    

    上記の方法をさらに手を加えると、複数のテーブルを扱う時に便利になります。私は、object literalとArrayオブジェクトを組み合わせて、データベースの構造を宣言して、SQL文のテーブルの宣言部分を書いています。

    以上のように関数の中に関数が多重で入っており書きにくく、読みにくく、間違いやすい構文になっています。このために、"Listing 4-5 SQL insert query example"にあるような書き方は、面白いとは思いますが・・・関わりになるのは避けたいです(苦笑)

    SafariのopenDatabase

    数年前にSafariにSQLiteのデータベースがついて一時期話題になりましたが、その後も色々と改善が続いているようです。その解説が以下のURLにあります。

    Safari Client-Side Storage and Offline Applications Programming Guide: Introduction
    http://developer.apple.com/safari/library/documentation/iPhone/Conceptual/SafariJSDatabaseGuide/Introduction/Introduction.html

    ちなみに、この資料の日付は2010/01/20となっていますが、PDF版の作成日にはいくつかのバージョンがあるようです。

    この資料では"HTML 5 Offline Application Cache"や"Key-Value Storage"の解説が追加されています。

    データベースに関する解説も手が加えられています。"Relational Database Basics"はSQLの初心者を対象にデータベースの解説があり、"Using the JavaScript Database"でJavaScriptからデータベースを利用する方法が解説されています。"APPENDIX A: Database Example: A Simple Text Editor"にはサンプルコードを元に解説があります。

    解説中のサンプル コードはわかりやすい書き方になっていますが、まだ完成には時間が必要ではないかという気がします。例えば"Listing 4-1 Creating and opening a database"にあるデータベースを開く時の処理です。

    try {
     if (!window.openDatabase) {
      alert('not supported');
     } else {
      var shortName = 'mydatabase';
      var version = '1.0';
      var displayName = 'My Important Database';
      var maxSize = 65536; // in bytes
      var db = openDatabase(shortName, version, displayName, maxSize);
      // You should have a database instance in db.
     }
    } catch(e) {
     // Error handling code goes here.
     if (e == 2) {
      // Version number mismatch.
      alert("Invalid database version.");
     } else {
      alert("Unknown error "+e+".");
     }
     return;
    }
    alert("Database is: "+db);
    

    この書き方であれば、データベースの名前やバージョンなど後から調べる時に便利そうです。

    ただし、このコードは関数内に入っていません。「最初に実行されるコード」の項目の1stの方法と同じようにすればこのままでも動作します。しかし、最初に一度しか実行しないコードをdeleteせずにメモリ上に置いておくのは無駄です。関数の中に入れて最初に実行させ最後にdeleteするのが妥当だと思います。ただし、この時には変数宣言のvar dbは式の外に置いてグローバル変数としないと他の関数でトランザクション処理ができなくなります。

    また、サンプルにある// You should have a database instance in db.というコメントは具体的に何をしようとしているのかが分かりません。データベースと同時にtaransaction()メソッドで'CREATE TABLE'を使ったテーブルの処理も考えているのかもしれませんが、この解説ではテーブルの処理は別の関数で処理しています。

    古いサンプルコードと比べるとopenDatabaseでデータベースが開けない時の処理がなくなり、try-catchcatchでエラー処理ができるようになったようです。エラー処理は"Handling Errors"と言う項目で解説されていますが、この通りには動いていないように思います。例えば上記のデータベースを開く時のcatchでの処理です。試しにversion1.12.0にすると、アラートに"Invalid database version."が表示されずに、以下のようなエラーとなりました。

    "Unknown error Error: INVALID_STATE_ERR: DOM Exception 11."

    さらに、"APPENDIX A: Database Example: A Simple Text Editor"にあるエラー処理では2の代わりに変数"INVALID_STATE_ERR"を置いていますが未定義のエラーになります。

    エラーのメッセージやエラーコードの処理が紹介されています。ただ、後半部分が何を意味するのか分かりません。
    function errorHandler(transaction, error)
    {
     // error.message is a human-readable string.
     // error.code is a numeric error code
     alert('Oops.  Error was '+error.message+' (Code '+error.code+')');
    
     // Handle errors here
     var we_think_this_error_is_fatal = true;
     if (we_think_this_error_is_fatal) return true;
     return false;
    }
    

    先にも書いた'CREATE TABLE'を使ったテーブルの処理は"Listing 4-2 Creating a SQL table"に書かれています。しかし、'CREATE TABLE'のSQL文は長文になりやすく、読みにくいものです。以下のような書き方の方が後から調べやすいと思います。また、複数のテーブルを扱う場合には、この方法を発展させると便利になります。

    db.transaction(
     function (transaction) {
      var mySQL = 'CREATE TABLE people(' +
       'id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, ' +
       'name TEXT NOT NULL DEFAULT "John Doe", ' +
       'shirt TEXT NOT NULL DEFAULT "Purple");';
      transaction.executeSql(mySQL, [], nullDataHandler, errorHandler);
     }
    );
    

    以上の内容をまとめると、今のところデータベースを開く関数は以下のような書き方が便利そうです。

    function initDB() {
     try {
      if (!window.openDatabase) {
       alert('not supported');
      } else {
       var shortName = 'mydatabase';
       var version = '1.0';
       var displayName = 'My Important Database';
       var maxSize = 65536; // in bytes
       db = openDatabase(shortName, version, displayName, maxSize);
       // You should have a database instance in db.
       db.transaction(
        function (transaction) {
         var mySQL = 'CREATE TABLE people(' +
          'id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, ' +
          'name TEXT NOT NULL DEFAULT "John Doe", ' +
          'shirt TEXT NOT NULL DEFAULT "Purple");';
         transaction.executeSql(mySQL, [], nullDataHandler, errorHandler);
        }
       );
      }
     } catch(e) {
      // Error handling code goes here.
      if (e == 2) {
       // Version number mismatch.
       alert("Invalid database version.");
      } else {
       alert("Unknown error "+e+".");
      }
      return;
     }
     // alert("Database is: "+db);
     delete initDB;
    }
    

    最初に実行

    最初に実行されるコード
    AppleのSafari 5.0.1とMac OS X版 Firefox 3.6.8でしか試していないのですが、JavaScriptで最初に実行されるコードを四つの方法で試してみました。

    試したコードは以下のような物です。
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
            "http://www.w3.org/TR/html4/loose.dtd">
    <html lang="en">
    <head>
     <meta http-equiv="content-type" content="text/html; charset=utf-8">
     <title>Untitled</title>
    <script type="text/javascript" language="javascript">
    <!--
    // 1st
    alert('without any function');
    
    // 2nd
    function init() {
     alert('called from body');
    }
    
    // 3rd
    window.onload = function() {
     alert('called from window.onload');
    }
    
    // 4th
    function loaded() {
     alert('called from addEventListener');
    }
    
    addEventListener('load', loaded, false);
    
    //-->
    </script>
    </head>
    <body onload='init()'>
    </body>
    </html>
    
    上記のコードをSafari 5.0.1で実行すると1st、4th、2ndの順で実行され、3rdは実行されません。

    また、上記のコードのbodyタグの引数onloadをなくすと、1st、3rd、4thの順で実行され、2ndは実行されません。

    Mac OS X版のFirefox 3.6.8で実行すると、1st、2nd、4thの順で実行され、3rdは実行されません。

    Safariと同様にbodyタグの引数onloadをなくすと、1st、3rd、4thの順で実行され、2ndは実行されません。

    3rdと4thは一般的に良く使用されるコードですが、1stと4thはAppleのエンジニアが書いたサンプルコードで見つけました。1stの方法はSafariに付属しているSQLiteのデータベースをJavaScriptから開く時に利用し、データベースのテーブルを開く時に4thの方法を利用していました。データベースを一番最初に開くという意味では1stの方法は便利かもしれませんが、メモリのフットプリント(占有領域)を小さくすると言う意味では以下の内容を考慮した方が良いと言えるでしょう。

    もったいない
    Appleの資料"Apple JavaScript Coding Guidelines"に、onload関連してメモリのフットプリント節約方法が書かれていました。

    http://developer.apple.com/safari/library/documentation/ScriptingAutomation/Conceptual/JSCodingGuide/Introduction/Introduction.html

    初期化コードなど一度しか実行しないコードは実行後にdeleteしてフットプリントを小さくすることを推薦しています。この資料では起動時の初期化コードを例として以下のようなコードを紹介しています。
    var foo = function()
    { 
     // code that makes this function work 
     delete foo; 
    } 
    window.addEventListener('load', foo, false);
    
    おそらくはiPhoneなどメモリを多く積んでいない装置を想定した話しでしょうが、不用意にメモリを浪費するのは問題を引き起こしやすいですし、「もったいない」です(笑)

    Safariのデータベース

    Mac OS XにはFileMakerなどの便利で高性能なデータベースがありますが、SafariのSQLiteのようにオマケでついてくるデータベースもあります。

    SafariのSQLiteにはFileMakerのようなGUIによるわかりやすい開発環境やデバッグ環境はなく、HTMLとJavaScriptをテキストエディタで書かなくてはなりません。おそらくは、開発途上にあるデータベースと言っても良いと思います。

    Safariがデータベースとして使用しているSQLiteには以下のような利点があると思います。

    • 1.オープンソースである
    • 2.仕事として利用しても無料である
    • 3.デーモンを走らせる必要がない
    • 4.起動 終了が早い

    1.のおかげでSQLiteのデータベース ファイルを参照し、編集できるツールがいくつか公開されています。2.は個人使用だけでなく、仕事として利用しても無料であると言う意味です。3.はデータベースを利用する度に逐一デーモンを起動や終了しなくてもよいので便利です。デーモンを起動したままにするのも一案ですが、そのためにわずかでもシステム起動時間が遅くなり、メモリなどを無駄にするのは私には納得できません。ただし、トランザクション処理のために呼び出しが非同期コールのようになり、初めての人には分かりにくく使いにくかもしれません。4.はSafariの起動も速いことも相まって、チョットしたメモや参照に便利です。

    簡単な動作検証として小遣い帳を作り半年ほど利用してみました。小遣い帳のような小さなデータベースであれば十分に実用できます。ただし、SafariはWebブラウザのため、検索できても置換できません。日記(Blog)などの文章を入力するデータベースではJavaScriptやJavaなどによる検索置換のプログラムが別途に必要です。

    2010年7月6日火曜日

    オブジェクトのメンバを見る

    色々とJavaScriptで書いていると、オブジェクトのメンバを見たくなることがあります。他のことをやっていて偶然気付きました。他にも紹介されていると思いますが、メモしておきます。

    for(var i in this) {
     alert(i);
    }
    

    ただし、注意しないと大量のメンバが表示されて、OKボタンを押すだけで飽きてしまいます(笑)
    また、Mac OS X上のSafari 5でしか動作確認していません。ご注意ください。

    もう一つの表<table>の描き方

    表の描画はinsertRowinsertCellを使わずに以下のようにもできます。Model、View、Controllerを考えるともう少し工夫が必要ですが、こんな事もできるという意味で紹介します。ただし、Mac OS X上のSafari 5とFirefox 3.6.3でしか動作確認していません。ご注意ください。

    createElementはJavaScriptでHTMLを生成する時に良く使用される方法ですが、当然<table>でも利用できます。また、この方法であれば<th>を直接生成できます。この例では先頭行で<th>を使用してその後に<td>を置いています。

    また、ここでは表の定義に配列を使用しています。for( i in fooArray )を使って行を生成していますので、testTable関数に行数と表のタイトルとセル幅を与えるだけで作表します。CSSの設定はclassName、その他の各行やセルの設定はsetAttributeが使えます。たとえば、setAttribute('contenteditable', true)とすれば、表の中身を書き換えられるようになります。さらに、addEventListenerでイベント駆動もできます。

    window.onload = function(){
     argTable = {
      numberRow: 5,
      myMenue: {
       "key": 35,
       "input date": 100,
       "item name": 200,
       "item number": 100
      }
     }
     myTable = new testTable(argTable);
     delete argTable
    }
    
    function testTable(arg) {
     var myTable = document.createElement('table');
     myTable.setAttribute('border', '1');
     var myTr = document.createElement('tr');
     for (var index in arg.myMenue) {
      var myTh = document.createElement('th');
      myTh.innerHTML = index;
      myTh.setAttribute('width', arg.myMenue[index]);
      myTr.appendChild(myTh);
     }
     myTable.appendChild(myTr);
    
     for (var i = 0 ; i < arg.numberRow ; ++i) {
      var myTr = document.createElement('tr');
      for (var index in arg.myMenue) {
       var myTd = document.createElement('td');
       myTd.innerHTML = 'test';
       myTd.setAttribute('width', arg.myMenue[index]);
       myTr.appendChild(myTd);
      }
      myTable.appendChild(myTr);
     }
     document.body.appendChild(myTable);
    }
    

    insertRowとinsertCell

    JavaScriptで表を扱う時の関数insertRowinsertCellですが、よく紹介されている方法とは少々異なる使い方のメモです。ただし、Mac OS X上のSafari 5とFirefox 3.6.3でしか動作確認していません。ご注意ください。

    insertRowinsertCellはJavaScriptで表を描画する時に利用される命令の一つで、insertRowにより表に一行追加でき、insertCellではセルを一つ追加できます。例えばinsertCell(n)としてnに数値を渡すと、nの位置にセルを挿入します。このninsertCell()またはinsertCell(-1)とすると行の一番最後にセルを追加します。サンプルコードなどで表を描画する時にループ文を利用しますが、この時に逐一nの値を与える必要はなく、insertCell(-1)とするだけで描画できます。これはinsertRow()でも同じです。

    さらに、insertCell()では<td>タグが生成されます。しかし、先頭項目などを表す<th>タグを直接生成する命令は見あたりません。代案としてinsertCell()<td>タグを生成して、その中身を設定する時にouterHTMLを使用することで<th>タグを間接的に生成できます。

    上記の方法をまとめて例を書くと以下のようになります。

    testData = new Array(10, 12, 15, 43);
    --- some codes ---
    for (var index in testData) {
     var myTh = myTr.insertCell(-1);
     myTh.outerHTML = "<th>" + index + "</th>";
     --- some codes ---
    }
    delete testData;
    

    ただし、Safari 5ではinsertCell(-1)としないとindexの順が逆になる場合があるようです。

    2010年6月20日日曜日

    文字の大きさ

    MacBook Pro 17"を購入しました。プロセッサをi7に、またハードディスク ドライブをシリコン ドライブ(ソリッド ステート ドライブ)に交換するなどしています。

    起動して一番に思った事は「文字が小さい」

    初期設定の解像度では12ポイントの文字が小さくて、老眼が進行している私には読みにくくなっています。WYSIWYGで有名になったMacintoshも、今や紙に印刷するのではなく、コンピュータ上で自分の好きな大きさにして読み書きするので、文字の大きさにポイントを用いる意味が無くなってしまいました。

    ただ、自分が読みやすい文字の大きさとは、書きやすい文字の大きさとは、などと余計な事を考えなくてはならなくなりました(笑)

    平安時代などの古い手紙の写真を見ると、書かれた文字に多少の大小はあってもかなり大きなものでした。それが、江戸時代の版画技術の向上(欧州の印刷技術の向上)などにより、大量の印刷物が市場に流通するようになり、それに伴って貴重で高価な紙の量を減らし経費を削減するために、読むための文字の大きさが小さくなった…ように思います。

    また、鉛筆や万年筆の登場で小さな文字が書けるようになり、さらにシャープペンシル、ボールペンで加速化されました。

    それがコンピュータ技術により、好きな大きさの文字で書いて、好きな大きさの文字で読むようになった、と言う事でしょう。

    実際、ノートPCにシリコン ドライブを搭載することで、故障を心配することなく読み書きできるようになりました。さらに、iPhoneやiPod touchで読み書きする場所や時間などの制約が少なくなり、iPadでそれが加速化されようとしています。

    iPhoneやiPod touchで書いて送信した文章はその内容に関係なく、書いた場所と時間は自動的に記録されますので、その統計だけでも大量の情報を未来に残す事になります。68億ある世界人口の四分の一でもTwitterなどインターネットで何かを書くようになれば、世界はどうなるのか?などと夢想します。

    2010年6月9日水曜日

    Safari 5の互換性

    データベースは変更せずに動きましたが、以下のようなタグで表示されるテキスト フィールドの幅が変わりました。
    < input id="xxx" size="12" type="text" />

    Safari 5のデータベース

    Safari 5をダウンロードしてデータベースを試した結果。少なくとも、私がSafari 4を使って試しに書いたデータベースを開く事が出来ました。

    また、[環境設定]の[セキュリティ]で[データベースを表示]ボタンを押して表示されるデータベースのリストが改善されました。今までは開いたデータベースのみを表示したのですが、Safari 5では開かなくても表示されるようになりました。Safari 4ではこれが不便でした。

    [開発]メニューの[エラーコンソールを表示]で表示されるウィンドウで、データベースを表示する機能は今までと同様です。データベースを開いた状態で、上欄から[ストレージ]を選択して、左欄から[データベース]を選択すると、データベース名やテーブル名が表示され、ウィンドウ内にデータが表示されます。

    ただし、[ストレージ]に便利な機能が追加されていました。開いているページのCOOKIEの詳細を表示してくれます。これが標準で付いているのは便利そうです。

    2010年6月6日日曜日

    Apple - HTML5

    私が2007年の資料に手こずっている間に、Appleは現在のHTML 5などの技術を使ったデモを発表しています。

    Apple - HTML5
    http://www.apple.com/html5/

    Appleお得意の見た目のきれいさと、そのための技術には唖然とします。

    2010年6月5日土曜日

    8. 後日談

    <最初にもどる> <pre>
    謎などと大袈裟な事を書きましたが、どうしても定義が見つからなかった構文があったのです。以下のオブジェクトのメンバ宣言です。何処かにあるはずなのですが、見つかりません。

    オブジェクトのメンバ宣言をするときに以下の例ようにしてSettingとGettingを簡単に宣言し、利用方法も簡単になります。
    function MyObject() {
    }
    
    MyObject.prototype = {
     get id() {
      return this._id;
     },
     set id(x) {
      this._id = x;
     },
    }
    
    function myCode() {
     myObject = new MyObject();
     myObject.id = 3;
     alert('id is ' + myObject.id);
    }
    
    上の式でメンバ変数を宣言できますし、WebKitのサンプルコードsticky-notesのようにメソッドも宣言できます。

    この便利な点はメンバ変数とそのset getが羅列するだけで簡単に宣言できる点です。また、下のtest()のように簡単にメンバ変数への代入と呼び出しができます。ただし、上の関数を使えるのは一度だけのようです。同じオブジェクトに追加宣言はできず、追加できるのはメソッドのMyObject.prototype.methodNameだけのようです。

    ストレステストはしていませんが、上記のサンプルコード程度ならFirfox 3.6.3でも動作しました。

    ECMAScriptにおける「オブジェクトリテラル」と言う書式では、配列を拡張してオブジェクトを宣言できます。
    myObject = {
     myVar: -- numbers,
     myVar: '-- words',
     myFunc: function() {
      -- definition
     }
    }
    
    似てはいるのですがどうも違うように思います。
    <最初にもどる> <pre>

    7. 恐怖の仮面this

    <pre> <next>
    myHandlerに渡される引数のeはイベントが発生した位置などを含む情報が入っています。しかし、サンプルコード2のaddEventListenerに渡されるthis.myHandlerには引数がありません。さらに、試しに、サンプルコード1のfunction(e) { self.myHandler(e) を function() { self.myHandler()とするとエラーになります。これでも良いような気もするのですが、どうもSafariの実装が
    怪しいような気も・・・(笑)

    いずれにしても、最初の二行は同じですし、動作も同じです。その後も変数が一カ所違うだけだと思って見逃すと・・・
    探偵失格です(大笑)

    それでは事件解明にかかりましょう。

    犯人はthisなのです。二つのサンプルにあるthisは別人…いや、別のオブジェクトを指しています。

    addEventListenerの使い方として良く紹介されているのですが、サンプルコード2のthisはHTMLの<div>を指しています。JavaScriptの仕様では、イベント駆動の元になるオブジェクトがJavaScriptのオブジェクトではなく、HTMLの<div>であると考えているようです。

    ところがサンプルコード1のthisではMyObjectから作られたmyRectオブジェクトを指しています。たとえば、サンプルコード1では以下のようになっています。
    alert(this.myObject.offsetLeft);
    
    これはthis.myObjectで表す四角の左端の座標offsetLeftを表しています。ではthis.myObjectとは?と言うと、MyObject()内にある以下のコードで以下のように表しています。
    this.myObject = myObject;
    
    そう、例の問題のコードです。この左辺のthisがmyRectになるわけです。だからこそサンプルコード1では以下の式でmyRectのプロパティが呼び出せたのです。逆に、サンプルコード2ではHTMLの<div>にはthisというプロパティがないので「undefined」になってしまったわけです。
    alert(this.myVar);
    
    サンプルコード2ではHTMLの<table>などHTMLの入れ子構造(ネスト構造)になっているものを扱うには分かりやすく便利そうです。しかし、上記のように親となった関数を指したくなる場合がある事も事実です。

    実際にWebKitのサンプルコードsticky-notesでは、addEventListenerで呼び出されたハンドラから、さらにaddEventListenerでハンドラを登録してそれぞれで変数を共有しています。グローバル変数という手もありますが、オブジェクトが繰り返し生成される(四角が作られる)たびにグローバル変数を生成していては後始末が大変です。

    個人的には明示的にどちらを選択するのかを引数を追加するか、関数名で明示したほうが分かりやすいように思うのですが・・・。

    閑話休題、一件落着したと思ったのですが、まだ謎が残っていました。それは・・・つづく(笑)
    <pre> <next>

    6. addEventListenerの浮気

    <pre> <next>
    二つのサンプルコードの違いは以下の通りです。二つのウィンドウにそれぞれのサンプルコードを左右に並べて表示してじっくりと比較してみてください。
    サンプルコード1
    myObject.addEventListener('mousedown', function(e) { self.myHandler(e) }, false);
    
    サンプルコード2
    myObject.addEventListener('mousedown', this.myHandler, false);
    
    サンプルコード2が一般的によく紹介されている書き方です。this.myHandlerは生成されたオブジェクトのmyHandler関数です。サンプルコード1ではfunction(e)でハンドラを定義しています。分かりやすいように改行を入れると以下のようになります。
      myObject.addEventListener(
        'mousedown', 
        function(e) { 
          self.myHandler(e) 
        }, 
        false
      );
    
    ここは関数定義の中ですので、ここでthisを使えば新規の関数定義となります。そこでコンストラクタ内のthisをselfに入れてself.myHandler(e)とすることでオブジェクト内のmyHandlerメソッドを指しています。

    なぜこのような面倒な事をしているのでしょう?また、この後のthis.myObject = myObject;という式も妙です。さらに、もう一つ気になるのは謎の引数eの存在です。実はthisがこの一件に強く絡んでいるのですが・・・三文探偵小説なら事件はいよいよ混迷を深めてきたというところでしょうか(苦笑)
    <pre> <next>

    5. サンプル コード2

    <pre> <next>
    サンプルコード1と同様に、このコードもhtmlのファイルにしてSafariで実行してみてください。

    実行すると灰色の四角が表示され、表示された灰色の四角をクリックするとクリックした位置のX座標と四角の左端の座標、そして謎の「undefined」がアラートボックスで表示されます。
    <html>
    <head>
    <style>
    .myCSS {
      background-color: rgb(240, 240, 240);
      height: 250px;
      width: 200px;
      position: absolute;
      left: 200px;
      top: 200px;
    }
    </style>
    <script>
    function MyObject() {
     var self = this;
     var myObject = document.createElement('div');
     myObject.className = 'myCSS';
     myObject.addEventListener('mousedown', this.myHandler, false);
     this.myObject = myObject;
     document.body.appendChild(myObject);
    }
    
    MyObject.prototype.myHandler = function(e) {
     alert(e.clientX);
     alert(this.offsetLeft);
     this.style.left = '100px';
    }
    
    function loaded() {
     myRect = new MyObject;
    }
    </script>
    </head>
    <body onload="loaded()">
    </body>
    </html>
    
    <pre> <next>

    4. addEventListenerとthis

    <pre> <next>
    謎は二つです。

      1.addEventListenerに書かれた謎のfunction()

      2.myHandler関数内のthisとはだれか?

    この二つが「奇妙な愛憎劇」のように絡んでいます(笑)

    addEventListenerは先にも書きましたように、マウスのボタンが押された時にシステムから渡されるイベントを取り込んで、そのイベントを扱う(ハンドルする)関数としてmyHandler()関数を登録しています。このmyHandler()関数はすぐには実行されずイベントが発生した時に(非同期に)実行されます・・・と言う事は他のサイトにも書かれていて、言わずもがなの話しです。

    構文は以下のようになります。

      addEventListener(イベント名, ハンドラ関数名, falseまたはtrue)

    イベント名はclickやkeyup、mousedownなどイベント駆動型のプログラミングでおなじみのもので、指定したイベントが発生するとハンドラ関数が呼び出されます。最後の引数はイベントが呼び出されるタイミング(登りか下りか)を表します。

    論より証拠です。実際にサンプルコード1を書き換えて、この構文に合わせてaddEventListenerを呼び出すとどのようになるか「現場検証」してみましょう(笑)
    <pre> <next>

    3. コードの流れ

    <pre> <next>
    コードの流れは以下のようになります。

    1.ファイルの読み込み
      最初に<body onload="loaded()">からloaded()関数を
      経由してMyObject()のコンストラクタが呼び出されます。

    2.コンストラクタ
      コンストラクタではcreateElement('div')で<div>タグが
      生成され、classNameで.myCSSのスタイルが指定され
      ます。

    3.スタイル
      .myCSのスタイルでは四角の色、高さと幅などが指定され
      ています。

    4.イベント登録
      addEventListenerでマウスのボタンが押された時のイベ
      ントをフックしてハンドラとしてmyHandler()関数を非同
      期で呼び出します。

    5.メンバ登録
      オブジェクト自身を自分のメンバとして登録します。

    6.オブジェクト生成
      最後にappendChildでオブジェクトを生成します。

    以上が起動時の動作ですが、その後に四角の上でマウスのボタンが押されると以下のようになります。

    7.ハンドラ関数myHandlerが起動します。

    8.座標などを表示します。

    さて、最初からもう少し詳しく見ていきましょう。オリジナルsticky-notesでは少々違和感のある起動コードが書かれていますが、1では分かりやすくするために良く知られた方法にしています。

    2.は6とともに、<div>タグをcreateElement()で生成し、スタイル シートや各種の属性など宣言してappendChild()で生成しています。この方法はJavaScriptから<div>や<table>などのタグをJavaScriptで生成する方法としてあちらこちらのサイトで紹介されてますので、特に問題はないと思います。

    3.は画面の好きなところに四角を描く方法です。種明かしされれば「ナンダ」という気が…(笑)ただし、leftとtopは絶対位置で指定しますので、position: absolute;で絶対位置を指定し忘れると四角が左上の隅に張り付いてしまいます。もちろん、この失敗をしたので気付きました(笑)

    4.これが難問です。5と7、8とも絡んで理解を阻んでいます。・・・と言う事で項目をあらためましょう。iptで生成する方法としてあちらこちらのサイトで紹介されてますので、特に問題はないと思います。

    3.は画面の好きなところに四角を描く方法です。種明かしされれば「ナンダ」という気が…(笑)ただし、leftとtopは絶対位置で指定しますので、position: absolute;で絶対位置を指定し忘れると四角が左上の隅に張り付いてしまいます。もちろん、この失敗をしたので気付きました(笑)

    4.これが難問です。5と7、8とも絡んで理解を阻んでいます。・・・と言う事で項目をあらためましょう。
    <pre> <next>

    2. サンプル コード1

    <pre> <next>
    まずは、以下のコードを見てください。このコードはファイルにしてSafariでローカルに実行できます。

    実行すると灰色の四角が表示され、表示された灰色の四角をクリックするとクリックした位置のX座標と四角の左端の座標、そしてmyRectオブジェクトのメンバであるmyVarの"this is myVar"がアラートボックスに表示されます。
    <html>
    <head>
    <style>
    .myCSS {
      background-color: rgb(240, 240, 240);
      height: 250px;
      width: 200px;
      position: absolute;
      left: 200px;
      top: 200px;
    }
    </style>
    <script>
    function MyObject() {
     var self = this;
     this.myVar = "this is myVar";
     var myObject = document.createElement('div');
     myObject.className = 'myCSS';
     myObject.addEventListener('mousedown', function(e) { self.myHandler(e) }, false);
     this.myObject = myObject;
     document.body.appendChild(myObject);
    }
    
    MyObject.prototype.myHandler = function(e) {
     alert(e.clientX);
      alert(this.myObject.offsetLeft);
      alert(this.myVar);
    }
    
    function loaded() {
     myRect = new MyObject;
    }
    </script>
    </head>
    <body onload="loaded()">
    </body>
    </html>
    
    <pre> <next>

    1. SafariのJavaScript

    AppleがSafariに(実験的に?)搭載しているHTML 5の仕様にはデータベースなど興味深いものがたくさんあります。そのデータベース機能などを利用したサンプルがWebKitのサイトに公開されています。

    http://webkit.org/demos/

    サンプルはこの下の各ディレクトリにまとめてありますので、Safariでソースコードをもとにファイルを一つずつ手元に保存すると、ローカルでも実行できます。wgetなどのツールをご存じの方はまとめてダウンロードすると良いでしょう。ちなみにこの項目を書いている2010/06/01の時点では以下の四つのデモが入っています。
    • calendar
    • editingToolbar
    • sticky-notes
    • transitions-and-transforms
    また、デモの一つeditingToolbarは、Mac OS Xに標準で付属しているDeveloper向けキットにもあります。深いディレクトリにあるので、"FancyEditingToolbar"で検索するとよいでしょう。

    このサンプルの中で一番古いsticky-notesは2007年10月19日公開されています。このsticky-notesのHTMLファイルを読み込むと、画面に黄色い四角が表示されています。この四角には文字を書く事ができます。HTMLで画面に四角を書くとなると、とりあえず<table>タグを使う事を考えてしまう私には驚きです(苦笑)

    しかも、この四角をクリック ドラッグするとウィンドウ内の好きなところに移動します。その移動は昔のMacintoshの用に枠をアニメーション表示して、ボタンを放したところに表れるというものではなく、パワフルなリアルタイム描画です・・・と書けば年寄り扱いされますね(笑)

    さらに、「New Note」ボタンを押すと黄色い四角が追加表示されます。黄色い四角の上にマウス カーソルをおくと左上にDashboardと同じボタンが表示され、クリックすると四角がアニメーションで閉じます。アニメーションの動きが良くわからない方はシフト キーを押してクリックしてみてください。Dashboardと同じゆっくりとしたアニメーションを楽しめます。このコード自体はDashboardのStickiesの簡易版と考えれば良さそうですが、これを発展させればWebブラウザ内にウィンドウ システムが出来ます。

    このコードのデータベース部分に関しては英語や日本語で紹介しているサイトがありますが、他の部分もなかなか難しい事をしています。他の部分に関してインターネットを調べてみたのですが、解説している資料が見つかりませんでした。やむなく、コードを書いて調べた結果が以下の項目です。きっと何処かに仕様書や解説があると思うのですが、枯れ木も山の賑わい と思い紹介します。
    データベース部分は、関してはSafariとSQLiteをキーワードにしてインターネットを検索すれば、さまざまな解説が日本語と英語で出てきますので、そちらを参照ください。これはこれで面倒で色々とある事は確かなのですが、今回は話しが長くなるのでパス!だれも年寄りの長話は聞きたくない、いや読みたくないでしょう(笑)

    なお、実験した環境はMac OS X 10.5.8、Safari 4.0.4 (5531.22.7)とBBEdit 9.5(2740)のPreviewですが、Firefoxでも動く事があります。
    <next>

    2010年4月10日土曜日

    MPEG2の音声問題

    以前からAppleのMPEG2コーデックを購入して利用していたのですが、最近になってMPEG2のデータを再生すると音声が出なくなる問題が発生しました。気付いたのは先週ですが、いつ頃からこの問題が発生したのか分かりません。再インストールする事で問題が解消されましたが、どうもなぜこのような問題が発生したのか判然としません。

    一ヶ月ぐらいまでは問題なく再生できていて、それ以降にQuickTime関連で最近に実行したアップデートで記憶に残っているFlip4Mac WMVなのですが・・・、他にもあったかもしれません。

    Mac OS Xにはこの種のアンインストーラが無いのが辛いです。旧Systemの頃は比較的簡単に元に戻せていましたが、Unixが入った事による障害で、起動ファイルの設定を独自にしているものなどは面倒な作業が必要ですし、そのようなファイルがどれだけあるのか私は知りません。どうかするとこう言う事を知らずにプログラムを書いている人すらいます。

    もちろん、Windowsに見られるアンインストーラはかなりリスクの高いもので、アンインストールした後で正常に動くかは自己責任ですが…。

    理由は色々と聞きますが使いにくい事に変わりありません。

    iPhone OS 4の発表サイト

    AppleのiPhone OS 4発表のサイトですが、私のSafari4.0.5 (5531.22.7)で見ると奇妙に表示されます。
    http://www.apple.com/iphone/preview-iphone-os/

    まず、むやみに大きな図に隠れて文字が読めなくなっています。
    最後も普通なら横に並べそうな写真を縦にだらしなく並べています。

    Appleが新製品を発表する時に、こう言うだらしのないレイアウトをするのはいったいどういう意味なんでしょうね?

    TidBITSの記事

    TidBITSに興味を引く記事が二つありました。

    ■ iPadとKindle
    一つはiPadとKindleに関するもので、
    http://db.tidbits.com/article/11175?...
    雑に訳すと以下のような感じです。
    AmazonのKindleは2007年の登場から100万台以上を販売しているが、iPadは一週間に満たない期間にその約半分近く(45万台)を売った。
    まぁ、そうとも言えなくもない・・・かな?(笑)
    ■ iPhone OS 4 SDK契約書変更
    また、以下の記事にはiPhone OS 4 SDKの契約内容変更に関する記事です。
    http://db.tidbits.com/article/11177?...
    契約書の変更は仕事を続ける上で重要ですが、契約内容が変更される度に全文を読んで前の契約書との違いを探すには時間がかかります。TidBITSはこの種の契約書変更を敏感に捉えて解説してくれるので助かります。

    今回の指摘もなかなか重要でApple以外が作ったAPIの使用に関するものでしたが、訳すのは面倒なので自分で呼んでください(笑)

    2010年4月5日月曜日

    SQLite 管理編集ソフトウェア

    Mac OS Xで利用できるSQLiteのデータを構築し編集できるアプリケーション(プラグインを含む)は以下の五つです。
    以下の三つはアプリケーションの形式でSQLiteのデータベースを作ったり変更したりできます。
    他にもあるかもしれませんが、これだけあれば十分かと思います。

    2010年4月3日土曜日

    Airbus A321-200

    Asiana AirlinesのA321-200という飛行機に乗る機会があったのですが、PCでも使える電源とUSB充電用の電源がそれぞれ準備されていました。 

    AC電源は座席の下にあって、さまざなプラグに対応しています。ただし、接続するのはMacなので電圧は調べませんでした(笑)
     前の咳の背もたれにはUSB充電用プラグも用意されています。iPod touchの充電に便利です。ただし、Internetへの接続はできません(笑) 
    ちなみに就寝照明はこんな感じです。この写真は分かりやすくするために照度を上げていますが、雰囲気のよい照明です。

    2010年3月17日水曜日

    JammingからLogophileへ

    これまで愛用してきた辞書検索ソフトJammingをアップグレードしてLogophileにしました。JammingとLogophileは複数の辞書を一度に検索して表示するのでとても便利です。 Jammingが持っていた文字の入力などの問題はLogophileで解消されていますが、今まで使ってきたCambridge Advanced Learner's Dictionaryという辞書が使えなくなりました。Logophileの説明ではこの辞書の第二版と第三版はサポートしているそうですが、第一版はあまりにも古いので除外したのかもしれません。現行版を買う良い機会です。 ところで、私の環境(PowerPC)でLogophileが奇妙な挙動をしています。研究社の和英英和辞典*1で参照の→をクリックすると全て"zzz, z-z-z-"(マンガのいびき)という単語にジャンプします。PowerPCでは遅すぎて寝てしまうようです(笑) *1) 研究社 1995 新英和中辞典 第6版 新和英中辞典 第4版 LogoVista

    2010年3月15日月曜日

    SQLiteとPHP

    AppleのサイトにSQLiteとPHPをMac OS Xで使う方法が書かれていました。

    PHP the Easy Way: Enabling PHP and SQLite on Mac OS X Leopard http://developer.apple.com/mac/articles/internet/phpeasyway.html

    しかし、ここに書かれているPHPとSQLiteを使用するスクリプトはそのままではMac OS X 10.5.8では動きません。すこし調べてみると、ソースコードを以下のように変更すると動作しました。
    ■ 変数を表す'\$'を全て'$'に変更
    ■ PDOの引数を変更
    1. PDO命令の引数'sqlite:'の後にデータベース名'../Public/Drop Box/test.db'を追加
    2. PDOは引数のセパレーターを','に変更
    3. 引数のユーザ名が変数'$user_db'を初期化宣言
    最初の項目はPHPの通常の変数宣言方法にしただけです。

    次の項目は、PDO命令の引数を三カ所変更しています。
    まず、データベース名が指定されていない問題の修正と、データベースを保存する場所の指定です。'../Public/Drop Box/'ディレクトリのパーミッションは他のユーザからは書き込みのみの設定になっています。'~/Sites'ディレクトリのパーミッションを書き込み可能にする方法もありますが、後で元に戻すのを忘れた場合に危険であると考えてこのようにしています。

    次に、セパレータが'.'になっていたものを','に変更しました。

    最後に本来はユーザ名が設定されるべき引数に初期化宣言されていない変数'$user_db'が設定されていたため、この変数を初期化宣言しています。今回は暫定的に'myName'で初期化していますが、変数'$user_db'自体を削除してしまうのも一案です。この場合には文末の'echo'文にある変数'$user_db'も削除します。

    以上の変更を加えて、さらにHTMLに入れたものが以下のようになります。
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
            "http://www.w3.org/TR/html4/loose.dtd">
    <html lang="en">
    <head>
     <meta http-equiv="content-type" content="text/html; charset=utf-8">
     <title>php_sqlite</title>
    </head>
    <body>
    <?php
    // create a SQLite3 database file with PDO and return a database handle (Object Oriented)
    $user_db = 'myName';
    try {
     $dbHandle = new PDO('sqlite:../Public/Drop Box/test.db','$user_db');
    }catch(PDOException $exception){
     echo 'test error<br>';
     die($exception->getMessage());
    }
    // create page view database table
    $sqlCreateTable = 'CREATE TABLE pageView(id INTEGER PRIMARY KEY AUTOINCREMENT, page CHAR(256), access INTEGER(10))';
    $dbHandle->exec($sqlCreateTable); // remove or 'comment out' this line after first run
    // insert page visit in database with a prepared statement
    $sqlInsertVisit = 'INSERT INTO pageView (page, access) VALUES (:page, :access)';
    $stmt = $dbHandle->prepare($sqlInsertVisit);
    $stmt->bindParam(':page', $_SERVER['PHP_SELF'], PDO::PARAM_STR);
    $stmt->bindParam(':access', time(), PDO::PARAM_INT);
    $stmt->execute();
    // get page views from database
    $pageVisit = $dbHandle->quote($_SERVER['PHP_SELF']);
    $sqlGetView = 'SELECT count(page) AS view FROM pageView WHERE page = '.$pageVisit.'';
    $result = $dbHandle->query($sqlGetView);
    $pageView = $result->fetch(); // store result in array
    // print page views and filename
    echo '<blockquote>This page has been viewed <b>'.$pageView['view']. "</b> times, according to <em>$user_db</em>.</blockquote>";
    echo '<blockquote>Edit <em>'.$_SERVER['SCRIPT_FILENAME'].'</em>
    to learn how this works.</blockquote>';
    ?>
    </body>
    </html>
    
    上記のスクリプトをファイル名"test1.php"等として、ホームディレクトリの'~/Site/'に置いて以下のULRでアクセスします。
    http://localhost/~(userName)/test1.php
    
    なお、上記のファイルの少し編集すると「Web 共有」を「切」にしたままでTerminalから以下のように実行する事もできます。
    php -f (ファイル名:例test2.php)
    
    まず、上記コードの'<?php'から'?>'までを別のテキストファイル(ファイル名:例test2.php)にし、データベースの保存場所を変更します。コードは以下のようになります。
    <?php
    // create a SQLite3 database file with PDO and return a database handle (Object Oriented)
    $user_db = 'myName';
    try {
     $dbHandle = new PDO('sqlite:test.db','$user_db');
    }catch(PDOException $exception){
     echo 'test error<br>';
     die($exception->getMessage());
    }
    // create page view database table
    $sqlCreateTable = 'CREATE TABLE pageView(id INTEGER PRIMARY KEY AUTOINCREMENT, page CHAR(256), access INTEGER(10))';
    $dbHandle->exec($sqlCreateTable); // remove or 'comment out' this line after first run
    // insert page visit in database with a prepared statement
    $sqlInsertVisit = 'INSERT INTO pageView (page, access) VALUES (:page, :access)';
    $stmt = $dbHandle->prepare($sqlInsertVisit);
    $stmt->bindParam(':page', $_SERVER['PHP_SELF'], PDO::PARAM_STR);
    $stmt->bindParam(':access', time(), PDO::PARAM_INT);
    $stmt->execute();
    // get page views from database
    $pageVisit = $dbHandle->quote($_SERVER['PHP_SELF']);
    $sqlGetView = 'SELECT count(page) AS view FROM pageView WHERE page = '.$pageVisit.'';
    $result = $dbHandle->query($sqlGetView);
    $pageView = $result->fetch(); // store result in array
    // print page views and filename
    echo '<blockquote>This page has been viewed <b>'.$pageView['view']. "</b> times, according to <em>$user_db</em>.</blockquote>";
    echo '<blockquote>Edit <em>'.$_SERVER['SCRIPT_FILENAME'].'</em>
    to learn how this works.</blockquote>';
    ?>
    
    上記のファイルをphp命令の引数(例test2.php)として渡して実行させます。なお、手軽に試す事を目的としているために、出力結果は正しく改行されず<em>などのhtml文字列も含まれます。

    さらに、上記のファイルを以下のようにするとTerminalから通常の命令と同様に実行できます。
    まず、上記のファイルの先頭に以下の一行を付け加えます。
    #!/usr/bin/php
    
    上記のファイルをファイル名'test.sh'等として保存し、Terminalから以下の命令を実行します。
    chmod 744 (ファイル名:例test.sh)
    
    上記の変更を加えて実行形式にしたファイルは以下のように実行できます。
    ./(ファイル名:例test.sh)
    
    なお、上記の二例ではデータベースのファイル'test.db'はそれぞれのファイルが置かれている場所に保存されます。

    2010年3月8日月曜日

    iPhone側でFTPやWebDAV


    iPhone OS側でFTPやWebDAVのファイルサーバを開いてデータをやり取りしているAppを続けて見つけました。

    EBPocket free
    無料の辞書検索ソフトで、EPWINGという書式の辞書データを検索できます。コンピュータから辞書データをiPhone OSに転送して検索しますが、この転送時にiPhone OS側でFTPサーバを開いて転送します。Finder標準の[サーバへ接続...]命令のFTPは読み出し専用のため、Mac OS X標準のftp命令をターミナルで使います。

    Discover
    無料のファイル共有ソフトです。AppleのMobileMeのiDiskでも採用されているWebDAVでiPhone OSにファイルサーバを開き、iPhone OSにファイルを転送するとpdfなどのファイルが見られます。Finder標準の[サーバへ接続...]命令で、WebDAVサーバ内のファイルを読み書きできます。

    ただし、Discoverは取り込んだデータを呼んでいる最中もWebDAVサーバが起動したままのように見受けられ、消費電力が気になります。

    似たようなプログラムにDoc Viewer Liteがありますが、こちらはMac OS X側でFTPサーバを開いて、Doc Viewer Liteから取り込みます。無料版ではコピーできるファイル数に制限があります。

    Apple標準のファイル共有ソフトとしてiDiskがありますが、わざわざInternet上のサーバ経由でデータをやり取りするのは面倒ですし、重要なデータをInternet経由で転送するのは保安の意味でも気になります。

    EBPocket freeとDiscover、Doc Viewer Liteの三つに共通して言える事は、ユーザインタフェースのデザインが悪いという点です。本当に必要な機能の選択と配置ができていないために、色々と機能がありますが使いにくいデザインになっています。

    2010年2月7日日曜日

    iPod touchとiDisk

    iPhone OSが3.1になった辺りから、iPod touchとiDiskの相性が悪くなっています。

    WiFiが使えない、あるいはWiFiを切った状態でiDiskを起動したり、「最近使った項目」のPDFファイルを読もうとすると「予期しないエラー (年月日と時間)予期しないエラーが起きました(22)。」と表示されます。

    この件に関するAppleのSupport Discussionsを見つけましたが、結論は出ないままでした。

    Apple - Support - Discussions - MobileMe iDisk app broken on iPhone OS ...

    iPhone OSが3.1.3になっても状況は変わらず、2009年9月11日の最初の投稿以来 5ヶ月間、解決策がないままになっています。Appleでは症状が出ないとか書かれていて、不思議な話です。

    2010年1月14日木曜日

    OptiBay Hard DriveKit

    チョット気付かなかった商品が出ました。

    MacBook Proは私も使っていますが、なぜかこのような商品は思い付きませんでした。

    MCE OptiBay Hard DriveKit(オプティベイ ハードディスクKit) for for MacBookPro 15/17インチ(ユニボディ) and MacBook(ユニボディ) スリムドライブ内蔵用ケース付 [OBSATA0GB-UNB+Case]:秋葉館楽天市場店
    http://item.rakuten.co.jp/akibakan/10012744/

    光ドライブをHDDに入れ替えようという商品で、さらに取り外した光ドライブは外付けドライブに利用しています。

    HDDの容量が増えるという点でもよいのですが、取り外した薄型光ドライブを外付けにして無駄にしないだけでなく、持ち運びによる故障からも守れるという点が秀逸です。

    正直言って薄型の光ドライブを持ち運びに使用するのは・・・個人的にはいい気持ちがしません。もちろん数年前と比べれば雲泥の差で良くはなっていて、少々のホコリにも強くはなっていることは聞いていますが・・・心配です。その意味でMacBook Airや最近の光ドライブなしの小型で廉価なノートPCは思い切った良い製品だと思っています。

    この商品はそのような心配をなくし、さらに容量を増やせるという意味で興味深いと思います。また、元のHDDも含めてSSDにして振動対策も万全にするというのも一案かもしれません。

    欲しくなってきました(笑)

    2010年1月7日木曜日

    WebページのPDF変換

    AppleのSafariでWebページをPDFに変換しようとするとうまくできない場合があります。たとえば以下のIBMのサイトです。

    http://www.ibm.com/developerworks/library/j-classpath-unix/

    このページをMac OS XのプリントでPDFに変換すると以下のようになります。


    きっと何処かに見たままにPDF変換できる方法がありそうに思うのですが、見つかりません。不便に思っていると、以下のような記事を見つけました。

    [ウェブサービスレビュー]ウェブページの好きなところだけを印刷できる「PrintWhatYouLike」:レビュー - CNET Japan
    http://japan.cnet.com/review/editors/story/0,3800080080,20397652,00.htm

    実際のサイトは以下の場所にあります。
    PrintWhatYouLike.com
    http://www.printwhatyoulike.com/

    試すと以下のようになりました。

    2010年1月5日火曜日

    ACアダプタの謎

    昔から不思議に思っていた謎が解けました。

    AppleのACアダプタは真四角のデザインで、日米の二端子コンセントプラグであれば美しくまとまったデザインです。しかし、他の国で採用されている三端子プラグなどはどういうデザインなのだろうと思っていました。

    こう言うデザインです。
    まずは220Vの三端子プラグ アダプタはこんな感じで、かなりデカイです。

    組み立てるとこんな感じになりますが、ブザマと言うのは言い過ぎでしょうか?