ドアラッチの故障

一週間前くらいからガタガタと言い出していたドアラッチが、ノブ制御不能になり作業部屋へ入る事ができなくなってしまいました。参考動画でドアラッチ自体を薄く硬いもので押せば引っ込むのが分かったので、針金ハンガーを折って向かうと、

枠に返しがあり直接アクセスできないので、仕方なくドアノブ修理の検索で掛かった業者に来て見積をお願いしました。赤枠部分を切断する必要があり料金は交換混みで3万超えの作業費で、少し業者さんと話したところ次のようなことが判明したので、自分で解決してみようと思いました。

  1. 木枠を削ればドアラッチが見えるので開けることは簡単
  2. ドアラッチの高さは片方づつ異なっており、押して開く側の方が低い

賃貸物件のため(1)は管理会社と相談する必要があります。外から部屋を見ると窓の鍵が開いて管理会社で梯子を借りてということも思いついたので一旦メール連絡を入れつつ、(2)によって力を加える方向が分かったので差し込む物を材質から検討しました。

  • 子供のコロコロのおまけについているカードゲームの少し硬めの厚紙
  • ツナ缶の蓋
  • 針金ハンガー
  • スーパーのパイナップル用プラスチック容器

3分ほど押し引きしていると開きました。

コツは強く押し少し引きながらラッチがあるであろう写真四角グレーがある中心まで動かして行くことです。実際に下から上への方向で開いた気がします。

参考

様々な大きさの円を重ならないように描く

あるテレビ撮影現場で解像度1920×1080のスクリーンに700個程の円を敷き詰めて描き動かすという要件があり JavaScript の Canvas を使ったのですが、円の座標を取得する際にブラウザの応答がなくなってしまう問題を避けるために注意した点を二つ書き留めておきます。

この画面を避ける

一つ目は重なり判定に Math.sqrtMath.pow を使わないことです。二つの円が重なる条件を言語化すると「中心点からの距離が、半径の合計よりも小さい」となって、直訳すると Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)) < r2 + r1 と表すことができるのですが、三平方の定理を平素に解釈し関数を使わず (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1) < (r2 + r1) * (r2 + r1) とした方が処理が速くなります。

参考

二つ目は Web Workers の利用です。表示する円座標を格納しておく配列の数が上限数に到達するまで繰り返す部分 while(circles.length < circlesMax){...} を丸ごと worker.jsself.addEventListener('message', (e) => {...}); に記述しました。座標計算が終わるまで「読み込み中…」を表示をするのは UI としても良いし、処理時間の計測をしておき長い場合に中断しやり直すということも可能になり便利なこと極まりありません。

const worker = new Worker('./worker.js');
 
worker.addEventListener('message', (e) => {
  circles = e.data;
  circles.forEach(function(circle){
    drawCircle.call(this, circle.x, circle.y, circle.r);
  });
});
 
worker.postMessage({
  radiusMax: /*最大半径*/,
  radiusMin: /*最小半径*/,
  circlesMax: /*最大表示円数*/
});

これに関連して注意したのは、動作実機はウェブサーバがなくデスクトップ等に置いたファイルを実行する状況から同一生成元ポリシーによるエラーになってしまうので、Chrome にオプションを付けて起動することを予め伝えておく必要があります。

参考

実際には円同士を線で結んだり円や線の増減アニメーションがあったりで、今回初めて書いた Web Workers は参考したコードにもある Promise との併用がとても効果的になる場面が増えてくるのではないかと思いました。

Xcodeプロジェクトを複製してホーム画面にアイコンを並べる

基本的な挙動は同じだけど、数パターンでアプリを提示しないといけないという状況があります。そんな時には元になるプロジェクトを複製してアプリ名称の末尾に数字等を添えてホーム画面に並べられるように AdHoc 形式で配布する事になるのですが、半年以上に一度くらいの頻度でやってくるこの作業の度に同じ Stack Overflow ページを参照しているのと、日本語で検索した結果の手法が若干回りくどいものが散見されたので書いておこうと思います。環境について、現在は Xcode Version 9.4.1 (9F2000) を使っていますが、参照している Stack Overflow の回答の日付から察するに Xcode 6くらいから同じ作業だった気がします。コマンドラインのみで行う方もいましたが、今回は GUI 操作を選びました。

Duplicate and rename Xcode project & associated folders – Stack Overflow

具体的な手順を簡易に訳すと、

  1. ファインダでプロジェクトフォルダを複製し名称変更
  2. Xcode の左パネルでプロジェクトを選んだ状態で右パネル Identity and Type の Name を変更
  3. Manage Schemes からスキーム名称を変更
  4. Targets > General > Bundle Identifier を変更
  5. ファインダで複製したプロジェクトフォルダ内直下のソースフォルダ名称を変更
  6. Xcode の左パネルのファイル名が赤色に変わるので、フォルダを選んだ状態で右パネル Identity and Type の Name を変更、更にその直下 Location にあるグレーのフォルダアイコンを押して該当するソースフォルダを選択
  7. Targets > Build Settings > Packaging > Info.plist File にあるパスを変更

覚えておくにはかなり面倒で、うる覚えで作業順序を間違えると方法も変わり試行錯誤の露頭に迷った結果、複製後のフォルダを削除してやり直しという厄介な作業になります。

日本語でググった結果上位5つくらいを確認してもっと簡単な方法があるなと思ったのは手順3のスキーム名称の変更のやり方で、左下の「+」や「-」ボタンで追加削除、右上の「Autocreate Schemes Now」ボタンを使う事なく、

表示されるスキーム名をクリックすると変更可能になるので、

名前を変えてリターンすると完了します。

もう一つは同様の手法を取る手順7で、

変更箇所の文字列をクリックすると、

簡単に変更ができます。

参考にしている Stack Overflow ページにも書いてあるのですが、検索窓に複製元のプロジェクト名を入れると外部ライブラリを使うプロジェクトの場合にも変更が容易になります。

参照

最終的に納品先の端末にはこのようにアプリ名がずらずらと並んでいく事なります。

最後に暴言を吐くと、Android と比較してク*面倒臭い事極まりないという感想になります。

Grade Sync Issues: (5 warnings) 回避

数ヶ月ぶりに Android アプリ案件をやったところ表題のようなエラーに出くわして回避したお話です。

内容はリンク先にもある通り、先方の都合で2018年末に使えなくなるから変更しろということで、 Gradle Script/build.gradle(Module:app) に記述のある “compile” 文字列を全て “implementation” に書き換えてから右上の Sync Now リンクを押します。具体的には、dependencies の中にある4箇所、compile fileTreeandroidTestCompilecompiletestCompile を implementation fileTreeandroidTestImplementation implementationtestImplementation とします。

解決前:

解決後:

参考:

ICSからTVPIDファイルを作る

先日作成したワールドカップ用のカレンダーファイルを利用して、EyeTV の予約に使う iEPG データを作りました。尚、このソニーが提唱した電子番組表の規格は終了する事になるようですが理由は不明です。

ICS ファイルの読み込みは公開されていたものを拝借して利用しましたが、2点変更を加えました。1つ目は、ics クラスで icsData 値を全て取得する際の explode の区切り文字列が \n になっていたのですが、作成した(というか元にしていた) ICS ファイルの改行コードが CRLF だったので次のようにしました。

$icsDatesMeta [$key] = explode ( "\n", str_replace(["\r\n", "\r"],  "\n", $value) );

また、このクラスから $icsEvents 取得後に TVPID ファイルを作る際に終了時間のタイムゾーンが設定されていなかったので次の1行を追加しました。

$endDt->setTimeZone ( new DateTimezone ( $timeZone ) );

更にこの追加行の直上に、決勝トーナメント以降の対戦は延長戦の可能性を考慮して終了時間に1時間を追加しました。

if($i > 47) {
  $endDt->add(new DateInterval('PT1H'));
}

この PHP ファイルと同階層に iepg というディレクトリを 777 権限で作成して実行すると、ブラウザ上では日付順の日程を表示しつつ、iepg-{n}.tvpi というファイルを64種作成します。装置は EyeTV 250 を UNIDEN 地上デジタルチューナー DTH11 からのコンポジット入力で使用しているので、station 値は固定し EyeTV 側の「録画ソース」には「100 コンポジットビデオ」となるようにしました。

Content-type: application/x-tv-program-info; charset=shift_jis
version: 1
station: コンポジットビデオ
year: 2018
month: 06
date: 15
start: 00:00
end: 02:00
program-title: FIFAWC2018 ロシア vs サウジアラビア - A組 第1節
genre: 1
subgenre: 2

iEPG ファイルの準備ができたら、重複を回避するために EyeTV の既存の予約をスタンバイ状態(チェックを外す)にし、全てのファイルをダウンロードフォルダにドロップすると予選リーグ第3節の重複を警告してきますので、それぞれどちらの対戦名を優先するか決定して読み込みが完了します。

スタンバイ状態にした既存の予約を有効にして行くと、重複した予約の対戦名をダイアログで警告してきますので、それらの予約をスタンバイにしながら最終的にどちらの予約を優先するか調整する事になるかと思います。

最後に今回作成した iEPG ファイルをこちらに置きましたので、PC 録画を予定されている方のお役に立てば幸いです。
WC2018IEPGs.zip

P.S. チューナーの方は面倒臭い…

参考:

Googleファミリーリンクで子供の端末を制御する

昨年、安価な子供の位置情報確認方法について書いたのですが、iOS のようなペアレンタルコントロール機能が Android には無いので、アプリを無効化しても Chrome ブラウザを使い際限なく Youtube 視聴をしてしまったり、子供の友人が勝手にロック画面からカメラを起動して街中で動画を撮影するといったような子供あるある問題が表面化してきたので対策を考えていたところ、Google が「ファミリーリンク」という制御アプリを日本向けにリリースしたので導入してみました。環境は前回同様、子供の端末に Huawei SIMフリースマートフォン P8 lite に 0 SIM を利用します。

まず現在年齢を詐称して登録していた子供の端末のアカウントのデータをバックアップしました。
$ adb backup -f backup_20180604.ab -all -nosystem -apk -obb

次にこの端末に親管理者となる自分のアカウントを追加し Google ファミリーリンクのアプリをインストールして進むのかと思いきや、別端末から管理する必要がある事が分かりました。公式の文書には「〜の端末」や「〜の Android」と言った記述がなく分かり難い事半端ありませんでした。

気を取り直して子供の端末を初期化し、自分の端末(iOS と Android 共)にも Google ファミリーリンクのアプリをインストールし、子供のアカウントを正しく再取得した後に2台並べて設定、Chrome のフィルタで youtube.com ドメインの追加、アプリ管理、位置情報、その他からフォト共有をオフにし、1日の利用上限とおやすみ時間を指定して無事完了しました。

次に上部スワイプからショートカットで Wi-Fi をオフにしてデータ通信での挙動を確認してみたのですが、先のアプリの管理で「端末管理」と「EMUI」をブロックすると「設定>データ通信量の管理」の項目が非表示になってしまう事が分かったので、一旦許可済みにして「ネットワーク通信を行うアプリ」と「1ヶ月の利用可能なデータ通信量」の設置を行いました。

そしてネットワーク通信を行うアプリを観測してみたところ、10085 というアプリが位置情報を取得する際に必要な事が判明したので「ネットワーク通信を行うアプリ>システムアプリ」でモバイルデータのチェックを入れてみたのですが、Google ファミリーリンクのアプリにある他の設定を変更する事ができませんでした。

もう一度設定画面を確認してみると、10085 前後に存在している 10008, 10012, 10014, 10017, 10026, 10029, 10031, 10032, 10045, 10050, 10058, 10064, 10070, 10074, 10080, 10081, そして 10086 という多数の怪しい名称のアプリが関係しているだろうと推測して全てにチェックを入れるとうまく動きました。

それぞれのアプリがどの設定に関連するのか調べるのは面倒だったので放置していますが、 10032 をオフにする際「モバイルデータ通信の無効化」というタイトルのダイアログを表示し「MMS メッセージの送受信」が不可能になる旨の警告をしていました。結構な数のアプリなので通信量が若干心配なのですが、幸運にも 6.0(Marshmallow)端末で対応できましたし、フィルタリングや時間制限など MacOS に近い制御が可能だという事で、iPhone SE2 が出たらどうなるか分からないところ、暫くこれで運用してみようと思います。

参考:

サポート対象外のMacでNight Shiftを使う

昨年内部ディスクを SSD に換装して快適さを取り戻した開発機で使っている iMac Mid-2011 ですが、リビング用に購入した MacBook と比較してみるとスマホでは一般的な機能になっている Night Shift の設定が欠けている事に気が付きました。調べてみると、iMac に関しては2012年型から使える機能なようで、ブルーライトで失明してしまったお婆さんの体験談を近所にお住いの方から伺った事もあって、ソフトウェア側から何かできないものかともう少し追いかけると、MacRumors のフォーラムに相当する内容が書かれていました。

参考:

インストーラがあったので簡単に済ませようとしたのが運の何とかではありませんが、再起動後の起動画面で無線キーボードとトラックパッドを認識しなくなると言う問題に直面、内容をよく読むと macOS 10.13.2 は検証中だと…。背面の電源ボタンで強制終了し、コマンド+Rキーで内蔵の macOS 復元システムを立ち上げ、クソ長いクリーンインストールと Time Machine バックアップからの復元か〜と思っていた矢先、SSD にした恩恵に与る事ができました。

気を取り直し原典に当たる事にして、日本語の説明も参考にしつつも、その手順の内容が箸折ってあったのと途中で問題があったので経過を書いておこうと思います。

まず CoreBrightness.framework のバックアップは、デスクトップ等にドラッグしたり直接副クリックからの圧縮をしてデスクトップに移動させるのでも良いのですが、パーミッションが {User}:staff に変更されてしまうため戻すことの手間や後述する手順の作業内容を考えるとゴミ箱にぶち込むと言う手もありそちらの方法を選択しました。

次にエディタアプリで CoreBrightness.framework を開く場合、このフレームワークの置いてある場所 /System/Library/PrivateFrameworks/ で書き込み権限が無いため、一旦デスクトップ等の場所に複製したものを編集しました。編集アプリには iHex を利用しました。

そして、CoreBrightness.framework の ModelMinVersionBLR と言うシンボル名のアドレスを拾います。
$ nm /S*/L*/PrivateFrameworks/CoreBrightness.framework/CoreBrightness|grep _ModelMinVersion
0000000000035000 S _ModelMinVersionBLR

更に16進数ダンプを表示して編集箇所の目星を付け、編集アプリでファイル内検索を利用し実際の編集箇所を見つけます。
$ xxd -s 0x35000 -l 28 /S*/L*/PrivateFrameworks/CoreBrightness.framework/CoreBrightness
00035000: 0900 0000 0100 0000 0d00 0000 0600 0000 ................
00035010: 0500 0000 0600 0000 0800 0000 ............

今回は iMac12,1 に対応させるべく 0d000c00 に書き換え、保存した CoreBrightness.framework を /System/Library/PrivateFrameworks/ へ戻し、$ sudo chown -R root:wheel /System/Library/PrivateFrameworks/CoreBrightness.framework と権限を元に戻しました。

これで最後と思った codesign コマンドでエラーが返ってきました。
$ sudo codesign -f -s - /S*/L*/PrivateFrameworks/CoreBrightness.framework/Versions/Current/CoreBrightness
/System/Library/PrivateFrameworks/CoreBrightness.framework/Versions/Current/CoreBrightness: replacing existing signature
codesign_allocate: error: unable to locate xcodebuild, please make sure the path to the Xcode folder is set correctly!
codesign_allocate: error: You can set the path to the Xcode folder using /usr/bin/xcode-select -switch
/System/Library/PrivateFrameworks/CoreBrightness.framework/Versions/Current/CoreBrightness: the codesign_allocate helper tool cannot be found or used

2つ目のエラーに書いてある sudo xcode-select --switch /Applications/Xcode.app を試しても、Xcode の「環境設定>Locations>Command Line Tools」を確認するも問題がなく、結局1つ目のエラーにあるように .bash_profile ファイルへ export PATH=${PATH}:/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ とパスを記述し再読み込みして解決しました。

$ vi .bash_profile
$ source .bash_profile

ここまでやっておいて何なんですが、OS の更新毎に作業が発生する事や、子供が産まれてからは17時以降の作業はやらないようにしているのであまり必要がなかったのかもしれません。

参考:

照会カレンダーを作る

4年に1度のサッカーの祭典が迫って来たところで恒例のカレンダーファイルを作成し共有したいと思います。技術的な要件としては次の3つになります。

  1. 日本語表記にする
  2. DropBox を使って照会カレンダーの形式で共有する
  3. スマホの2大 OS とデスクトップでの表示に対応する

(技術的な事はどうでも良いのでカレンダーファイルを入手したい方はこちらからどうぞ。)

  1. 日本語表記にする

    まず ICS ファイルを作成するのですが、英語やロシア語などの表記を使ったカレンダーファイルは既に幾つか存在しているのでそれを利用します。今回は Fixture が提供しているものを利用しました。一旦カレンダーアプリに読み込んだ後、ファイルメニュー>書き出す>書き出すを選び、書き出した ICS ファイルをテキストエディタで開き、日本語に書き換えます。国名やスタジアム名、対戦ラウンド名やグループ節などは一括置換してグループ組名のアルファベットを追加しました。

    更新:詳細にスタジアムの所在地名と放送テレビ局名を追加し、決勝トーナメント以降の「未定」となっていた対戦国名に試合 ID を利用した表記にしました。

    参考:
  2. DropBox を使って照会カレンダーの形式で共有する

    決勝トーナメント以降の未定となっている対戦国名を更新するためにダウンロード形式では無く照会カレンダーとして共有します。コストを掛けない保存先として DropBox を選択しましたが、ここで一つ罠がありました。

    DropBox でファイルを共有した時にデフォルトで付与される dl 引数は 0 なのですが、これを 1 にすることによって解決しました。

    http://hkitago.tumblr.com/post/173940229306

    また DropBox の共有リンクアドレスはファイル名が変わらない限り普遍だと言う事で、更新が必要な照会カレンダーファイルを配置する条件に合致しています。

    参考:
  3. スマホの2大 OS とデスクトップでの表示に対応する

    具体的には、Apple の MacOS と iOS のカレンダーアプリ、Google カレンダーのウェブアプリ版と Android のカレンダーアプリになり、デスクトップとスマホで同期できるようにします。実はここにも一つトリックがあって、アドレス文字列をクリップボードにコピーした後にカレンダーアプリのコマンドを使って照会(追加)する場合と、ハイパーリンクを使ってカレンダーアプリを起動し照会(追加)する場合で方法が異なります。参考まで、Apple では「照会 (Subscribe)」、 Google では「追加 (Add by URL)」)と言うコマンド名称になっています。

    最初に、アドレスをクリップボードにコピーしてカレンダーアプリから直接追加する場合、MacOS/iOS 共に https://webcal:// のどちらのスキームを使う事が許されていますが、Google カレンダーでは webcal:// のみ使う事ができます。https:// のアドレスを使うと一見読み込みに成功したように見えますが内容を表示する事ができません。また、iOS で webcal:// を使うと SSL オプションが外れた状態になるので気になる方は https:// を使うと良いと思います(MacOS のカレンダーアプリには SSL オプションがありません謎)。

    次に、ウェブ上にあるハイパーリンクを踏んでカレンダーアプリを起動して照会(追加)する場合、MacOS/iOS では href="https://… とすると ICS ファイルがダウンロードされ照会カレンダーの扱いになりませんので href="webcal://… を使う必要があります。この場合も先述した通り SSL オプションはオフのままなのでご注意ください。そして Google カレンダーへ遷移し追加する場合は、href="https://www.google.com/calendar/render?cid=webcal://… と記述する必要があります。

    参考:

と言う訳で長々と書きましたが、リンク先はこちらになります。

Apple 用
FIFA World Cup 2018 照会カレンダー日本語版
Google 用
FIFA World Cup 2018 照会カレンダー日本語版

それぞれのカレンダーアプリから直接照会(追加)する場合は、このアドレスをコピーしてお使いください。

最後に注意点としては、iOS で照会すると MacOS へ同期する事ができないので両端末で同期する場合は MacOS で照会し場所を iCloud にする事と、Android のカレンダーアプリはデフォルトで同期がオフになっている事があります。それでは楽しいW杯ライフを!

参考:

Passive Event Listenerを使う

シングルページアプリケーション(SPA)や最近話題のプログレッシブウェブアップス(日本語ではアプリ)をやっていると利用者にスクロールさせたくない場合、イベントリスナーを使った JS コードので対応ができていたのだけど、iPhone で思うようにならなくて調べると、こんなバグ報告がありました。

ところがもう少し調べるとまたもや Stack Overflow に助けられ、公式文書によると iOS 11.3 と macOS 10.13.4 に搭載されている Safari 11.1 からパッシブモードを使う事が必須になったそうです。

Android は未だ昔のやり方で動いているのですが時間の問題かと思います。

参考に記した日本語文献は2016年のもので、そう言えば微かに当時言われていた記憶が…としても唐突過ぎてバグ報告したくなる気持ちも察しつつ、過去のプロダクトを含めて見直しを啓蒙したいところで書きました。

参考:

iOSのOpenCV環境構築

簡単だった Android に比べて癖が強かった iOS の OpenCV 環境構築について、Xcode 9 と Swift 4 で且つ CocoaPods を使わないという条件下で3つのハマった事を記録しておきます。

  1. 使用する OpenCV のバージョン

    まずはやっぱり最新バージョンと思って OpenCV 3.4 を使うも “Apple Mach-O Linker Error” でビルドに失敗したので Stack Overflow のお世話になると 3.1 以下を使うべしという事。実際には最後に判明した事だけど重要度から最初の項目にしました。

    参考:
  2. フレームワークとラッパーファイルを配置する場所と Create Bridging Header プロンプトが表示されない問題

    この辺りのチュートリアルを説明している日本語文献は多いのだけど、フレームワークとラッパーファイルをプロジェクト直下では無くてグループのフォルダ内に置くと openCVwrapper.mm ファイルのヘッダで #import "opencv2/opencv.hpp" とすると 'opencv2/opencv.hpp' file not found とエラーを出力します。

    結論からすると、ターゲットの Build Settings にある Framework Search Path を正しく指定すればどこに置いて良いという事ですが、プロジェクトフォルダの第一階層に置くのが理想的かと思います。

    http://hkitago.tumblr.com/post/172359880316

    もしグループフォルダに置いた場合、右手にあるプルダウンから再帰(recursive)を選べば通るようになります。

    この模索中にフレームワークの追加と削除を繰り返す事になったのですが、2回目にフレームワークを追加しても Bridging-Header.h を自動的に作成するダイアログが表示されない問題にぶつかりました。フレームワークと3つのラッパーファイルを削除したらターゲットの Build Settings にある Bridging Header を削除する事で解決します。参考の Stack Overflow にスクショ付きで解説があって助かりました。

    参考:
  3. ビルド時の Documentation Issue 警告

    最後は深刻ではないのですが、ビルドすると大量の警告を出力してくるという気持ち悪さ回避で、プロジェクトの Build Settings にある Documentation Comments を NO にしました。

    参考:

最後にサンプルコードを Github で漁っていたのですが、 Swift 3 のコードが多く、しかも Swift 4 でカメラ周りの API の変更点が多い事や、Android との兼ね合いを考慮してできるだけ OpenCV のコードで Swift を使わないものを探してみると、Twitter 検索で面白いものを見つけました。(Google 検索には引っかからなかったのがとても現代的)

Swift 4 用に若干変更を加え、先に Android で作っていたコードを流用して簡単に実装できました。

環境構築1日、実装5分という情けないお話でした。