投稿

2017の投稿を表示しています

HTTP/1.1 Transfer-Encoding: chunked

Web Scraping 用のプログラムを組んでいて、HTTP レベルの Socket プログラムを自前で組むか、Client レベルの処理は言語環境のライブラリーに任せて HTML を解析・処理する程度のものを組むかという、二択問題によく悩む。これまでの経験上、後者の方が敷居が低く取りかかるのに容易であるというメリットがある。一方、一旦何らかの壁にぶち当たると、ブラックボックスのない前者の環境で試行錯誤を進めた方が、心理的にもまさしく“急がば回れ”の典型のような結果となり、トータルで楽になる。 そんなわけで、今回取り組んでいる物件についても、スタートアップは Java の URLConnection で一通り組み上げてしまって、それで問題なく全体的に動くものが出来上がっていたので、そのまま運用していたものだった。ゼロ状態からのスタートとなるプロジェクトでは、まずはどんな形であれ、全体としてちゃんと動くものへと到達できるかどうかが不明な状態なので、「まずは全体としてちゃんと動くもの」まで辿り着くことが何よりも重要である。そのためには、Client レベルのものは Java のコアライブラリーに任せて、Web Scraping にターゲットを絞った方が確実にプロジェクトを成功まで推進することができる。 それでそのまま動くようになったままで運用し続けていて、プログラムには手を入れていなかったのだが、今度、Lanterna を使って GUI 化したりして、使い勝手が向上したので、さらに前から欲しいと考えていた機能を追加したりした。最終的には GUI 化したらしたで CUI の時は気にならなかった処理速度が気になったので、ネットワークからのデータの読み込みをマルチスレッド化するところまで行き着いた。 このネットワーク読み込み処理のマルチスレッド化で、ある問題が表面化したのだった。 どうやら Java の URLConnection は、スレッドセーフではないようなのだ。とはいっても、このプロジェクトに関して言えば、Cookie がスレッド間で共有されていることが問題の核心であり、それを URLConnection 自体がスレッドセーフではないという話に含めていいのかどうかはわからない。ともかく、Cookie が上書きされてしまうのが原因で、サーバー側が付与する JS

Exception の使い処

Perl では Exception のことは気にしないでプログラミングできたので、Java で当初特異に感じたのが Exception の扱いだ。仕様に強制される形で try-catch を行う必要があるという認識で今まで凌いできた。 そもそも CUI でプログラミングしている段階では、例外処理については別段の配慮はせずとも、コンソールに JVM が吐くエラーメッセージが表示されるので、自分でエラーに備える処理を明示的にコーディングする必要はなかった。CUI というのはそういった意味でユーザーとプログラマーが完全に同一レベルの視点で体験を共有しているので、ある意味貴重な環境なのかもしれない。 そういった CUI の貴重な環境の習慣をそのまま引き摺ってしまっていて、GUI で Android のアプリなどを作っていても、例外処理について、標準メソッド側が要求するから受動的に try-catch を記述する程度で、自分から能動的に Exception クラスを用いるという経験があまりなかった。 ところで最近 Web のフォーム送信操作を自動化する Java プログラムを作成していて、想定外のエラーが発生した時、そのエラーがどの段階で出たエラーなのかということがわかった方が、自分自身で利用するだけでなくもしアプリを公開するという前提では、その方が良いと考えた。そこで、各段階で、想定通りではない結果になっていた場合、Exception を発生させるようなコードにすることにした。 当初は字義的に、RuntimeException を使っていた。ところがこれでも「どの段階で発生したのか?」がわかりにくかったので、最終的には IOException を使うことに落ち着いた。 GUI ライブラリーとして Lanterna という ncurses ライクなライブラリーを使っており、コンソールではなく、GUI の表示にエラーメッセージも表示させたいと考えた。当初の RuntimeException だと、どこかでエラーが発生していることがコンソールには表示されるのだが、どの段階で起ったのかが把握しにくく、GUI 側でもどこでキャッチすればいいのかがわかりにくい。そこで IOException にして、GUI 側で catch させることにしたのである。 ネットワークにアク

APFS は case-sensitive で

APFS を何も考えないでデフォルトのままフォーマットして macOS High Sierra をインストールして使っていたが、case-insensitive であることに気付いて、再度、SSD を完全に初期化し、case-sensitive フォーマット(非暗号化)にして、High Sierra をインストールし直した。 通常は、APFS を case-sensitive にする必要はなく、例えば、Android Studio(Android 用のアプリ開発環境)ではシステムのフォーマットが case-sensitive だと警告が出たりする。一方、OpenWrt のような Linux 系 OS のカーネルをクロスコンパイルする場合、Linux は case-sensitive なので、macOS 側でも case-sensitive である必要がある。そういったレアケースに対応したいのであれば、case-sensitive にしておく。そうでない場合はよっぽどでない限り、case-insensitive が無難だろう。 OS インストール後の各設定のカスタマイズや、基本ツールのインストールなどは、一度それぞれの方法を確立した後だったので、今回はそれらを通してメモにまとめておくことができた。FileZilla の設定 .xml はちゃんと iCloud ドライブに退避させておかなければならない、などの要点を整理するいい機会だった。 ちなみに、なぜ非暗号化でフォーマットしたかというと、一度暗号化でフォーマットしたのだが、OS のインストール後、暗号化されたドライブ用のユーザーアカウントが表示されるようになったので、気持悪かったので、非暗号化でフォーマットして仕切り直した次第である。OS のインストール完了後に、FileVault を有効化して暗号化したが、完全に暗号化が終わると、APFS のフォーマット自体が暗号化されたものに置き換った。ということは結局、最初から暗号化しておいた方が、時間的に遠回りしなくてスマートだったことになる(意味不明のユーザーアカウントはどうにか消す方法がある)。

QNAP の SSH のアクセス元制限の不完全な仕様

OpenVPN で実家の LAN につなぎ、VPN 経由で NAS(QNAP)にアクセスできるようになったので、ネットワークセキュリティを強化すべく、NAS の SSH にアクセス元制限を付けた。/root/.ssh/authorized_keys の公開鍵リストに、from="(ネットワークアドレス)" のオプション設定を追記したわけだ。 ところで、元々ブリッジモードの VPN 設定だったのを、ルーターモードに変更したため、アクセス元のクライアント機のネットワークアドレス(192.168.11.0/24)は NAS 側のネットワークアドレス(192.168.0.0/24)と異なるものとなった。そのため、from にカンマ(「,」)区切りでネットワークアドレスを列挙する必要がある。 from="192.168.0.0/24,192.168.11.0/24" ssh-rsa AAAAB3N... しかし、どうやら QNAP の SSHd では仕様が不完全なようで、from として列挙したものを与えると、正常に動作しない(すべてのネットワークからアクセスできなくなった。仕方なく、一時的に telnet を使って復旧作業をする羽目になった)。 つまり、authorized_keys の from 設定としては列挙で設定することはできず、一種類の設定しか与えることができないのである。 簡単に思い浮ぶのは、VPN をルーターモードで運用するのをやめて、ブリッジモードに戻すことである。そうすれば、クライアント機のネットワークアドレスは NAS 側のネットワークアドレスと同一なので、from のエントリーは一種類で済む。 それでもせっかくルーターモードにしたのにブリッジに戻すのも何となく嫌だったので、(専門家でもないのに独学でネットワークエンジニアの資格をパスしたという“昔取った杵柄”を活用できたのか)ポク・ポク・ポク・チーンと思い付いたのが、ネットワークアドレスに、192.168.0.0/23 という値を使う方法。 23 ビットというネットマスクを使う奇策 である。この設定は、192.168.0.0 〜 192.168.1.255 の範囲の IP を意味するネットワークアドレスである。 from="192.16

OpenVPN を TAP(ブリッジ)→ TUN(ルーター)へ変更

イメージ
基本的に VPN と NFS を使った利用環境は構築できたので、最後に少しでも VPN を最適化しておきたくなり、OpenVPN のモードを TAP(ブリッジ)から TUN(ルーター)へ変更することにした。 .ovpn まずはサーバー(DD-WRT)側と、クライアント側(Mac、Linux)双方で、.ovpn 中の dev 設定を tap から tun に変えることが基本となる。 dev tun クライアント側はこれだけで他にやることはない。一方、サーバー側ではルーターモード制に伴ういくつかの副作用的な状況を解決するための設定が必要となる。 サーバー(DD-WRT)側 設定中で tun にする以外に、VPN 専用のサブネットの設定が必要になる。DD-WRT の設定の、TUN / TAP を選択する直下の Network と Netmask の部分がそれである。ここの例では 192.168.11.0/24 としてみた。 ブリッジモードではクライアントはそのままサーバー側のサブネット(192.168.0.0/24 とする)に参加する形となり、VPN サーバーが DHCP サーバーとしてクライアントに IP プールの中から一つ割り当てる形だった。ルーターモードでは、VPN 用のサブネット(192.168.11.0/24)丸ごとが IP プールとなりそれをクライアントに割り当てる。なので、VPN クライアントはサーバー側の本来のサブネットには直接参加しない形となるので、VPN 用のサブネットからサーバー側の本来のサブネットへとアクセスするためのルーティング設定が必要となる。そのために、DD-WRT の Additional Config においてクライアントにプッシュする形でルーティング設定をセットする。 push "redirect-gateway def1 bypass-dhcp" ※ "route 192.168.11.0 255.255.255.0" を別途 push する必要はない。redirect-gateway でリダイレクトされる Gateway 設定に同じ route 情報は含まれている。 さらに、これで VPN サブネット側のクライアントがサーバー側の本来のサブネットにアクセスでき

ローカルディスク ⇄ NFS ディスク間の rsync

イメージ
👉 前回 で OpenVPN の接続と NFS のマウントまで自動化できたので、あとは特定のフォルダーをローカルディスク ⇄ NFS ディスク間における rsync をボタン一発でできるようにするだけだ。 最新の rsync macOS 標準の rsync はバージョンが旧いので、Homebrew で最新バージョンにするのが常套のようだ。 brew install rsync だけで ok。brew tap してからという情報は既に古いものなので注意。 OS 標準の元から存在する rsync は /usr/bin/rsync に、brew でインストールされた新しい rsync は /usr/local/bin/rsync にある。 ローカルディスク ⇄ NFS ディスク間における rsync 下の例では、~/eclipse-workspace フォルダを丸ごと、NFS にマウントした NAS の共有フォルダにバックアップしている。また、NAS 側で NFS のオプションを ALL_SQUASH で自分のアカウント名に割り当てているため、ファイルの所有者などの情報は rsync 側のオプションで制御していない。rsync 自体の詳しいオプションについては別途詳細を調べて欲しい。また下の例では省略したが、実際には --exclude オプションなども指定して、キャッシュデータは一々バックアップしないように等している。 /usr/local/bin/rsync -ruv --delete ~/eclipse-workspace /Volumes/NFS Automator によるアプリ化 上記 rsync のコマンド内容のシェルスクリプトを Automator を使ってアプリ化する。 Automator の使い方自体については 簡潔な解説 があり参考になる。

VPN 接続(Tunnelblick)と NFS マウントの自動化

👉 先の記事 で sudo がパスワード入力なしで実行できるようになったので、それを前提として VPN 接続に連動して NFS のマウント/アンマウントを自動化する方法を確立した。 (Tunnelblick のベースである)OpenVPN 自体の仕様で .ovpn ファイルの設定で up / down 用のスクリプトを指定できるようになっている。この仕様に加えて、Tunnelblick では、connected.sh と pre-disconnect.sh という名前のスクリプトをそれぞれ up / down 用スクリプトとして割り当てることによって「接続後」「切断前」に実行するスクリプトとし扱ってくれるようだ。 なので、connected.sh と pre-disconnect.sh を用意し、それぞれにおいて、NFS をマウント/切断する処理を記述しておいた。 connected.sh #!/bin/sh sudo mkdir /Volumes/NFS sudo mount_nfs -P 192.168.0.1:/share /Volumes/NFS pre-disconnect.sh #!/bin/sh sudo umount /Volumes/NFS ※ umount 時に /Volumes/NFS は自動的に rmdir されるので、rmdir は明示的に行う必要はない。 以上の 2 種のスクリプトを用意した上で、.ovpn に .ovpn up ~/OpenVPN/connected.sh down ~/OpenVPN/pre-disconnect.sh といったような形式の設定を追加する。 最後に、Tunnelblick で .ovpn をインポートする。これだけである。 ※ .ovpn や .sh を修正した場合、都度 Tunnelblick にインポートし直す必要がある点に注意する。Tunnelblick はインポート時に自前で .ovpn や .sh をコピーしてそれを直接使うので、インポート元の .ovpn や .sh を修正しただけでは Tunnelblick の挙動に反映されない。 Mac から NFS を使ってみた結果…… iCloud ドライブや Google ドライブのような感覚で使いたいと思

sudo のパスワード入力を省略できるようにする

OpenVPN で、接続確立後に自動で NFS をマウントし、接続切断時(直前)に NFS をアンマウントするシェルスクリプトを使おうと思った。ところが、mount / umount には root 権限が必要なので、通常では sudo するのにパスワード入力が求められてしまう。 色々調べた結果、/etc/sudoers という設定ファイルによって制御が可能であり、さらに sudoers を編集するのには危険が伴うので、visudo を通じて編集するのが常識的だということがわかった。 macOS / Linux のいずれにおいても、基本的には %admin ALL=(ALL) ALL となっている部分を %admin ALL=(ALL) NOPASSWD:ALL とすればよい。これは管理者グループに所属するユーザーを対象に、sudo コマンドの実行時にパスワードを不要とする設定である。(また、このようにグループの設定からアプローチするやり方ではなく、個々のユーザー単位で同様の設定をするアプローチでも可能である) 注 1:エントリーの順番 Mac では root と %admin しか元々エントリーがなかったので、気にする必要はなかったが、Linux(Ubuntu GNOME 16.04LTS)では root / %admin / %sudo となっていて、グループのエントリーが %admin と %sudo の 2 種類あった。この状態で %admin のエントリーを NOPASSWD にしても %sudo のエントリーで上書きされてしまうので、エントリーの順序を入れ替えて、%sudo の後に %admin のエントリーが来るように編集しなければならない。 注 2:Ubuntu GNOME 16.04LTS での管理者グループ ID Ubuntu GNOME 16.04LTS では管理者グループの ID が admin ではなく、 adm であった。にもかかわらず、sudoer のエントリーは %admin となっていたため、%adm と修正する必要があった。 注 3:visudo visudo はその名の通り、vi がベースになっているので、操作がよくわからない場合は vi の情報を調べてみるとよい。

SSH の公開鍵認証+IP制限

過去に NAS(QNAP)の SSH の設定を色々いじっている時にも SSH について触れたこと があったが、その時は rsync の環境を構築しようとしていた記事の中で SSH も含めていたため、なぜ SSH 単独の話題ではなかったのかという事情についてまでは忘れていた。その時の本目的はあくまでも NAS を使ったデータのバックアップ環境の確立だったので、SSH 自体は使っても使わなくてもよかったからだ。 その当時においては、当初、VPN から NAS にアクセスして、NFS を使う方策を試みたが、VPN が PPTP を使ったセキュリティ的に脆弱なものであり、SSH によって rsync ができるようになったので、VPN も NFS も忘れていた。ところが、今現在、OpenVPN でセキュリティ的に十分な環境が整い、Mac から VPN 経由で NAS をクラウド的に利用する方法を模索し始めてみると、Samba よりも NFS の方がちゃんと動くし、Windows 抜きで Mac か Linux かで動かすのだから、よりによって(本来 Windows ちゃんと仲良く戯れるための)Samba など使わないに越したことはないのだ。 ともかく、VPN 前提で考えてみると QNAP の SSH のセキュリティも改めてちゃんと見直したくなり、アクセスを LAN からのアクセスに制限できないかと調べてみると、ちゃんと方法があったので、早速そうした。方法はサーバー(QNAP)側 .ssh/authorized_keys のエントリーに、from="192.168.0.0/24" のような形式のオプションを追加することである。次のような感じで: from="192.168.0.0/24" ssh-rsa AAAAB3...AgRiOf my Ubuntu from="192.168.0.0/24" ssh-rsa AAAAB3...v17zrd my Macbook こうすることで、SSH は LAN 内からの接続しか受け付けなくなった。 注 1: VPN 経由での接続 OpenVPN を使ってアクセスする際、ssh admin@192.168.0.1 のように、IP アドレスで NAS にアクセス

VPN 環境の OpenVPN 化

イメージ
Mac をいじり出して、iCloud を軸にした標準アプリの設計思想が非常に気に入ってしまった。一般のユーザー視点なら無料 5GB で十分である。 ところが、Mac をメイン機とするならば、僕の場合、エンジニア(プログラマー)的側面も、一般ユーザーとしての立場に加えて必要になってくる。外にも持ち歩く MacBook に、開発中のデータが入っているのは非常にリスクが高いから、データの保管場所が MacBook の実機に依存するのは避けたい。だが、アプリを開発するためのプロジェクトファイルを iCloud ドライブにぶち込んでしまうと、どうやってもすぐに無料で利用できる 5GB の限界に達してしまう。かといって課金までして iCloud を増量したいとも思わない。 となると、せっかく実家で運用している QNAP 製の NAS があるので、それを使って iCloud のような運用ができないかと考えた。これまではデータを随時バックアップするという用途に NAS を使っていたのだが、クラウド的に、データ本体を常に NAS 側に置いておいて、それを端末側で参照するという形である。 ところが、写真などのマルテメディアデータはそのような専用のアプリが存在するのだが、ファイル一般となると iCloud ドライブのような使い方のできるオープンなアプリが存在しない。iCloud ドライブは macOS 専用だし、Google Drive にしても専用アプリをインストールする必要があり、それも Windows と macOS のみで Linux では使えない。 また、昔からある SMB の場合、LAN での利用を前提としていて、クラウドよりも一昔前のスタイルのまま停滞している感がある。 WebDAV 選択肢が限られていたので、まず最初に QNAP NAS で使える WebDAV を使ってみることにした。これは、macOS でも Linux でも標準で使えて、ネットワークドライブとして iCloud ドライブや Google Drive のようにアクセスが可能である。 ところが、WebDAV にはバグがあり、それは WebDAV が依存している apache のバグに由来するようだが、フォルダに index.html のファイルが存在すると、そのフォルダが空っぽ状態でファイル

macOS カレンダーで Google の共有カレンダーを表示する

カレンダーは Linux とは関係がなく Android で Google カレンダーを使っていたのみ(Linux ではブラウザ上で利用)。Mac に乗り換えたのでついでに macOS 標準のカレンダーアプリ(iCal)に、Google のカレンダーをセットしてみた。 基本的には Google アカウントをセットするだけだが、Google で共有している他のユーザーのカレンダーの表示を On/Off するには、 同期設定 で少々調整する必要がある(iCal 側で表示を On/Off できるのは、Google 側の同期設定で選んだものに限られる)。このような iCal 向けの設定がわざわざ用意されているのは、iCal でも祝日や連絡帳の誕生日の表示機能があるので、Google 側の表示と二重に表示されないような配慮からだろうか? 自分の場合は基本的に祝日・誕生日などの表示は iCal 側に任せて、Google カレンダーの方は同期設定で off にした。 もちろん、iPhone と Mac の組み合わせなら、Google カレンダーを止めて、iCloud ベースのカレンダーにしてしまえる。自分の場合現状は MacBook と Android との組み合わせなので、Google カレンダーベースにしている。

Thunderbird (Linux) から Mail (macOS) へのデータの移行

イメージ
Thunderbird 同士であれば、Linux でも macOS でも(Windows でも)、基本的に Profiles ディレクトリ下にある XXX.default フォルダを移動すればいいので、データの移行に苦労することはない。 今回は、Linux から macOS の移行に伴って、メーラーも Thunderbird から macOS 標準の Mail アプリに乗り換えてみることにしたため、多少記録に値する点はあった。 まず、Linux から macOS には、Thunderbird の XXX.default を持ってくるだけでよい。macOS 側でわざわざ Thunderbird をインストールする必要はない。 次に、ここがネット上の情報では誰も触れていなかった点だが、Mail アプリで「ファイル > メールボックスを読み込む」によって XXX.default を読み込ませる時、Thunderbird 用のオプションが存在せず、「mboxフォーマットのファイル」を選ぶという点である。おそらく、Thuderbird 用のオプションがあったというのは古い情報なのだろう。 以上で問題なくデータの移行が完了した。

Samba

元の Linux マシンと MacBook の間でファイルを移動するために、Linux 側に Samba を導入した。Linux 黎明期から異 OS 間でのファイル共有で定番だった Samba だが、今でも代替が出てきておらず、第一線で使われているということを知って少し驚いた。 いくつか詰まった点としては、GUI で共有オプションなどを指定しても、何も機能せず、結局は /etc/samba/smb.conf を直接編集する必要があった。もしかしたらこれは権限の問題で、root 権限でログインしていたら、GUI でも直接操作できたのかもしれない。 また、Samba の設定でいくらパーミッションを設定しても、それが実際のファイルに付与されている権限を変更するわけではないので、あくまでも Samba で設定した権限の範囲内で、実際のファイルへそのファイルの権限に基いたアクセスが行われるという扱いのようである。 さらに、Samba を通じてアクセスするクライアント側で求められるユーザー認証は、Samba で独自に設定するユーザーとパスワードなのには注意する。Linux マシンにおけるユーザーアカウントとは関係がない。次のコマンドで設定する: sudo smbpasswd -a <user name>

FileVault

初代 MacBook のこのマシンで、暗号化に約 10 時間かかった。

Night Shift

イメージ
Sierra からだったと思うが、今は macOS も標準で Night Shift が使えるので、当然利用する。 設定 > ディスプレイ > Night Shift > スケジュール:日の入から日の出まで Night Shift が自動で有効になっている時間帯に、一時的に Night Shift を切りたい場合は、「設定 > ディスプレイ > Night Shift > 手動:✅ 日の出までオンにする」のチェックを外せばよい。

ナチュラルスクロール

残念ながら(というか賢明でもあるのだが)、トラックパッドのジェスチャーと、マウスのホイールのスクロールの方向性をナチュラルスクロールにするか(リバーススクロールにするか)という設定は連動しており、別々に設定できない。 現状では未だ完全に Mac に移行できていないので、Linux と Mac の両股をかけている状態なのだが、Linux の方はマウスのホイールの方向を設定する余地がなく(トラックパッドのみ設定可)、Windows と同じ、リバーススクロール一択なので、そちらとの関係上、当面は(トラックパッドとの間の操作性の一貫性に反するものの敢えて)マウスのホイールに関してはリバースにしたかったのだが、Mac は Mac で仕様的に不可能であった。

Mousecape(左利き用マウスポインター)

イメージ
Mac でマウスポインターを左利き用に表示するための定番は Mousecape (0.0.5)を使うことだが、以前の macOS で発生していなかった問題が、最近の OS では発生しているようである。Mac を再起動すると、自動で左利き用の .cape 設定に切り替ってくれないのである。 同様の問題は公式 github でも issue #45 として報告されており、 ghost 氏のコメントの詳述 が当てはまることが確認できた。すなわち、Mousecape をインストール後、OS デフォルトのマウスポインターを dump し、その dump した .cape を左利き設定で適用する。起動時に自動的に適用されるようにするために、(Mousecape の中から)Helper Tool をインストールする。が、そもそも .cape を適用しても、実は適用されておらず、Applied Cape: None のままで選択した .cape に緑のチェックマークが付いていない。.cape を適用する処理で、左利き用に反転する処理は行われるものの、何らカスタム .cape が選ばれた状態になっていないのである。そのため、再起動時にカスタム .cape を適用する処理が走らず、そのために左利き用に反転する処理も行われないので、このような問題が発生する。ghost 氏は、dump の使用は諦め、.cape を新規作成してこの問題を回避したと述べている。 ghost 氏のように新規作成するのはそれはそれで大変そうだったので、僕の場合、この MacBook を譲り受けた際、元々僕が頼まれて Mousecape の左利き設定なども行っていたという経緯があり、初期化前に .cape だけ旧いのをバックアップしてあった。それを持ってきて、Mousecape に .cape をインポートしたもの適用すると、上のような問題は起きず、Applied Cape: Cursor Dump という風に表示され緑のチェックマークも付く。再起動でも Helper Tool が適切に働く。 ただし、この Cursor Dump は旧い macOS での dump なので、サイズなどが違うせいなのか、微妙に色などが異なっていて、レインボーカーソルなどが白っぽい表示になってしまっている。これを解消しよ

Apple ID の 2 ファクタ認証の落し穴(というか明確なバグ)

イメージ
Apple ID のアクティベーションにまつわる問題はようやくクリアされ、OS を High Sierra にアップデートし、色々と初期設定していた。その過程で、FileVault による暗号化処理を開始したのだが、いかんせん初代 MacBook のせいか、残り時間が「あと 1 日以上」と表示され、いつになったら終わるのかわからないような状況になっていた。 FileVault による暗号化処理の進行中でも、並行して Mac は使える。ちょうどそのタイミングで、High Sierra の追加アップデートが配信された。それでそちらもアップデートしたら、再起動を伴うアップデートだった。これが、FileVault で中途半端に暗号化処理がされていたことと競合し、OS のアップデートの処理が再起動した後に進まなくなり、仕方ないので再度 HDD 初期化、OS の再インストールすることを余儀なくされた。 ところが、iCloud の初期設定で Apple ID でログインしようとしたところ、2 ファクタ認証の、2 ステップ目、6 ケタの認証コードがスマートフォン(非 iOS デバイス)に届かないのである。音声通話で認証コードをリクエストしても同じ。 OS の初期化以前は、MacBook 自体が信頼できるデバイスとして、MacBook に認証コードが届いていた。初期化によって MacBook は一旦削除されたので、残るはスマートフォンの SMS か音声通話しかない。 ウェブから直接、Apple ID アカウントにログインしようとしても、やはり 2 ステップ目で進めなくなるのは同じである。アカウントのパスワードリセットをしようとしても、そのためにもまた 2 ファクタ認証となり埒が明かず、何度も繰り返していたら、今度は一時的なロック状態になり、サポートに相談したところ数時間待つようにと、言われた。しかし、これは短時間での連続ログインによるロックだから、どのみちそのロックが解除されても、やはり 2 ステップ目の問題は何も解消できていないのである。 連続ログインによるロックの時限解除を待って、ウェブから Apple ID アカウントのパスワードリセットを試みられるようになっていたので、とりあえずパスワードリセットの手続を開始した。 アカウントのリセットの場合、これは、セキュリティ

この Apple ID は、App Store で使用されたことがありません

自分が買うつもりでスペックを見立てた MacBook Pro(13 インチ・タッチバー付)の購入計画を身内に取られた(?)ので、自分自身の Mac 購入計画は一旦流れた形になったが、その身内が元々使っていた MacBook(初代 2015 年モデル)をもらってひとまず使ってみることにした。メイン機として使う場合は、Android やゆくゆくは iOS アプリのプログラミングに使うつもりなので、処理能力的にはすぐに不満になってしかるべきスペックの iMac または MabBook Pro を購入する可能性はあるが、今はひとまず一通り使ってみて、様々な使い勝手を知り尽す目的でこの MacBook を使うことにした。 まあ、元来 Linux ユーザーである身からすれば、macOS というのはエキスパートユーザーであっても、非エンジニア(プログラマー)人種、せいぜいシステムアドミニストレーター系の人種(ジーニアスバーとかサポートの人たちもこれに含まれるだろう)にとっての進化の最先端にある OS であって、Windows との比較で圧倒的な価値を持つものの、Linux のような、ユーザー層とエンジニア層の重なる度合いが高い世界とはベクトルが異次元であり、比較にならない。Linux ユーザーにとって、自分で OS をインストールすることのようなシスアド業務は、まず最初のスタートラインに過ぎないわけである。 ちょいちょいとネットで情報を収集して、譲り受けた MacBook をおもむろにフォーマットして初期化し、OS の再インストールを行った。何一つ難しいことはなく、ほとんど勝手にインストールは終った。こういうのを怖がって、最初の一歩すら踏み出せない人って何なんだろう?──だが、非エンジニア人種という名の世間の一般ユーザーは、そういうものである。Apple 製品の主たるユーザー層に何を求めるというのだ? OS の再インストールで、OS のバージョンは古い、El Capitan あたりに戻ってしまうので、App Store から最近出たばかりの High Sierra をダウンロードして、アップデートしようとした。 ここで問題が発生した。 Apple ID によるサインインができないのである。もちろん、パスワードを紛失したとかの、素人レベルのミスではない。「この Apple

一石二鳥は諸悪の根源

飛行機の搭乗手続におけるオーバーブッキングのケースについての記事「 なぜ全日空は定員オーバーで飛ぼうとしたのか? 」で「一石二鳥は諸悪の根源」という設計工学の考えが紹介されていた。 設計工学の世界には「一石二鳥は諸悪の根源」と考える学派がある。一つの部品に複数の役目を負わせると、事故はそこから始まることが多いのだ。 …… ミスをなくすには、「一人二役」を分離することが望ましい。 僕はこれを設計工学特有の話としてではなくて、むしろ「設計工学でもそういう風に言われているんだ」と思った。 中学数学の1次方程式で、やり方は一応授業で習って理解できているのに、実際に問題を解く場面で計算ミスを多発してテストで失点する生徒というのは、移項(加減)と x の係数を 1 にする計算(乗除)を一緒くたにして暗算しようとするのが原因であるのが多い。こういう子供には、移項と x の係数を 1 にする計算は途中式を分けてそれぞれのステップできっちり書いてやるべきだと強調することになる。まさしく上の引用の通りだろう。 同じようなことは、プログラミングでの、メソッドの定義にも言えるだろう。一行のコードで魔法のように処理が済むコードを考えたくなるのは山々で、特に、Perl で正規表現などに懲るとそういう傾向が増進されるのだが、Java でシンプルなループを記述した方がメンテナンス性も良いコードになるものである。このあたりが、関数型とオブジェクト指向の違いだろう。関数型は一石多鳥を目指す指向と親和性が高く、オブジェクト指向は一人一役に分けていく指向と親和性が高い。

MacBook Pro(13 インチ/タッチバー付/メモリー 16GB)購入

結局、MacBook Pro は ASCII カードではなく、ドコモ口座の VISA プリペイドで購入した。ちょうどドコモ口座がキャンペーンでキャッシュバック率が 1% → 4% になっていたのが理由。ちなみに、ASCII カード(オリコ)はポイント率 1% である。 このことで、2 年目までの補填率が 100% → 70% となってしまう。しかし、20 万以上する MacBook Pro の場合、70% になっても、依然、保険基準額は 14 万であり、どの道、補償上限の 10 万は超えてしまっている。つまり、部分的損失ではなく完全に損失した場合の話ではあるが、ASCII カードで購入するメリットはないわけである。そんなわけで、タイミング良くドコモ口座のキャンペーンがあったので、+3% を迷わず選んだ。 余談だが、実のところ自分用に買うつもりでいたはずの MacBook Pro だが、諸般の事情から結局今回は自分用ではなく身内用に買うことになった。もちろん、ASCII カードの関係上、名義は自分名義ではある。なので、この記事で、MacBook Pro を買ったと言いながら、一方で Mac ユーザーとしての話題が今後も出ないとしても全く自然なので、そこは誤解なきよう。 その MacBook Pro のセットアップだけはやってあげたのだが、タッチバー付 13 インチ版の最小スペックの CPU(3.1GHz デュアルコア Intel Core i5(Turbo Boost 使用時最大 3.5GHz)、64MB eDRAM)だったのもあるのだろうか。それほど速い感じはしなかった。今、自分が使っている 2011 年 8 月に購入した HP の 17 インチノート(Pavilion dv7-6100)は Core i7 2630QM(2.0GHz クワッドコア(Turbo Boost 時 2.9GHz)L3: 6MB)だが、それと比べて、コンパイル作業などが速い感じはしなかった。まあ、デュアルとクワッドの違い、macOS と Linux の違いもあるのだろうけど、6 年も経ってる割には、そんなに違いがないなと。 まあやはり、CPU の高速化の限界もあるし、15 インチ MacBook Pro ではなく、そもそも 13 インチの MacBook Pro であるから、

ASCII カード

イメージ
そろそろ Macbook Pro でも購入しようかと考えていたところ、 ASCII カード なるものの存在を知り、作ってみた。オリコ版(Mastercard)とニコス版(VISA)があり、海外旅行傷害保険が自動附帯という点だけではあるが優れていたので、オリコにした。 Macbook Pro のようなノートパソコンの場合、外に持ち歩くことを想定すると、保険のようなものは考えておきたくなる。とはいえ、AppleCare+ はそれなりに高くつく。AppleCare+ が念頭にあって、ASCII カードの補償内容を考えた場合、結構いいかなと思った。 例えば、13 インチ/タッチバー付/メモリー 16GBの Macbook Pro だと 220800 円(税別)で AppleCare+ は 25800 円(税別)である。AppleCare+ によって、購入後 2 〜 3 年目に自己負担 11800 〜 33800円(税別)で修理が 2 回まで受けられるようになる。 一方、ASCII カードの保証では、購入後 3 年を過ぎてからも、永久に何回でも補償が受けられる。ただし、自己負担は 1 万円で 1 万円を超えた分が補償され、上限は 1 回 10 万円。また、通常の故障に対する補償はされない。あくまでも、盗難や事故によって破損したようなケースについて補償対象となるので、AppleCare+ とは全く趣旨が異っている。 しかし、外に持ち歩くノート PC で補償を付けたくなる理由は、まさしく通常の故障ではなく偶発的な事故を恐れてのことなので、ASCII カードの補償内容でいいと思う。AppleCare+ が購入後 3 年目までで上記のケースでは 25800 円(税別)であるのに対して、ASCII カードの場合は年会費 1950 円(税別)であるから、3 年間で比較しても 5850 円(税別)となる。ASCII カードがあれば、AppleCare+ を付けようかどうか悩む必要はないと考えたわけだ。 ところで、カードが送付されて規定に目を通してから初めて気付いたことが一つだけあって、ASCII カードで購入しなかった場合は補填率 70% のところ、ASCII カードで購入した場合は補填率 100% となるという部分だが、これが購入後 2 年までという制限があった。2 年を

QNAP で仮想ホスト運用を断念

実家の QNAP NAS の貧弱な性能では、CGI が使い物にならず、Web サーバーは結局、さくらインターネットでマルチドメインを運用することを廃止できないという結論に達した。その上、StartSSL が使い物にならなくなってしまったため、Let's Encrypt に移行したのだが、その機会に、QNAP のポートの割り当ても、デフォルトに戻した。つまり、Web UI 用に、80 (HTTP) と 443 (HTTPS) を割り当て、仮想ホストに 8080 (HTTP) と 8081 (HTTPS) という形である。index.php も元のものにした。 XXX.myqnapcloud.com 用のセキュリティ証明書だけ、Let's Encrypt で用意し、Web UI に HTTPS でアクセスしても証明書エラーが出ないようにしておいた。

Firebase Remote Config

Firebase Remote Config は Resources をクラウド化したようなもので、クラウド上から Resources の定義値を更新するような感覚で利用できる。Resources の内容の更新のためだけに APK を都度アップデートする必要がなくなるので、かなり勝手が良くなる。 もちろん、Resources の値にアクセスする場合よりはいくつかの手続が必要だが、かなり簡素化されている。一定の手続というのは、1: デフォルト値として用意したアプリ内部のリソース(XML)ファイルを読み込む; 2: キャッシュをクラウドから取得して更新する、という 2 つの手続である。後者は、キャッシュの更新間隔を決めることも含む。 以上の理解には、Google 公式ガイドの Sample App Walkthrough とそのサンプルの ソースそのもの を見るのが無駄なく必要十分だろう。 具体的内容については、Google 公式ではないどこかの誰かのブログのサンプルコードの類から学ぼうとしない方がいいと思う。

池上彰の英語力

イメージ
イランの街で掲げられた“DOWN WITH THE U.S.A”を見て曰く『「打倒アメリカ」と書いてある』ってドヤ顔で池上さん…… アメリカが中東(シリア)なんかで空爆してるのを指して、「爆弾がアメリカと一緒に降ってくる」って言ってるだけ、絵に描いてあることそのまんま、中学レベルの英語でしょう。 誰が「打倒」なんて言ってるかというと、イランの人がそのポスターで言っていないセリフだから、他ならぬ、池上さん(の脳内の誰か)のセリフってことになる。 というか、ちょっと以前にも、池上さんの出身母体である NHK の通常のニュースで、アメリカのシリア攻撃に対してイランで反米抗議運動が広がってるというものを見たことがあるけど、英語では“Americans go home!”で、単に中東への派兵をやめて「家に帰れ」ということしか言ってないのに、NHK の字幕は、「アメリカに死を!」だった。NHK と NHK ブランドに肯定的な日本全国津々浦々の視聴者はこういうレベルで世界を認識したつもりになっている。 池上彰は英語が堪能である。自らの海外取材に駆使するだけではなく、NHK時代には国際シンポジウムの司会も英語でこなした。 (公式ファンクラブの解説より) 大学入試で英語の配点が高い慶應大学の出身。 これが日本の英語の現状。

Firebase と Admob のリンク

イメージ
Firebase アカウント(A)で独自の Admob アカウントを用意しないで、別の Admob アカウント(B)に Firebase プロジェクトをリンクしたい場合のポイント。 普通に Admob アカウント(B)で Firebase とリンクしようとすると、その Admob アカウント側の Firebase アカウント内に新規にプロジェクトが作成されて Admob とリンクしようとする。これを避けるには、Admob アカウント(B)側の Firebase アカウント内に、Admob とリンクしたい Firebase(A)のプロジェクトを共有しておく必要がある。これは、Firebase(A)で、Admob アカウント(B)をユーザーとして追加しておく必要がある。この時、権限は オーナー権限である必要がある ようだ。編集権限だと、Admob アカウント(B)側の Firebase アカウント内に Firebase(A)のプロジェクトが共有された状態になることはなるのだが、依然、Admob からリンクできない。 オーナー権限で共有された状態であると、Admob からリンクする際に、(新規プロジェクトの作成ではなく)既存のプロジェクトとして選択できる状態で認識されるようになる。

Handler(mainLooper).post() を使うやり方と、runOnUithread() を使うやり方の違い

基本的に runOnUiThread() は Handler(mainLooper).post() へのラッパーとして用意されているが、 メイン UI スレッドから実行する場合は挙動が異なる 。 メイン UI スレッドから実行した場合は、Handler(mainLooper).post() されずにスルーされて、そのまま Runnable の内容を実行する扱いとなる。なので、View の再描画など、強制的にタスクを発生させたいがために Handler(mainLooper).post() したい場合に、メイン UI から runOnUiThread() を使っても無意味なので、この場合は明示的に Handler(mainLooper).post() を記述して実行する必要がある。 cf. runOnUiThread vs Looper.getMainLooper().post in Android

PreferenceFragment

1 年以上ぶりくらいに本格的な Android プログラミングに回帰。そのせいか、固定観念から多少自由になったかもしれない。 例えば、PreferenceFragment。古い PreferenceActivity が obsolete になって、代わりに PreferenceFragment を使うように 公式リファレンス に書かれている。それで、ネット上の情報をいくつか見ても、受け売りの解説ばかりなものだから、皆が自前の MyPreferenceActivity 的なるものを用意して、その中で PreferenceFragment を実装するような感じにしてる。 そこで今回、「そもそも、MainActivity で直接 PreferenceFragment を使っちゃいけない理由なんてあるのかい」と思って、やってみたら──できた! 今までの MyPreferenceActivity をわざわざ専用に用意して PreferenceFragment を使うやり方って、何だったのだろうか……。 受け売り情報撒き散らすのやめて欲しい。 いや、まあ、ブログなんだから、本来は各人の私的なメモという性格のものではあるんだろうけど。

プログラミング・パラダイム

結局、「オブジェクト指向プログラミング(OOP)」というのは、1) 手続指向は構造化で、2) データは構造体で、ということであり、この両者を、3) 構造化された手続(メソッド)を、構造体(オブジェクト)単位で整理することでまとめた、というだけの話であり、これ以上でもないし、これ以下でもないのではないかと思う。 手続自体は、あくまでも構造化プログラミング的な観点で整理を行なうべきで、これを生半可なオブジェクト指向的観点で整理すると、コードが無茶苦茶になって却って“百害あって一利なし”といっても言い過ぎにはならない気がする。少なくとも、自分の場合はそうである。 そうやって、構造化プログラミング的にすっきりと整えられた個々のコードが、集合して複数のコード群としてそのままそこいらにぶちまけられている時に、手続指向の限界が急にクローズアップされてくる。 この時に整理整頓の“容れ物”として俄かに脚光を浴びることになるのが、構造体(オブジェクト)である。手続のためのコードをそのまま“裸”でそこいらにぶちまけては置かないようにしよう、必ず、構造体に入れられた(カプセル化)状態で置いておくことにしようね、というのが僕流のオブジェクト指向像である。 上のことをちゃんと自覚していないで、「オブジェクト指向スゲー」で何でもかんでもオブジェクト指向のノリを持ち込もうとすると、むしろコードの見通しが悪くなって、あっちへ飛んだり、こっちへ飛んだりと、ダイクストラ先生が「goto は使わないようにしよう」といった時代の事情に逆戻りして、あっちのメソッドこっちのメソッドを飛び回るような、いわば「goto なきスパゲッティ化プログラミング」に陥ってしまう。 新しいコードをスクラッチで組んでいく時、ここは手続指向で素直に、一つ一つの処理を継ぎ足して行ってプログラミングするのが、やはり王道なのではないかと思う。そしてそのコードが伸びるにつれ、(2回以上)多用される同様の処理は、サブルーチンとして分離する。そのことで、「コードをコピー&ペーストして使い回すことを避ける」というのが、構造化プログラミングの単純かつ肝となる原点だと思う。ある処理に関するコードが記述される場所を一元化することで、後に変更の必要が生じた時に、あちこちを修正して回るというようなことは避けないと、例えば、一部を修正し、一部

オブジェクト指向プログラミングと構造化プログラミング

オブジェクト指向プログラミング(OOP)と構造化プログラミング(手続指向)を対立する概念だと思っていたが、どうやら間違っていたようだ。 詳細は別の機会でもあれば書くかもしれないが、両者は共存可能、というか共存させるのが適切だと思った。 この結論に達することで、メソッド定義の private と public、static と dynamic の使い分けもはっきり線引きできるようになったと思う。 構造化プログラミングは static で、そのうちのサブルーチン部分は private、メインルーチンは public。 オブジェクト指向プログラミングは dynamic で、オブジェクトの操作に関するインターフェイスとしてのメソッドは public。 大ざっぱな分け方としてはそんな感じ。

期間限定dポイントの裏技

イメージ
年末年始のキャンペーン( 【dケータイ払いプラス】冬のスーパァ~チャンス! )で獲得したボーナスポイントの期限がそろそろ迫ってきたので、適当に対処しておきました。 合計ポイント数は変わっていませんが、10 回の処理の結果、内訳の期間・用途限定ポイントが 500 ポイント分減って(通常ポイントと入れ替わって)いるのがわかります。 2017-03-12 追記:3月初めに、ローソンのシステムが修正され、上記裏技が塞がれたようです。(期間限定ポイントはすべて変換済ではあったものの)たった一回しか活躍の機会がなかったとは、とほほ……