理系学生日記

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

忍者TOOLS

リダイレクト時の遷移挙動がおかしかったらリバプロ設定を疑ってもいい

リバースプロキシ経由でアクセスしたときにリダイレクトでおかしくなるケースって、だいたいリバプロの設定と社会が悪いです。

リバースプロキシを導入する理由というのは多々あります。セキュリティだったらい、SSL オフロードであったり、負荷分散、圧縮もそう。

トラフィックを受けつけるポイントでもあるので、それを利用した様々な処理を埋め込むこともできます。認証や認可もそう。

それでですね、こういうリバプロを経由したときに、ちょっとしたところで「あれ」って挙動をするときがあります。例えば、

  • リダイレクトしたときにエラーになるんだけど
  • 一部の画面遷移で 404 になるんだけど

といった場合。こういう場合は、リバプロ設定がおかしいことが多いです。

リバースプロキシって、基本的にはバックエンドのサーバを隠して「代理」(Proxy) になることが前提になります。そういう意味で、リバプロは必死にバックエンドのサーバを隠蔽しなければなりませんし、ネットワーク設計もそれが前提になることが多い。

例えば外部からバックエンドへ直接繋がるトラフィックは遮断されますし、バックエンドサーバの名前解決は外部からできなくても良いでしょう。

一方で、バックエンドから外部に、バックエンド自身の情報を出力しちゃうケースがあります。バックエンドサーバが生成する HTTP ヘッダとかですね。

  • Location ヘッダ
  • Content-Location ヘッダ
  • Cookie

バックエンドは、普通、リバプロの情報の存在を前提に実装しません(X-Forwarded-For とかは見ることはある)し、自身が「バックエンド」であり自身の情報を「隠さないといけない」ということは意識しないのではないでしょうか。 だからこそ、バックエンドサーバの返却するリダイレクトレスポンスの Location ヘッダが バックエンドサーバのホスト名/IPアドレスになっている のは当然で、これを外部から隠すのは、リバプロの責務だとぼくは思っています。

例えば、Apache の mod_proxy では、ProxyPassReverseディレクティブ がこのあたりをやってくれていて、例えば以下の設定だと、 http://backend.example.com/quux へのリダイレクトレスポンスは、リバプロが http://example.com/mirror/foo/quux へのリダイレクトに「書き換え」てくれます。

ProxyPassReverse  "/mirror/foo/" "http://backend.example.com/"

逆に、これを設定しない場合、外部へ返却されるリダイレクトレスポンスがバックエンド宛になってしまい、ブラウザはそのホスト名が引けなかったり、ネットワーク疎通できなかったりして、404 になることが多いです。 特に、PRG パターンとかで実装されていた WebApp だと、特定のページ遷移のみでこれが起こったりしますし、レスポンスヘッダを見てもアプリ観点では問題がないので、原因切り分けに悩むケースもあったりします。

なので、リダイレクトが関わるケースで挙動がおかしくなるのであればリバプロ設定を疑えっていうのは、なんか法則みたいなかんじで覚えておいても良いかもしれないですね。

参考文献

我が家の猫が亡くなりました

今日の未明に、うちの愛猫が亡くなりました。横になって、口でしか呼吸ができなくなって、その呼吸の間隔もだんだんと長くなっていって、いつしか呼吸をしなくなって、眠るように息を引き取りました。

妻が元々飼ってた猫です。アメリカン・ショートヘアのシルバータビー。すごくかわいい猫でした。

仕事から帰ると猛ダッシュで玄関前まで迎えに来てくれて「水が飲みたい!」とねだったり、気分がのらないときはぼくたちがどれだけ遊んでやろうとしても無視したり、それでいて寂しくなったときはぼくたちの足に頬を擦りつけたり、猫って自由だなーというのを地でいくような。 もう年齢的には大人なんですけど、体はすごく小さくて、引越し業者の人も「仔猫ですか!」と言ってたりして。2 kg くらいしかない小さな体で、猫じゃらしの玩具をずっと追いかけていたりしました。

最初は、我が家に赤ちゃんが産まれたことによるストレスかなと思っていたんですが、ぜんぜんキャットフードを食べなくなって、次第に水も飲まなくなっていきました。 痩せていく体が気になって、病院でレントゲンを撮ったときにはもう大きな腫瘍がおなかの中にできていて、お医者さんからは、こんな小さい体だと、手術にも抗癌剤治療にも耐えられないんじゃないかと言われました。他の病院でステロイド投与をしてもらって、10 % の奇跡にかけたんですがそれも芳しくなく。 自分からはもうご版も食べられず、水も飲めなくなっていき、数時間おきにシリンジで強制的に給餌させるといったことをしていました。

それでも、一日、一日と弱っていく猫。歩くのにもフラフラになって、それでもぼくたちの後をついて来てくれました。二ヶ月前は超スピードで走り回っていたのが嘘のようなゆっくりとしたスピードで。

今日家に帰ったのは 24:00 に近くなっていて、いつものようにうずくまっていました。それからちょっと立ち上がって、ニャーって鳴いたみたいです。ヨロヨロと歩いて、横になって、鼻呼吸が口呼吸になりました。 ちょっとだけ足を動かしながら、呼吸の間隔が長くなって、あれ、もう呼吸してないよ?っていう感じで、亡くなりました。

一晩して、起きて、近所の火葬場に電話しました。これまでの想い出をしたためた手紙を目元に置いて、ブーケの花で小さな体を飾り、最後は食べられなかったたくさんのキャットフードを山盛りにして、火葬してもらいました。

家に帰ったら、猫が爪とぎをしてボロボロになったソファとか、やっぱり爪とぎをしてボロボロになったオフィスチェアとか、今まで猫が使っていた皿とか、トイレとか猫砂とか、家にこんなに猫の想い出が詰まっているんだなと思って、今日何度目だろうって思いながらみんなで泣きました。

なんだろ、心の一部が欠けたような、そういう寂しさがあります。この欠けた部分はどうやって埋まっていくんだろと考えると、やっぱり時間なのかなと思います。欠けて尖った部分は、きっとすぐには埋まらないんだろうけど、ちょっとずつ時間とともに角が取れていって、丸くなっていって、 ときどき猫のことを思い出して「あー寂しいなぁ」というくらいに振り返られるようになれば良いなと思います。

登られることのなかったねこタワーは、いまはポンデライオンの住処になっています。 f:id:kiririmode:20180212185731j:plain

困ったときのパケットキャプチャ+curl

リバースプロキシから渡ってきた HTTP リクエストで WebApp がエラーになるという状況が発生しました。 状況としては、

  • リバプロにはぼくたちはアクセスできないし、そのリバプロにリクエストを送ることもできない。
  • リバプロから WebApp 用 FW に何らかの HTTP ヘッダを連携することになっているが、果たして送られているのかが不明

という状況。正確に何が起こっているのか分からない状況で鍵になるのは事象の再現であり、このときに採った戦略はパケットキャプチャでリクエスト内容を確認し、それを curl で再現することでした。

容易にサーバ上にツールを導入できる状況でもなかったので、tcpdump が使えたことは本当に有り難かったです。また、自分の端末にもソフトウェアを簡単に導入できない環境ではあったものの、WireShark が入っていたのも良かった。 この 2 つが揃っていれば、あとやることは多くない。

tcpdump

WireShark が使えてトラフィック量も多くないことは分かっていたので、フィルタすることなく、全パケットを取得するようにした。フィルタ自体は WireShark でやれば良いだろという雑な考え方。 tcpdump でプロミスキャスモードにするときは、一般にはログが自動的に記録されてしまうので、これってポリシ的にだいじょうぶ??という点は気を配った。

ぼくが tcpdump を使うときは、-s0 は必ず指定するようにしていて、昔これを付けていなかったばっかりに、各パケットの切り詰められた結果しかキャプチャできていなかった辛い思いをもうしたくないからです。

# tcpdump -i <interface> -n -s0 -w /tmp/capture-$(date +%Y%m%d-%H%M%S).pcap

あとは、ここで取得した pcap ファイルを WireShark にかければ良い。

リクエストの再現

WireShark で適切なフィルタをかけることで、エラーを発生させたリクエストは確認できるので、あとはそのリクエストを curl あたりで再生すれば再現できる。

まがりなりにもストートレスかつテキストなプロトコルである HTTP だとこのあたりが楽で良いなと思います。HTTP 2.0 だとどうなるんでしょう。

logbackの設定を動的に変更する

そういえば昔、Java のアプリでログレベルを動的に変更したいんじゃ、という要望がありました。 当時、結局その要望は諸事情によって受けられなかったんだけど、Logback でそういうの簡単にできる方法があるらしい。主な方法としては、以下の 2 つ。

  • logback.xml を監視する
  • logback の提供する JMX を使用する

logback.xml の定期監視

logback には、logback.xml の修正結果を自動的にリロードしてくれる機能がある。デフォルトでは OFF なんだけど、設定ファイルの root 要素である configurationscan 要素を明示的に true に指定することで有効化される。

<configuration scan="true"> 
  ... 
</configuration> 

この設定によって別スレッドが立ち上がり、定期監視が行われる。ソースを見る限り、「変更」の判断は ConfigurationWatchList の以下のメソッドで行われているようで、基本的には lastModified で変更検知される。

    public boolean changeDetected() {
        int len = this.fileWatchList.size();

        for(int i = 0; i < len; ++i) {
            long lastModified = (Long)this.lastModifiedList.get(i);
            File file = (File)this.fileWatchList.get(i);
            if (lastModified != file.lastModified()) {
                return true;
            }
        }

        return false;
    }

アプリケーションが起動しているときにログ設定を変えたいニーズというのは、以下のような場合だと思うけど、変更後の logback.xml で変更前の logback.xml を上書けば良いということになる。

  • 監視不要だけどアラートが発行されちゃうログエントリを一時的に出力しないようにする
  • 異常動作のトラブルシュートのために、特定のクラスのログを出力するようにする

監視間隔はデフォルトで 1 分。それが遅すぎる、というような場合は、さらにl scanPeriod 要素でその間隔を指定する。以下の例は「秒」単位指定だけど、最小粒度だとミリ秒単位で指定できる。 これほどの粒度でのファイル監視が、いったい何のニーズなのかはよくわからん。

<configuration scan="true" scanPeriod="30 seconds" > 
  ...
</configuration> 

JMX を利用する

logback は、その設定を JMX 経由でも許可している。 実行方法は簡単だけど、Web アプリに載せるときには結構注意しないとメモリリークが発生する。

実行方法は、以下のように jmxConfigurator 要素を設定ファイルに追加するだけ。

<configuration>
  <jmxConfigurator />
  ...
</configuration> 

これにより、jconsole でアプリケーションに接続すると、以下のような UI が立ち上がる。 ここでは ROOT ロガーのログレベルを INFO に変更したけど、その変更は確かにアプリケーション側に反映された。

f:id:kiririmode:20180204171834p:plain

WEB アプリに載せるときの注意というのは、WEB/APP サーバから JMXConfigurator への参照が解除されず GC されないことに明示的に対応が必要なことで、このあたりの問題は Logback だけでなく Log4j2 とかにもあるようだった。Logback については、ServletContextListener#contextDestroyed あたりで、

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.LoggerContext;

public class MyContextListener implements ServletContextListener {

  public void contextDestroyed(ServletContextEvent sce) {
    LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
    lc.stop();
  }

  public void contextInitialized(ServletContextEvent sce) {
  }
}

とかすれば良い模様。

参考文献

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 の編集を有効化できるようになります。ホントに便利。