iOS 8のデバイスの回転可能な方向の設定

iOSのネイティブアプリケーションを開発するとき、Xcodeのビルドするアプリケーションの設定のDeployment InfoにあるDevice Orientationにあるチェックボックスの設定が重要です。iOS 6以降、この設定がそのままInfo.plistファイルに設定され、アプリケーションはその設定に応じた動きをします。このDevice Orientationは、その方向にデバイスを向けたときに、画面が回転して、画面の上端が実際に上に見えるようになるということを示しています。通常、Upside Downつまり、ホームボタンが上に来る縦長の状態にしたときには、回転は行われないということになっています。つまり、Upside Downの方向にしたときには、写真は90度あるいは180度傾いて見える状態のままになるということです。

shot9897

前の図のDevice Orientationの設定は、iOS 7までは、iPhoneとiPadで別々でした。それぞれで回転可能な方向を決めることができました。iOS 8つまりXcode 6からは、その上のMain InterfaceがiPhoneとiPadで共通になっているので、Device Orientationも共通かと思ったら、Xcode 6.1.1で作ったプロジェクトでは、iPhoneとiPadのDevice Orientationの設定が、別々に定義された状態になっています。以下は、Infoをクリックして見たところで、Supported interface orientationが、iPhone向けの設定であり、General(前の図)で見えている設定です。それに加えて、Supported interface orientation (iPad)もあり、4つの方向がチェックされています。このiPadの設定はGeneralには見えていません。したがって、General側で設定をどう変更しようと、iPadの場合はこのInfoで見えている設定に従うために、すべての方向に回転ができるようになります。

shot9898

ちなみに、iPhoneとiPadの両方の設定が必要なら、Generalのパネルに双方の設定ができるようにすべきです。もしかして、iPadのDevice Orientationの設定は間違えて紛れ込んでいるのでしょうか? ここで、iPad側の設定を削除したいなら、Supported interface orientation (iPad)の項目を選択し、項目名の右に見える、丸にマイナスの部分をクリックします。これで削除できます。

shot9899

ここで、まず、Info.plistに項目が存在するかどうかによって、どのように稼働するのかを見てみます。これを見る限り、既定の動作をさせるには、要するに、これらのInfo.plist項目はそもそもない方が素直な設定の気がします。既定の動作をさせないときに、項目を定義するというのが理にかなっているような気もします。

Supported interface orientation Supported interface orientation (iPad) 回転の動作動作
設定なし 設定なし iPhoneはUpside Down以外が可能、iPadはすべての方向へ可能、つまりデバイス既定の動作
設定あり、要素なし 設定あり、要素なし
設定あり、要素あり 設定なし iPhoneもiPadも、iPhone側の設定に従う
設定あり、要素あり 設定あり、要素あり iPhoneはiPhoneの設定に、iPadはiPadの設定に従う

Supported interface orientationにチェックが入れば、その方向で回転するというのが概略の説明ですが、正しくは1つの場合だけ回転しません。回転しない例が、iPhoneの場合のUpside Downです。つまり、このチェックを入れるだけでは、その方向に回転しないのです。つまり、デバイスの規定値の方が優先順位が高いとみていいでしょう。

では、iPhoneでもUpside Downを可能にするにはどうすればいいか? UIViewControllerにあるsupportedInterfaceOrientationsメソッドにヒントがあり、このメソッドをオーバーライドするのがポイントです。このメソッドは、UIViewControllerであらかじめ定義されており、ビットマスク値を返します。ホームボタンの位置が上下左右のそれぞれに対応する4ビット分のマスク値を返します。UIViewControllerに実装されているメソッドだと、iPadだと4つのビットがすべて1、iPhoneだとUpside Downを除く3つのビットが1になっています。実際に回転していい方向は、Info.plistの設定と、supportedInterfaceOrientationsメソッドの返り値をビットANDをして、残ったビットが回転をしてもいい方向になります。なので、Info.plistの設定で全部にチェックされていても、iPadでは全方向に回転は可能ですが、iPhoneでは、Upside Downはマスク設定で0になっていて、キャンセルされてしまうのです。

それでは、自分で定義しているUIViewControllerの継承クラスで、supportedInterfaceOrientationsメソッドを実装して、全部のビットが1になっている値を返せばいいではないかと考えるところです。しかしながら、この回転の判断は、いちばんルートにあるビューコントローラで判定されます。Single View Applicationで作ったようなプロジェクトだと、いきなり自分で定義しているビューコントローラのクラスがルートにあるので、そこでメソッドを組み込めばいいでしょう。以下のコードに追加されているメソッドを加えます。しかしながら、Master-Detail Applicationのテンプレートで作ったプロジェクトでは、例えば、MasterViewControllerやDetailViewControllerクラスにsupportedInterfaceOrientationsメソッドを作ってもうまくいきません。これらのクラスのオブジェクトはルートのビューコントローラではないからです。Master-Detail Applicationで作ったプロジェクトのストーリーボードファイルを見れば、ルートはUISplitViewControllerクラスのオブジェクトです。そこで、以下のような、UISplitViewControllerクラスを継承したMyRootViewControllerクラスを定義します。そして、メソッドにはsupportedInterfaceOrientationsだけを定義すれば良いでしょう。returnの後のenum型の値が、すべての方向のビット値が1に設定されたものです。返り値がIntなので、rawValueプロパティを使ったり、Int型に変換するなど、Swiftではちょっとややこしいですね。

shot9900

そして、ストーリーボードのUISplitViewControllerクラスのオブジェクトを選択します。右側のユーティリティエリア上部では左から3つ目のアイコンを選択して、アイデンティティインスペクタを表示して、Classのところで、前の図にあるMyRootViewControllerを選択します。

shot9901

こうしておけば、Master-Detail Applicationで作ったプロジェクトでも、iPhoneでUpside Downの方向でも回転ができるようになります。もちろん、プロジェクトのDeployment Infoの設定にあるDevice Orientationのチェックボックスは4つともオンにしておく必要があります。

NELog.logに大量の書き込みはAdobe Creative Cloudの問題

珍しく、Adobe関連の話題ですが、いつも通りトラブルシューティングです。

ある日、OS X Yosemiteでコンソールを開くと、~/Library/LogsにあるNELog.logおよび「NELog 11-21-2014 02-58-57.log」みたいな日付つきのログが大量にあることを発見しました。しかも、毎分40KBあまりも出力している。1日50MBくらいだけど、消している時間があるので30MBくらい? 日付を見れば、何ヶ月か前からあるようで、数ギガくらい使っていそうな勢いです。しかし、なんでしょうね?このNSLog.logの正体は? 中身を見ると、こんな感じで、ちょっと手がかりがありません。SQLite関連のエラーが目に付きます。

01/12/15 03:28:07:157 | [WARN] | | ANSClient | | NELocalDataManager | | | 9983 | Not able to get the settings from local db for key (KLastNotificationResponseOlderTimestamp). Error msg - Sqlite Error: The database disk image is malformed
01/12/15 03:28:07:158 | [INFO] | | ANSClient | | NEGlobalData | | | 9983 | Unable to get last Notification Response Timestamp. Fetching notifications from server epoch
01/12/15 03:28:07:286 | [WARN] | | ANSClient | | NELocalDataManager | | | 9984 | Not able to get the settings from local db for key (KLastNotificationResponseOlderTimestamp). Error msg - Sqlite Error: The database disk image is malformed
01/12/15 03:28:07:286 | [INFO] | | ANSClient | | NEGlobalData | | | 9984 | Unable to get last Notification Response Timestamp. Fetching notifications from server epoch
01/12/15 03:28:07:287 | [INFO] | | ANSClient | | NEGlobalData | | | 9984 | Mode is online
01/12/15 03:28:08:159 | [WARN] | | ANSClient | | NELocalDataManager | | | 9983 | Not able to get the settings from local db for key (KLastNotificationResponseNewerTimestamp). Error msg - Sqlite Error: The database disk image is malformed
01/12/15 03:28:09:073 | [WARN] | | ANSClient | | NELocalDataManager | | | 9984 | Not able to insert the settings in local db. Error code - 0, and Error msg - Sqlite Error: The database disk image is malformed
01/12/15 03:28:09:073 | [INFO] | | ANSClient | | ConfigurationManager | | | 9984 | Unable to save parameters in Database. Default Configurations are set
01/12/15 03:28:09:076 | [WARN] | | ANSClient | | NELocalDataManager | | | 9984 | Not able to update create new notification in local db. Error code : 0, and Error msg : Sqlite Error: The database disk image is malformed
01/12/15 03:28:09:076 | [WARN] | | ANSClient | | NENotificationsProcessor | | | 9984 | Unable to create notification for notification ID: 8c1f6505-824e-43e9-8a57-15ad8f47ba7c
01/12/15 03:28:09:076 | [WARN] | | ANSClient | | NEDataFetcherAndProcessor | | | 9984 | Unable to complete Notification process operation
01/12/15 03:28:09:076 | [WARN] | | ANSClient | | NELocalDataManager | | | 9984 | Not able to insert the settings in local db. Error code - 0, and Error msg - Sqlite Error: The database disk image is malformed
01/12/15 03:28:09:076 | [WARN] | | ANSClient | | NEGlobalData | | | 9984 | Unable to store last Notification Response Timestamp
01/12/15 03:28:09:076 | [WARN] | | ANSClient | | NELocalDataManager | | | 9984 | Not able to insert the settings in local db. Error code - 0, and Error msg - Sqlite Error: The database disk image is malformed
01/12/15 03:28:09:076 | [WARN] | | ANSClient | | NEGlobalData | | | 9984 | Unable to store last Notification Response Timestamp
01/12/15 03:28:09:076 | [WARN] | | ANSClient | | NELocalDataManager | | | 9984 | Not able to insert the settings in local db. Error code - 0, and Error msg - Sqlite Error: The database disk image is malformed
01/12/15 03:28:09:076 | [WARN] | | ANSClient | | NEGlobalData | | | 9984 | Unable to store last Notification Response Timestamp
01/12/15 03:28:09:076 | [WARN] | | ANSClient | | NEDataRequestHandler | | | 9984 | Unable to get Notification Data from the requested timestamps
01/12/15 03:28:09:164 | [WARN] | | ANSClient | | NELocalDataManager | | | 9983 | Not able to get the settings from local db for key (KLastNotificationResponseNewerTimestamp). Error msg - Sqlite Error: The database disk image is malformed

手がかりがまるでないのですが、まず見つけたのはこのドイツ語のBBSです。ドイツ語はよくわかりませんが、これから、Adobe CCが出力することを見つけました。そして、このNELog.logを開いているプロセスをlsofでチェックして、そのプロセスIDからCreative Cloudアプリケーション、つまり、メニューバーにある無限大のみたいなアイコンのアプリケーションであることがわかります。

$ lsof | grep NELog.log
Creative   3443 msyk   66w     REG                1,4   2876129  3280800 /Users/msyk/.Trash/NELog.log
$ ps -p 3443
  PID TTY           TIME CMD
 3443 ??         0:55.59 /Applications/Utilities/Adobe Creative Cloud/ACC/Creative Cloud.app/Contents/MacOS/Creative Cloud

ここまでくると、「adobe creative cloud nelog」みたいに検索ができるわけで、そうすると、ここの先のようなメッセージがあり、そこに書いてあることをヒントにして、解決ができました。要するに設定ファイルのフォルダを作り直させれば良い模様です。手順は次のようなものです。

  1. Creative Cloudアプリケーションを終了します。メニューバーにあるアイコンをクリックしてウインドウを表示し、右上にあるギアのアイコンをクリックして表示されるメニューから「終了」を選択します。
    shot9808
  2. 以下のようにターミナルからコマンドを入力して、設定フォルダを一旦空にします。念のため、現状を別のフォルダ名にバックアップします(別にターミナルでなくてもよく、Finderで作業してもいいです)。
cd "~/Library/Application Support/Adobe"
mv OOBE OOBE_old
  1. アプリケーションフォルダにあるAdobe Creative Cloudフォルダの、Adobe Creative Cloudアプリケーションをダブルクリックして起動します。

これで大量のログ吐き出しはなくなりました。NELog.logは1分ごとに数行程度の出力をしていますが、まあ、それは無視していいくらいかと思います。なお、記憶しているAdobe IDは消えてしまうようで、その再入力は必要です。

なお、Creative Cloudは他にoobelib.log、ACC.log、PDApp.logというログもけっこう大量に吐き出しますが、まあ、NELog.logほどではありません。こちらは、アプリ起動時に大量のログを書き出します。数ヶ月で100MB程度ですが、これらについても日付のついたファイルは不要と思います。

[IM] 2015年に向けての組織化を考える

INTER-Mediatorの開発を始めてから、ちょうど丸5年くらいが経過しました。いろいろあったものの、一貫して、新居雅行個人のプロジェクトのような形態だったのですが、エミックさんをはじめとしていろいろな展開が始まっており、そろそろ個人プロジェクトではなくそうかと思っています。かといって会社作るということではありません。こうしたプロジェクトは組織そのものも、プロダクツに見合ったものをコミュニティプロセスで発見的に開発しないといけないと考えています。

まず、INTER-MediatorがMIT Licenseであり、オープンソースである点はそのままにしますが、クレジットは「INTER-Mediator Development Project」にしようと考えています。加えて、その開発そのものをマネージメントしている「INTER-Mediator Directive Committee」が存在するという形態にしたいと思います。人数少ない中、組織ばっかり作るかという話もありますが(笑)、先々の方向性を決めるINTER-Mediator Directive Committeeがあって、実際の開発はINTER-Mediator Development Projectがやっているという状況とみなすのです。本来は、さらにINTER-Mediator利用者としての開発者やシステム開発を行うエンドユーザもいるのですが、今のところはこれらのみなさんに対する「組織」は作らないで、時機が来るのを待ちたいと思っています。

「INTER-Mediator Development Project」のミッションは、INTER-Mediatorの継続的な開発を進めることです。これは明確ですね。コードに書くクレジットはこれになります。また、GitHubの主体も「INTER-Mediator Development Project」にするつもりです。GitHubは現在新居のアカウント上にありますが、「組織」という仕組みがあるので、それに移行するつもりです。「INTER-Mediator Development Project」のメンバーは、Contributor、Special Thanks、そしてcloneやforkした皆さんというゆるい定義にしたいと思います。つまり、集まっている方々はプロジェクトに関わっているというみなしをするという組織であり、言い方を変えれば求心力はないものの影響力はあるというところでしょうか。今の所、動いている唯一のコミュニティであるFacebookのグループは、「INTER-Mediator Development Project」の活動の一貫であるということにします。

「INTER-Mediator Directive Committee」のミッションは、INTER-Mediatorの継続的な発展を促す活動を行うということです。こちらは、立候補や推薦と同意などを含めて、メンバーが誰であるのかということを明確にします。したがって、入会と退会を明確にする必要があります。「INTER-Mediator Directive Committee」は役割を明確に定めることと、必要に応じて担当者を設定するものとします。役割は、次のようなものです。

  1. INTER-Mediatorの今後の開発計画を立てて、方針を示す(例えば、半年に1度、ドキュメントをリリースする)
  2. Webサイトを運用する
  3. GitHubでのpull requestに対処する
  4. 普及のための活動(勉強会やもくもく会など)を主催、あるいはリードする
  5. トレーニングマテリアルを整備し、提供する

5についてはすでに私自身がお金をいただきながらやっていることですが、位置付けは普及活動になるかと思います。2についても私がやっていますね。1については、Project側の意見も吸い上げないといけませんが、決定して声明を出すのはCommiteeの役目と考えています。

現在のWebサイトは3つのドメインで同じものを表示していますが、以前に松尾さんから想定されていたように、.orgはCommitee、.infoはマニュアル、.comは総合的な紹介サイトということにしようと考えています。人や作業が増えた時に、分割されていると、作業分担がしやすいのではないかと思っています。この作業は、さっそく、2015年前半の作業プランに入れるべきかもしれません。

そういうことで、大きな意味では「Committeeを作り、名乗ります」ということになりますし、それだけといえばそれだけですね。会則とかややこしいことは初期段階では不要かと思います。私がChairmanですということでもいいのですが、役割分担ではないroleの割り当ては、Committeeの人数が増えてからにしようと思います。

Committeeメンバーについては、松尾さんには入ってもらいたいと思っています。エミックさんではFM Publisherを開発して提供しており、INTER-Mediatorの動向は自社ビジネスに少なからず影響するわけですから、言い換えればコントロールする側に立つ意味もあるかと思います。また、立候補、推薦等も受け付けますが、本人が嫌がった場合には当然ながらメンバーとは言えないかと思います。みなさんの中でも立候補される方はご連絡ください。もちろん、開発関係の方の参加が想定されますが、開発に関係ないもののこうしたコミュニティにより深く関わってみたいという方の参加も歓迎します。

言語ごとのiOSシミュレータを用意する

Xcodeでシミュレータが見えなくなるトラブルが発生しましたが、復旧過程で「機種ごとだけでなく、言語ごとにデバイスを用意する」ということができることに気づきました。その方法を紹介しましょう。

いろんなバージョンのXcodeを行き来しつつ、ユーザも切り替えながら使っていることもあるせいなのか、ある日、XcodeでiOS向けのプロジェクトで、iOSシミュレータがまったく選択できなくなりました。現在は、Ver.6.1.1が公開されている中で最新ですね。

shot9502

ここで見えるシミュレータは、WindowsメニューのDevicesで確認できます。やっぱりみんな消えています。なぜかはわかりません。

shot9503

シミュレータを追加するには、左下の+部分をクリックします。すると、次のようにシートが表示されて、名前や機種、iOSのバージョンなどを指定してシミュレータを追加できます。全部消えてしまっても、もちろん、こうして追加すればOKです。

shot9504

ここで、ふと「同一の機種は追加できるのか」と思ってやってみたらできました。そこで、さらに思いつきました。たとえば、iPhone 4sを2つ登録して、それぞれで、シミュレータの言語を「日本語」と「英語」にしておけば、言語の切り替えがポップアップからできるようなものではないだろうかということです。

以下のように、iPhone 4s-EnとiPhone 4s-Jaの2つのシミュレータを追加登録します。どちらもDevice TypeはiPhone 4sを選択しています。

shot9509

Xcodeでは、このように、指定した名前(Simulator Name)のポップアップメニュー項目が出てきます。

shot9506

それぞれのシミュレータでアプリケーションを起動するなどして起動し、「設定」アプリケーションで言語を日本語と英語に設定しました。そうすれば、以下のように、もちろん、それぞれの言語でシミュレータが即座に立ち上がります。シミュレータ側でのHardwareメニューのDeviceでは、名前でなくデバイスタイプが出るようで、ちょっと不便ですが、まあ、Xcode側で選択できさえすればいいので、これで、Xcode側から言語を指定したシミュレータの呼び出しができるということです。

shot9508 shot9507

ちなみに、XocdeからプロジェクトのRun等をしないでシミュレータを起動するには、Xcodeで、XcodeメニューからOpen Developer ToolのiOS Simulatorを選択すれば良いでしょう。

shot9505

以下の書籍ではこの話題は入れられませんでした。こちらの書籍もよろしくお願いします。

ios_programming_cover1

[IM] MySQLでエンコードにはまったとき

INTER-Mediatorの話題です。こういうことがあるかどうは微妙かもしれませんが、私の郵便番号検索のサイトで、以下のような状況になりました。

  • 郵便番号検索のアプリケーション(A)はmysql_Connectで稼働している(あー、5.5ではついに書き直さないといかんなー)
  • UTF-8で動いているつもりだったが、MySQLで、エンコーディングの指定をしないままに動かしてしまっていた(これは失敗、でも、UTF-8でなんとなく動いている)
  • その上に、INTER-Mediatorで作った、書籍販売サイト(B)を動かす。これも、なんとなく動いている。郵便番号とは別のデータベースを作ったので、独立しているから問題なかった。
  • INTER-Mediatorでの郵便番号検索ページ(C)をいくつかの理由で立ち上げて、郵便番号データを読み込んでいるデータベースを利用して検索しようとしたら、文字化けた。

とまあ、要するに、2項目目が失敗なのですが、なんとなく動いているという状況下気づかなかったものの、最後の項目ではちゃんとやろうとして失敗に気づいたということです。my.cnfに、エンコードとしてUTF-8をつけると、(C)はきちんと動きました。それから、(A)もきちんと動きました。はいおしまいと思っていたら、(B)が文字化けます。つまり、(A)(B)(C)、同時に動かなくなったのです。なお、(C)の後追加した「character_set_client=utf8」が問題(かどうかも問題)のようで、これはmy.cnfから削除しました。(C)の発覚後、「character_set_server=utf8」も追加しましたが、最終的にはこれは残してあります。

結局どうしたか? (A)は、実は、「SET NAMES utf8」というSQLコマンドを発行して、うまく動かしていたのです。つまり、これを動かさないとうまく行かない大昔の状況のまま運用していて、エンコードの指定が適切でなかったことに気づいたわけです。(A)(B)(C)全部を動かすために結局何をしたかというと、INTER-Mediatorのアプリケーションで「SET NAMES utf8」を実行するようにしました。クエリーするたびにまず、このコマンドを実施して、SELECTを出すようにしました。これも、定義ファイルの設定でできます。こんな感じの定義ファイルです。scriptというキーワードは、FileMakerではよく使いますが、すべてのデータベースで利用可能です。

IM_Entry(
    array(
        array(
            'name' => 'postalcode',
            'view' => 'pcode',
            'records' => 50,
            'maxrecords' => 50,
            'paging' => true,
            'script' => array(
                array(
                    "db-operation"=>"load",
                    "situation"=>"pre",
                    "definition"=>"SET NAMES utf8"
                ),
            ),
        ),
    ),
    null,
    array('db-class' => 'PDO'),
    false
);

そういうことで、あっさりトラブル解決できました。まあ、でも、郵便番号サイトは、今シーズン終わったら、PHP 5.5か5.6で動くように、全面改修だな。

[IM]ページ上のオブジェクトに機能を割り付ける

データベースの内容を一覧するときに、検索結果を適用するという仕組みを一切プログラムを書かずに実現するために、ボタンやテキストフィールド、あるいは一般的なノードに対して機能を割り当てるという考え方を導入しました。要素のdata-im属性を利用して、ローカルコンテキスト(名前は「_」)に特別なキー名でバインドすることで、機能が割り当てられます。今の所、検索ページを作るための以下のものが利用できます。抽象的に記述してもわかりにくいと思いますので、具体的なタグのテキストともに紹介します。

検索条件の付加

テキストフィールドを「_@condition:….」のローカルコンテキストへバインドさせると、そのテキストフィールドに入れた文字列が検索条件になります。また、Enterキーで、コンテキストの更新が実行されます。

 <input type="text" data-im="_@condition:postalcode:f3,f7,f8,f9:*match*">

@以降は、コロン(:)で4つのセクションに分かれます。

  • 第1セクション(例:condition):この文字列
  • 第2セクション(例:postalcode):コンテキスト名
  • 第3セクション(例:f3,f7):フィールド名。複数の指定も可能
  • 第4セクション(例:*match*):演算子

最初の2つはいいとして、3つ目のフィールドは複数指定も可能です。複数指定をすると、それぞれのフィールドに対して同じ値の検索条件をORで与えます。演算子は、一般的なものに加えて「*match」「match*」「*match*」の3つが用意されています。データベースエンジンに関わらずに、部分一致や前方一致などをこの演算子で記述します。

上記のテキストフィールドに、例えば「新宿」と入れてEnterキーを押すと、以下の検索条件がコンテキストに付加されて、再度検索を行い、そのコンテキストのエンクロージャー内が更新されます。

(f3 LIKE '%新宿%' OR f7 LIKE '%新宿%' OR f8 LIKE '%新宿%' OR f9 LIKE '%新宿%')

表示件数の制御

以下のポップアップメニューを選択すると、レコードの表示件数をポップアップの選択肢で指定でき、選択と同時にコンテキストが更新されます。「limitnumber」が決められた名前で、コロンより後にはコンテキスト名を記述します。changeイベントにより、コンテキストの更新します。

<select type="text" data-im="_@limitnumber:postalcode">...</select>

コンテキストの更新ボタン(検索ボタン)

以下のボタンをクリックすると、指定したコンテキストが更新されます。つまり、「検索」ボタンとして機能するということです。「update」が決められた名前で、コロンより後にはコンテキスト名を記述します。clickイベントにより、コンテキストの更新します。

<button data-im="_@update:postalcode">search</button>

並べ替えフィールドの指定

以下のSPANタグ内の▲をクリックすると、f3フィールドの昇順で並べ替えを行います。同一のコンテキストに対する「addorder」の機能を持った要素は連動します。たとえば「f3で昇順」の後に「f9の降順」を選択すると、「f9の降順」を最優先とし、続くキーとして「f3で昇順」を設定します。最後に設定した条件が最優先になるようになっています。このバインドはclickイベントに対応しており、クリックすれば指定したコンテキストが更新されます。

<span style="cursor: pointer" data-im="_@addorder:postalcode:f3:asc">▲</span>

@以降は、コロン(:)で4つのセクションに分かれます。

  • 第1セクション(例:addorder):この文字列
  • 第2セクション(例:postalcode):コンテキスト名
  • 第3セクション(例:f3):フィールド名。1つのみ
  • 第4セクション(例:asc):昇順ならasc、降順ならdesc

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

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

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

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

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

shot1110-1

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

shot1111-1

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

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

 

Yosemiteのmanは2本指スライドでスクロールするぞ!!

Yosemiteを入れた方、ターミナルを起動して、たとえば、「man diskutil」と入れてください。長いmanをスクロールするのは、えーっとcontrlなんだっけ〜と思う前にトラックパッドで2本指でスライドさせてください。なんと、manがスクロールします。Linuxマシンにつないでもできますよ。

ということで、manというより、Terminal.appの動作がトラックパッドに最適化されたってことですが、わかりやすいタイトルをつけてみました。

[IM]ContributorとSpecial Thanksの定義

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

Contributor

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

Special Thanks

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

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

[IM]日付時刻関数の実装

INTER-Mediatorに日付時刻関数を実装しようとしています。というか、少し実装しました。とりあえずの目標はマニュアルに書いた関数のサポートです。クライアントサイドで動かすので、JavaScriptの仕組みとうまく連動させないといけません。しかし、そのままのスペックはちょっとどうかと思い、このような仕組みを考えました。

日付や時刻は原則として整数あるいは小数点数を取るにしても、連続した数値になります。この点は問題ないのですが、JavaScriptなら1ミリ秒が「1」、Excelだと1日が「1」というように、そのルールを知らないといけませんし、処理系によっては1秒が1の場合もあります。覚えておけばいいといえばいいのですが、決まっているから書かないという状況になると、つどつど調べないといけません。これは不便です。

この1単位の問題に加えて、データベースでは、DATE、TIME、DATETIMEという3つの型を併用します。もちろん、1ms=1にまとめるメリットはあるかと思いますが、あえて、INTER-Mediatorの中では、2つのスタンダードを作ることにしました。

  • 1日=1、つまり、DATE型フィールドに対応(date関数で生成=日付データ)
  • 1秒=1、細かい点はさておいて、TIME、DATETIMEに対応(datetime関数で生成=日時データ)

とします。日付の計算は日単位、日付時刻の計算は秒単位とするわけです。つまり、

  • date(‘2014-10-8’) – date(‘2014-10-6’) → 2
  • datetime(‘2014-10-8 09:00:00’) – datetime(‘2014-10-6 21:00:00’) → 129,600(36時間)

とすることで、データベースの型と、日付時刻関数の結果の対応付けを考えました。

ちなみに、JavaScriptではなぜgetMonth関数だけが0〜11になって実際の月の数値を得るには+1しないといけないのかとか、見方を変えればgetDate関数が0スタートになっているべきなのではなど、疑問は多々わきます。日付計算のしやすさなどの理由はあるかもしれませんが、ここがけっこうJavaScriptのはまりどころだったりします。

そこで、日付時刻の要素取得(つまり月や日を数値として取り出す)関数と、特定の要素に対する計算を行う関数を用意すれば、結果的には「見える通りの数値」として扱えるのではないかと考えました。たとえば、月を得る関数がmonth()だとして、11月なら11という数字が得られ、加えて3ヶ月後などの日付を求めるaddmonth(d, x)があれば用途は足りると考えたわけです。しかし、日付と日時というダブルスタンダードを持ち込むデメリットがここで発生します。整数化された数値を見て、どちらの型なのかがわかりません。結果的に、

  • 日付データの月を返す:monthd(x)
  • 日時データの月を返す:monthdt(x)
  • 日付データに指定した月数を加えた値を返す:addmonthd(x)
  • 日時データに指定した月数を加えた値を返す:addmonthdt(x)

という手法にならざるを得ないと考えました。関数が増えるだけ面倒もあるかもしれませんが、要素取得や計算の関数の末尾が「d」なのか「dt」なのかという点を注意すればいいので、さほどややこしいルールとも考えられません。

しかし、このままだと、month関数やaddmonth関数の存在が気になります。「なし」でもいいのですが、名前的にはもったいないです。考えたのは、なんらかの設定で、日付計算するか、日時計算するのかということを、定義ファイル上のオプション指定で決められるようにするという手法です。たとえば、デフォルとは日付としても、何かの指定をすれば日時になるという具合です。キーワードなどはまだ考えていません。つまりこういう関数があるということです。

  • 月を返す(単位は設定依存):month(x)
  • 指定した月数を加えた値を返す(単位は設定依存):addmonth(x)

 

関数の数は増えますが、把握できる内容ではないかと思います。

タイムゾーンもまともに考えれば頭が痛いですが、日時の解釈の問題と考え、そしてデータベース内ではタイムゾーンは一定にする、あるいはしたいぞと思うことが普通なので、日付あるいは日時データの書式化の問題かとも考えていますが、ここはまだじっくり考えていません。

以上のような方針で実装を考えていますが、どうでしょうか?ちなみに、今現在レポジトリにあるものは、date関数とdatetime関数は実装されています。