読者です 読者をやめる 読者になる 読者になる

さんまの梅煮

あずにゃん ごはん

食べたくなったのでさんまの梅煮を作りました。

あずにゃん、さんまの梅煮、炊き込みご飯、大根と豚バラの味噌炒めです。

さんまの梅煮:こんぶつゆ25cc、日本酒25cc、梅干し(塩分22%)2個、水適量(煮込むと蒸発するので量はどうでもよい)を煮立ててから弱火にして、頭と内臓を取ったさんまの筒切りを投入して煮込みます。落し蓋がないと味がうまく行き渡らないと思います。 今回は1時間半くらい煮込んだところ、骨まで柔らかくなりました。微妙に生ぐさいので生姜を入れたほうがいいかも知れません。前回はネギを入れたんですが、塩味をめっちゃ吸ってしまいネギとして食べるのは厳しい感じになりました。というかそもそもこのレシピだと塩が強いので、こんぶつゆの代わりに塩分のないダシを使うのが良いかもしれません。今度やります。

炊き込みご飯:米2合にこんぶつゆ25cc、日本酒25cc、戻したひじき(乾燥時5gくらい)、きざみ揚げ、まいたけを入れて炊きます。結論から言うと味が薄いので、醤油を倍量くらい入れてよいと思います。まいたけは食べるとあまり味がしなくなっているのでご飯にダシが出ているんだと思いますが、よく分からないです。でも動物性の具を使わずにそれなりの味になりそうな気配は見せているので、ベジタリアンの人になんか振る舞うとき便利かもしれません。

大根と豚バラの味噌炒め:大根(いちょう切りで24枚くらい)、ネギ1本、豚バラ100gくらいをこの順で炒め、味噌小さじ2くらいとチューブ生姜適量を日本酒と水で溶いて和えます。豚バラをフライパンの上で放置しておくと自分の脂で勝手に揚げ焼きになり、香ばしくなるということを発見しました。大根は火の通りが遅く、固いと悲しい気持ちになるので忍耐が必要です。

あずにゃんfigmaです。Amazonの履歴によれば6年前に買ったらしいです。当時はけいおんのアニメ2期が放映されていましたが、今もNHKBSで放映されていることが知られています。

あずにゃんとEscapeキー

あずにゃん

新しいMacBookでは、キーボードからEscapeキーがなくなるらしい。

最初にそう聞いたとき、僕はただ、ふぅんと思っただけだった。Escapeキーなんてそんなに使うものでもないし、消えても困るものではないだろう。

「あ、また何か変なこと考えてましたね」

しかし、現実は時として予想外の景色を見せるものだ。今、僕の手元にある新しいMacBookは、女の子がEscapeキーの働きをしている。


「私がそのMacBookのEscapeキーです。よろしくお願いします!」

僕がMacBookを買ったとき、彼女は突然そのように挨拶してきた。腰まで届くかというような黒い髪を頭の両横で結んで垂らしている、小柄な女の子だ。なんだこいつ、と思う間もなく彼女が説明を始めたところによると、Escapeキーがキーボードからなくなる代わりに、付属の女の子がEscapeキーとして働くのだという。そんなことあり得ないだろうと思って彼女を試したのだが、僕が彼女に合図を送ると、MacBookの画面は本当にEscapeキーが押されたかのような振る舞いを見せる。

「分かっていただけましたか?」
「ああ、分かったよ。Escapeキーを押したい時には君に言えばいいんだね?」
「はい、そうです!」

元気よく応える彼女。

「でも、名前がないとちょっと声をかけにくいな。君はなんて言うの?」
「うーん、Escapeキーなのでこれと言って特別な名前はないんですが……。製造コードは『ナカノアズサ』となってます」
「じゃあ『あずにゃん』でいいかな。アズサの『アズ』を、あだ名っぽく可愛くした感じで」
あずにゃん……あずにゃん。いい響きですね。じゃあ改めまして、よろしくお願いします!」

こうして、僕と「あずにゃん」の生活が始まった。


女の子がEscapeキーであると言っても、そもそもEscapeキーはそんなに使うものでもないので、必然的に彼女の仕事は少なくなる。一番よくある出番はゲームを終了するときで、僕はタイトルから終了の項目を選んで終了するのでもいいと思っているのだが、ゲームで一通り遊んでいざ終わろうとすると、それまで横で画面を眺めながら、へぇ、とか、おぉ、とか声を上げていたあずにゃんが、期待に満ちた目で僕を見つめてくる。Escapeじゃなくても終了できるんだけどな、と思いつつも仕方ないかという気持ちでEscapeキーの入力をお願いすると、あずにゃんは待ってましたとばかりにEscapeのキーコードを発行して、ゲームを終了するのである。一瞬だけ画面が暗転してデスクトップに戻った後、あずにゃんはこちらを向いて、どうだ、やってやったぞとばかりに自慢気な笑顔を見せてくるので、まあ、こんな可愛い顔が見られるのであれば次もお願いしようかな、などと僕は考えてしまうのだった。

ゲーム以外でEscapeキーが必要になる場面は、日本語入力の変換を間違えた時が一番多い。変換の文節区切りがうまく認識されなかったり、開こうと思った漢字まで変換されてしまった時などはEscapeキーの出番となるのだが、しばらく一緒に過ごしているとあずにゃんの方も僕のそういった癖を飲み込んでくるようで、あ、またですねと言いたげな顔で促してくる。心の中を見透かされているような気恥ずかしさを覚えつつ、うん、間違えてしまったからEscapeキーお願い、と頼むと、してやったりという表情を隠そうともせず、誇らしげに変換をひらがなまで巻き戻してくれる。そんなあずにゃんを見ていると、なんだか心強い味方ができたような気がして、僕の心が温まるような感覚を覚える。


ある日、あずにゃんとEscapeキーを巡ってケンカをした。発端は僕がVimを使い始めたことで、最初の不慣れなころは何か操作をするたびにEscapeを押してNormalモードまで戻る羽目になり、いちいちあずにゃんに頼んでいた。突然仕事が増えたあずにゃんは嬉しそうで、僕が「あっ」という声を上げるたびに、Escapeを発行したくてたまらないらしく、猫じゃらしを前にした猫のように、うずうずした様子を見せていた。

しかし、僕がVimの操作に習熟していくにつれて、Escapeを使う頻度は減ってきて、代わりに<C-[>を使うことが多くなってきた。別に大きな理由はないのだが、やはりホームポジションから手を動かさずに入力できるし、自分のペースで打てるため、こちらの方が使いやすい。次第に、あずにゃんにEscapeキーを頼む機会も減っていき、あずにゃんはなんだか寂しそうな表情を見せるようになった。

「<C-[>はいいですね、いつも使ってもらえて。私もEscapeキーなんかじゃなくて、Ctrlになればよかったのかな……」

あずにゃんが時折こう呟くのを聞くと少し胸が痛んだが、<C-[>のほうがなんとなくしっくり手に馴染んでしまったこともあり、段々とEscapeキーからは疎遠になっていった。

そしてある日。僕が久しぶりにゲームをしようとすると、なぜか起動しなくなっていた。そんなはずはない、と思って何回か繰り返すと、どうやら起動しないのではなく、起動した瞬間に終了させれられているようだということに気がついた。もしかして、と思ってあずにゃんを見ると、顔をクッションに半分うずめて、怒っているような、泣いているような、どっちつかずの表情を少し見せた後、そっぽを向いてしまった。

あずにゃん、怒ってる?」
「別に、怒ってないです」
「でも、ゲーム……」
「さあ、知らないです。どうせVimの操作を間違えて、設定ファイルを壊したんじゃないんですか」

取り付く島もない。僕はゲームを諦めて、Twitterを眺めることにした。独創的なVimプラグインを書くことで有名な人が、今日もVimネタのツイートを繰り出している。

Vimはいいですよね、こんなに好きでいてくれる人がいて。私の出番なんてないんです」
「そんなこと……」
「私だって、最初の頃は仕事が増えて、大変だけど楽しかったです。Escapeキーなんて全然使われないと思っていたのに、突然主役みたいになって。ああ、Vimっていいな、Vimがあれば、Escapeキーでもこんなに使ってもらえて、話しかけてもらえるんだって、そう思いました」
「でも……」
「でも、モードを切り替えるのは<C-[>の方がやりやすいんですよね。Vimも最初からそのキーバインドがあるし、元からそういう物だったんですよ。勝手に調子に乗って、喜んでた私がバカみたいじゃないですか。結局Vimに踊らされてるだけで、そのVimにもこんなに熱心なファンの人がいる」
あずにゃん……」
「もう、ほっといてください。Escapeキーなんていらないんでしょう!」

僕は、それ以上何を言えばいいのか分からなかった。MacBookを閉じた後も、頭の中ではあずにゃんの言葉がぐるぐると渦を巻いていた。

ISUCON6予選で負けたので反省します

ICFPCが楽しかったのでまたチーム戦しようという話になり、かねてから興味のあったISUCON6にチーム「イーグルジャンプ」として、id:pepsin_amylaseとmkutとともに参加しました。Python実装を選び、8時間かけて12830点しか取れず、社会的には完全に人権を喪失しました。以下、反省文です。

やったこと

  • Opsフローの策定 (osa_k)
    • 基本的にはpull-reqベースで開発を進める。masterは常にデプロイ可能な状態に保っておき、featureをマージするときにはmasterからfast-forwardできることを要求する。
    • 設定ファイル類はすべてリポジトリに入れておき、通常のデプロイ操作だけでnginxやMySQLの設定まで変更できるようにする。
    • デプロイ時に変な操作をして環境破壊することを防ぐため、Rundeckジョブを叩いてデプロイする。
  • 本番サーバの他にテスト用サーバを立てる (osa_k)
  • 秘伝のタレnginx.confとmy.cnfをサーバに置くが、たまたまアプリ実装のバグでアプリの起動に失敗し、原因を切り分けるため設定ファイルをロールバックしたまま忘れる (osa_k)
  • RundeckとSlackのインテグレーションを設定する (osa_k)
  • 静的ファイルをnginxで配信する (osa_k)
  • isutarをisudaに併合する (mkut)
  • ついでにスター処理をRedis化する (pepsin_amylase)
  • ログイン処理とキーワード一覧の取得をRedis化する (pepsin_amylase)
  • リンクのsha1をキャッシュする (pepsin_amylase)
  • htmlifyの結果をキャッシュする(別プロセスでひたすら最新30件のキャッシュを作りRedisに突っ込む) (osa_k)

やってよかったこと

情報共有の時間を取る

全員の作業のキリがよくなりそうなタイミングで小休止を挟み、現在自分が何をやっているか、何が分かったかという情報を共有する時間を設けることで、全員が全体の状況を把握できるようになるとともに、改善案を取捨選択して重要そうなものに注力することが可能になりました。相談せずにずっとコードを書いているとだんだんノッてきて書きたいものは増えていくのですが、すべて実装する時間はないのでアイデアの切り捨てが必要になります。強制的に休憩を取ってミーティングを行うことで、全員でアイデアの共有と吟味ができるため、大きな手戻りは防ぐことができました。1人でもそのへんは同じだと思いますが、チーム戦だと誰か1人が言い出せば良いので、アイデア吟味の時間を取り忘れる可能性が下がるのが良い点です。

開発フローを定める

今回はmasterを常にデプロイ可能な状態に保ち、各自がfeatureブランチをmasterから作ってfast-forwardな状態を保つことで全体の信頼性を確保する、いわゆるGithub FlowContinuous Deliveryと呼ばれている手法を使いました。ISUCONのようにあるタイミングで必ず動くものを提出しないといけないというコンテストでは、常にmasterがデプロイ可能という状態は安心感がありました。

ただし、featureの粒度を小さく保つのが難しく、あるfeatureで関係ない箇所のバグに気づいてfixを混ぜてしまい、他のfeatureでもそのfixが必要になったため、masterからではなくfeatureからブランチを生やすというケースが発生してしまいました。こうなるとそのfixを含んだfeatureがrejectされたときに大変面倒な状況になるため、運用には専用のgitコマンド群を用意するなど、ある程度のDevOps作業が必要になると感じました。

やるべきでなかったこと

Rundeckを小規模オペレーションに使う

これが(自分が担当した中では)一番の敗因でした。コンテスト中は、アプリのデプロイ手順はテスト環境でも本番環境でも変わらないという理由により、ひとつのRundeckジョブにテスト用と本番の両方のノードを登録して、ジョブを叩く人がデプロイ先を選ぶ形にしていました。しかし、そもそもRundeckはChefやCapistranoのように、複数のサーバで同じコマンドを同時に叩くというオペレーションが主眼に置かれており、本番とテストのデプロイ操作をひとつのRundeckジョブで共有しようというのは、かなり踏み込んだ自動化をしないと無謀です。実際、テスト用サーバで作業している最中に間違ってデプロイを叩かれ、作業中のデータが消えるという事件がありました。また、ノードのマシン名やログイン情報などは手書きでXMLを編集しないといけなかったり、ジョブ定義のUIが煩雑でTry & Errorを前提とした改修に向かなかったりと、設定作業が割と煩雑なため、どうしても使いたいのであれば、プロジェクトの生成から全部スクリプトで自動化するべきでした。練習中はRundeckジョブを叩いてくれるhubotを運用していたのですが、Rundeckを通してデプロイしていると開発のテンポが悪くなることと、そもそも本番で設定がうまく行かずに動いてくれなかったため、手動でRundeckを叩く運用にしたのも良くなかったです。

とは言えGUIでサーバを触れるようにするという方針は、実行ログや処理内容が一箇所に集約できて管理が楽になるという点で、間違っていなかったと思います。後述のように本番環境と開発環境の分離がうまくできず、Rundeckで管理する対象の大きさが不必要に膨れ上がってしまった点が問題なので、これは本当に集約管理しないといけないか?という切り分けをリソースごとにじっくり考えるべきだったと言えます。

環境設定をしていた時間のほとんどはRundeckの設定を調整していた時間になっていたので、この規模の用途でRundeckを使ったのは完全にオーバーキルであったと思います。使うにしても、設定を可能な限り自動化してやるべきでした。

開発用サーバをケチる

練習の段階では、ローカルで環境構築する手間を省くために個人ごとに作業用VMを立てようという話をしていたのですが、AzureのFree tierプランでは1リージョンに4コアまでしかマシンリソースを置けないという制約があり、面倒だったので開発用兼テスト用サーバの1台しか用意しませんでした。また、前述のようにRundeckの設定が煩雑だったため、ノード数を増やすと作業量が増えてしまうという問題もありました。結果として、3人チームなのに2人しかサーバ環境が使えず、1人はローカルで環境構築する必要があるという二度手間になってしまいました。

急な方針転換はオペレーションが混乱するため、可能な限り避けるべきです。設定ファイルのチューニング忘れも完全にこの辺の混乱が尾を引いてしまった形です。また、アプリの開発環境整備は、処理系のバージョンを揃えたり、DBの導入をする必要があったりと結構面倒な作業を(特にMacを使っていたりすると)含むため、なるべくなら自動化されたものをそのまま使う方が良いです。

開発環境とテスト・本番環境の分離をはっきりしない

開発用サーバとして用意したサーバは、実質テスト用サーバを兼ねており、作ったブランチを試したいときにはアプリをデプロイし、ベンチマークに投げるという運用がなされていました。しかし、当初はデプロイ処理の大部分がRundeckジョブとして記述されており、ちょっとしたテストをするにもブランチをpushしてどこかにデプロイするという作業が必要で、全体で1〜2分ほどかかっていたため、かなりまどろっこしい運用になってしまっていました。

後半ではデプロイ作業の大部分をdeploy.shとしてまとめ、Rundeckジョブではこのシェルスクリプトを叩くだけになりました。こうすることで、開発用サーバ上でも開発者がdeploy.shを叩くだけでデプロイできるようになったのですが、開発環境はコードの編集からデプロイまでの素早いイテレーションが求められ、テスト環境では可能な限り本番に近づけた運用が求められるということに気づかず、ごちゃ混ぜの運用をしていたのは大きなミスでした。そもそも今回は短時間コンテストな上、間違えて環境を破壊しても復帰が容易だったので、テスト環境という概念自体が不要だったと思います。

プロファイルを取らない

ボトルネックの特定は主にnginxのアクセスログの解析と目視のコード確認で行っており、トップページのレンダリングにかなり時間がかかっていることは比較的早い段階で分かっていたものの、キーワードやログイン情報のキャッシュなど、本質的でない箇所の高速化に時間を割いてしまい、htmlifyのキャッシュに取り掛かったのは終了2時間前でした。ちゃんとした経験か洞察力があれば、巨大な正規表現ボトルネックであると看過できたはずなのですが、そうでない以上は闇雲に最適化を進めるのではなく、行レベルのプロファイリングなどで実行時間を測定し、定量的にボトルネックを探すべきでした。

このあたりはサーバ設定が遅れたことでオペレーションが混乱し、データが欲しいときにすぐ得られる状況でなかったため、nginxのログの確認すらスムーズに進められなかったことも大きな原因になっていると思います。環境構築の遅れはとにかく致命的です。

まとめ

せっかくのチーム戦だし、普段から興味のあったオペレーション役をやりたいと思っていたのですが、過度に複雑なオペレーションを組んでしまって爆死しました。開発経験なさすぎですね……。ツールの使い方や最適な開発フローなど、自分1人の開発でも勉強できた点は多かったと思うので、個人プロジェクトでいろいろ試して来年のISUCONまでに経験値を積みます。

ICFPC2016 Team 天羽々斬

ICFPC2016にTeam 天羽々斬として参加しました。チーム名は、直前に観に行ったシン・ゴジラ(名作なのでまだ観てない人はこんなブログ読んでないで今すぐチケットを予約しましょう)で、ゴジラ討伐部隊の1つが「天羽々斬」と呼ばれており、それを聞いた瞬間にシンフォギアだ!!!!となって勢いでチームSlackのドメインをamenohabakiriにしたところ、そのまま流れでチーム名となってしまいました。

f:id:osa_k:20160811023921p:plain

チームメンバーは弊社同期の8人です。8人!多いですね。確か2012年にBoulder Dashやったときも東工大の西8号館にそれくらい集まってた気がしますが、人数が多いとそれはそれでうまく回すのが大変ですね。

ICFPCはチームを組むと作業の分担ができて楽しいのですが、今回も例に漏れず、アルゴリズム班とインフラ班になんとなく分かれるような感じで計画していました。最終的にはインフラ1:アルゴリズム4:手動(!)3みたいな配分になっていました。僕はアルゴリズム力が(比較的)弱い&サーバ周りの作業が好きという理由でインフラをやりました。自分以外の人間が集中的に使うサービスの管理って実際に手を動かさないと勉強できないんだけど、意外とそういう機会ってないんですよね……。

ということで、自分が何をやったのかを中心に、3日間のチームの動きを書いていきます。ちなみに同じチームの id:pepsin-amylase は仕事が速く既に記事を書いているので、合わせて読むと面白いかもしれません。

pepsin-amylase.hatenablog.com

あと提出したコード群。

github.com


0日目

せっかくのチーム戦だし、普段できないサーバの使い方をしてみたいと思ったので、imosさんの記事を参考にして環境を作ることにした。チームメンバーと相談して、結局以下のような方針に決まった。

  • サーバはEC2のr3.8xlargeをスポットインスタンスで使う。1時間あたり$0.4程度が相場のようなので、72時間取っても$30程度。十分安い。
  • ファイルは基本的にサーバ上に置き、各自sshfsでマウントして管理する。imosさんの記事にあるDropBoxはメリットがよく分からないので見送り。
  • 上記の性質上Gitは使えない or 使いにくいため、バージョン管理はしない。定期的にバックアップは取る。 -- マイクロサービス群も特別なデプロイ作業はせず、共有ディレクトリ上から直接実行する。
  • コンパイルと実行は環境を揃えるため、サーバ上で行う(これはあまり徹底されていなかった)。

チーム名が天羽々斬なので、サーバのドメインtsubasa.osak.jpにした。

1日目

開始と同時に公式ブログに飛んで問題文を読む。折り紙を折った後の形が与えられるので、そういう形になるような展開図を構成する問題らしい。えっ、幾何問題なの……。無限精度の有理数ライブラリが必要とされているらしく、ICPCにありがちな誤差ゲーは避けられるものの、多倍長が組み込みの言語かそういうライブラリを持ってないと無理だよなぁという空気になる。GMPを使うかHaskellを使うかみたいな話が出たものの、kawateaが有理数ライブラリを持っていてなんとかなるかもと言っていたので、とりあえず任せることになる。

問題背景のセクションには、大ブッダ像に祝福されたオリガミを供えて庇護を得るだの、古事記にも数々のオリガミが登場するだの、色々とパワーワードが散りばめられている。電通大が主催だし、やっぱりニンジャスレイヤー好きなんだろうなぁ。

1人で黙々とサーバのセットアップをしている間に、他の人々は折り紙の性質について議論をしたり、本物の折り紙を買いに行ったりしていた。開始から2時間くらい経ったところで各人のやっていることをすり合わせるフェーズに入り、いくつかの事実と、いくつかの方針案が出た。

  • 目標となる形がすべて有理数の座標だからと言って、展開図にしたときも有理数の範囲で表現できる座標に収まるの?→折り紙の周は有理数長さでしか分割されないので、必ず有理数の座標が取れる。
  • スコア効率を良くする方法は?→問題サイズによって決まる基準点があり、完全に一致する折り紙を折れたN人でそのうちのN/(N+1)を山分けし、残りの1/(N+1)を完全一致でない人たちが一致度で比例配分する、という採点方式なので、完全一致解以外はほとんど意味がない。近似ソルバ作ってないで厳密解ソルバに全力を注ぐべき。
  • そもそも展開図から折ったときの形って一意に定まるの?→どうやら定まるらしい。今回は重なりの順番は無視していい(物理的に不可能な重なり方であってすらよい)ので、一般の折り紙よりは楽。
  • 凸包を作ってその形に合わせて折っていけばよいのでは?
  • DPっぽく外周になり得る辺をたどって、長さ1の辺を4本復元できたらなんとかなるのでは?

このうちDP解は展開図の復元が無理そうだったので、凸包解をkawateaが書き、その他の人は折り紙の折り方を研究するなり、必要そうなツールを書くなりすることになった。自分はREST APIを使った問題クローラを書いていた。今回は運営側からREST APIが提供されていて、すべてのアクセスはAPI越しでやれ、むしろ人間用のUIをクロールするな、あと1時間に1回しか更新しないから無駄にクロールしてきて負荷かけんな、という今までのICFPCの反省をふんだんに盛り込んだ制約がかかっていて、運営めっちゃ頑張ってるなぁと思った。

クローラを書き終えるころ、yuustiがビジュアライザ書いたんだけど、これWeb UIで見せることできますかと聞いてくる。どんなのを作ったか聞くと、問題ファイルを入力にして、imosさんのJSビジュアライザの関数呼び出し列を吐くようなものだったので、まあ外部プロセス呼び出しでくっつければいいかと思ってSinatraでフロントエンドを書く(この時は多倍長有理数ライブラリをつかっておらず、doubleを超えるような入力が来て破綻したので後でRubyにポートした)。ついでにUserJSを書いて、公式の問題ページからビジュアライザに飛べるようにする。今思えばこの判断は微妙で、とっとと静的な画像を生成して一覧表示しておくべきだった。あと、無駄に1回生成したJSをキャッシュするような機構にもなってたが、プロセスの呼び出しなんてそんな負荷でもないので、ビジュアライザがアップデートされて情報が増えることを考えると、おとなしく毎回生成するべきだった気がする(実際後で何回も問題になった)。

必要最低限のインフラはできたので、次は各人のプログラムをすべての問題に対して実行した結果を残しておき、性能比較ができるようなシステムを作ることにする。とりあえず逆羅刹と名付ける。実行のスケジューリングとかをRubyで書くのは流石にだるかったし、コケたときのログを残すのも面倒なので、JenkinsのParametarized Buildで実行対象のバイナリを指定したら勝手に走らせてくれるようにする、という方針にした。Jenkinsはなんかゴツいイメージなのでカ・ディンギルと名付けた(適当)。

ビジュアライザで古事記(運営が用意した問題は、すべて古事記に記されているらしい)の問題を見て、10番台に1回だけ折った問題が多いことに気付いたkeitakが、1回折り専用のソルバを書いていて、ちょうど逆羅刹の完成と同じくらいだったので試してみる。

f:id:osa_k:20160811143306p:plain f:id:osa_k:20160811143310p:plain

(Problem 11と12)

何回か失敗したものの、ちゃんと走った。実行結果一覧を眺めていたら、これ一括サブミットできるといいよねとkawateaが言い出したので、ボタンを押した瞬間に全サブミットのループが走り、終わるまで返ってこないという闇のエンドポイントを生やす。このあたりで単純なファイルだけではデータの管理が難しくなってきたので、MongoDBを導入する。その後kawateaの凸ソルバも走らせるようにする。ビルドまでJenkins側でやるようにしたら、jenkinsユーザが644の他人のディレクトリに書き込みできなくてちょっと面倒くさいことになったので、パーミッションを777にすることで解決した(sysadの屑)。

yuustiがまたなんか言ってくる。どうやら今度は解答のビジュアライザを書いたらしい。問題ビジュアライザと同じ仕組みが使いまわせるのでそのようにする。今ひとつ役に立つのか分からなかったが、手動でひたすら折り紙を折っては展開し、折り目を見て手作業で座標を計算していた勢(主にhyonhinaとmkut)には便利だったっぽい。

mkutは「ねじり」を理解したとか言って、方眼紙の上でひたすらねじりの入った折り紙の座標計算をしていた。後で聞いたところ、ねじりは大体90度回転させると一致するやつだから問題は普通の折り紙の4倍簡単で、辺をじっと見てうまく繋がりそうなパスを見つければいいだけだみたいな事を言っていた。よくわからない。

f:id:osa_k:20160811143738p:plain f:id:osa_k:20160811143820p:plain

(Problem 19と98)

この辺で手作業で解かれた問題が溜まってきて、とはいえ運営の用意したフォームで提出するとログが残らなくて不便なので、何かしらログが残る手段で提出したいという自然な需要が生えた。インフラしかやっていなくてもその必要性は十分に感じていたので、即座に提出用のコマンドと、サブミットキューを消化していくデーモン(蒼ノ一閃)を作る。このデーモンが止まると点数が取れなくてやばいので、 id:pepsin-amylase が作ったコマンド(レイシス)でチームSlackに死亡通知を流すようにしたところ、文章が面白かったらしくなんかウケた。

f:id:osa_k:20160811041416p:plain

開始から24時間までがLightning Roundで、この時点での1位は別に表彰されるので結構頑張っていたのだが、3位~4位をうろうろしている上、凸包解法ではそれ以上伸ばせそうになく、半ば諦めていた。するとkawateaが突然、手で座標入力したら折れる気がすると言い出してツールを書き、ビジュアライザで表示した頂点の座標を見ながら簡単な問題を手動で解き始めた。やばい。しかし奮闘むなしく、4位(だっけ?)に留まってしまう。

24時間を過ぎたところからは各チームの問題提出が始まる。解答ファイルをアップロードすると運営側で自動的に折られて問題が作られるようになっており、(5000-解答ファイルのバイト数)/(厳密解で解いた人数+1)の点が入る。解いた側の基準点は解答ファイルのバイト数になるため、2500バイト以内であれば提出するだけ得となる。とりあえず古事記にあった、Fの形をした折り紙をhyonhinaが手作業で解いており(やばい)、他のチームも解いていないようなので、こいつをmkutのGideon(解答ファイルを食わせてコマンドを指定すると、平行移動・回転・任意の直線で折り返しした解答ファイルを吐くやつ)でちょっと回転させたものを提出することにして、家に帰って寝た(ここで朝10時くらい)。

f:id:osa_k:20160811144015p:plain

(Problem32 「F」)

2日目

16時くらいに目覚めて会場に向かう。どうやらcronで仕掛けておいたクローラが寝ている間にうまく動いておらず、問題の更新が滞っていたらしい。cronは難しすぎてよく分からないので、クローラもJenkinsで回すことにする。最初からそうするべきだった……。

kawateaが完全に手折り職人と化してしまったので、折り紙ヘルパーを作ることになる。折り途中の折り紙から折りたい辺と面を指定するとその通りに折れるというもので、例によってバックエンドで動くステートレスなC++プログラムをSinatraが叩いてユーザに送り返すというシステムになった。

https://raw.githubusercontent.com/osak/ICFPC2016/master/images/gekirin.png

これを得たkawateaがものすごい勢いで折り紙を折り始め、簡単だけど手入力は厳しいような問題を次々と人力で解いていってしまった。AIなんていらんかったんや……。手動で解いていたhyonhinaとcarbon_twelveも謎の才能に目覚め始め、特にhyonhinaが、未知の折り紙を勘でどんどん実際に折っていっては展開して座標計算してSubmitという行為を繰り返しており、まさに若者の人間離れだと思った。

f:id:osa_k:20160811145728p:plain

(Problem18 「パカ」(yuusti命名) 現実には内側を開いて潰すように折る操作(潰し折り)が必要になるが、今回の問題では過程は無視して展開図さえ作れれば受理されるため、直線で折り返すだけで作れる(途中で面が切れてもう一度くっつく))

その間に id:pepsin-amylaseグレイスを作って平行移動、回転、鏡像反転で同じ問題になるものを使いまわせるようにしたり、yuustiが天空の夜明けを作って非凸の折り紙を1回だけどこかで展開し、凸にした上でkawateaの凸ソルバに食わせ、最後にmkutのGideonで元の線で折るというパイプラインによる解法を開発し、100問くらい解いた(らしい)。Gideonは元々、古事記の難しい問題をもう1回折ればめちゃくちゃ難しくなるだろうし、回転させると適当な合同判定ルーチンしか持ってないチームには解かれないだろう、という発想の出題用ツールだったのだが、問題を解くためのパイプラインになったのは面白い。この方針でもっと解けばよかった気がする。

そんなことをしていたら、なんとUnagiを抜いて1位になった。魔剤?

Unagiは潜伏しているのかもしれないけど、他のチームも似たようなもんだし、こんな探索しづらそうな問題で大きく差は付かないだろうと思い、現状維持の方針を取ることにする。結果的にはこれが完全に分水嶺だった。とりあえず、グレイスが合同かつ未解決な問題をクラスタリングして提示してくれるようになったので、逆羅刹にクラスタを見るページを作り、手動勢は大きいクラスタから解いてもらうようにする。あと、このクラスタが解けたら何点取れるかも計算したのだが、なんか出力がおかしいのでとりあえず放置する。

このへんから、DAOを書かずに色々なアプリケーションから勝手気ままにMongoを叩いていた影響で、あちこちのフィールドで型が想定とズレて死に、火消しに奔走する。朝になって集中力が保たなくなってきたので、帰って就寝。たしか13時くらい。

3日目

寝て起きたらまたクローラが止まっていたらしい。どうやら前日に帰る直前に入れた変更が良くなかったらしい。ずっと起きてると無自覚でも思考能力がガタ落ちしているので、変なことしちゃだめですね……。そもそもなんでテストしなかったのか。

点数計算のバグがわかる。Problem IDから自分のベストスコアへのHashだと思ってたオブジェクトが実はArrayだったため、変な数値を計算に使っていた。静的に型の付かない言語はこれだから……(責任転嫁する屑)

夕食に寿司を食べていたら、スコアボードも寿司になっていた。一瞬もう凍結されたのかと思った。

Unagiとギリギリ競っているので、Unagiが解けなさそうな問題を出して差を広げようという話になる。とりあえずUnagiがFの折り紙を解けないとは思えないので、もっと難しい問題を作りたい。Unagiが提出している問題を見ると、そもそも折っていくにしろ開いていくにしろダントツで難しい。そこで、Unagiは古事記くらいは解けるにしても、彼らが自分自身で出している問題は解けないんじゃないかという仮説を立て、同じような問題を作ることにする。が、そもそもUnagiの問題が手動でも解けない。仕方がないので、Unagiの問題を解こうとしながら天ノ逆鱗で試行錯誤している最中にできた、Unagiの問題もどきを提出すればいいのではないかとkeitakが主張し始めたので、そういうのを出してみることにする。Unagiの似非なので穴子と命名される。

f:id:osa_k:20160811145533p:plain

(Problem3937 「穴子」)

穴子を出して様子見していたところで2時になる。と、Unagiが10万点くらいスコアを上げて一気に引き離された。えっまじで。潜伏していたのはいいにしても、戦闘力が想定と全然違うっぽい。やばい。 このままだと2位も危うそうなので、特殊ソルバでもいいからもっと頑張って作ろうということになる。自分が起きてくる前に問題一覧をサーベイした人たちによると、yowaさんの問題がかなり特殊な形式になっているらしく、簡単(簡単とは言っていない)な貪欲で解けるらしい。id:pepsin-amylase が専用のソルバを書き始める。

f:id:osa_k:20160811151742p:plain

(Problem1726 ひとつ角を固定し、その角を通るような直線で扇状に折りたたんだ図形になっている。対角線で折られることがないようなので対角の特定が容易にできて、あとはその角から生えている2辺を特定すればよい。)

スコアボード凍結直前の3時。Unagiが70万点くらい、天羽々斬が20万点くらいと、もう話にならなそうな差が付いている。既存の問題を見てみても、1チームだけが厳密解を提出しているものがザクザク出てくる……。これはどう考えてもUnagiが厳密解ソルバを持っているということなので、今から勝つのは無理っぽいし2位維持をがんばろうということになる。つらい。

インフラはいい加減やることがなくなってきたので、少しmkutと議論をする。与えられたシルエットから面どうしの繋がりを維持しつつ正方形にパッキングしていく問題を考えると、探索として解けるかもしれないらしい。ぱっと見はめちゃくちゃ計算量が大きそうだが、確かに色々な枝刈りが考えられるので、枝刈りのプロがいれば実装できるかもしれない。しかし6時間でバグなく高速なソルバにできる自信はなかったので見送られてしまった。

そうこうしている間にyowaソルバが完成する。数回のデバッグと実行を経た後、yowaさんの問題をすべて解くことに成功する。やったー。

また、Skobochkaというチームが、細長くたたんだ折り紙をS字に曲げたものを大量に出しているのを発見したので、yuustiがソルバを書き始める。正確には最初はめんどくさがっていたのだが、Gideonで折る面と折らない面を区別できるようになったら実装してやると言ってmkutを煽っていたところ、mkutが実際にGideonをアップグレードしてしまったため、ソルバを書く羽目になっていた。かわいそう。 残念なことに、このソルバは終了までに間に合わなかった。

f:id:osa_k:20160811153218p:plain

(Problem3961 「S」)

kawateaとhyonhina、keitak、carbon_twelveがひたすら手動で問題を説き続け、時間が来て試合終了。結局手動解法に偏りすぎてしまったのが少し残念。

反省

成り行き上仕方なかったとはいうものの、1人でインフラを全部回すのは厳しかった。システムを作るところまではまあいいけど、実装に使う技術をちゃんと考えておかないと、だんだん体力が削れていく中でデバッグと保守を行うことになり、少しずつシステムが壊れていく。

チームの戦略としては、ソルバにモジュール性を持たせて、雑ソルバでもいいから量産するべきだった。というかそういう風にしたかったのだが、インフラ開発が忙しすぎて自分ではソルバが書けなかったので、他人を説得してそういう方針に引きずり込むのもちょっと難しいという状況になっていた。チームで反省会をしたときにも話題に出たが、数時間に1回くらい完全に作業を中断し、みんなで状況を共有して次の一手を決めるような会議が必要だと思う(というのをICPCに参加していたときからずっと言っているができておらず、成長していない……)

とはいえ、良いサーバを使ってマイクロサービスを立てまくるのは、サービスの本当に最初期の設計を考えるという点でかなり得るものがあった。人数が少なければ指数的に規模が膨らむことはないので、精神的に余裕があれば割といつでもリファクタリングはできる。ファイルベースの管理からMongoに切り替えるとかね。ただし複雑度は指数的に膨らんでいくので、ある程度長期に使われそうなコードならバグりにくい設計を考えておくべきだと思った。あと既存かつ実績のあるプロダクト(Jenkinsとか)はハマリどころが少ないので神。

また、一般論としてサーバサイドアプリとしては異常な構成であっても、割りきってコードの簡略化やモジュール化を進めるのはかなり有効だった。たとえば、REST APIを叩くときにはRubyのNet::HTTPではなく外部コマンド実行でcurlを叩くようにしたり(楽だから)、stdin / stdoutを介した通信でバックエンドのC++プログラムに面倒な幾何をすべて任せたりすることで、管理しないといけない領域を効果的に狭めることができた。

Gitを使わずにsshfsでみんなのファイルを共有して、かつ即デプロイするような環境を作ったのは一長一短だった。他人の成果物へ即座にアクセスできるのはかなり使いやすい。しかし、誰かが使っているコマンドやサービスを改修しようとすると必ず干渉してしまうという欠点がある。特にSinatraのviewは変更が即座に反映されるので、実装途中の機能がユーザに見えてしまうことがよくあって一瞬ではあるものの混乱を招き、精神的に負担が大きかった。

総括

3日間ずっとめまぐるしくコードを書いていたのは楽しかったです。自分がインフラを作っていると、他の人がインフラを使って成果を出してくれるという体験をこの密度でできるのは、なかなか得難い体験ですね。折り紙という題材を最初に見た時はどうなることかと思いましたが、最初の印象以上に問題もジャッジシステムも完成度が高く、ずっと飽きずに、かつシステム面でフラストレーションが溜まるようなことがなく、遊び続けることができました。

チームの動きとしては、もっと探索して計算機の力を使うようにするべきだった感はあります。なまじ人数が多いというのも考えもので、今回のように人間がある程度能力を発揮できる問題だと、すぐに人海戦術に流れてしまう。4,5人しかいなければ確実に探索の方針を考えていたのではないかと考えると、もっといい戦い方はできたんじゃないかなぁと思います。

来年はうなぎに勝ちたいですね。

Windows10 on VirtualBox

Windowsでないと動かず、かつ使えないと困るプログラムがそれなりにあるので(ScanSnapのドライバとかiTunesとか)、立てて放置してた自宅サーバにWindows10を入れることにしました。まあWindowsにホストは渡したくないのでVirtualBox上です。

一応Headlessでサーバ管理したいみたいな目標があるので、GUIフロントエンドを使わずにVBoxManageでちくちく頑張って仮想マシンを立ち上げることにしました。よく分かんないので適当にぐぐったところ、良さそうなページを見つけたので、真似して以下のようなコマンド群でVMを作りました。

$ VBoxManage createvm --name Windows10 --ostype Winddows10_64 --register --basefolder `pwd`
$ VBoxManage createhd --filename Windows10/Windows10.vdi --size 20000
$ VBoxManage storagectl Windows10 --name "SATA Controller" --add sata --controller IntelAHCI
$ VBoxManage storageattach Windows10 --storagectl "SATA Controller" --port 0 --device 0 --type hdd --medium Windows10/Windows10.vdi
$ VBoxManage storagectl Windows10 --name "IDE Controller" --add ide
$ VBoxManage storageattach Windows10 --storagectl "IDE Controller" --port 0 --device 0 --type dvddrive --medium host:/dev/sr0
$ VBoxManage modifyvm Windows10 --ioapic on
$ VBoxManage modifyvm Windows10 --boot1 dvd --boot2 disk --boot3 none --boot4 none
$ VBoxManage modifyvm Windows10 --memory 2048 --vram 64
$ VBoxManage modifyvm Windows10 --nic1 bridged --bridgeadapter1 enp0s25

DVDドライブをIDEで繋いでてちょっとどうなのという気がしなくもないですが、変にアレンジしてハマるのも嫌だったのでそのままにしました。長いものには巻かれろ精神です。この状態でWindows10のインストールディスクを入れて

$ VBoxHeadless -s Windows10

するとVMが立ち上がるので、

$ rdesktop kadingel:3389

とかやってリモートデスクトップで繋ぎます。するとインストーラが出てくる……はずだったんですが、CPUが64bitに対応してないよ的なエラー(0xc000035a)が出てきて進めませんでした。ちゃんとCPUは64bitだし、VT-xも有効化してるのにどういうことなんだ……。

しばらく調べてると、どうやらWindows10は新しいチップセットしかサポートしていなさそうという情報が見つかったので、

$ VBoxManage modifyvm Windows10 --chipset ICH9

すると、今度はうまくインストーラが立ち上がってくれました。ハマるの嫌だから先に色々調べたのに、結局3時間くらいかかってしまった。

原田ひとみ アコースティックライブ2016

ライブ

原田ひとみのアコースティックライブに行ってきた。そもそも原田ひとみを知ったのが2007年頃にアニメ経由でefを知って、ゲームPVで聞いた悠久の翼に感動したのが初めなので、実に9年の時を経てついにライブイベントで実物を見られたことになる。

事前に1stアルバムのglanzendを何回か聞いたが、結論から言えば、今回のライブはカバー曲ばっかりだったので特に関係なかった。自分は声が好きなので、カバーでも聞ければよいというスタンスである。

カバーとはいえ、原田ひとみのよく通る力強い声で歌うと、元の曲とはまた違った味わいがあって楽しい。歌い方や声質の似ている林原めぐみの「Infinity」や島谷ひとみの「アンジェラス」はもちろんうまくハマっているし、アイマスの「エージェント夜を往く」や初音ミクの「メルト」もとても良かった。というか、メルトを生で安定して歌えるのがやばい。人間を殺しにかかってくる高音部もなんなく歌い上げ、その後すぐに普通の声に戻してまったくブレないのは、さすがと言ったところ。

MCトークも面白かった。Twitter等で結構エキセントリックな人だというのは知られているが、現実でもあのままの言動で、隙あらばおっぱいの話をしている。入院中に暇だったからという理由で一気に作り上げた同人ノベルゲームが、周囲の知り合いにイラストや音楽、声を頼んだらみんなプロだったので、同人とは思えない異常に豪華なキャストになっているという話は、面白いというのはもちろん、純粋にすごいと思った。これが業界人か……。あと、MC中も座っている回転椅子を左右に振ったり、履いているタイツをしきりにいじったりしていて、落ち着きがないのがちょっと面白かった。

坂本真綾の古いアルバムの曲や、「ショムニ」の歌を歌いつつ、新人声優が10代でジェネレーションギャップを感じるという話から、犬夜叉の「アンジェラス」は最近だからみんな知ってるよね!と言い始めたのは様式美という感じ。犬夜叉ってもう12年とか前……。

最後は回レ!雪月花で、全員起立&ペンライト振り。音域のやばいメルトはちゃんと歌えてたのに、早口がやばいこの曲は途中で歌えなくなってた。まあしょうがないね。

欲を言えば、efの曲を歌ってほしかった。とは言ってもefすらもう8年とか前の話なんだよなぁ。

最近見た映画

映画

アイアムアヒーローとレヴェナントのネタバレを含むので注意してください。

アイアムアヒーロー

予告編が邦画にしては感動っぽい要素がなかったり、音声による煽りがなかったりして、かなり攻めている要素があったので面白そうだと思っていた。見ようと思ってタイミングがなくずるずると先送りになっていたのだが、Twitterで評判が良かったのでこれは観ないといけないと思って映画館に行った。

少年漫画のように、かなり分かりやすくヒーロー物という内容だった。鬱屈した主人公であるヒデオがZQN(要するにゾンビ)と戦って成長する物語……というと荒すぎるか。劇中を通して徹頭徹尾臆病で、ZQNに襲われれば腰を抜かし、散弾銃を持っていても外で撃つと銃刀法違反だからと言って撃たず、道中で助けて行動を共にした女の子にも手を出さない、そんなヒデオが最後の瞬間だけ、自分を信じてくれた人と自分が守りたいと思った人のため、自分から進んでZQNの大群との戦いに身を投じる。そんな最後の瞬間で最大限にカタストロフィを生み出すため、それだけのために途中の全ての展開が存在したのだという、説得力のある清々しさを感じた。最初は照れと自虐、それと願望の混ざった感じに「英雄と書いてヒデオです」と言っていたのが、最後に仲間を助けて本当の英雄となった途端に「ただのヒデオです」と言ったのは、本当に等身大のヒーローという感じでよい。ヤブに評価されていた、ヒロミちゃんを助けてZQNを発症しても連れて歩いたというエピソードも、ギリギリ普通の人でもできそうというラインを保っていて、過度に超人という描写がないのがすごい。

逆に本筋以外のストーリーについては、全体としての完成度を損なわせるまでではないにしても、多少のアラが目についた。富士山に向かえばZQNの感染を阻止できるという情報をすんなりと信じた点や、高飛びを繰り返している陸上選手のZQNを危険視せず放置していた点など、ストーリーを進めるためとは言え、強引でご都合主義という面は否めない。ただ、ヒデオの英雄譚という観点で言えば、特に問題になるほどではないと思う。

あと、予告編を観て、コメディタッチの映画かと思っていたら、かなりZQNの描写がえげつなくて少し後悔した。叫び声とともに突然アップでZQNが襲いかかってきたり、ZQNを鈍器や刃物で攻撃して肉が見えたり、逆にZQNに食われた人間に痛々しい食い跡があったり……。最後の展開のためにこの映画を見る価値は確実にあったが、それでも怖いのとか痛いのは苦手……。ただ、そういう層を取り込むという意味でも、コメディだと思わせる予告編の演出には意味があったのだと思う。実際、怖いゾンビものだと分かってたら観なかったと思うし。

レヴェナント

これも予告編で観て、子供を殺された父親の復讐譚というニンジャスレイヤーのようなストーリーに惹かれた。子供を殺した犯罪者集団を父親が次々と殺していくタイプの話かと思っていたのだが、予想に反して、フィッツジェラルドに子供を殺されたグラスが、フィッツジェラルドのみを標的として、瀕死の状態から蘇って追跡の果てに殺すという、かなりストイックな物語だった。

役者の演技はどれもうまく、映像は美しいし、アクションも派手でこそないものの息を呑ませるシーンが多いので2時間半という長丁場にも関わらず飽きることなく観ることができたのだが、やはり次々と敵を殺していくという話を期待していると肩透かしを喰らった。性質としてはおそらくオデッセイに近く、グラスがいかにして死の淵から蘇り、途中で出会った人々と関わりつつフィッツジェラルドに肉薄していくかという、泥臭い道程を追体験することに主眼がある作品なのだが、やはり映像では泥臭さの表現に限界があり、淡白になりすぎてしまっている印象を受けた。

明確な悪役とヒーローがいるのではなく、どの登場人物も各人の信念に基いて正しいと思う選択を取り続けており、わずかな不運によって悲劇が起こり復讐劇に繋がっているという設定が、アメリカ映画にしては珍しく感じた。しかも復讐という、基本的には復讐する側とされる側の双方にとって不幸な結末が待っていることの多い題材に対して、最終的にグラスがフィッツジェラルドを殺すことに成功し、そのグラスも雪山で力尽きつつ愛したポワカ(でいいんだよね?)の幻影を見て終わるという、ある種のハッピーエンドにも見える結末になっており、爽快感こそないものの、現実はこんなもんだよねという、地に足の着いた物語だと感じた。

原作が小説であるためか、オデッセイと同じく映画としては説明不足な点もある。アリカラ族の娘のポワカについては、グラスがポワカを奪い、その子供がホークであることを示唆する言動は多々あるものの明確には言及されなかったし、アリカラ族がポワカを求めてアメリカ人を追っていることの背景についても、彼らがなぜ強くこだわるのかの説明はなかった(ホークが既に青年と言える歳なので、ポワカの事件は20年程度昔の話であるはず)。また、アメリカ人たちが毛皮商としてインディアンと戦いつつも毛皮を買っている理由もあまり明らかではなかった。アメリカ史としては常識なんだろうか?

俳優の演技は総じてクオリティが高く、特にホークの心の奥底に色々な思いを貯めこんでいるような青年の演技と、ブリッジャーの経験の浅さからくる優柔不断さと、フィッツジェラルドの断定的な決断に流されてしまう演技はかなりリアリティがあった。