理系学生日記

おまえはいつまで学生気分なのか

忍者TOOLS

iPhoneの「その他」領域を大幅に削減するためにiPhoneをリセットした

iPhone に DISK FULL のエラーが出るようになった。iPhone 7 の 32 GB モデル。

「設定」アプリの 一般 > iPhoneストレージ にて、ストレージの使用状況を確認できるが、それを見ると 32 GB のうち、「その他」に 13 GB くらい使っているという状況になっていた。全体の 40 % が「その他」か。 そもそも、この「iPhone ストレージ」にて使用状況が収集されグラフ表示がなされるまで、数分かかるというゴミのような状況。

iPhone を再起動しようが「その他」領域の肥大化は解消しなかったので、以下のエントリで紹介されている通り、iPhone のリセット(工場出荷時に戻す) を実施した。 結果として、「その他」領域が 4 - 5 GB になったので、リセット最高という結論。

気をつけたのが、iPhone の完全なバックアップをローカルに取得しておくところ。iCloud へのバックアップは、その対象が全体の一部でしかないので、バックアップから復元しても元のようには行かなかったりする。 あと、暗号化してデータを保存するようにすると、パスワードとかも一緒にバックアップされて幸せになれる。

f:id:kiririmode:20180106235718p:plain

全体を通して見ると、なんだろう、かつての Windows でよく実施せざるを得なかったデフラグの記憶が思い出されてウッてなった。

1年ほどやってみたタスクシュートでのタイムマネジメント状況

昔、タイムマネジメントについて昔にこんなエントリを書きました。もう 5 年前になるのか。

このときの気持にはあまり大きな変化はなくて、

まず最初に、そして明確に認識しておかないといけないのは、「現状把握をまともに行っていない状態での"計画"はうまくいくはずがない」ということです。

というのは今もって真であると思っています。何度も引用してしまうんだけれど、P.F.ドラッガーのタイムマネジメントも、時間の記録からスタートします。

私の観察によれば、成果をあげる者は仕事からスタートしない。時間からスタートする。計画からもスタートしない。何に時間がとられているかを明らかにすることからスタートする。
(中略)
重要なことは、記録することである。記憶によってあとで記録するのではなく、ほぼリアルタイムに記録していくことである。

プロフェッショナルの条件――いかに成果をあげ、成長するか (はじめて読むドラッカー (自己実現編))

プロフェッショナルの条件――いかに成果をあげ、成長するか (はじめて読むドラッカー (自己実現編))

時間管理にタスクシュートを利用している理由

何にどのくらいの時間を使っているのかという時間の記録とともに、そうやって記録したデータを使って次の時間管理にシームレスにフィードバックできる、という点が大きいです。
もともとは、Rebuild.fm で typester さんがタスクシュートを実施してうまくいっているという話を聞いたのがきっかけでした。

ここでは、確か以下の本も紹介されていて、著者の佐々木さん、大橋さんは「スピードハックス」でもよく参考にさせて頂いていたので、素直に導入してみようという気になりました。

なぜ、仕事が予定どおりに終わらないのか? ~「時間ない病」の特効薬!タスクシュート時間術

なぜ、仕事が予定どおりに終わらないのか? ~「時間ない病」の特効薬!タスクシュート時間術

タスクシュートとは

まぁこのあたりにも書いてあるんですが。

本から引用しますと、以下のような方法による時間管理になります。時間管理というか、一日のシミュレーションと記録をいっぺんに実行するという方法と言った方が良いかもしれない。

タスクシュート式の基本的なルールは、次のとおりです。

  • 「本日1日分の仕事」を1シートで管理する
  • 「これからやる仕事のリスト」と「ここまでにやった仕事のリスト」を一元管理する
  • 「1分以上時間のかかること」はすべて管理する
  • すべての仕事の「見積もり時間」を出しておく
  • 「本日1日分の仕事」がすべて終わったら何時になるかの予測を自動算出することで、常に仕事の終わる時間(または就寝時刻)をリアルタイムに把握する

これまでのぼくは、ToggleToodledo なんかを使って時間管理をしていたのですが、1 年半くらい前からタスクシュートのスキームを使用していまして、これが今までで一番長く使っている時間管理のスキームになっています。

タスクシュートの方法については、大きく分けて

Taskuma --TaskChute for iPhone

Taskuma --TaskChute for iPhone

  • Sayaka Tomi
  • 仕事効率化
  • ¥3,600

の 3 つがあります。
ぼくは、iPhone アプリである「たすくま」を使用して、TaskChute を行っています。

で、実施してどうなん?

色々と明らかになることが多くて、面白いです。例えばぼくの場合、以下のような時間がかかります。

  • RSS のフィードチェックに 33 分
  • Blog を 1 エントリ書くのに 52 分
  • 朝の歯磨きに 7 分
  • 休日の昼食を取るのに 16 分
  • 休日の夕食を作るのに 46 分

他にも、NARUTO を 1 話読むのに 3 分かかる一方で、銀魂を 1 話読むのに 6 分かかります。

P.F.ドラッガーは、

空間感覚は、誰でも保てる。だがたとえ電気の明かりがあっても、何時間も密閉された部屋に置かれると、ほとんどの人が時間間隔を失う。経過した時間を過大に評価したり、過少に評価したりする。

とも言っていますし、コンピュータ業界にも「推測するな、計測せよ」という格言もありますが、これは本当にその通りで、フィードチェックに 30 分かかっているとは思っていなかったし、夕食を作るのは 30 分くらいだと自分では感じていました。人間の時間感覚なんて信じられないと思った方が良いでしょう。

そういうわけで、ルーティンについては時間が凡そ見積れるようになっているんですが、残業はなかなか減らない。「知的労働」とはドラッガーが言っていた言葉ですが、この種の労働については時間がなかなか見積もれない。
過去やったことが無いようなタスクが表れて、なかなかそこに対する見積もりが適正にならない (だいたい過少になる)。うまく残業なしに回している方もいるので、これは必ずしも解決不能な問題ではなく、個人としてのスキル不足なのだと思っています。
そういうわけで、このあたりは 2018 年になってもまだまだ課題だと思っています。

Spring徹底入門

年末年始に Spring 徹底入門をようやく読めた。

Java の FW といえば、Spring を知っておかないともうダメみたいな雰囲気を感じはじめており、以前に買ったままずっと積読してしまっておりました。

Spring徹底入門 Spring FrameworkによるJavaアプリケーション開発

Spring徹底入門 Spring FrameworkによるJavaアプリケーション開発

Spring は、Spring MVCSpring Batch を 3 年前くらいに使っていたようなのだけれど、当時のエントリを確認するとまだ Spring が 3.1 だった頃のようだった。 今確認すると Spring Framework は既にメジャーバージョンが 5 に到達しており、隔世の感がある。

そういう時代錯誤の状況なのでなんとかせねばならんし、そもそも Spring Boot って何ものじゃい、みたいな老害っぽい状況でもあったので、なんとか時代にキャッチアップしようと思います。

Spring についての感想

Spring については、あんまり大きく変わってないんだなというのが一番の感想でした。当たり前ですが、DI、AOP まわり(Spring Core まわり)は Spring 3 の頃の知識がほぼ使える。Spring Test も大きくは変わっていないように見えました。

一方で、container configuration の方は、当時使っていなかっただけなのか、そもそもそういう機能が無かったのか覚えていないんだけれど、設定を Java で書けるというのは非常に便利なように感じました。 XML で表現できない設定を表現できるというのは良いし、Lint をかけられるし、型の安全性も担保できるし、補完もコードと同様のものが効く。XML は悪くないんだけど、何より書くのに時間がかかるから、Java で設定を記述できる世界感なのはすごく良かった。

FW 自体も疎結合になっているのはすごく柔軟そうで、ViewResolver 等、逐一 Interface が切られているので拡張もずっとやり易そうだと思いました。 Spring Security についても、MVC との統合の方法が分かりやすくて、これだったら導入しても良さそう、という感覚を得るのにすごくよかった。

書籍についての感想

徹底入門シリーズにも個人的には当たり外れはあるんですが、これは当たり。買ってすごく良かったです。

「ここは知っておかないといけないよね」という部分は押さえつつ、ThymeleafMyBatis との統合方法といった Spring という枠に留まらない記載、そして Spring Boot や Spring Security 等の関連プロジェクト等、取り上げる箇所の選定がさすが NTT DATA やなという内容。

Spring に関しては公式のドキュメントが異常に充実していて、基本的にはそこを読めば全貌が把握できるといえばできるんですが、 全体がどのようにできていて、それをどう使っていくのかの概要を俯瞰するためには非常に有用な書籍だったと思います。

あとは公式ドキュメントに目を通していきたいとおもいます。

IntelliJ IDEA ハンズオン

Java については、いままでずっと中途半端にやってきたもので、Eclipse で良いんじゃねということで Eclipse でしか書いてなかった。

(大学の頃は、JDEE を使って Emacs で書いていた(使えという指示だった気がする)けどさすがに苦行だった)

現代の Java の IDE は IntelliJ IDEA を使うのが良いというのは割と共通認識ぽいし、まわりでも IntelliJ を使う人が多い。 このような状況から、ぼくもそろそろ乗り換えないとマズいんだろうなぁと思う節もあり、最近出版されて Twitter でも良くみかけた IntelliJ IDEA ハンズオンの本をこの年始に読んでみました。

IntelliJ IDEAハンズオン――基本操作からプロジェクト管理までマスター

IntelliJ IDEAハンズオン――基本操作からプロジェクト管理までマスター

内容としては、本当に IntelliJ IDEA という IDE そのものの機能にスコープを当てた内容であって、そういう意味では Eclipse の以下の本と同列にある本だと思います。

JavaデベロッパーのためのEclipse完全攻略[4.x対応版]

JavaデベロッパーのためのEclipse完全攻略[4.x対応版]

総じて、そんなに覚えることは多くないんだという印象。IntelliJ 自体が空気を読んでくれる (Intention Action: いわゆる DWIM) こともあり、それに任せていれば、最初の壁は突破できるんだろうなぁと思いました。

公式サイトやヘルプでいくらでも必要な情報が入手できる中であってもこの手の本が有用なのは、「最初に」必要な情報を分かりやすく説明してくれることにあると思っています *1。 書籍の中にも書いてあるように、IntelliJ は必ずしも初心者向きの IDE ではないので、ぼく自身、実際、最初に DL して使ってみたときはその使い方に戸惑いました。 どこから入っていけば熟達していくのかな、という迷いもあって、なかなか本格的に導入しようとできていなかったので、その意味でも買っただけの価値はあったのかなぁと思っています。

*1:そういう意味では、Maven のドキュメントはなんとかした方が良いと思う

2017年の締めにチャーシューを作る

ずっと欲しかったのだけれど、ようやく圧力鍋を買った。 骨まで食べれる煮魚とか、徹底的にやわらかい肉の煮込みだとか、そういうものを料理したいという欲求が著しく高くなる時期(意識が高い時期)があったのだけれど、鍋に 10,000 円か〜〜という価値感がネックになり、なかなか手が出せなかった。 しかし、プライベートで色々あった結果としてお祝いにカタログを頂き、そのカタログに圧力鍋が入っていたので、迷わず GET と相成りました。

ちなみにだけれど、我が家でカタログでゲットしているものとしてはコーヒーメーカー、出刃包丁と料理器具に偏っており、料理に飢えている雰囲気がある。

チャーシューつくるよ

もともと大きな肉ブロックを相手にした料理というのはずっとチャレンジしたい課題だったのだけれど、従来から以下のような課題があった。

  1. 自宅近くに肉のブロックを売っているような店がない
  2. 大きな肉のブロックを相手にできる鍋がない

前者については、先日秘密裏に実施した引越しにより近隣にある業務スーパーに容易にいける環境が整い解決、後者についても今回敢えて 5.5L という大き目の鍋を購入したことにより解決した。

というわけで、チャーシューである。

                __________
                       /ハ
                   |.  ヘ⌒ヽフ   |
                   |  (・ω・ ).   |
                   |   U U l   |
                   |  .ヾ.,____,ノ  |
                   |         |
                   -------------
                    () () () () () ()      _
    ∧,,∧  チャーシュー  ===============/  \
   (`・ω・´)  つくるよ!  |            ① |
   m9   o           ======================
    しー-J            ■          ■

チャーシューとは何か。豚肉を焼いた料理であるとされるが、日本においては醤肉を指すことが多い。豚肉を醤油ベースのスープで煮込むので、焼き料理というよりは煮込み料理の色合いが強い。 今回は激安(100g で 80 円くらいだったと思う)の豚肉の肩ロースを 1.2 kg くらい買ってきたので、こいつを料理します。

まずは肉をフォークで刺しまくる。料理中は、この行為についてはあまり考えておらず、人を刺したらこんな感触なのかな〜〜〜やわらかいな〜〜〜という年末年始とはおよそ相応しくない感想を抱いていたが、肉が柔らかくなるらしい。 その上で、おろしたニンニクを擦りつける。

先の通り、チャーシューは実質的に煮込料理だと思うのだけれど、とはいえ、肉を焼いた際の香ばしさというのは食欲をそそるし、焼き色というのも視覚に訴える。ということで、まずは焼いた。 偉そうに書いてるけど、このへんは全部に書いてあったので、クックパッドを見てくれ。

フライパンで表面に焼き色をつけた後、圧力鍋に放り込んで砂糖、味醂、醤油あたりを投入する。チューブの生姜を大量に入れたけど、あまり効かなかった。

f:id:kiririmode:20171230143409j:plain

f:id:kiririmode:20171230144332j:plain

それから、圧力鍋で 30 分ほど調理して、30 分放置する。放置した後に取り出したら、すでにチャーシューっぽい威厳を出すようになっていた。

f:id:kiririmode:20171230174525j:plain

でも、このままだとあまり肉全体に味が回っていない。圧力鍋とはいえ、それは望み過ぎというものなのかも。 この鍋にチャーシューを戻し、茹で卵も一緒に叩き込む。茹で卵は煮卵の幼生であり、この中でゆっくり成長させることで、翌日に美しい煮卵として羽化することになる。

感想

かなりおいしいくて全体として大変よかったのだけれど、残念だったのは、肉があまり良くないからか、食感がパサパサしていた。 このあたりは、チャーシュー丼化させ、油分をマヨネーズで補わせることで暫定的には解決される。

今後の課題

うまい肉をやすく買う必要がある

git-grep を Emacs で呼び出す helm-git-grep

git grep を Emacs から起動できたら捗るだろうなぁと思い立ってちょっと調べてみたら、そのものズバリの拡張である helm-git-grep が存在していました。

これを導入すると、Emacs から git grep を呼び出せるようになり、

  • helm インタフェースで使用し、インクリメンタルに該当箇所を検索
  • 当然、その結果ファイル・行に瞬時に移動する

なんてことができるようになります。 なんでおれは、これを調べていなかったんや…というレベル。

f:id:kiririmode:20171224074145p:plain

helm-git-grep 導入

ぼくの elisp 管理は現在も Cask なので、Cask ファイルに helm-git-grep を以下のように宣言た後、コマンドラインから cask を実行します。

(depends-on "helm-git-grep")

これで load-pathhelm-git-grep.el が組込まれるので、あとはこのファイル用の設定を書いていけば良いでしょう。

(require 'helm-git-grep)
(global-set-key (kbd "C-c g") 'helm-git-grep)
;; Invoke `helm-git-grep' from isearch.
(define-key isearch-mode-map (kbd "C-c g") 'helm-git-grep-from-isearch)
;; Invoke `helm-git-grep' from other helm.
(eval-after-load 'helm
  '(define-key helm-map (kbd "C-c g") 'helm-git-grep-from-helm))

wgrep.el との連携

Emacs で grep といえば、wgrep.el を使いたくなるところです。

wgrep.el は、Emacs で行なった grep の結果一覧バッファを直接編集することでその編集結果を実ファイル側に反映できるという elisp なのですが、helm-git-grep はこの wgrep.el との連携が可能です。

helm-git-grep の結果一覧画面から、C-x C-s を押すと、helm-git-grep-run-save-buffer が呼び出され *hggrep バッファにその内容が保存されます。あとは、(wgrep.el を使用できる設定にしていれば) e を押下すれば wgrep の編集を有効化できるようになります。ホントに便利。

終わり行く2017年にgrepを

みんな大好き grep についてですが、かなり機能が豊富な一方でなかなかそれがまとまっていないこともあるのと、自分自身、結構細かな Tips を忘れたりするので、ここで簡単にまとめてみたいと思います。

OR 検索

後述する拡張正規表現でも可能といえば可能ですが、サクっとできるのは -e (--regexp) を複数与えることです。

$ grep -e abc -e xyz hoge.txt
abcdefg
vwxyz

この OR 条件がときどき変わって、その都度シェルスクリプトを変えたくないという場合、これらの条件は外出しすることも検討して良いでしょう。外出ししたファイルには、条件を 1 行 1 条件で並べます。 このファイルを -f (--file=filename) で与えれば、grep はそれらを OR 条件として解釈します。

$ cat cond.dat
abc
xyz

$ grep -f cond.dat hoge.txt
abcdefg
vwxyz

行全体ではなくて、特定のパターンに合致する部分だけ抽出して表示する

たとえば テキストファイルの中の IP アドレスだけ抜き出したいときとか。

具体例として、こんなゴミみたいなファイルがあるとします。 この中から IP アドレスだけ出してくれというゴミみたいな依頼がある場合があり、このような作業で時間を浪費するには人生は短すぎます。

$ cat ipaddr.txt
jdisa;eoiuraajf
dsaea
dfa;eiue127.0.0.1da324
dsai;255.255.255.240dsa;ewapa3242
324632hogesada192.168.3.0;safdsa
0.0.0.0dsaafs10.252525.0.0.dsadfsa

こういうときには、-o (--only-matching) オプションを使います。合致したところだけが標準出力に出力されるので、「検索」ではなく「抽出」に使用できます。

ちなみに、以下の例では拡張正規表現 (-E) を使っています。拡張正規表現については、別段 grep 限定の話でもないので、雰囲気で感じてもらえれば良いと思います。

$ grep -oE "([0-9]{1,3}\.){3}[0-9]{1,3}" ipaddr.txt
127.0.0.1
255.255.255.240
192.168.3.0
0.0.0.0

ちなみに、これを利用すると以下のようなことも可能になります。

grep さん、そのファイルはバイナリではなくテキストなんやで…

バイナリファイルに対して grep をかけても、grep さんは 「マッチしたよ」という情報しか教えてくれません。

$ grep . app/WEB-INF/lib/jackson-dataformat-yaml-2.8.6.jar
Binary file app/WEB-INF/lib/jackson-dataformat-yaml-2.8.6.jar matches

ホントにバイナリなら良いんですが、ときどきテキストファイルであるにも関わらず、バイナリと判定してしまうケースがあります。 この場合、テキストファイルであると、明示的に教えてあげると良いでしょう。-a (--text) オプションで指定できます。

今回のファイルは普通にバイナリファイルなので、ちょっとおかしくなっちゃいましたが。

$ grep -a . app/WEB-INF/lib/jackson-dataformat-yaml-2.8.6.jar | head -3
_tjr @&&h4ci8hv%PcON miwdMW8@ݤ- Hl&?JDi&J#rdhu߿.gQK>
\4Mh̉FMcpݎzI<b_m.k[cj49%8"bɊ<ZgBt9WWw_r*]=A8TPj"1kv''
tm"hSwa]׳/1oJ
             

リアルタイムに tail -fgrep したいんだけど

grep はバッファリングした後出力するのがデフォルトなので、表示するまでには若干の時間がかかります。 これをリアルタイムに行うには、--line-buffered を付与しましょう。

$ tail -f access.log | grep --line-buffered ERROR

合致する行の前後のn行を表示する

システム運用やエラー調査でよく使ったりします。特定のエラーログの直前に出力されたログの傾向から大まかな対応方針が得られることが多々あります。 前の行を num 行表示するときは -B num (--before-context=num)です。

$ grep -iB2 QRS hoge.txt
abcdefg
hijklmn
opqrstu
--
ABCDEFG
HIJKLMN
OPQRSTU

後の行を num 行表示するためには -A num (--after-context=num)、前後の num 行を表示するためには -C num (--context=num) が使用できます。 ちなみに、上記のとおり「複数箇所」がヒットする場合の区切りには -- が使用されますが、これは --group-separator オプションで変更が可能です。

 grep -i -A2 --group-separator='=====' QRS hoge.txt
opqrstu
vwxyz
ABCDEFG
=====
OPQRSTU
VWXYZ

grep に時間をかけたくない

1 件でも検索結果に合致すれば grep を打ち切りたいときがあります。 しかし、特に command | grep ... というようにパイプの後段に grep を配置する場合、command の実行が遅いと grep も終わりません。 こういうときは、合致する行が num 行になったら処理を打ち切るという -m (--max-count=num) を使います。

このあたりについては、以下のエントリが詳しいです。

netstat | grep が遅いなぁと思ったときにはgrep -m - As a Futurist...

word 検索をしたい

要するに、hoge を検索するとき、abc hoge fuga にはヒットさせたいけど、abchogefuga にはヒットさせたくない、という要件。 これは、-w (--word-regexp) オプションを使います。

どこかで書いたと思ったら、ここだった。

大文字と小文字を区別しない

このあたりは知名度が高いオプションですね。-i あるいは --ignore-case のオプション付与で実現できます。いわゆる case-insensitive な検索をしたいときに使います。

$ grep -i FgH a.txt
defghijkgrep 

合致「する」行数を数える

合致した行ではなく、合致した行数だけ知りたいときには、-c あるいは --count を使います。なんかシェルのワンライナーを作るときとか、使ったりするときもあるのではないでしょうか。

$ grep -ic FgH a.txt
1

合致「しない」行を抽出する

-v あるいは --invert-matchオプションを使います。 ps -ef | grep -v grep とかのパターンでよく見かけます。もちろん、-c と組み合わせれば、合致しない行数も知ることができます。

$ grep -icv FgH a.txt
3

合致する行が「ある」ファイル名を知る

-l あるいは --files-with-matches オプションを使うことで、ファイル名のみを出力することができます。 たとえば、/etc/pam.d から password を含むファイル名を一覧するときは、以下のように使えば良いです。

$ find /etc/pam.d -type f | xargs grep -l password | head -3
/etc/pam.d/other
/etc/pam.d/passwd
/etc/pam.d/su

合致する行が「ない」ファイル名を知る

-L あるいは --files-without-match オプションを使えば良いでしょう。

$ find /etc/pam.d -type f | xargs grep -L password
/etc/pam.d/config-util
/etc/pam.d/runuser
/etc/pam.d/runuser-l

ディレクトリを grep 単体で再帰検索する

上記では、/etc/pam.d 配下のファイルを find を使って取得していますが、grep 単独でもこの再帰検索をサポートします。 多くの場合、これは -r オプション (--recursive) で実現しますが、実はこれ、--directories=recurse でも実現できます。

$ grep -rl pam_unix /etc/pam.d
/etc/pam.d/smartcard-auth
/etc/pam.d/system-auth
/etc/pam.d/fingerprint-auth
/etc/pam.d/runuser
/etc/pam.d/password-auth
$ grep -c --directories=recurse password /etc/pam.d | head -3
/etc/pam.d/other:1
/etc/pam.d/passwd:2
/etc/pam.d/su:1

また、-r ではシンボリックリンクを追ってくれませんが、-R (--dereference-recursive) を使うと、シンボリックリンクを追ってくれるようになります。使ったことないけどな。

この再帰検索において、対象から除外したいファイルやディレクトリも指定できます。ファイルの場合は --exclude=glob、ディレクトリの場合は --exclude-dir=glob という形式です。

たとえばここでは、auth で終わるファイルは除外しましょう。

$ grep -rl pam_unix /etc/pam.d
/etc/pam.d/smartcard-auth
/etc/pam.d/system-auth
/etc/pam.d/fingerprint-auth
/etc/pam.d/runuser
/etc/pam.d/password-auth

$ grep -rl pam_unix --exclude '*auth' /etc/pam.d
/etc/pam.d/runuser

食器洗浄器のために自力で分岐水栓をつける

12 月になって引越しをしていたんですが、元々の家はシステムキッチンに食器洗浄器がついていたのが、引越し先には付いていない。 こういうときに何が困るのかというと、食器洗浄器に引き込む水を取水するための栓がないことでした。

引越し先の蛇口はタカギ製の JG-1230 で、この蛇口について問合せてみると、分岐水栓 CB-STKB6 というのを噛ませれば良いらしい。 Amazon で 10,000 円くらいで購入できる。

パナソニック(Panasonic) 分岐水栓 CB-STKB6

パナソニック(Panasonic) 分岐水栓 CB-STKB6

というわけで、今日は深夜 0 時くらいから 3 時くらいまで、ずっとこれを蛇口に取り付けるために四苦八苦してました。 特に苦労したのが、水栓を締めるところと、シングルレバーをとるところ。あとは結構なんとかなる範囲だった。 業者に頼んだら万を超えるかんじになりそうだったので、自分たちでできたのはそこそこ大きい。

水栓を止める

分岐水栓の説明書どおり、まずは作業中の水漏れを防止するために、水栓を止める。

前提として水栓は、住居単位の水栓があり、そして、キッチンや洗面所単位の水栓があります。今回のキッチンは、シンクの下の棚の中に水栓がありましたので、これを強引に閉めます。冷水用と温水用があるので、それぞれ閉める。

おそらくキッチンが完成してから一度も閉められたことがなかったようで、相当固かったけどパワーで閉めることができた。これにより、キッチンの蛇口をひねっても水もお湯もでなくなった。

シングルレバーを取る

シングルレバーというのはこういうヤツ。

多くの場合、シングルレバーを取るための専用の六角ネジとかあることが多いんですが、JG-1230 にはない。なんかマジでなにもない。 で、どうやってシングルレバーを取れば良いのかというと、パワーで取る。パワー。パワーを一心に込めて取る。パワー万能じゃね??とか思いながら取る。 じつはここが今回一番時間がかかったところで、フルパワーをかけても抜けない。心折れかけていて、実はぼく自身は心が折れてて、業者に頼もうぜとか言ってたんだけど、妻が抜いた。立場がなかった。

あとは

あとは、分岐水栓の説明書のとおりにやったらなんとかなった。蛇口の中にいろいろ埋まっているんだなぁというのがここでの乾燥。 水道まわりは間違ってしまうと大惨事になるので二の足を踏むかんじだったのだけれど、インターネットの記事や Youtube 動画を含め、見ることができるところにノウハウが公開されるようになり、専門的な知識が一般的な知識になってきたようなきがする。

インターネットに接続できないオフライン環境でPython製ツールをインストールしたい

ときに、インターネットに接続できない環境というのが存在します。 しかし、今回はこういう環境において Python 製のツールを使いたいという状況が発生しました。

今日びのパッケージマネージャというものはパッケージリポジトリからダウンロードするのが一般的で、Python についても多くの場合、PyPI からパッケージがダウンロード・インストールされる構成になります。 このため、べき論で言えば、オフライン環境においても内部的にパッケージリポジトリを構築し、pip --install-url でも使ってそのリポジトリを指定すれば良い。他の人も使えてハッピーですね。

一方、今回利用できるのはインターネット接続できない Windows 端末のみという状況ではてどうすれば良いのだという状況でしたので、かなりローテクですが以下のような内容を使いました。

  • インターネットに接続できる端末で依存モジュールをダウンロード & 圧縮
$ pip download --dest modules --requirement requirements.txt
$ tar czvf modules.tgz modules

requirements.txt には以下のようにインストールしたいモジュールを記載しています。

$ cat requirements.txt
javasphinx == 0.9.15
sphinx == 1.6.5
  • 圧縮した依存モジュール群をオフライン端末になんとかして転送
  • オフライン端末で依存モジュールをインストール
$ pip install --no-index --find-links modules --requirement requirements.txt

--no-index でモジュールを探すときに PyPI を見に行かないようにしており、--find-links で依存モジュールが存在している場所を示しています。

Cookieのpath属性に対するブラウザ毎の挙動の違い

ブラウザ毎の Cookie の path に対する挙動の違いによって、検証しているアプリに色々とバグっぽい挙動が出てきたので、あらためて Cookie における挙動をまとめてみます。

検証内容

  • セットするCookie の path 属性に /path、あるいは /path/ を指定した Web アプリを作成
  • 個々のブラウザで、次のパスにアクセスし、Cookie が送信されるかどうかを確認
    • /path
    • /patha
    • /path/
    • /path/a

このへんのアプリだったら Perl とかでサクっと作った方が早いので、PSGI アプリとして実装しました。 だいたい以下のようなかんじです。

#!/usr/bin/env perl
use Plack::Builder;
use Plack::Request;
use Plack::Middleware::Session::Cookie;

my $app = sub {
    my $env = shift;

    my $req = Plack::Request->new($env);
    my $cookies = $req->cookies;
    my $res = $req->new_response(200);

    $res->body(%{$cookies}? 'cookie sent' : 'no cookie');
    $res->finalize;
};

builder {
    enable 'Session',
        state => Plack::Session::State::Cookie->new(path => '/path'); 
        # path は '/path' と '/path/' の双方を試した
    $app;
}

まずは結果を

○ が「Cookie が送信された」、- が「Cookie は送信されなかった」ことを表現しています。 挙動が大きく違っていたのは IE 11 だったんですが、家に Windows がないので、調べることができませんでした。

後述しますが、Chrome と Safari は、RFC 6265 に沿っています。 FIrefox もほぼ沿っているんですが、Cookie の Path の末尾が / の場合に、RFC 6265 と挙動が異なるように見えます。

path=/path

ブラウザ /path /patha /path/ /path/a
Chrome 61.0.3163.100 -
Firefox 56.0.2 -
Safari 11.0 (12604.1.38.1.7) -

path=/path/

ブラウザ /path /patha /path/ /path/a
Chrome 61.0.3163.100 - -
Firefox 56.0.2 -
Safari 11.0 (12604.1.38.1.7) - -

RFC はどうなのか

Cookie について定義しているのは RFC 6265 ですが、この 5.1.4. Paths and Path-Match に、 path をどのようにしてマッチさせるべきなのかの定義があります。

詳細は見て頂ければ良いのですが、まず最初に、cookie の path と比較する対象として、uri-path を定義します。 これは、リクエスト URI のうち、ホスト名の後の / からクエリパラメータの ? より前の最後の / の前までと url-path とされています。 - /hoge/fuga/piyo なら /hoge/fuga - /hoge なら /

これに対し、cookie の path が以下のどれかを満たすなら、そのときに cookie が送出されます。 読めばなるほどなぁと分かるんですが、これを日本語で簡潔に説明すると難しいので、読んで頂いた方が誤解がないと思います。

   o  The cookie-path and the request-path are identical.

   o  The cookie-path is a prefix of the request-path, and the last
      character of the cookie-path is %x2F ("/").

   o  The cookie-path is a prefix of the request-path, and the first
      character of the request-path that is not included in the cookie-
      path is a %x2F ("/") character.

参考文献