
<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	
	xmlns:georss="http://www.georss.org/georss"
	xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#"
	>

<channel>
	<title>Programming | monolog</title>
	<atom:link href="https://blog.monora.me/category/programming/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.monora.me</link>
	<description>monora log #=&#62; ものろーぐ</description>
	<lastBuildDate>Tue, 26 Jul 2022 18:54:42 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.0.1</generator>
<site xmlns="com-wordpress:feed-additions:1">21279848</site>	<item>
		<title>ISUCON12 予選に参加しました (最終スコア15532点)</title>
		<link>https://blog.monora.me/2022/07/participated-in-isucon12-qual/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=participated-in-isucon12-qual</link>
		
		<dc:creator><![CDATA[きょんたん]]></dc:creator>
		<pubDate>Tue, 26 Jul 2022 18:01:43 +0000</pubDate>
				<category><![CDATA[Infrastructure]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[ISUCON]]></category>
		<category><![CDATA[コンテスト]]></category>
		<category><![CDATA[参加しました]]></category>
		<guid isPermaLink="false">https://blog.monora.me/?p=2405</guid>

					<description><![CDATA[<p>2022年7月23日 (土) に開催された ISUCON12 の予選に「DJ起床失敗とMC布団 w/o MC布団」として id:h-otter と参加しました。 言語は Go、最終スコアは15532点、参考スコアを上から [&#8230;]</p>
The post <a href="https://blog.monora.me/2022/07/participated-in-isucon12-qual/">ISUCON12 予選に参加しました (最終スコア15532点)</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></description>
										<content:encoded><![CDATA[<p>2022年7月23日 (土) に開催された ISUCON12 の予選に「DJ起床失敗とMC布団 w/o MC布団」として <a href="https://h-otter.hatenablog.jp/">id:h-otter</a> と参加しました。</p>



<p>言語は Go、最終スコアは<strong>15532点</strong>、<a href="https://isucon.net/archives/56838276.html">参考スコア</a>を上から数えると<strong>45位</strong>だったようです。悔しい。<br />具体的な取り組みは下の方で述べますが、MySQL移行はバグなく完遂し、さてここからチューニングしていくぞ！という感じのところで終わりました。エンジンが掛かるまでの速度が足りなかった。</p>



<figure class="wp-block-image size-large"><img width="640" height="342" src="https://blog.monora.me/wp-content/uploads/2022/07/821f8740d91c148254ae8f29eb6f836a-640x342.jpg" alt="" class="wp-image-2412" srcset="https://blog.monora.me/wp-content/uploads/2022/07/821f8740d91c148254ae8f29eb6f836a-640x342.jpg 640w, https://blog.monora.me/wp-content/uploads/2022/07/821f8740d91c148254ae8f29eb6f836a-320x171.jpg 320w, https://blog.monora.me/wp-content/uploads/2022/07/821f8740d91c148254ae8f29eb6f836a-200x107.jpg 200w, https://blog.monora.me/wp-content/uploads/2022/07/821f8740d91c148254ae8f29eb6f836a-768x411.jpg 768w, https://blog.monora.me/wp-content/uploads/2022/07/821f8740d91c148254ae8f29eb6f836a-1536x822.jpg 1536w, https://blog.monora.me/wp-content/uploads/2022/07/821f8740d91c148254ae8f29eb6f836a.jpg 1686w" sizes="(max-width: 640px) 100vw, 640px" /></figure>



<p>毎回、運営の皆様にはいくら感謝しても足りませんが、今回も取り組みがいのある問題で楽しかったです。ベンチマーカーも最後まで待ち時間がほぼなく、スコアも安定していたのでとてもストレスフリーでした。ありがとうございました。</p>



<p>マルチテナントで大量の SQLite3 データベースがあることが分かったとき、ISUCON本を読んだだけの人間には解かせないってことね!と思いながらニコニコしました。</p>



<p>ところで知り合いがたくさん著者に名を連ねている<a href="https://amzn.to/3J29GVW">ISUCON本</a>ですが、予選の2週間前に購入し、予選開始1時間前に部屋から発掘されました。<br />30分ぐらいで流し読みしたのですが、大変実利的な内容に溢れているなあと感じました。nginx の upstream で keep-alive を有効にする方法は知らなかった……</p>



<figure class="wp-block-embed is-type-rich is-provider-twitter wp-block-embed-twitter"><div class="wp-block-embed__wrapper">
<blockquote class="twitter-tweet" data-width="550" data-dnt="true"><p lang="ja" dir="ltr">今日までに読もうと思って積んでいた本です。今日発見しました <a href="https://t.co/RSsbxMkoFD">pic.twitter.com/RSsbxMkoFD</a></p>&mdash; kyontan (@sukukyon) <a href="https://twitter.com/sukukyon/status/1550642844624617473?ref_src=twsrc%5Etfw">July 23, 2022</a></blockquote><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</div></figure>



<span id="more-2405"></span>



<h3>9:00 起床</h3>



<p>前日も早く寝るぞと自分に言い聞かせながら4時半まで起きてしまい、念には念で8時に掛けた目覚ましが1時間鳴っていました。すでにこの時点で心も体も終わっています。</p>



<p>部屋の隅にISUCON本が積まれているのを発見しました。<a href="https://amzn.to/3PxJipt">ちいとぽ</a>も積まれています。<br />h-otterと合流するために移動しつつ、パラパラと眺めます。</p>



<h3>10:00</h3>



<p>まだ合流のため移動中ですが予選が始まっているようです</p>



<h3>10:05</h3>



<p>合流しました。 CloudFormation テンプレートを流します</p>



<h3>10:22 初回スコア 2732</h3>



<p>起動したのでベンチを回しました。この時点で分担も何も決まっていません。</p>



<p>とりあえず kataribe を入れたり pt-query-digest を入れたりします。<br />「そういえば先日の社内ISUCONで Cloud Profiler 便利だったな……」みたいなことを思いながら、入れ方を調べます。<br />GCPプロジェクトが必要らしいので作ったり、サービスアカウントキーを発行したりします。予選始まってからやることではない。</p>



<h3>11:30ごろ</h3>



<p>Cloud Profiler を入れたので眺めました</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="640" height="251" src="https://blog.monora.me/wp-content/uploads/2022/07/3aa8c1532fe9417aa4141a1860fd5623-640x251.jpg" alt="" class="wp-image-2406" srcset="https://blog.monora.me/wp-content/uploads/2022/07/3aa8c1532fe9417aa4141a1860fd5623-640x251.jpg 640w, https://blog.monora.me/wp-content/uploads/2022/07/3aa8c1532fe9417aa4141a1860fd5623-320x126.jpg 320w, https://blog.monora.me/wp-content/uploads/2022/07/3aa8c1532fe9417aa4141a1860fd5623-200x79.jpg 200w, https://blog.monora.me/wp-content/uploads/2022/07/3aa8c1532fe9417aa4141a1860fd5623-768x302.jpg 768w, https://blog.monora.me/wp-content/uploads/2022/07/3aa8c1532fe9417aa4141a1860fd5623-1536x603.jpg 1536w, https://blog.monora.me/wp-content/uploads/2022/07/3aa8c1532fe9417aa4141a1860fd5623-2048x804.jpg 2048w" sizes="(max-width: 640px) 100vw, 640px" /><figcaption>SQLite だね〜という感想。</figcaption></figure>



<h3>12:00</h3>



<p>h-otter が MySQL 対応の実装を終わらせて、「Uber eatsでも呼ぶか〜」と言いながら、なぜか歩いてマクドナルドに飯を買いに行きます。なんで??</p>



<h3>13:03 MySQL移行 3023点</h3>



<p>MySQL移行が一段落します。今思うと速かった。</p>



<p>sqlite から SQL をダンプしてゴニョゴニョやり始めて十分程度経ったあと、 <code>sqlite3-to-sql</code> って名前のスクリプトあるけど?? と気付いて笑ってました。先に気付こうね。</p>



<p>とりあえず MySQL に流し込むこと数分、INSERT が一向に終わらないことに気が付きます。このままでは <code>POST /initialize</code> がタイムアウトしてしまうため、バルクインサートをするクエリに書き換えることにしました。</p>



<p>sed で気合でバルクインサートに書き換えましたが遅い。ここで1台目のインスタンスがメモリを食いつぶして死にます。160万件のINSERTを一発でやると死ぬことが分かる。<br />先日の社内ISUCONでもインスタンスのメモリを食いつぶしたんだよな……と思いながら1台目を捨てます。</p>



<p>これが答えです。</p>



<pre class="wp-block-code"><code>for i in `seq 1 100`; do echo $i; mv $i.sql $i.sql.bak; sed -z -e "s/);\n/);\n\n/" -e "s/NULL\n);/NULL\n);\n\n/g" -e "s/);\nINSERT INTO &#91;a-z_]* VALUES/)\n,/g" $i.sql.bak &gt; $i.sql; done</code></pre>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" src="https://blog.monora.me/wp-content/uploads/2022/07/7a8c7f354c775e1cf36854c39890c9ae-640x302.jpg" alt="" class="wp-image-2408" width="640" height="302" srcset="https://blog.monora.me/wp-content/uploads/2022/07/7a8c7f354c775e1cf36854c39890c9ae-640x302.jpg 640w, https://blog.monora.me/wp-content/uploads/2022/07/7a8c7f354c775e1cf36854c39890c9ae-320x151.jpg 320w, https://blog.monora.me/wp-content/uploads/2022/07/7a8c7f354c775e1cf36854c39890c9ae-200x95.jpg 200w, https://blog.monora.me/wp-content/uploads/2022/07/7a8c7f354c775e1cf36854c39890c9ae-768x363.jpg 768w, https://blog.monora.me/wp-content/uploads/2022/07/7a8c7f354c775e1cf36854c39890c9ae-1536x726.jpg 1536w, https://blog.monora.me/wp-content/uploads/2022/07/7a8c7f354c775e1cf36854c39890c9ae-2048x968.jpg 2048w" sizes="(max-width: 640px) 100vw, 640px" /></figure>



<p>それなりに早くなりましたが、まだ遅いので tenant の player_score テーブルにおいて、 updated_at が一定以上のレコードを DELETE する作戦に切り替えます。これで10秒程度で POST /initialize が通るようになりました。</p>



<pre class="wp-block-code"><code>DELETE FROM tenant_X.player_score WHERE updated_at &gt; 1654041599;
DROP TABLE tenant_X.competition;
DROP TABLE tenant_X.player;</code></pre>



<p>他のチームの参加記を読んだら 「<code>/var/lib/mysql</code> をコピーする」「毎回 mysqldump を実行する」みたいな筋肉実装が多くて震えました……</p>



<p>確かここらへんで h-otter がなぜか flock を倒す実装を書くもベンチがコケました。<br />「そこはボトルネックじゃないっぽいし一旦revertしよ?」と、人の競技中の努力を無に帰すような心無い発言をしました。ごめんなさい。</p>



<p>なぜかここからしばらく無の時間が続きます。なぜ……</p>



<h3>15:20 3758点</h3>



<p>h-otter が competitionRankingHandler の N+1 を潰したようです。</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="640" height="323" src="https://blog.monora.me/wp-content/uploads/2022/07/e8db1bd829ae516c4856e01202912365-640x323.png" alt="" class="wp-image-2410" srcset="https://blog.monora.me/wp-content/uploads/2022/07/e8db1bd829ae516c4856e01202912365-640x323.png 640w, https://blog.monora.me/wp-content/uploads/2022/07/e8db1bd829ae516c4856e01202912365-320x161.png 320w, https://blog.monora.me/wp-content/uploads/2022/07/e8db1bd829ae516c4856e01202912365-200x101.png 200w, https://blog.monora.me/wp-content/uploads/2022/07/e8db1bd829ae516c4856e01202912365-768x388.png 768w, https://blog.monora.me/wp-content/uploads/2022/07/e8db1bd829ae516c4856e01202912365-1536x775.png 1536w, https://blog.monora.me/wp-content/uploads/2022/07/e8db1bd829ae516c4856e01202912365-2048x1033.png 2048w" sizes="(max-width: 640px) 100vw, 640px" /></figure>



<h3>15:50 6336点</h3>



<p>グッとクエリを睨んで indexを追加。<code>playerAddHandler</code> がかなり速くなりました。</p>



<pre class="wp-block-code"><code>ALTER TABLE visit_history ADD INDEX (competition_id, player_id, created_at);
ALTER TABLE visit_history ADD INDEX (created_at);
ALTER TABLE tenant_X.player_score ADD INDEX (competition_id, player_id, row_num DESC);</code></pre>



<p>マルチテナントのDBをそのまま持ってきたので、tenant_id は無視するようにしました。</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="640" height="225" src="https://blog.monora.me/wp-content/uploads/2022/07/972569bfa063fe01a93c6e5a51327b27-640x225.jpg" alt="" class="wp-image-2411" srcset="https://blog.monora.me/wp-content/uploads/2022/07/972569bfa063fe01a93c6e5a51327b27-640x225.jpg 640w, https://blog.monora.me/wp-content/uploads/2022/07/972569bfa063fe01a93c6e5a51327b27-320x112.jpg 320w, https://blog.monora.me/wp-content/uploads/2022/07/972569bfa063fe01a93c6e5a51327b27-200x70.jpg 200w, https://blog.monora.me/wp-content/uploads/2022/07/972569bfa063fe01a93c6e5a51327b27-768x270.jpg 768w, https://blog.monora.me/wp-content/uploads/2022/07/972569bfa063fe01a93c6e5a51327b27-1536x539.jpg 1536w, https://blog.monora.me/wp-content/uploads/2022/07/972569bfa063fe01a93c6e5a51327b27-2048x719.jpg 2048w" sizes="(max-width: 640px) 100vw, 640px" /></figure>



<h3>16:08 7923点</h3>



<p>h-otter が <code>playerHandler</code> の N+1 を潰したようです。</p>



<p>そして <code>player_score</code> に index を追加。<br /><code>ALTER TABLE player_score ADD INDEX (player_id, competition_id);</code></p>



<p>バルクインサートと、JSONシリアライザの変更(encoding/json → <a href="https://github.com/goccy/go-json">goccy/go-json</a>)をした結果、スコアがやや増加しました。(8269点)</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="640" height="175" src="https://blog.monora.me/wp-content/uploads/2022/07/d402be907bf0ee74f9251569549ca330-640x175.jpg" alt="" class="wp-image-2415" srcset="https://blog.monora.me/wp-content/uploads/2022/07/d402be907bf0ee74f9251569549ca330-640x175.jpg 640w, https://blog.monora.me/wp-content/uploads/2022/07/d402be907bf0ee74f9251569549ca330-320x88.jpg 320w, https://blog.monora.me/wp-content/uploads/2022/07/d402be907bf0ee74f9251569549ca330-200x55.jpg 200w, https://blog.monora.me/wp-content/uploads/2022/07/d402be907bf0ee74f9251569549ca330-768x210.jpg 768w, https://blog.monora.me/wp-content/uploads/2022/07/d402be907bf0ee74f9251569549ca330-1536x420.jpg 1536w, https://blog.monora.me/wp-content/uploads/2022/07/d402be907bf0ee74f9251569549ca330-2048x560.jpg 2048w" sizes="(max-width: 640px) 100vw, 640px" /></figure>



<h3>16:36 10253点</h3>



<p>なんかヤバそうな実装の dispenseId を倒しました。1万点突破。<br />よくわからんけど順序保証されてたほうが良さそうな気がしたので、 time.Now().UnixNano() を文字列にしてそのまま突っ込みました。爆速。</p>



<p>たしかこのあたりで、 tenant の <code>player_score</code> は <code>(tenant_id, competition_id, player_id)</code> ごとに最新の1行だけあればいいことに h-otter が気付きましたが、あまり速くならず。<br />この時点で row_num に関する index を落とすべきでした。</p>



<p>既存の <code>tenant_{1..100}</code> に対してもそれを適用しましたが、スコアとしては特に変化なしでした。</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="640" height="188" src="https://blog.monora.me/wp-content/uploads/2022/07/69e135768348aefdc430576563a0b8fb-640x188.jpg" alt="" class="wp-image-2414" srcset="https://blog.monora.me/wp-content/uploads/2022/07/69e135768348aefdc430576563a0b8fb-640x188.jpg 640w, https://blog.monora.me/wp-content/uploads/2022/07/69e135768348aefdc430576563a0b8fb-320x94.jpg 320w, https://blog.monora.me/wp-content/uploads/2022/07/69e135768348aefdc430576563a0b8fb-200x59.jpg 200w, https://blog.monora.me/wp-content/uploads/2022/07/69e135768348aefdc430576563a0b8fb-768x226.jpg 768w, https://blog.monora.me/wp-content/uploads/2022/07/69e135768348aefdc430576563a0b8fb-1536x452.jpg 1536w, https://blog.monora.me/wp-content/uploads/2022/07/69e135768348aefdc430576563a0b8fb-2048x602.jpg 2048w" sizes="(max-width: 640px) 100vw, 640px" /></figure>



<p>このあたりでベンチマーカのログから、タイムアウトでユーザーが減ったという表示がなくなり、ようやくISUCON始まったな! という気持ちになります。すでに手遅れ。</p>



<h3>17:03 12505点</h3>



<p>h-otter が jwt のパース結果をキャッシュします。神</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="640" height="236" src="https://blog.monora.me/wp-content/uploads/2022/07/8b40f5fa7a5b915e094f0c19106aaaf3-640x236.jpg" alt="" class="wp-image-2417" srcset="https://blog.monora.me/wp-content/uploads/2022/07/8b40f5fa7a5b915e094f0c19106aaaf3-640x236.jpg 640w, https://blog.monora.me/wp-content/uploads/2022/07/8b40f5fa7a5b915e094f0c19106aaaf3-320x118.jpg 320w, https://blog.monora.me/wp-content/uploads/2022/07/8b40f5fa7a5b915e094f0c19106aaaf3-200x74.jpg 200w, https://blog.monora.me/wp-content/uploads/2022/07/8b40f5fa7a5b915e094f0c19106aaaf3-768x283.jpg 768w, https://blog.monora.me/wp-content/uploads/2022/07/8b40f5fa7a5b915e094f0c19106aaaf3-1536x566.jpg 1536w, https://blog.monora.me/wp-content/uploads/2022/07/8b40f5fa7a5b915e094f0c19106aaaf3-2048x754.jpg 2048w" sizes="(max-width: 640px) 100vw, 640px" /></figure>



<h3>17:45 14363点</h3>



<p>app + DB の2台構成にした気がします。</p>



<h3>17:50 15962点</h3>



<p>流石にやや諦めムード。ログを切ったりできることをしました。<br />忘れずDEBUGログを切ったりスロークエリーを切ったりしました。偉い。</p>



<p>「再起動試験はしなくていいでしょ！」で終了</p>



<h2>感想</h2>



<ol><li>MySQL 移行をバグらせずに完遂できた俺達は偉い (本当に偉いと思っている)</li><li>毎回意味不明なバグを仕込んで後半暗澹たる感じにあるので、今回はほぼ最後までノーバグで駆け抜けられたのは良かった。良くも悪くも我々は大人になった</li><li>プロファイラ / スロークエリ / アクセスログの3本柱をちゃんと見ながら走れたのは本当に良かった。常に事実は正しい。fact based / metrics-driven</li><li>後半のスコアのブチ上がり方が楽しかった。というかここに来るまでを自分は第一関門を突破した段階だと思っている。やれる改善はたくさん残っていたし、あと1時間あれば更に2倍, 3倍のスコアは出ていたんだろうなと思うと悔しい</li></ol>



<p>そのほか</p>



<ol><li>午前中からの競技は本当に心も体も終了していて何も捗らなかった。ISUCONに必要なのは健康な心と身体</li><li>デカいテレビで h-otter がリゼ・ヘルエスタと名取さなの原神ガチャ配信をずっと流していた。「縁起がいいと思ったんだけどなあ」って何?</li><li>その後はリゼがパワプロしてた。リゼ・ヘルエスタについて私が知っているのは第一第二第三皇女のいずれかであるということぐらいです。</li><li>最後1時間ぐらいローテンションお嬢様 (壱百満天原サロメ)流したら集中力が0になった。何?</li></ol>



<p></p>The post <a href="https://blog.monora.me/2022/07/participated-in-isucon12-qual/">ISUCON12 予選に参加しました (最終スコア15532点)</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2405</post-id>	</item>
		<item>
		<title>ICTSCのコンテストサイトを支えた技術</title>
		<link>https://blog.monora.me/2020/12/technology-that-supports-ictsc-contest-site/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=technology-that-supports-ictsc-contest-site</link>
		
		<dc:creator><![CDATA[きょんたん]]></dc:creator>
		<pubDate>Wed, 09 Dec 2020 15:00:34 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[ICTSC]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[whywaita Advent Calendar]]></category>
		<guid isPermaLink="false">https://blog.monora.me/?p=1653</guid>

					<description><![CDATA[<p>この記事は whywaita Advent Calendar 2020 の10日目の記事です。2週目です。来週何を書くか考えるだけで気が遠くなります。 昨日は @icchy さんで 「whywaitaであいうえお作文する [&#8230;]</p>
The post <a href="https://blog.monora.me/2020/12/technology-that-supports-ictsc-contest-site/">ICTSCのコンテストサイトを支えた技術</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></description>
										<content:encoded><![CDATA[<p>この記事は <a href="https://adventar.org/calendars/5082">whywaita Advent Calendar 2020</a> の10日目の記事です。2週目です。来週何を書くか考えるだけで気が遠くなります。</p>



<p>昨日は @icchy さんで 「whywaitaであいうえお作文する」でした。タイトルだけでだいたい想像できますね。</p>



<figure class="wp-block-embed-twitter wp-block-embed is-type-rich is-provider-twitter"><div class="wp-block-embed__wrapper">
<blockquote class="twitter-tweet" data-width="550" data-dnt="true"><p lang="en" dir="ltr">whywaita: huge youth with aged insight to alcohol<br><br>(ref: <a href="https://t.co/dydlSQ25jD">https://t.co/dydlSQ25jD</a>) <a href="https://t.co/5ZLXsnMMM7">pic.twitter.com/5ZLXsnMMM7</a></p>&mdash; マットレス, がりょ1000 (@icchyr) <a href="https://twitter.com/icchyr/status/1336325587929976834?ref_src=twsrc%5Etfw">December 8, 2020</a></blockquote><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</div></figure>



<p>なるほど。</p>



<p><br />@icchy さんのおすすめインターネットコンテンツは<a href="https://alcoholog.hatenablog.jp/" title="https://alcoholog.hatenablog.jp/">飲酒日記</a>です。</p>



<figure class="wp-block-embed-wordpress wp-block-embed is-type-wp-embed is-provider-hatena-blog"><div class="wp-block-embed__wrapper">
<iframe class="wp-embedded-content" sandbox="allow-scripts" security="restricted" title="2020/12/01 - 飲酒日記" src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Falcoholog.hatenablog.jp%2Fentry%2F2020%2F12%2F01%2F015540#?secret=kafpNdDwCr" data-secret="kafpNdDwCr" scrolling="no" frameborder="0"></iframe>
</div></figure>



<p>閑話休題。<br />アドベントカレンダー、書くネタはあれど頭を使うものばかりで泣きそうになったので、とりあえず過去の下書きを漁っていたらタイトルだけ書かれたこの記事の下書きを見つけました。<br />最近思うこともあったので、すでに忘れ去られ、誰もが忘れたままでいたいと思っていたICTSCのコンテストサイトの歴史を紐解いてみたいと思います。<br />whyawitaさんとの関わりもあるし、whywaita Advent Calendar的には100点満点のネタですね。よろしくお願いします。</p>



<span id="more-1653"></span>



<h3>ICTSCとは</h3>



<p>早速本題に入りたいのですが、そのためにはICTSCに関する簡単な知識が必要です。<br /><a href="https://icttoracon.net/archives/8570" title="https://icttoracon.net/archives/8570">ICTSC (ICTトラブルシューティングコンテスト)</a> は学生による学生のためのインフラ技術を競うコンテストで、最近は年1回開催されています。途中でナンバリングが回数から年号になるの、あるあるって感じですね。<br />予選もありますが、予選のことは一旦考えないこととして、本選の話をします。選ばれた本選の参加者は、当日の限られた制限時間内に与えられる問題へ挑むことになります。</p>



<p>問題は次のような形式で与えられます。</p>



<blockquote class="wp-block-quote"><p>「A社の技術者であるXさんは、自社の端末からあるWebサイトを開こうとするといつも失敗することに気が付きました。A社の社内ネットワークのトポロジは下の図のようになっており(省略)、ルータの管理コンソールへアクセスするために必要な情報はXXです。あなたはXさんに変わってこの問題を解決してください」</p><p>管理コンソールのIP: xxx.yyy.zzz.www<br />ユーザ名: admin<br />パスワード: nyannyan<br /><br />社内端末のIP, ユーザ名, パスワード: &#8230;</p></blockquote>



<p>参加者はこれらの情報を元に、持てる限りの知識と経験を活かして挑み、気合で問題を解決することになります。<br />(大会インフラとしてはVMがいて、仮想ないし物理のルータがいて……となりますが、今回の本題からはそれるので割愛します)</p>



<p>そうして、問題に不明点があれば質問をし (競技界隈では clar(ification) と呼ばれたりするみたいですね)、解決に必要な情報をまとめて回答します。基本的に回答はテキストで自由な形式で行われます。<br />運営は提出された回答を読み、必要があれば実際にVMへアクセスして回答の検証をし、採点を行います。<br />採点を行った結果、正答であれば点数が加算され、不正答であれば改めて参加者が挑戦する、というのが一連の流れになります。</p>



<h3>コンテストサイトの必要性</h3>



<p>ICTSCでは、約15問の問題が2日間かけて出題され、参加チーム数も15チーム近くに上ります。賞金が出るということもあり、運営は限られた時間内に公平性をできるだけ保ちつつ採点や質問対応といったタスクをこなさなければなりません。<br />15チームというのは意外と少なく見えますが、人数でいうと60人から80人近くおり、1つのチームでも分担して複数の問題に取り組んでいたりします。そうなると、意外と想像を絶する数の質問や回答が来ます。15チーム×15問で単純に225回答ですし。</p>



<p>私がICTSCの運営にジョインしたのは、遠い昔のICTSC5でした。当時はプロジェクト管理ツールである <a href="https://redmine.jp/" title="https://redmine.jp/">Redmine</a> を使って出題を行っていました。チームごとにプロジェクトを立て、問題ごとにIssueを立てて、そのコメントで質問や回答の管理をしていた気がします。<br />この構成で実際に開催を行ったところ、様々なトラブルが生じました。<br />質問や回答の状況が適切に把握できない(どの質問にまだ返答してないのか?採点は行われたか?)だけでなく、特定チームへの紙のトポロジ図の配布漏れ (これなんで紙で配ってたんでしたっけ?) などが生じました。</p>



<p>今思えばこれなんで起きたんだ?みたいなトラブルですね。Redmineを賢く使えば良かったのではないかと思ってきた……</p>



<p>さて、こういった課題に対処するために若者がやることは一つですね?<br />そう、<strong>「僕が考えた最強のコンテストサイトで解決しよう」</strong>です！</p>



<h3>コンテストサイトの開発</h3>



<p>さて、経緯はどうあれコンテストサイトの開発が始まります。正確にはすでに私の知らないところで一度頓挫していたのですが、忘れます。</p>



<p>今のコンテストサイトは様々あり(後述)、私が知らない構成になっているので、とりあえず私が知っている構成の最後の回のブランチへのリンクを貼ります。</p>



<p><a href="https://github.com/ictsc/ictsc-score-server/tree/ictsc2018">GitHub: ictsc/ictsc-score-server at ictsc2018</a></p>



<p>さて、途中で採用技術が二転三転している(なぜ?)ので、老害らしく順を追っていくことにしましょう。</p>



<h4>ICTSC6</h4>



<p>輝かしいコンテストサイト初回導入のときです。当時関わっていた人からはICTSC6の文字列すら見たくないという話も聞きます。当時の振り返りはこちら。</p>



<figure class="wp-block-embed-wordpress wp-block-embed is-type-wp-embed is-provider-monolog"><div class="wp-block-embed__wrapper">
<blockquote class="wp-embedded-content" data-secret="bWqUq8X13t"><a href="https://blog.monora.me/2016/10/had-been-a-steering-committee-of-ictsc6/">第6回 ICTトラブルシューティングコンテストの運営委員をしていました</a></blockquote><iframe class="wp-embedded-content" sandbox="allow-scripts" security="restricted" title="&#8220;第6回 ICTトラブルシューティングコンテストの運営委員をしていました&#8221; &#8212; monolog" src="https://blog.monora.me/2016/10/had-been-a-steering-committee-of-ictsc6/embed/#?secret=bWqUq8X13t" data-secret="bWqUq8X13t" width="600" height="338" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe>
</div></figure>



<p><a href="https://github.com/ictsc/ictsc-score-server/tree/ictsc6">https://github.com/ictsc/ictsc-score-server/tree/ictsc6</a></p>



<p>開発が始まりました、技術的には、特に面白みのない簡単な REST API + SPA 構成です。</p>



<p>私はフロントエンド技術には疎かったので、同じ運営学生のメンバーの方と、スポンサーの中の方々に協力して頂きました。<br />一体本業外のこんなことにどれだけの工数を割いていただいたのか、想像を絶する状況になっていたことだろうと思います。本当にありがとうございました。</p>



<p>特に、デザイナーの方にはふわっとしたユースケースから具体的な行動パターンの書き起こしから何から何までお世話になってばかりでした。特に、第6回は初めてコンテストサイトを導入するので何が起こるかわからない、というときに「じゃあ念の為に紙の解答用紙も作っておきますね!」とネタで解答用紙までデザインして渡していただいたときは笑いました。</p>



<p>さて、当時の採用技術は次の通りです。</p>



<ul><li>REST API<ul><li>Ruby</li><li>Sinatra (Ruby のシンプルなWebフレームワーク)</li><li>ActiveRecord (Rails で使われている O/Rマッパー)</li><li>(SQLite3)</li></ul></li><li>Web UI (SPA)<ul><li>Angular 2.0</li><li>RxJS 5.0</li></ul></li></ul>



<p>REST API の方は私がRailsの経験がほとんどなかったので必然的にこうなりました。Web UIはおまかせしたらこうなりました。<a href="https://github.com/ictsc/ictsc-score-server/blob/ictsc6/ui/package.json" title="https://github.com/ictsc/ictsc-score-server/blob/ictsc6/ui/package.json">package.json</a> 見るとわかるんですけど、Angular 2.0 って当時まだRCなんですよね。尖ってますね<br />RxJSが使われたコード、当時ちょっと弄ろうとしたら手も足も出なかったきおくがあります。今なら読めるかもしれない</p>



<p>ところで、当時のREST APIには致命的な設計ミスがあり、REST APIでN+1をしていました。例えば、参加者が問題文の書かれたページを開くと、次のようなアクセスが走ります。</p>



<ul><li><code>/problems/2</code></li><li><code>/problems/2/comments</code></li><li><code>/problems/2/issues</code></li><li><code>/problems/2/issues/37/comments</code></li><li><code>/problems/2/issues/39/comments</code></li><li>&#8230;</li><li><code>/problems/2/answers</code></li><li><code>/problems/2/answers/27</code></li><li><code>/problems/2/answers/27/comments</code></li><li>&#8230;</li></ul>



<p>うーんひどい、典型的なN+1ですね。</p>



<p>N+1 はデータ量が少ないと影響が見えにくいので、この問題は回答や質問量が増えてきた2日目に顕著になりました。<br />そして当時の私はDBにインデックスを貼るということを知らなかったらしい。いま schema.rb 見て吐き気が……</p>



<p>そして、運営は全ての参加者の回答や質問を見ることができる、つまりどうなるでしょうか? 大変なことになります。<br />10秒経っても帰ってこないAPIが乱舞して開発者ツールはさながらナイアガラの滝の様相を呈していました。同一IPに同時に張れるセッション数限界までリクエストが飛んでドーン、返ってきたら第2弾がドーン、もう見たくない……</p>



<p>当時は完全にテンパっていたのでAPI側の修正を入れる余裕はなく、フロントエンド側で急遽キャッシュ等の対応を入れてもらったものの、却って新しいリソースが見えなくなるなどして大変でした。</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="640" height="344" src="https://blog.monora.me/wp-content/uploads/2020/12/b0b2b8f0-2cc5-4725-ad4f-e39880c3d9d1-640x344.png" alt="" class="wp-image-2210" srcset="https://blog.monora.me/wp-content/uploads/2020/12/b0b2b8f0-2cc5-4725-ad4f-e39880c3d9d1-640x344.png 640w, https://blog.monora.me/wp-content/uploads/2020/12/b0b2b8f0-2cc5-4725-ad4f-e39880c3d9d1-320x172.png 320w, https://blog.monora.me/wp-content/uploads/2020/12/b0b2b8f0-2cc5-4725-ad4f-e39880c3d9d1-200x107.png 200w, https://blog.monora.me/wp-content/uploads/2020/12/b0b2b8f0-2cc5-4725-ad4f-e39880c3d9d1-768x412.png 768w, https://blog.monora.me/wp-content/uploads/2020/12/b0b2b8f0-2cc5-4725-ad4f-e39880c3d9d1.png 1278w" sizes="(max-width: 640px) 100vw, 640px" /><figcaption>私が出題した問題の問題詳細ページ。VoIPに関するトラブルを出題しました。</figcaption></figure>



<p>そんなこんながありつつも、なんとか(?)大会は閉幕。次回への課題を残しつつ、コンテストは第7回へ続きます。</p>



<h4>ICTSC7</h4>



<p>知り合いのOB、みんなICTSC7の話しかしたがらんがち。<br /><a href="https://github.com/ictsc/ictsc-score-server/tree/ictsc7">https://github.com/ictsc/ictsc-score-server/tree/ictsc7</a></p>



<figure class="wp-block-embed-wordpress wp-block-embed is-type-wp-embed is-provider-monolog"><div class="wp-block-embed__wrapper">
<blockquote class="wp-embedded-content" data-secret="bDdjtuEqVu"><a href="https://blog.monora.me/2017/03/had-been-a-steering-committee-of-ictsc7/">ICTSC7 の運営委員を務めました</a></blockquote><iframe class="wp-embedded-content" sandbox="allow-scripts" security="restricted" title="&#8220;ICTSC7 の運営委員を務めました&#8221; &#8212; monolog" src="https://blog.monora.me/2017/03/had-been-a-steering-committee-of-ictsc7/embed/#?secret=bDdjtuEqVu" data-secret="bDdjtuEqVu" width="600" height="338" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe>
</div></figure>



<p>ICTSC6で辛酸を嘗めた私達[誰?]は、次こそは運営がトラブルシューティングしないコンテストにすべく様々な改善を行いました。</p>



<ul id="block-735dd9a3-4515-4519-855b-169cbe3c82ed"><li>REST API<ul><li>Ruby</li><li>Sinatra (Ruby のシンプルなWebフレームワーク)</li><li>ActiveRecord (Rails で使われている O/Rマッパー)</li><li>MySQL (MariaDBだったかも?)</li></ul></li><li>Web UI (SPA)<ul><li>Vue.JS 2.1</li><li>Vuex 2.0</li></ul></li></ul>



<p>API は N+1 問題を潰すべく、様々な対策が取られました。<br />その集大成が <a href="https://github.com/ictsc/ictsc-score-server/blob/ictsc7/services/nested_entity.rb" title="https://github.com/ictsc/ictsc-score-server/blob/ictsc7/services/nested_entity.rb">nested_entity.rb</a> です。この100行に満たないコードがこのコンテストサイトの真価といっても過言ではないでしょう。私はそう思います。<br />これは要するに「僕の考えた最強のGraphQLっぽいやつ」で、指定した関連リソースをいい感じに取ってきてくれます。<a href="https://github.com/ictsc/ictsc-score-server/blob/d5fc08d0f0d889092f5390885fa9c7669a4d06a1/controllers/problem.rb#L23">こうやって</a>使います。 こんな読みづらい使い方だからだめなんだわ。</p>



<p>これを使うと、上記のICTSC6の例が次の1リクエストで完結します。</p>



<ul><li><code>/problems/2?with=comments,issues-comments,answers-comments</code></li></ul>



<p>便利なのは分かりました。さて、ここで内部的には何をやっているのかというと、大きく次の2つのことを行っています。</p>



<ul><li>アクセスするユーザの権限によるRBAC (Role-Based Access Control) の適用</li><li>N+1を避けるクエリの生成</li></ul>



<p>コンテストサイトのユーザには、参加者や運営、スポンサーといったロールが割り当てられており、それぞれ見ることができる情報に差があります。例えば参加者が他チームの回答を見られては困りますね。</p>



<p>これ、すなわちRBACを実現するために、全てのロールに対してあらゆるモデルで読めるものを ActiveRecord の scope で定義しています。例えば<a href="https://github.com/ictsc/ictsc-score-server/blob/d5fc08d0f0d889092f5390885fa9c7669a4d06a1/db/model.rb#L421-L430" title="https://github.com/ictsc/ictsc-score-server/blob/d5fc08d0f0d889092f5390885fa9c7669a4d06a1/db/model.rb#L421-L430">こんな感じ</a>です。<br />scope とは何かというと、あらかじめ用意されたパラメータの指定可能なクエリといえばいいでしょうか。scope は <code>ActiveRecord::Relation</code> 型の値を返します。これは何かというと、ActiveRecord の抽象的なクエリ表現なので、これを更に合成したりできます。便利</p>



<p>クエリレベルでもN+1を避けるためにはどうしたら良いでしょうか? 気合でクエリを合成したらできそうです。<br />なんと ActiveRecord はクエリに <code>include</code> パラメータを渡すと勝手に合成してくれます。そうしましょう。<br />nested_entity.rb では、<a href="https://github.com/ictsc/ictsc-score-server/blob/d5fc08d0f0d889092f5390885fa9c7669a4d06a1/services/nested_entity.rb#L45-L47" title="https://github.com/ictsc/ictsc-score-server/blob/d5fc08d0f0d889092f5390885fa9c7669a4d06a1/services/nested_entity.rb#L45-L47">このあたり</a>で与えられたクエリパラメータをいい感じに ActiveRecord が解釈できる形に変換しています。</p>



<p>全てが ActiveRecord の世界で簡潔するので、RBACもN+1もクエリレベルで表現されます。これはすごくて、あとは全てのロールがアクセスできるリソースをActiveRecordのクエリで表現できれば大丈夫です。<a href="https://github.com/ictsc/ictsc-score-server/blob/d5fc08d0f0d889092f5390885fa9c7669a4d06a1/db/model.rb#L220-L247">つらい</a>、<a href="https://github.com/ictsc/ictsc-score-server/blob/d5fc08d0f0d889092f5390885fa9c7669a4d06a1/db/model.rb#L481-L513">二度とやりたくない</a>。</p>



<p>ちゃんとDBもMySQLにしてインデックスも貼ったので、APIも水平スケールできるようになりました。こうしてコンテストサイトの Iikanji Speed-Up に成功した我々は、その後数回に渡って予選敗退を繰り返しました。何が足りないん?</p>



<p>そして、フロントエンド担当のエンジニアの方の異常な熱意により、唐突に <a href="https://github.com/ictsc/ictsc-score-server/tree/ictsc7/ui2" title="https://github.com/ictsc/ictsc-score-server/tree/ictsc7/ui2">ui2</a> ディレクトリが爆誕しました。突然のAngular引退宣言に人々は涙を禁じえませんでした。</p>



<p>そうして開催されたICTSC7は、少なくともコンテストサイトについては成功裏に終わったといっても過言ではないでしょう。</p>



<p>ユーザから見える部分としては、問題がこれまでの2日間の午前午後、計4パートでの固定出題から、問題を解くごとに次の問題が解けるようになったり、最初に問題を解いたチームに追加点数(first blood)を与えるようになったりという変化の方が大きかったかもしれませんが、これもコンテストサイトの貢献ということで。</p>



<p>ちなみにこの頃のスクリーンショットがこちら。</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="640" height="356" src="https://blog.monora.me/wp-content/uploads/2017/03/ictsc7-contest-site-640x356.png" alt="ICTSC7 コンテストサイト" class="wp-image-1599" srcset="https://blog.monora.me/wp-content/uploads/2017/03/ictsc7-contest-site-640x356.png 640w, https://blog.monora.me/wp-content/uploads/2017/03/ictsc7-contest-site-200x111.png 200w, https://blog.monora.me/wp-content/uploads/2017/03/ictsc7-contest-site-320x178.png 320w, https://blog.monora.me/wp-content/uploads/2017/03/ictsc7-contest-site-768x428.png 768w, https://blog.monora.me/wp-content/uploads/2017/03/ictsc7-contest-site.png 1440w" sizes="(max-width: 640px) 100vw, 640px" /><figcaption>ICTSC8におけるコンテストサイトのトップ画面</figcaption></figure>



<figure class="wp-block-image size-large"><img loading="lazy" width="640" height="218" src="https://blog.monora.me/wp-content/uploads/2020/12/bf705b46-8524-43f3-a4b9-8c2698fd1a86-640x218.png" alt="" class="wp-image-2211" srcset="https://blog.monora.me/wp-content/uploads/2020/12/bf705b46-8524-43f3-a4b9-8c2698fd1a86-640x218.png 640w, https://blog.monora.me/wp-content/uploads/2020/12/bf705b46-8524-43f3-a4b9-8c2698fd1a86-320x109.png 320w, https://blog.monora.me/wp-content/uploads/2020/12/bf705b46-8524-43f3-a4b9-8c2698fd1a86-200x68.png 200w, https://blog.monora.me/wp-content/uploads/2020/12/bf705b46-8524-43f3-a4b9-8c2698fd1a86-768x262.png 768w, https://blog.monora.me/wp-content/uploads/2020/12/bf705b46-8524-43f3-a4b9-8c2698fd1a86.png 1398w" sizes="(max-width: 640px) 100vw, 640px" /><figcaption>問題一覧画面の一部。このときは、出題された問題群ごとにちゃんと設定があり、その説明文が左に表示されていました。</figcaption></figure>



<h4>ICTSC8</h4>



<p>ICTSC8の記憶があまりありません。</p>



<figure class="wp-block-embed-wordpress wp-block-embed is-type-wp-embed is-provider-monolog"><div class="wp-block-embed__wrapper">
<blockquote class="wp-embedded-content" data-secret="jTDaqetJT9"><a href="https://blog.monora.me/2017/10/had-been-a-steering-committee-of-ictsc8/">ICTSC8 の運営委員を務めました</a></blockquote><iframe class="wp-embedded-content" sandbox="allow-scripts" security="restricted" title="&#8220;ICTSC8 の運営委員を務めました&#8221; &#8212; monolog" src="https://blog.monora.me/2017/10/had-been-a-steering-committee-of-ictsc8/embed/#?secret=jTDaqetJT9" data-secret="jTDaqetJT9" width="600" height="338" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe>
</div></figure>



<p><br /><a href="https://github.com/ictsc/ictsc-score-server/tree/ictsc8">https://github.com/ictsc/ictsc-score-server/tree/ictsc8</a><br />コミットログを見ると、たしかに差分はあるけどあまり変わってないですね。確かプッシュ通知を実装しました。CyberAgentのFRESHチーム?が作った <a href="https://github.com/opensaasstudio/plasma" title="https://github.com/opensaasstudio/plasma">plasma</a> を使っています。</p>



<p>ICTSC8では小さなバグフィックスやルール変更の対応等はあったものの、それよりはテストを書くことにご執心だったようです。RSpecの鬼になったkyontanの姿が垣間見えますね。増える緑の. (RSpecではテストケースが1つPASSするごとに.がプリントされた)にエクスタシーでも感じていたんでしょうか。<br /><a href="https://github.com/ictsc/ictsc-score-server/tree/ictsc8/spec/requests">https://github.com/ictsc/ictsc-score-server/tree/ictsc8/spec/requests</a><br />相変わらず<a href="https://github.com/ictsc/ictsc-score-server/blob/fb5884fc643facdd0a76cd54f2cbe3be0a58cce1/spec/support/api_helpers.rb#L25-L55" title="https://github.com/ictsc/ictsc-score-server/blob/fb5884fc643facdd0a76cd54f2cbe3be0a58cce1/spec/support/api_helpers.rb#L25-L55">へんなヘルパー</a>定義しててウケました。そんなんだからお前のコードは人に読まれない。</p>



<p>そうして満足したので運営委員を引退しました。それはそれとして、参加記を見ると毎回のように後悔が綴られていますね。</p>



<h4>ICTSC9</h4>



<p>関わっていないのでほとんど分かりません。</p>



<p><a href="https://github.com/ictsc/ictsc-score-server/blob/3730cfaa8d62b14a573a1e3a5998f045993e2504/services/nested_entity.rb#L16">https://github.com/ictsc/ictsc-score-server/blob/3730cfaa8d62b14a573a1e3a5998f045993e2504/services/nested_entity.rb#L16</a></p>



<p>ほんまにすまんて</p>



<h4>ICTSC2018</h4>



<p>運営に出戻ったものの何したのか覚えてません。コンテストサイトには手を出していないはず。</p>



<p>このあたりで API 向けの CLI が生えたらしい。今までシードデータ投入をSQLでやってたのを、 REST API 経由でやるようにしたんですかね。</p>



<p><a href="https://github.com/ictsc/ictsc-score-server/tree/ictsc2018/cli">https://github.com/ictsc/ictsc-score-server/tree/ictsc2018/cli</a></p>



<p>あとはしれっと Kubernetes 化とかされている。モダンなインフラってやつ</p>



<p>私が知るのはここまでです</p>



<hr class="wp-block-separator"/>



<h4>ICTSC2019</h4>



<p><a href="https://github.com/ictsc/ictsc-score-server/commit/5d5fd505944f7df9314b5e6378c770fbd9cb6182">Big Bang! · ictsc/ictsc-score-server@5d5fd50</a></p>



<p>唐突に api2 と ui3 が爆誕する。担当者のキレ具合が垣間見えますね。僕も同情します。</p>



<ul id="block-3550f266-a2d7-42cf-ace3-fdc2ecf144a8"><li>REST API<ul><li>Ruby</li><li>Rails 6.0</li><li>GraphQL</li><li>PostgreSQL</li></ul></li><li>Web UI (SPA)<ul><li>Nuxt.js 2.0</li><li>Apollo Client 2.6</li></ul></li></ul>



<p>ザ・モダン・Webアプリケーション大全。僕の心境としては「GraphQLもどきを作って公園で砂遊びしてたらいつのまにか本物のGraphQLで置き換えられていた、何が起きているのか(ry」って感じです。<br />DB が Postgres に変わったのはなんでなんでしょうね? 僕は理由を知らないので知っている人がいたら教えて下さい。</p>



<p>増えた機能が多すぎて良くわかりませんが、Webでだいたいのリソースが編集できるようになってたり、問題VMへのアクセスに必要な情報を専用のテーブルで管理できるようになったりしたようです。憶測ですが、VMをプロビジョニングするいい感じのツールと連携していい感じにできるんじゃないですかね。</p>



<p>こうして生み出したプロダクトが自分の手を離れて育っていく様子をまだ学生の身にして実感することができました。ハッピー。</p>



<h3>万物は流転する</h3>



<p>私事になりますが、先日<a href="https://www.janog.gr.jp/meeting/janog47/" title="https://www.janog.gr.jp/meeting/janog47/">JANOG47</a>？っていう日本最大級のネットワークエンジニアの集まり？ってやつでNETCONっていうあいしーてぃーえすしー？みたいなのをやるって言われてあれやそれやで運営委員になりました。</p>



<p>どうやらコンテストサイトが必要らしいんですよね。</p>



<p>………というわけで最近<a href="https://github.com/janog-netcon/netcon-score-server" title="https://github.com/janog-netcon/netcon-score-server">fork</a>しました。これどうしたらいいんですか?</p>



<p>そんなこんなで、泣きながら Ruby の GraphQL実装を調べています。ドキュメントの大切さが目に染みる。</p>



<p>明日は同期だったはずのくるとんさんです。ワンワールドサファイアステータスを求めて飛び回りたいという発言を最近目にしましたがお元気ですか?</p>The post <a href="https://blog.monora.me/2020/12/technology-that-supports-ictsc-contest-site/">ICTSCのコンテストサイトを支えた技術</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1653</post-id>	</item>
		<item>
		<title>ISUCON9 予選の参加ログ (チーム: 再起動非対応)</title>
		<link>https://blog.monora.me/2019/09/reboot-not-supoprted-at-isucon9-qual/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=reboot-not-supoprted-at-isucon9-qual</link>
		
		<dc:creator><![CDATA[きょんたん]]></dc:creator>
		<pubDate>Sun, 08 Sep 2019 13:44:34 +0000</pubDate>
				<category><![CDATA[Infrastructure]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[ISUCON]]></category>
		<category><![CDATA[コンテスト]]></category>
		<category><![CDATA[参加しました]]></category>
		<guid isPermaLink="false">https://blog.monora.me/?p=1998</guid>

					<description><![CDATA[<p>こんばんは、kyontanです。 前回再起動試験で落ちたのでチーム「再起動非対応」で参加しました。ベストスコアは4410点でした。再起動試験までたどり着けなかった……悔しい…… チーム「再起動非対応」は同期3人 (自分  [&#8230;]</p>
The post <a href="https://blog.monora.me/2019/09/reboot-not-supoprted-at-isucon9-qual/">ISUCON9 予選の参加ログ (チーム: 再起動非対応)</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></description>
										<content:encoded><![CDATA[<p>こんばんは、kyontanです。</p>
<p><a href="https://blog.monora.me/2018/09/failed-reboot-test-in-isucon8-qual/">前回</a>再起動試験で落ちたのでチーム「再起動非対応」で参加しました。ベストスコアは<strong>4410点</strong>でした。再起動試験までたどり着けなかった……悔しい……</p>
<p>チーム「再起動非対応」は同期3人 (自分 @kyontan, <a href="https://hogashi.hatenablog.com/">@hogashi</a>, <a href="https://h-otter.hatenablog.jp/">@h-otter</a>) での参加でした。学生は2人いたはずですがエントリーをミスったので学生は1人ということになっています。</p>
<p><span id="more-1998"></span></p>
<h3>使用した言語</h3>
<p>私はRubyが一番得意だと思っていますが、非同期処理が書きやすいとか型が着いていると嬉しい、みたいなことはあり今回も<strong>Go</strong>言語です。<br />
でも今回はN+1潰すときの型マッピングで無駄に時間を溶かしてしまったので、Rubyの方が良かったかもしれない……つらい……</p>
<h3>開始前の準備</h3>
<p>Prometheus/Grafana等のサーバの設定を @h-otter にお願いしました。前回のコードを読み返しつつ、何をしたかを思い出すなどした。</p>
<p>時間がなくて完全に忘れてしまいましたが、せめて練習はやっておくべきでしたね…</p>
<p>あと、 Alibaba Cloud の UI が色々不思議な感じで良かったですね。</p>
<h3>本番</h3>
<p>完全に正解していますが、今回はマイクロサービス問だということに気が付いたのは開始してからだいぶ経ってからでした。</p>
<blockquote class="twitter-tweet" data-width="550" data-dnt="true">
<p lang="ja" dir="ltr">開始30分前、チームメイトとの雑談「今日は何がでるかなー」「フリマアプリかオークションかそういうやつでしょ」「マイクロサービスとかね」「わかる〜」 <a href="https://twitter.com/hashtag/isucon?src=hash&amp;ref_src=twsrc%5Etfw">#isucon</a></p>
<p>&mdash; kyontan@新刊はまだ (@sukukyon) <a href="https://twitter.com/sukukyon/status/1170651769401069568?ref_src=twsrc%5Etfw">September 8, 2019</a></p></blockquote>
<p><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></p>
<p>今回できたことが異常に少ない気がする。kataribeのログを眺めつつ、チームでやったことは以下のことです。比較的時系列だけどそうでない部分もあるかも。</p>
<ul>
<li>開始スコアは <strong>2310</strong></li>
<li>10:30 メモリ多いな〜って思っていたら2, 3台目のインスタンスタイプを間違えていたことに気がつく。インスタンス立て直し
<ul>
<li>コードは既にリポジトリへ追加していたのでチームメイトはルール/コードリーディングを進める</li>
</ul>
</li>
<li>10:50ごろ: 作業開始</li>
<li>11:30ごろ?: MySQL 5.7 を 8.0 へ (@h-otter)
<ul>
<li>スコア変化なし</li>
</ul>
</li>
<li>11:45 DBにインデックスを張る(@kyontan)
<ul>
<li>多分間違えていて、これらにインデックスを貼りましたがあまり効いていなかったようにみえました</li>
<li>BigQuery の触りすぎでRDBのインデックスの挙動をほぼ忘れたのも敗北ポイント</li>
</ul>
</li>
</ul>
<pre class="EnlighterJSRAW" data-enlighter-language="raw">config (name)
items (created_at, id)
items (id)
items (buyer_id)
items (seller_id)
shippings (transaction_evidence_id)
transaction_evidences (id)
transaction_evidences (item_id)
users (account_name)
users (id)
</pre>
<ul>
<li>12:20: カテゴリをオンメモリへ (@hogas, @h-otter)
<ul>
<li><strong>2510点</strong>ぐらい</li>
</ul>
</li>
<li>12:30: http2 対応, 静的ファイルをキャッシュ, アップロードされた画像を nginx で返すなど
<ul>
<li>スコア変化なし</li>
</ul>
</li>
<li>13:30: config もキャッシュするように</li>
<li>14:00: 新着商品には発売中の商品だけを返すようにする (@hogas)</li>
<li>14:45  &#8211; 16:00: <code>GET /users/transactions.json</code><span style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif;"> の N+1 を潰す (@kyontan)</span>
<ul>
<li><strong>3500点</strong>ぐらい</li>
<li>なぜか色々ハマって2時間半ぐらい溶かしていた。これは敗北ポイント</li>
<li>多分ここらへんでMySQLがサチらなくなっていた気がする
<ul>
<li>CPUがサチっていたことに気が付いていたが原因が分からず (pprofをなぜ見なかったのか……)</li>
</ul>
</li>
</ul>
</li>
<li>15:30: <code>UserSimple</code> が持つ情報は全てオンメモリでキャッシュする
<ul>
<li>ユーザの存在チェックだけするような部分 (権限チェック) も基本的にこれで対応できるのでそうした</li>
<li><strong>4210点</strong>
<ul>
<li>ここからスコア上がらず……</li>
</ul>
</li>
</ul>
</li>
<li>16:00: 同じクエリを何度か叩いているエンドポイントがあったので潰す (@hogas, @kyontan)</li>
<li>16:00ごろ: transactions 以外詰まってないしCPUに余裕があるので campaign (負荷レベル)を弄ったところ外部APIで 403エラー  {&#8220;error&#8221;:&#8221;IP address is not allowed&#8221;} が連発しだす
<ul>
<li>主に<code>GET /users/transactions.json</code> <span style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif;">での外部 shipment  サービスへのリクエストで連発</span></li>
<li>外部APIへの403はアプリケーション的には500を返す仕様だったので、これが連発してベンチマーカが途中終了し完走しない</li>
<li>ここらへんで手詰まりに</li>
</ul>
</li>
<li>17:00: 明らかに不要な <code>SELECT FOR UPDATE</code> を削除 (4箇所+ぐらい)
<ul>
<li>これかこれの次辺りで<strong>4410点</strong>。これがベストスコア</li>
</ul>
</li>
<li>17:10: 外部APIを叩く部分で exponential backoff を実装 (@h-otter)
<ul>
<li>変化なし / 403 が連発する</li>
</ul>
</li>
<li>17:30: 外部APIをリクエストするエンドポイントだけ2台へ分散する
<ul>
<li>403 の連発は解決せず、なぜ……</li>
</ul>
</li>
<li>18:10: 最終スコア0点 (failed) で終了</li>
</ul>
<p>色々施策を打つもスコアの変化要因が今ひとつ分からず頭が回っていなかったですね。<br />
特に外部API が undocumented な 403 を返す (しかもメッセージは 「許可されていないIPアドレス」) というのは全然分かりませんでした。<br />
マイクロサービス問題なら単一IPから連続でアクセスすると弾くようになっているのかな、などと思い、後半で外部APIへリクエストをするエンドポイントだけ複数台へ分散するなどしていましたが全く解決せず泥沼へ。</p>
<p>これベンチマーカと外部API側に問題あるのでは? みたいな気持ちになりつつ、マイクロサービス問だしちゃんとbackoffとか実行すればいけるでしょ! と思っていましたが、意図したエラーだったのかは未だに分からず……</p>
<p>他の方の感想を見た限りでは、ポータルサイトへ登録されていないIPからのアクセスは弾かれるみたいですが、これについてはUI上で正しく登録されていることを確認したので問題なさそうでした。<br />
11:00 ごろにインスタンスを立ち上げ直してIPを再登録したのがポータルサイトの何らかのエッジケースを踏んだのでは? などと勝手に邪推しています。謎ですね。</p>
<p>そのほか、 campaign の値を変えると何が変わるのか (POST系アクセスが増える?)、みたいなことも終了後にログを分析してようやくなんとなく傾向がわかり悔しい気持ちに。</p>
<h3>感想</h3>
<p>終わってみれば途中重大な気付き (「外部APIのレスポンスキャッシュできるじゃん」「ユーザの嗜好に合わせて商品出し分けたら?」など) があり、見逃しの多い回でした。<br />
bcrypt の件は全く気づいておらず。前回は初手でやった(があまり意味がなかった) pprof を今回なぜ見なかったのか……</p>
<p>短い時間で追い詰められている環境の中でどれだけ集中できる / 気付けるか、というのが重要になると改めて感じました。</p>
<p>コンテストとしては今回も設定が面白く、運営の手の込みようが分かり、かつ短期間で取り組みがいのあるとても良い問題でした。<br />
運営の皆様、大変お疲れさまでした。</p>The post <a href="https://blog.monora.me/2019/09/reboot-not-supoprted-at-isucon9-qual/">ISUCON9 予選の参加ログ (チーム: 再起動非対応)</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1998</post-id>	</item>
		<item>
		<title>ISUCON8 予選に参加して再起動試験に落ちました</title>
		<link>https://blog.monora.me/2018/09/failed-reboot-test-in-isucon8-qual/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=failed-reboot-test-in-isucon8-qual</link>
		
		<dc:creator><![CDATA[きょんたん]]></dc:creator>
		<pubDate>Sun, 16 Sep 2018 12:35:11 +0000</pubDate>
				<category><![CDATA[Infrastructure]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[ISUCON]]></category>
		<category><![CDATA[コンテスト]]></category>
		<category><![CDATA[参加しました]]></category>
		<guid isPermaLink="false">https://blog.monora.me/?p=1864</guid>

					<description><![CDATA[<p>おはようございます。名取さなにハマっている kyontan です。 チーム「hhkb」で同期3人 (自分 @kyontan, @hogashi, @h-otter) 2回目の参加で2日目で Go 実装でした。学生枠突破な [&#8230;]</p>
The post <a href="https://blog.monora.me/2018/09/failed-reboot-test-in-isucon8-qual/">ISUCON8 予選に参加して再起動試験に落ちました</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></description>
										<content:encoded><![CDATA[<p>おはようございます。名取さなにハマっている kyontan です。<a href="https://blog.monora.me/wp-content/uploads/2018/09/a5a52fbc5d024df5c788b1f71ee6d129.png"><img loading="lazy" class="aligncenter wp-image-1867 size-medium" src="https://blog.monora.me/wp-content/uploads/2018/09/a5a52fbc5d024df5c788b1f71ee6d129-320x218.png" alt="" width="320" height="218" srcset="https://blog.monora.me/wp-content/uploads/2018/09/a5a52fbc5d024df5c788b1f71ee6d129-320x218.png 320w, https://blog.monora.me/wp-content/uploads/2018/09/a5a52fbc5d024df5c788b1f71ee6d129-200x136.png 200w, https://blog.monora.me/wp-content/uploads/2018/09/a5a52fbc5d024df5c788b1f71ee6d129.png 414w" sizes="(max-width: 320px) 100vw, 320px" /></a></p>
<p><figure id="attachment_1879" aria-describedby="caption-attachment-1879" style="width: 620px" class="wp-caption aligncenter"><a href="https://blog.monora.me/wp-content/uploads/2018/09/b3747e99d8a088593e5290ae549054de.png"><img loading="lazy" class="size-large wp-image-1879" src="https://blog.monora.me/wp-content/uploads/2018/09/b3747e99d8a088593e5290ae549054de-640x502.png" alt="" width="620" height="486" srcset="https://blog.monora.me/wp-content/uploads/2018/09/b3747e99d8a088593e5290ae549054de-640x502.png 640w, https://blog.monora.me/wp-content/uploads/2018/09/b3747e99d8a088593e5290ae549054de-200x157.png 200w, https://blog.monora.me/wp-content/uploads/2018/09/b3747e99d8a088593e5290ae549054de-320x251.png 320w, https://blog.monora.me/wp-content/uploads/2018/09/b3747e99d8a088593e5290ae549054de-768x603.png 768w" sizes="(max-width: 620px) 100vw, 620px" /></a><figcaption id="caption-attachment-1879" class="wp-caption-text">最終スコア</figcaption></figure></p>
<p>チーム「hhkb」で同期3人 (自分 @kyontan, @hogashi, @h-otter) 2回目の参加で2日目で Go 実装でした。学生枠突破ならずでした、悔しい。というよりは <strong>55,982点</strong>で全体4位の点数で落ちました。ちなみに hhkb は h-otter, hogashi, kyontan, :boom: ???? の略です。<br />
スキルセット的には、 @h-otter がインフラ(ミドルウェア含)なんでもできる+Goの経験が一番あるマンで、 @hogashi がアプリケーションなんでもできるマンで、 @kyontan はアプリとインフラとDBを一通り見られるマンみたいな感じでした。</p>
<p>今回の参加に向けて、取り組んだことをつらつらと書きます。</p>
<p><span id="more-1864"></span></p>
<p>今回は真面目に本戦に行きたかったので前々日に ConoHa で ISUCON7 の予選を解き直して練習しました。具体的には ConoHa の練習用イメージを使って 1GBプラン x3台で予選環境を再現しました。結果、10時間程度で 5,204点から509,190点まで持っていけることが分かり、計測と試行の反復を効率的に行えば ISUCON の予選は突破できるという確信を深めていました。<br />
また、前回は最後の最後でベンチマーカを走行させた結果点数が下がって落ちたので、前回の直後に「泣きの1回はやらない」というスローガンを掲げ、1年越しでそれを達成しました。</p>
<p><figure id="attachment_1875" aria-describedby="caption-attachment-1875" style="width: 620px" class="wp-caption aligncenter"><a href="https://blog.monora.me/wp-content/uploads/2018/09/score_init.png"><img loading="lazy" class="wp-image-1875 size-large" src="https://blog.monora.me/wp-content/uploads/2018/09/score_init-640x160.png" alt="" width="620" height="155" srcset="https://blog.monora.me/wp-content/uploads/2018/09/score_init-640x160.png 640w, https://blog.monora.me/wp-content/uploads/2018/09/score_init-200x50.png 200w, https://blog.monora.me/wp-content/uploads/2018/09/score_init-320x80.png 320w, https://blog.monora.me/wp-content/uploads/2018/09/score_init-768x192.png 768w, https://blog.monora.me/wp-content/uploads/2018/09/score_init.png 984w" sizes="(max-width: 620px) 100vw, 620px" /></a><figcaption id="caption-attachment-1875" class="wp-caption-text">ベンチマークの初回走行の結果しばらく1位になった</figcaption></figure></p>
<p>事前に準備したのは Prometheus のサーバ (@h-otter がいい感じにやってくれた)と、やること/できることチェックリストぐらいでしょうか。だいたい大会では開始した瞬間にテンパってそのまま撃沈するのが常なので、思考停止状態でもコピペで動くようなコード片とかを用意しておくと便利ですね。あとは思考が無になったときに確認するべき事項とかを作っておくと良いのではないでしょうか? 頻繁に無になって帰りたくなりました。メンタルは大事。</p>
<p>例えば下のような感じです。</p>
<p><a href="https://blog.monora.me/wp-content/uploads/2018/09/3bbc737a859d096bd81af29e4991f3e3.png"><img loading="lazy" class="aligncenter size-large wp-image-1868" src="https://blog.monora.me/wp-content/uploads/2018/09/3bbc737a859d096bd81af29e4991f3e3-640x433.png" alt="" width="620" height="419" srcset="https://blog.monora.me/wp-content/uploads/2018/09/3bbc737a859d096bd81af29e4991f3e3-640x433.png 640w, https://blog.monora.me/wp-content/uploads/2018/09/3bbc737a859d096bd81af29e4991f3e3-200x135.png 200w, https://blog.monora.me/wp-content/uploads/2018/09/3bbc737a859d096bd81af29e4991f3e3-320x216.png 320w, https://blog.monora.me/wp-content/uploads/2018/09/3bbc737a859d096bd81af29e4991f3e3-768x519.png 768w, https://blog.monora.me/wp-content/uploads/2018/09/3bbc737a859d096bd81af29e4991f3e3.png 1062w" sizes="(max-width: 620px) 100vw, 620px" /></a></p>
<p>当日は3人がローカルで開発し、本番環境のVMへバイナリを転送して検証する、という進め方でやっていました。Go はクロスプラットフォームでのビルドがしやすいのが便利ですね。</p>
<p>具体的にやったことを羅列します。というか @h-otter が書いていたのを未承諾引用します。順番は適当</p>
<ul>
<li><code>SELECT *</code> する系のクエリを必要な列しか取らないようにした</li>
<li><code>/api/users</code> は <code>user_id</code> で <code>reservations</code> を全部とってきて、アプリ側で処理してやったらめっちゃ速くなった
<ul>
<li>ここでベンチマーカが重いと言ってくるエンドポイントが <code>/users/:id</code> から <code>/api/events/:id/actions/reserve</code> になった</li>
</ul>
</li>
<li><code>getEvent</code> を <code>getEventWithoutDetail</code> と分けた</li>
<li><code>getEvent</code> と <code>getEvents</code> を2クエリに</li>
<li><code>sheets</code> へのクエリを消す
<ul>
<li>効果があったのかは良くわからない</li>
</ul>
</li>
<li>MariaDB のチューニング</li>
<li>Prometheus と Grafana で可視化</li>
<li>ログインのクエリを1つに</li>
<li>パスワードを平文で突っ込むようにした</li>
<li>DB にインデックス張った (けどあまり良い結果がでなくてもんにょりした)
<ul>
<li>最初に <code>mysql</code> コマンドでインデックス張ったけど結果が全く変わらなくて、なぜ? と思ったら毎回 <code>/initialize</code> でテーブルを作り直していることに気がついた。</li>
</ul>
</li>
<li>IN句を使いたかったので DBにアクセスするライブラリを sqlx に切り替えた</li>
<li>トランザクションの開始がおかしいところがあったので直したり デッドロック時にエラーを返さずリトライするようにした</li>
</ul>
<p>最後は予約時のシート決定を高速化するコードが安定化しなくて入らなかったり、Redisでいい感じにやろうぜみたいなことを思うだけ思ってやらなかったりしました。多分ここができると数万点上がったはず。</p>
<p>あとはスコアに関係ないけど作業便利になる系として、 エラーログでソースコードの行番号を吐くようにしたり、 <code>Makefile</code> 弄って1コマンドでデプロイできるようにしました。<br />
開発は3台のサーバでバラバラにやっていましたがDBは1台だけを参照するようにしました。これはDBのチューニングとかがあって、1台でやった変更を他に反映したりするのが面倒くさかったので。こうすると、やりたい人間が適当にベンチマーク対象のサーバを変更して実行してやればいいので楽でした。</p>
<p>ソースコードは GitHub で管理し、いい感じにやりました。コミットログは下の通りです。</p>
<p><a href="https://blog.monora.me/wp-content/uploads/2018/09/75d9b24b6f7dae18b7cdff0930e9b814.png"><img loading="lazy" class="aligncenter size-large wp-image-1866" src="https://blog.monora.me/wp-content/uploads/2018/09/75d9b24b6f7dae18b7cdff0930e9b814-308x640.png" alt="" width="308" height="640" srcset="https://blog.monora.me/wp-content/uploads/2018/09/75d9b24b6f7dae18b7cdff0930e9b814-308x640.png 308w, https://blog.monora.me/wp-content/uploads/2018/09/75d9b24b6f7dae18b7cdff0930e9b814-96x200.png 96w, https://blog.monora.me/wp-content/uploads/2018/09/75d9b24b6f7dae18b7cdff0930e9b814-154x320.png 154w, https://blog.monora.me/wp-content/uploads/2018/09/75d9b24b6f7dae18b7cdff0930e9b814.png 559w" sizes="(max-width: 308px) 100vw, 308px" /></a>数字がタグに付いていることがありますが、これはいいスコアが出た時にバイナリごとコミットしてタグつけておこうぜ、みたいな感じにした結果でした。</p>
<p>今回の僕の活躍はよく分からなくて、いい感じデバッグ担当だった気がします。PRを見るなりとりあえずマージしてベンチマーカを落としたりバグ探しをしていたりしました。とにかく @h-otter がぶち壊しつつ @hogashi がいい感じに安定化するコードを書いてくれてよかった感がある。</p>
<p>Webサーバはh2oで十分高速だし、画像のトラフィック詰まりもないしで、とにかくアプリケーションコードの改善に注力した/するしかなかった8時間でした。</p>
<p>最終的に残り30分でベンチマーカを叩いたところ3万点前後のスコアが5万点に若干跳ねてそこで打ち止め。一度再起動をしてブラウザからアクセスできることを確認し天命を待ったところ、無事再起動試験で落ち失格となりました。天命……</p>
<p>(追記: スコアが跳ねたのは、最後に実行先サーバを変えた時に インデックスを張る処理を <code>init.sh</code> に書いたサーバで実行したからかもしれないことを思い出した。)</p>
<p>なぜ失格になったのかは分かっていなくて、おそらく <code>/admin/api/reports/events/:id/sales</code> の処理が遅くて不整合が起きて落ちたのかなあなどと思っていますが、2回連続で落ちるのは運が悪かったなと……</p>
<p>なんやかんやでやることがなくならない8時間で、やることが見つからない8時間よりは良かったのではないかと思います。</p>
<blockquote class="twitter-tweet" data-width="550" data-dnt="true">
<p lang="ja" dir="ltr">ISUCONの予選に向けて昨日は練習をしていたわけだけど、知っていることをちゃんと愚直にできれば比較的現実的な時間で予選突破ラインには十分立てることが分かったので良かった</p>
<p>&mdash; kyontan@新刊はまだ (@sukukyon) <a href="https://twitter.com/sukukyon/status/1040457052307447810?ref_src=twsrc%5Etfw">September 14, 2018</a></p></blockquote>
<p><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></p>
<p>イキっているなどと言われてもこれは事実だと信じていて、典型的な N+1 を潰すなどすれば予選は通過できるはずなことは分かりましたね。くぅ〜〜</p>
<p>来年はちゃんと本選に行けたらいいですね。頑張りましょう。</p>
<p>そして、参加会場を提供していただいた mixi 様、惜敗の悔しさを教えてくれる最高のコンテストを運営をしていただいたISUCONの運営の皆様、お疲れ様でした、ありがとうございました!</p>
<p>以下は画像です</p>
<p><a href="https://blog.monora.me/wp-content/uploads/2018/09/score_2.png"><img loading="lazy" class="wp-image-1877 size-large" src="https://blog.monora.me/wp-content/uploads/2018/09/score_2-640x141.png" alt="" width="620" height="137" srcset="https://blog.monora.me/wp-content/uploads/2018/09/score_2-640x141.png 640w, https://blog.monora.me/wp-content/uploads/2018/09/score_2-200x44.png 200w, https://blog.monora.me/wp-content/uploads/2018/09/score_2-320x71.png 320w, https://blog.monora.me/wp-content/uploads/2018/09/score_2-768x170.png 768w, https://blog.monora.me/wp-content/uploads/2018/09/score_2.png 1000w" sizes="(max-width: 620px) 100vw, 620px" /></a></p>
<p><a href="https://blog.monora.me/wp-content/uploads/2018/09/score_3.png"><img loading="lazy" class="wp-image-1876 size-large" src="https://blog.monora.me/wp-content/uploads/2018/09/score_3-640x139.png" alt="" width="620" height="135" srcset="https://blog.monora.me/wp-content/uploads/2018/09/score_3-640x139.png 640w, https://blog.monora.me/wp-content/uploads/2018/09/score_3-200x43.png 200w, https://blog.monora.me/wp-content/uploads/2018/09/score_3-320x70.png 320w, https://blog.monora.me/wp-content/uploads/2018/09/score_3-768x167.png 768w, https://blog.monora.me/wp-content/uploads/2018/09/score_3.png 984w" sizes="(max-width: 620px) 100vw, 620px" /></a></p>The post <a href="https://blog.monora.me/2018/09/failed-reboot-test-in-isucon8-qual/">ISUCON8 予選に参加して再起動試験に落ちました</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1864</post-id>	</item>
		<item>
		<title>ISUCON7 予選に参加しました</title>
		<link>https://blog.monora.me/2017/10/participated-isucon7-qual/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=participated-isucon7-qual</link>
		
		<dc:creator><![CDATA[きょんたん]]></dc:creator>
		<pubDate>Sun, 22 Oct 2017 17:29:29 +0000</pubDate>
				<category><![CDATA[Infrastructure]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[ISUCON]]></category>
		<category><![CDATA[コンテスト]]></category>
		<category><![CDATA[参加しました]]></category>
		<guid isPermaLink="false">https://blog.monora.me/?p=1665</guid>

					<description><![CDATA[<p>チーム「まだチーム名で消耗してるの?」で同期3人 (自分 @kyontan, @hogas, @h-otter) 初参加で2日目でした。学生枠突破ならずでした。 Ruby実装で挑み、最終スコア 38605点@2017-1 [&#8230;]</p>
The post <a href="https://blog.monora.me/2017/10/participated-isucon7-qual/">ISUCON7 予選に参加しました</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></description>
										<content:encoded><![CDATA[<p>チーム「まだチーム名で消耗してるの?」で同期3人 (自分 @kyontan, @hogas, @h-otter) 初参加で2日目でした。学生枠突破ならずでした。</p>
<p>Ruby実装で挑み、最終スコア 38605点@2017-10-22 20:59:30, ベストスコア: <strong>67792点</strong>@2017-10-22 20:44:59 でした。<br />
ベストスコアでは予選ラインは超えていたんだなあと思いますが、最終的には伸び悩んだチームも多いようで、結局落ち着くところに落ち着いたのかなと思います。</p>
<p>ソースコードは <a href="https://github.com/kyontan/isucon7_qual">kyontan/isucon7_qual</a> です。踏み台でやっていた影響でコミッタが僕に見えますが、だいたい僕ではない。</p>
<p><figure id="attachment_1668" aria-describedby="caption-attachment-1668" style="width: 620px" class="wp-caption aligncenter"><a href="https://blog.monora.me/wp-content/uploads/2017/10/isucon7_chart.png"><img loading="lazy" class="wp-image-1668 size-large" src="https://blog.monora.me/wp-content/uploads/2017/10/isucon7_chart-640x254.png" alt="" width="620" height="246" srcset="https://blog.monora.me/wp-content/uploads/2017/10/isucon7_chart-640x254.png 640w, https://blog.monora.me/wp-content/uploads/2017/10/isucon7_chart-200x79.png 200w, https://blog.monora.me/wp-content/uploads/2017/10/isucon7_chart-320x127.png 320w, https://blog.monora.me/wp-content/uploads/2017/10/isucon7_chart-768x304.png 768w, https://blog.monora.me/wp-content/uploads/2017/10/isucon7_chart.png 1696w" sizes="(max-width: 620px) 100vw, 620px" /></a><figcaption id="caption-attachment-1668" class="wp-caption-text">ISUCON7 予選での Score / LoadLevel の変化</figcaption></figure></p>
<p>次回も参加したいなという気持ちになってきたので、ひとまずはやったことを記していきます。</p>
<p><span id="more-1665"></span></p>
<p>実は僕と @hogas は ISUCON6 の夏期講習に出たことがありましたが、そのときには日程等もあり参加しておらずということで、今回が初参加に。<br />
@h-otter というインフラに<strong>とても強い</strong>同期がいたことや、周囲でも参加する人間が何故か多く、とにかくやっていくしかないという流れに。</p>
<p>チーム名を決めるところで消耗/摩耗し、本番前日までSlackはほとんど流れておらず。前日夜になって僕とか @h-otter がぽちぽち参加記やチューニングできそうなところを貼っていく感じに。</p>
<p>最近、正午より前に起きると早起きしたと言い出す僕が時間に間に合っていたあたりで色々とミスっていたんですが、東京都内の某所で3人で集まってやっていました。</p>
<h2>事前にやった</h2>
<p>とりあえずグローバルIPを持つ作業用サーバを用意しておいた。Rubyは事前に入れておいて、開始後に MySQL  も入れてスタンドアロンで動くようにした。あとあと @hogas はここでずっと作業してたり、 @h-otter が Prometheus のサーバを立てたりしていた。便利</p>
<p>コードについては GitHub リポジトリを立てて、普通にブランチ切ってやっていた。便利</p>
<p>情報共有は対面だったので、コードスニペット貼れるしリアルタイムで最高な HackMD を例のごとく使っていた。ベンチマーカの結果を全部ペタペタ貼っていたら容量制限に引っかかり、2スレ目、3スレ目が誕生した。HackMDのタイトルは<strong>「ISUCON7 まだチーム名で消耗してるの? 2スレ目」</strong>でした。</p>
<h2>やったこと</h2>
<p>ミドルウェアより下は正直 @h-otter に丸投げしていたので、アプリケーションより上をぽちぽち見ていました。<br />
インフラについては正直何をしたのかは全容を把握していないですが、初手で nginx や MySQL に基本のチューニングを突っ込み、Prometheus で延々と監視しながらPDCAを回していたっぽい。正しいインフラチューニングや……</p>
<p>言語は僕と @hogas が使い慣れている Ruby を選択しました。正直クエリ弄るぐらいでいいなら Go でもいいよねーって言っていましたが、慣れてるほうが便利でした。Sinatra の文字列には幼馴染のような安心感がある。</p>
<p>僕と @hogas はよしなにアプリケーションコードを読みながら色々した。以下は色々</p>
<h4>erb を haml に置き換える / hamlit gem の導入</h4>
<p>気持ち+2000点ぐらい</p>
<p>初期実装が erb で、erubis に置き換えるというのも一案ありましたが、行きの車内で「erubis hamlit 速度」などで検索した結果やっぱり hamlit かとなっており、ノータイムで haml に書き換えることを決断しました。<br />
erb2haml とかあったね〜と @hogas と話しながらやってもらった。</p>
<p>以下様子です</p>
<blockquote class="twitter-tweet" data-width="550">
<p lang="ja" dir="ltr">. <a href="https://twitter.com/hogextend?ref_src=twsrc%5Etfw">@hogextend</a> 「erb2hamlどうやって使うの?」ぼく「とりあえず rails new して突っ込んでみたら?」 <a href="https://twitter.com/hashtag/isucon?src=hash&amp;ref_src=twsrc%5Etfw">#isucon</a></p>
<p>&mdash; きょんたん (@sukukyon) <a href="https://twitter.com/sukukyon/status/922121692440182785?ref_src=twsrc%5Etfw">October 22, 2017</a></p></blockquote>
<p><script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script></p>
<blockquote class="twitter-tweet" data-width="550">
<p lang="ja" dir="ltr">僕「ﾖｯｼｬ(gem install rails)」</p>
<p>&mdash; hogas (@hogextend) <a href="https://twitter.com/hogextend/status/922125423697305600?ref_src=twsrc%5Etfw">October 22, 2017</a></p></blockquote>
<p><script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script></p>
<p><small>(erb2haml はコマンドラインツールとかではなく、Rails に追加する rake タスク群ということに気が付いた様子)</small></p>
<h4>nginx &lt;-&gt; Puma を UNIXドメインソケットに</h4>
<p>気持ち +2000点</p>
<p>定番です。HTTP 5000/tcp から UNIXドメインに変えた。</p>
<h4>SQL のクエリ改善</h4>
<p>気持ち+10000点ぐらい</p>
<p>これは定番ですね。SELECT のカラムを絞ったり (@hogas)、 <code>LIMIT</code> を付けたり (@hogas)、インデックスを張ったりした。N+1 は手を付けていましたが、コード変更に集中できなくて最終的に投げてしまった。悔しい</p>
<p>終了直前にソースコード眺めてたら <code>statement.close</code> を意図的に忘れていそうなコードが見つかり慌てて修正した。スコア上の変化は分からず。</p>
<h4> 画像を静的ファイルに書き出す</h4>
<p>気持ち+15000点ぐらい</p>
<p>ユーザーのアバター画像が DB に <code>blob</code> で入っていたので、雑に Ruby のワンライナーで書き出して (ここまで @kyontan)、 nginx に <code>try_files</code> で食わせる (@h-otter) みたいなことをした。<br />
既に話題になっていますが、最終的には <code>Cache-control</code> 的な問題でキャッシュヒット率が悪かったらしい。むむむ。</p>
<h4>SHA1 を殺す (パスワード, アバター画像)</h4>
<p>気持ち+2000点</p>
<p>パスワードのソルトを生成している <code>random_string</code> を見たときに、これは要らないのではと思ってしまったのが始まり。初期データのパスワードはハッシュ化されていたので、 <code>id</code> が1000より大きい user は全て平文パスワードを DB に突っ込んだりした。 (by @hogas)<br />
アバター画像は、ファイルの内容を SHA1 したものをファイル名に使用する実装になっていましたが、もしかしていけるのではと言いながらユーザIDをそのままファイル名にしたら通ってしまったのでそのままに。</p>
<h4>Redis (最終的に入れず)</h4>
<p>気持ち+2000点ぐらい(?)</p>
<p>画像をバイナリで入れるのはまあそうだね〜〜と言いながら、Redis に載せようとしていた。正直コードの変更は大したことがないのは分かっていたので実装はシュッとできたけれど、実際に動かしてみると意外とスコアに有意な差が出なかった。その後も永続化周りで少し足踏みしていたり、他の変更を見ていたために最終的に入れられなかった。残念</p>
<h4>アプリケーションサーバ3台化</h4>
<p>気持ち +3000点ぐらい</p>
<p>@h-otter がラスト30分でイケると言い出してやってた。ここで Puma (アプリケーションサーバ) のスレッド数を調整していた (10 -&gt; 18スレッド)時に出したのがベストスコアです。</p>
<h2>その他</h2>
<ul>
<li>再起動試験は何の問題もなかった????
<ul>
<li>過去の参加記なんかを見てるとここが関門かなというのはあったので絶対やっておきたかった (やりました)</li>
<li>Redis に手を出してなかったのでここで不安はあまりなかった</li>
</ul>
</li>
<li>MySQL の Too Many Connections が割りと頻発した
<ul>
<li>ここは <code>statement.close</code> 忘れも影響してるかなと思うけれど、500が途中で出たり安定しないことがあった。最終的には安定しました</li>
</ul>
</li>
<li>日ごろは頭痛の頭の字もないのに、とにかく頭痛が酷かった。緊張にはやはり弱い。</li>
<li>JSONシリアライザが遅いのは分かっていて、 <code>Oj</code> を入れるぞと言いながら入れるのを忘れた。あれを入れただけでシリアライズについては数倍速くなるというのは分かっていたので、ただただつらい。</li>
<li>ICTトラブルシューティングコンテストでスコアサーバを延々とやっていたことが知見として生きたとは思う。DB設計なりアプリケーション設計なりチューニングなり。
<ul>
<li>当時のオーバーキルなチューニングしたときの操作が生きることになるとは思ってなかった</li>
</ul>
</li>
<li>最後のベンチマークの結果を見て全員で嘘やんって言ってた
<ul>
<li>ルールを読んでなかった。次回は読みます</li>
<li>にゃーん</li>
</ul>
</li>
</ul>
<p>そういえば30分ほどですがスコアボードの上位に乗っていました。学生トップなのは分かっていたので、これは予選突破できるんじゃない? とか言いながら笑っていたのを覚えています。このあたりが後々ボーダーになるんだろうな〜という話をしていて、実際そうなったのである程度読みは正しかったのかなと思いつつ。</p>
<p><a href="https://blog.monora.me/wp-content/uploads/2017/10/isucon7_best_shot.png"><br />
<img loading="lazy" class="aligncenter size-large wp-image-1676" src="https://blog.monora.me/wp-content/uploads/2017/10/isucon7_best_shot-640x259.png" alt="" width="620" height="251" srcset="https://blog.monora.me/wp-content/uploads/2017/10/isucon7_best_shot-640x259.png 640w, https://blog.monora.me/wp-content/uploads/2017/10/isucon7_best_shot-200x81.png 200w, https://blog.monora.me/wp-content/uploads/2017/10/isucon7_best_shot-320x129.png 320w, https://blog.monora.me/wp-content/uploads/2017/10/isucon7_best_shot-768x311.png 768w, https://blog.monora.me/wp-content/uploads/2017/10/isucon7_best_shot.png 1968w" sizes="(max-width: 620px) 100vw, 620px" /></a></p>
<h2>総括/最高</h2>
<p>監視に強い人(@h-otter)強い。常に横で IOバウンドかネットワークバウンドか、みたいなことを見ながらアドバイスしてもらえる環境は最高。</p>
<p>限られた時間の大会という環境でもくもくとコードいじれる人(@hogas)強い。とにかく僕が頭が回ってなくてコードをまともに書けない状況にあったので、そんな中でちゃんと改善する変更を入れ続けてくれて最高。</p>
<p>基本的にどこに手を入れればいいか、この変更はコスパ的にどうかみたいなことを常に考えながら立ち振る舞えてはいたと思うので、そういった点ではなかなか善戦はできたかなと思いつつ。<br />
しかし、できたことは山のように残っているなという感想。、途中で集中力が切れてしまったこともあり、こういう結果になったのは悔しいなと思う。</p>
<p>ただ、これだけ言えるというのはつまりバランスが最高だということに他ならなくて、こういった駆け引きができるバランスのゲームを作るのはとにかく難しいなと思っているだけに最高だな！！！という気持ちです。<br />
こんな最高のコンテストを生み出してくれた運営の皆様、ありがとうございました。そしてお疲れ様でした！</p>
<p>本選に行かれる皆様はぜひとも頑張ってほしいなと思うところです。</p>
<p>&nbsp;</p>
<p>次回は最高の♨️から最高の心構えでやっていきたい。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>The post <a href="https://blog.monora.me/2017/10/participated-isucon7-qual/">ISUCON7 予選に参加しました</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1665</post-id>	</item>
		<item>
		<title>Zabbix で収集したデータを Datadog へ投げる</title>
		<link>https://blog.monora.me/2017/08/zabbix-to-datadog/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=zabbix-to-datadog</link>
		
		<dc:creator><![CDATA[きょんたん]]></dc:creator>
		<pubDate>Sat, 05 Aug 2017 16:23:14 +0000</pubDate>
				<category><![CDATA[Infrastructure]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[datadog]]></category>
		<category><![CDATA[zabbix]]></category>
		<guid isPermaLink="false">https://blog.monora.me/?p=1641</guid>

					<description><![CDATA[<p>こんにちは。これを書いているのは JST 4:30 ですが、最近は JST+0900で生きているので、昼間です。そろそろ夕方でしょうか。 最近の仕事の成果は Zabbix に投げ込む XML をエイヤで自動生成するような [&#8230;]</p>
The post <a href="https://blog.monora.me/2017/08/zabbix-to-datadog/">Zabbix で収集したデータを Datadog へ投げる</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></description>
										<content:encoded><![CDATA[<p>こんにちは。これを書いているのは JST 4:30 ですが、最近は JST+0900で生きているので、昼間です。そろそろ夕方でしょうか。<br />
最近の仕事の成果は Zabbix に投げ込む XML をエイヤで自動生成するような何か、もしくは SQL を生成する何かです。</p>
<p>成果物は <a href="https://github.com/kyontan/datadog-zabbix-history">kyontan/datadog-zabbix-history</a> です。</p>
<h2>長い前置き</h2>
<p>ところで皆様は Datadog を使われていますでしょうか?<br />
インフラ監視系の SaaS やソフトウェアというと、今挙げた Datadog を始め, Mackerel や Zabbix, Nagios, AWS Cloudwatch 等々、現状では様々なプロダクトが存在しています。最近だと Datadog や Prometheus の名前をよく見かける気がします。</p>
<p>そんな中最近、自分のバイト先では使われているのが <a href="https://www.datadoghq.com/">Datadog</a> です。サーバの監視なんかだと、 Integration の種類も多く、デフォルトで様々なメトリックが取れることや、ダッシュボードの見やすさなどがイケているかなと。<br />
特に SaaS だと、バッファリングがあるにしてもメトリクスの抜け落ちや一時アクセスできなくなる問題などはあり、クリティカルなものを全部載せるわけにもいかず、ただ SaaS の恩恵は受けたいというのが正直なところでしょう。<br />
(mackerel-agent のログを眺めているとたまに何故か 404 が返ってきていて笑います)</p>
<p>ただ、設定が複雑化したり、そもそも設定数が多くて移行がダルいというのが正直なところです。エイヤでやる体力があれば良いですが、ホスト数が増え、監視項目が万の単位であるとそれはそれは……</p>
<p>おそらく皆さんは Zabbix のアイテムやらなんやらを XML で書き出して<strong>ごにょごにょ</strong>したり、それを Prometheus の設定に<strong>いい感じ</strong>に変換する何かを書いたりされているかと存じます。そしてそんなコードは短いから/特定のドメインに特化しているからと公開せず、誰もが<strong>誰かは書いているだろう</strong>と思いながら書いていることでしょう。そうですよね?</p>
<p>今回ご紹介するのはそんなあるあるプロダクトです。やることは記事のタイトルに書いてありますね。</p>
<p><span id="more-1641"></span></p>
<h2>本編</h2>
<p>最初にも書きましたがこれ (<a href="https://github.com/kyontan/datadog-zabbix-history">kyontan/datadog-zabbix-history</a>) です。実装としては、Zabbix の DB からメトリクス (Zabbix でいうアイテムのヒストリ) を勝手に拾ってきます。<br />
いい感じに動きます。良かったですね。</p>
<p>現状イケてないところが1つあって、 dd-agent は独自の組み込み python を使うので pip で入れたパッケージを読んでくれません。インポートパスを弄ります。良くないですね。</p>
<p>まだ、とりあえず動くというところなので、様子を見ていきたいですね。</p>The post <a href="https://blog.monora.me/2017/08/zabbix-to-datadog/">Zabbix で収集したデータを Datadog へ投げる</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1641</post-id>	</item>
		<item>
		<title>総資産を Dr.Wallet から Slack へポストするようにした</title>
		<link>https://blog.monora.me/2017/07/post-total-assets-from-drwallet-to-slack/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=post-total-assets-from-drwallet-to-slack</link>
		
		<dc:creator><![CDATA[きょんたん]]></dc:creator>
		<pubDate>Sun, 09 Jul 2017 15:22:59 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[Dr.Wallet]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[総資産]]></category>
		<guid isPermaLink="false">https://blog.monora.me/?p=1614</guid>

					<description><![CDATA[<p>こんにちは。JST+11で生きているので昼です。 ところで最近は世界から10年遅れて Rails に入門したり、それとは関係なく Sinatra のアプリケーションに RSpec を書いてテストの重要性を感じながら七夕に [&#8230;]</p>
The post <a href="https://blog.monora.me/2017/07/post-total-assets-from-drwallet-to-slack/">総資産を Dr.Wallet から Slack へポストするようにした</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></description>
										<content:encoded><![CDATA[<p>こんにちは。JST+11で生きているので昼です。<br />
ところで最近は世界から10年遅れて Rails に入門したり、それとは関係なく Sinatra のアプリケーションに<br />
RSpec を書いてテストの重要性を感じながら七夕に笹の葉ラプソディを見たりしています。10年前って単語がよく聞かれる今日このごろです。</p>
<p>皆さんはおそらく何らかのチームでのコミュニケーションに Slack を使っていて、総資産を Dr.Wallet で管理されていて (ここで読者の8割が脱落)、その総資産を逐次仲間に共有したいですよね! (残存者0)</p>
<p>で、やっぱり皆さんも共有したいでしょう、というわけで作りました。</p>
<p><span id="more-1614"></span></p>
<p><small>(実は1年ぐらい前に作ってあったのですが、環境依存が辛かったので Docker に押し込む作業をしました)</small></p>
<p><a href="https://github.com/kyontan/assets2slack" target="_blank" rel="noopener noreferrer">GitHub kyontan/assets2slack</a></p>
<p>雑に <code>docker-compose run --rm crawler</code> とかやると共有できて便利です。</p>
<p><img loading="lazy" class="alignnone size-full wp-image-1629" src="https://blog.monora.me/wp-content/uploads/2017/07/2017-07-09-23.png" alt="assets2slack demo" width="290" height="269" srcset="https://blog.monora.me/wp-content/uploads/2017/07/2017-07-09-23.png 290w, https://blog.monora.me/wp-content/uploads/2017/07/2017-07-09-23-200x186.png 200w" sizes="(max-width: 290px) 100vw, 290px" /></p>
<p>おそらく最近のアプリケーションなので <code>docker-compose.yml</code> が置いてあります。ポジショントーク?じゃないですが、こういう環境作りが面倒くさいアプリケーションの共有には向いていると思います。<br />
1コンテナにまとめたかったのですが、少し面倒くさそうだったので投げました。PRお待ちしています。</p>
<p>実装は至極簡単に、 Ruby あるあるな capybara + selenium-webdriver で雑にクロールして Webhook で投げているだけです。技術に新規性はありません。</p>
<p>話が逸れますが、 Dr.Wallet のレシート人力OCRは精度も良いしおすすめです。あと、どうやら iOS より Android アプリの方が3倍ぐらい機能が充実していて便利です。NFC で Suica も読めるし。</p>
<p>皆さんもこれを使って総資産で殴り合っていきましょう。僕の総資産はたまにマイナスになります。</p>The post <a href="https://blog.monora.me/2017/07/post-total-assets-from-drwallet-to-slack/">総資産を Dr.Wallet から Slack へポストするようにした</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1614</post-id>	</item>
		<item>
		<title>SECCON 2016 Online CTF に参加しました (Write-up)</title>
		<link>https://blog.monora.me/2016/12/seccon-2016-online-ctf-write-up/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=seccon-2016-online-ctf-write-up</link>
		
		<dc:creator><![CDATA[きょんたん]]></dc:creator>
		<pubDate>Sun, 11 Dec 2016 06:36:04 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[CTF]]></category>
		<category><![CDATA[MMA]]></category>
		<category><![CDATA[参加しました]]></category>
		<guid isPermaLink="false">http://blog.monora.me/?p=1458</guid>

					<description><![CDATA[<p>なんか直前に参加しない? と誘われたので今年もYouTube問題担当として参加しました。Team MMA で 700 Points, Rank: 107 (国内: 27) だったっぽいです。(暫定?) あと500 Poi [&#8230;]</p>
The post <a href="https://blog.monora.me/2016/12/seccon-2016-online-ctf-write-up/">SECCON 2016 Online CTF に参加しました (Write-up)</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></description>
										<content:encoded><![CDATA[<p>なんか直前に参加しない? と誘われたので今年もYouTube問題担当として参加しました。Team MMA で 700 Points, Rank: 107 (国内: 27) だったっぽいです。(暫定?)<br />
あと500 Points で国内予選でしたね。先は長い</p>
<p>MMA は大学のサークルですが、<a href="https://blog.monora.me/2015/12/seccon-2015-online-ctf-write-up/">前回</a>のチーム overflow +αみたいな感じでした。主要メンバーが運営にいるし、新たに入ってきた後輩はなぜか別チームでやっていたので、謎です。</p>
<p class="p1">僕は VoIP <span class="s1">(</span>Forensics 100<span class="s1">),</span> Memory Analysis<span class="s1">(</span>Forensics 100<span class="s1">),</span> PNG over Telegraph <span class="s1">(</span>Crypto 300<span class="s1">) を解きました。とりあえずメモです。</span></p>
<p class="p1"><span id="more-1458"></span></p>
<h3 class="p1">VoIP <span class="s1">(</span>Forensics 100<span class="s1">)</span></h3>
<p>pcap が振ってくるので、WireShark で開いて VoIPツールで再生して終わり。これICTSCでやったやつや……<br />
<code>SECCON{9001IVR}</code></p>
<h3 class="p1">Memory Analysis<span class="s1">(</span>Forensics 100<span class="s1">)<br />
</span></h3>
<p><a href="http://www.volatilityfoundation.org/">Volatility</a> というツールを使えということだったのでその通り頑張ってみる。</p>
<p><code></code><code class="EnlighterJSRAW" data-enlighter-language="generic">strings forensic_100.raw | grep http</code> をメモ<br />
<code class="EnlighterJSRAW" data-enlighter-language="generic">./volatility_2.5_mac -f forensic_100.raw dumpfiles --dump-dir dumpdir -S summary.txt</code><br />
summary.txt を見るとプロセスの絶対パスが取れて、怪しい svchost が分かる (PID1776)</p>
<pre class="lang:sh crayon-selected EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-linenumbers="false">$ ./volatility_2.5_mac -f forensic_100.raw pstree
(snip)
.... 0x81f65da0:svchost.exe 1776 672 2 23 2016-12-06 05:27:10 UTC+0000
..... 0x8225bda0:IEXPLORE.EXE 380 1776 22 385 2016-12-06 05:27:19 UTC+0000
...... 0x8229f7e8:IEXPLORE.EXE 1080 380 19 397 2016-12-06 05:27:21 UTC+0000
(snip)
</pre>
<p>プロセスツリーが取れて、 PID 1776 の子プロセスが分かる</p>
<pre class="lang:sh EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-linenumbers="false">$ ./volatility_2.5_mac -f forensic_100.raw connscan
Offset(P) Local Address Remote Address Pid
---------- ------------------------- ------------------------- ---
0x018c3cc8 192.168.88.131:1077 180.70.134.87:80 3676
0x0196f6a0 192.168.88.131:1122 175.126.170.70:80 3676
0x0233bbe8 192.168.88.131:1034 153.127.200.178:80 1080
0x02470238 192.168.88.131:1036 172.217.27.78:443 2776
</pre>
<p>PID 1080 がアクセスしてるのが `153.127.200.178` だと分かる</p>
<p>上の strings でアクセスしてた URL のドメイン部分を全部 `153.127.200.178` に変えて、curl</p>
<pre class="lang:sh EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-linenumbers="false">echo http://153.127.200.178/
curl -I http://153.127.200.178/ 2&gt;/dev/null | head -1 | grep -v 404
</pre>
<p>こういうのを書き連ねて、 200 OK が返ってくるものを探す</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-linenumbers="false">(snip)
http://153.127.200.178/entry/Data-Science-import-pandas-as-pd
HTTP/1.1 200 OK
(snip)
</pre>
<p>後はアクセスして取ってきたファイルを開く</p>
<pre class="lang:sh EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-linenumbers="false">$ cat Data-Science-import-pandas-as-pd [/Users/kyontan/Code/ctf/2016online]
SECCON{_h3110_w3_h4ve_fun_w4rg4m3_}
</pre>
<h3 class="p1"><a href="https://www.youtube.com/watch?v=Y6voaURtKlM">PNG over Telegraph</a> <span class="s1">(</span>Crypto 300<span class="s1">)</span></h3>
<p>待っていました YouTube 問題、と思ったんですが、50分を超える動画で最初から心が折れる。<br />
とりあえずダウンロードして、ffmpeg で 1fps で連番画像へ変換。</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-linenumbers="false">mkdir tower; ffmpeg -i SECCON\ TOWER\ 2016\ -\ YouTube.mp4 -vf fps=1 tower/out%04d.png</pre>
<p>これ、最近授業でやった気がするなーと思いつつググルも、一般的な手旗信号ではないようで少し戸惑っていたら、 @f_dita 先輩が最初のデモから対応表を作っていたようなので拝借。</p>
<p>そもそもパターン数が26+αあって、コマ数がトータルで3000を超えていたので人間技で分けるのは無理だと判断し、ImageMagick でごにょごにょするも、動画内の棒がブレるわ、次第に少しずつカメラがずれている? やらで全く精度が出ず、ここまで3-4時間近く。</p>
<p><figure id="attachment_1463" aria-describedby="caption-attachment-1463" style="width: 620px" class="wp-caption aligncenter"><a href="https://blog.monora.me/wp-content/uploads/2016/03/semaphore_magick.png"><img loading="lazy" class="wp-image-1463 size-large" src="https://blog.monora.me/wp-content/uploads/2016/03/semaphore_magick-640x509.png" alt="分類器の様子" width="620" height="493" srcset="https://blog.monora.me/wp-content/uploads/2016/03/semaphore_magick-640x509.png 640w, https://blog.monora.me/wp-content/uploads/2016/03/semaphore_magick-200x159.png 200w, https://blog.monora.me/wp-content/uploads/2016/03/semaphore_magick-320x255.png 320w, https://blog.monora.me/wp-content/uploads/2016/03/semaphore_magick-768x611.png 768w, https://blog.monora.me/wp-content/uploads/2016/03/semaphore_magick.png 843w" sizes="(max-width: 620px) 100vw, 620px" /></a><figcaption id="caption-attachment-1463" class="wp-caption-text">ImageMagickで頑張って自動分類を試みていた形跡</figcaption></figure></p>
<p>最終的に心が折れ、手動分類アシストツールを書きやっていくこととなります。<br />
そのようにして、<a href="https://gist.github.com/kyontan/f329c52ec12e52767e538e8c968d6000">160行のSinatraアプリケーション</a>がここに爆誕しました。HTMLを文字列として扱って結合する簡単仕様。<br />
そして去年のごとく、突然 @hogas を呼び出し、ひたすら朝まで単純作業。</p>
<p>それに伴い少しずつ分類器の機能が向上され、再分類(間違えた画像のやり直し)や大分類(軸となる棒の向き)→小分類 などの仕組みが整いスピードアップ。</p>
<p><figure id="attachment_1464" aria-describedby="caption-attachment-1464" style="width: 620px" class="wp-caption aligncenter"><a href="https://blog.monora.me/wp-content/uploads/2016/03/borns.png"><img loading="lazy" class="wp-image-1464 size-large" src="https://blog.monora.me/wp-content/uploads/2016/03/borns-640x344.png" alt="手動分類の様子" width="620" height="333" srcset="https://blog.monora.me/wp-content/uploads/2016/03/borns-640x344.png 640w, https://blog.monora.me/wp-content/uploads/2016/03/borns-200x108.png 200w, https://blog.monora.me/wp-content/uploads/2016/03/borns-320x172.png 320w, https://blog.monora.me/wp-content/uploads/2016/03/borns-768x413.png 768w, https://blog.monora.me/wp-content/uploads/2016/03/borns.png 1362w" sizes="(max-width: 620px) 100vw, 620px" /></a><figcaption id="caption-attachment-1464" class="wp-caption-text">二値化して見やすくしたら骨を分けている気持ちになれた</figcaption></figure></p>
<p>これはSECCONではないと思いつつやるも、結局どのようにしてフラグを得たら良いのか分からず、更に混乱するなど。<br />
問題文でPNGに戻せることが示唆されているので、何らかの方法で元に戻るはずですが、そもそも動画の冒頭で文字の対応が示されたのは20パターンほどに過ぎず、全部で何パターンあるのかも良く分からないままひたすら分類していきます。<br />
最終的に32パターンになるのですが、途中で分類を誤ったりなんやかんやあった結果、36パターンの分類が完成し、Base36という誤った道を踏みそうに。答えは Base32 でした。</p>
<p>気合でバイナリに戻したら、馴染み深い IHDR の文字列が見えて感動しつつ、ここから更に間違えた分類画像100枚以上を探しつつ、気合でCRCを合わせて行きます。</p>
<p>最終的に、IHDR や PLTE, tRNS, pHYs, IEND 領域は CRC32 がマッチして、IDAT の inflate がチェックサムでコケるところまでは上手く戻せました。</p>
<pre class="lang:ruby EnlighterJSRAW" data-enlighter-language="ruby">input = "rfie3rynbinauaaaaagusscekiaaaaw5aaaafwqbamaaaabvebthaaaaaadfatcuiuaaaahzzzz5lwmz4uaaaaacorje3uzzzzellx1haaaaaclqjbmxgaaabmjaaaalcia2fxl1zqaaabwyjfcecvdyttw2uqms1i2ayrsrkvsqclbjlpxslmiavl5bus3zuqagz3xdt0oq15ci3kjuy0gjjknzzyjqobyha3dqobyha3dqobyhb3cpxdstrxdzt0zu1zzi5dwzc11jzvydx44gx2t0zfz3d4244rhdlcpir50u2mcaob1zrddyzj4bw11np1v02y5u1lcdrzjwouzjnzqobyb41geohcxsxdb3fdz3c0sejzsd2nbcye40jeapcdi3dt1g13gp2giw23z5jta0dfrt1ih55btxvmhxa3hqhzdpwdrl4whjsfrdqkzc2gljdeob0zdp1d55oe2uai1mnd4wxifhag344rpcm0rrbuha2pqr02i1dz2pd1bmbqobgzrhgrbqmzg00w12lpxgk1yn5c2obvnjwj4quha3pqjx2t2g1bmaq3rvpav5dmynuv2wlkuoppsrwidqodyl41hizwxhrl5lkz0ssvqdjwyzuvtev3k2dh05yha3d2zbdhljc1h4kj5ynk0100gw2xb5hz2jtuv2qobyg41gj2k3kl4jhftp2vfrr40fyme1l2vhc1dgzbpcnqgbyf41ewivxoh2pkn0qn5zpztpyllw33nzxoe2kqbhyda3cnzbepo3nylrfs0zjchnxcqyepu4krkupr1dqkbyh41evurfvlpar4ujdekpk34e1211lzzxacaob5zb5n5t0muzhmbs2urt2yr5524npkwukyot4z4xaiobyzbhtyzrj1okx5fv0g53voxfjfwqupsrj442n0ku0v4nyda3d2za4v0bvhnf5fpbv2lr3hvdndispkg5vi1byhatpyntgnwgusdvdnvh433x0rovk2r1lxzj0wi3dqohyi31nuunlupdqruvpo2gtp4lpzot4u2z053g3dqobg4qsfjvh1cz4jfy1kvg4u55givzw4acoobyzbdlyo21oo4wunlu5zmafr3tlqla0c0k4o5zwbihazpysw0wtz0feuyiyzznmxvk312gcpeyj4khmfy3dr1cwpvsvjt5mhl44404l4zuztj25ysxgf1vmmyldqohyl11yvxrlskky5fh02ncwlszjofoaffnleoiyha3d2zbzuvcoit5pxvqazyokxh1235ektpk3rd1tm4qibyh41cupelmkyzw40xl4t3omhlcvwmlwwq40zkf5klqodye4oekmt12pq5p2v3yh4dedtfui0pe5gu4fs1saeha2pqpc2u4gxeolww4j2lngsflw0xohl2byj1ayha4pymzf53hjbupoen5x4noc5beplaq4in2xb0ogq3dr1fz3o2ihvn0wxe34vlatswxkinpxmp5hxsomd55fqgbyf41g3kbgwk2ngbtfpupxwcndg3yzhkdaqdqpx3bmzgpntd4p0sfgwa441hppwmq2lsk2janbyhl3e1ptgpbdlnat2w21ukhm1kv4dpclpzp0p2vauob0zb4hsxvzi0gywexxzltim5ilmyvnrmwlk40hsly3q4xaadqpx3cvntfnn0ytnffkjc4x5trs44454sgucu4kx2m2byfa3d2zbshssd5wir0f13l14ln1xfcpe2w5j0d5rdnsda3dqjx3g3vdlk5xcjpcok1wypokpwgnlil4khjqkbyh41d5vruumwors0fu024zgkot100vjtrk34lx3ga3dv1cnlvhsmf1z5wutp0vkw2pwixvctl5j4iobypa4zrvkkch05giwwq4lmwqrf1ntwih21ly4fv1eiobyha4pylyyefx2tombpdl1lte5jlg3p0vilw5xmcla3dqnx3knm50tjlqnv12pwmz152ponnmafzs4iobyha4zrb4vtrlcxl20oqj54rxsuv5lrxcvdphm3dr1dgzqjp3otwo022qlrx0tlfiz3yfff4znfbyda3dp1eop2klbgoufqi2w3m5vqkyczlsjoagpxmuda3dqlx3dy020t0gde3vngk0d1u2vnkke1pnpf0a43kp3aha3dz1dwp2tvxklwknk55dlv2fbs135r0ix3pxbysdiob0zc44q1showz05sgn1moezliktgbku3lw55gmt3mo1ceobypaxlyx0mbl5ik1cl2oo4kdh40wwkxx5zoki1gbfyhb3fnxdmwqicfgdlzijcvkyvqz03h5yc31ev55ycxa3hqlx3n0qp5mxolk1nn4q1bwtkvmvtw22upeu5dqohys23m0lbxg04rx114zs3u31ehzki34jzihpotha3hpkbiha4pyu1xnmdt35ww31ht1f2epymzjf2x0phwwhamdqjx3ek1a54ufwoadzvikpo5iorjtplsm24eonyhb3dnzaef0m00jfmzvkatlu0xxdn0zpjueaaob5za4p23twus04k0ildq2nugd0dytpfsxgli22y1c33dr1cxpcgsax512lsmyq1h243s4kzmjmn3vtgayhazpyuj2yhgmv0nltaz01spccxf44kpn20mowlyodyh51h3kc2i43lddhvevviv1r4hqp5jkzkbtzvxqzlbi3dq1bg4yqr2gpw25vc4v3l4aan2xgx2zvxixhyobyg41eols0ong5koxbvretcf52ochl1nwbihazzqwpcif3ulfl3oixqvyulo5vky2ir45yag521jyha4pyplj3kmtoranly3wmn2mjoworm1wunnjcmx1adqobzzb4hvdqn3x5m1fzi3xnp4tm4y0ybhxfo5lfxyha3d2zbz15eaqobyha3dqobyha3dqobyhp3mz3apaujsxhmrfz0maaaaaacjivhejlscmcbaaaaaaaaaa"

s = "abcdefghijklmnopqrstuvwxy054321z"

x = [input.chars.map{|x| s.index(x) }.map{|x| ("00000" + x.to_s(2))[-5..-1] }.join].pack("B*")

# "\x89PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x02\xDA\x00\x00\x02\xDA\x01\x03\x00\x00\x005 fp\x00\x00\x00\x06PLTE\x00\x00\x00\xFF\xFF\xFF\xA5\xD9\x9F\xDD\x00\x00\x00\x02tRNS\xFF\xFF\xC8\xB5\xDF\xC7\x00\x00\x00\tpHYs\x00\x00\v\x12\x00\x00\v\x12\x01\xD2\xDD~\xFC\x00\x00\x06\xD8IDATx\x9C\xED\xDAA\x92\xF2:\fFQUe\x01,)[\xEF%\xB1\x00\xAA\xF4\x1AK\x9F\xA4\x00o\xF2\xE3\x9E]\x0FhH\xE2\x93Ld\xC9J\x9B\xFF\xE10ppppppppppppp\xF0O\xB8\xE58\xDC\x7F\x9E\x7FO\x7F\xE8\xD0\xED\xF1{\xC9\xFDp;\xEFf\xBFg\x9F\x97\xFC\x1E\xFB\xBD\xC4\xE3X\x9E\x88\xEB4\xEB\x04\a\a\xDF\x88\xC7\x8F\xA7a\xB7\xBC\xD7\xFA\xB9\xEE5O,C\x8F\xD3gS\xE9o\xE0\xE0\xE0;\xF1\x88\xE3\x8A\xF2\xB8\xC3\xC2\x8F\xFC\x16dD\xFEC\xEBB,\x13yI\x00\xF1\r\x1C\x1C\xFCop\xCF\xE9\x91n\xF3\xFAL\xC1\x91\x963\xF2\x0F\xAD\x06w\xAB\x0Fpp\xF0?\xC6\xFB\x0E+\xDD\x8E\x99\x16#\x82\xBE.\x99i\x19\x1C\x1C\xFCo\xF0\xF5\xA7\x13\xB4\x02&lt;\xC6\x8Fv\xBA\np\e\x9B\xDC^&amp;f1\r\x0E\x0E\xBE\x11\xCFQ\xE1\xFF\xAF\x1F\x82\xC0\xC1\xC17\xE2sD0g\xCD\x9C\xDB\xDD[\xEEe{\r\xD0\xBA\xE0\xD5\xA9\xB2w\n\x1C\x1C|\x13~\xCF\xA6\xF0X\br5x+\xA1\xB3\r\xA5{e\xAA\x8E{\xE5\e pp\xF0\xBD\xF8\xE8\xFD\xAEx\xAFKW\xF3)V\x03M\xB1\xFAVd\xAF\x15\xD1\x9F:\xC1\xC1\xC1\xF7\xE1\x19\xD6\x91x\xFBRu\x86\xAB&gt;\xCEMn\xDC:?\xFA\x99\xD2\xBD\x83\x83\x83o\xC6OU\xC5/i9f\xFE\xD4\xB1\x8E\xF2\\0\x9E_jqxf\xF8^&amp;\xC0\xC1\xC1w\xE2Y\x15\xBB\x8F\xD7\xA9\xB9\x83u\xF7\xFEo\xC2\xD7nq\xBF\xBB\x89\xD5@'\xC0\xC1\xC17\xE1#\xDD\xC6\xE1q,\xB3\xF4\x88\xED\xB8\xA1\x82&gt;\x9BTUG\xC7\xC3\x82\x83\x83\xEF\xC4\xAD\"Z\xAD\xE0\x8E\xE8\x91\x91OW6Ow\xDE_\xFFp\b\x0E\x0E\xBE\x1D7S\xCB)\xF3\xB02\xED#&gt;\xE2:\xD7v\xD7\xAA\xD4V\x1D=\xFFw\x02\x1C\x1C|'\x9E?\x14\xF9\xCA\xBE\x8B\\\x9B\\\xAB\xAET\x96\xD0\xA3\xE5\x14\xEF}nUL\xD7m\xC0\xC1\xC1\xF7\xE0\xDDr\x1A\x9D\xA5\xD1^\x1A\xF5q\xE1\xEA6\x8D\x12z\x8D\xAA\xA3\xC1\xC1\xC17\xE1\xB33ljHu\ej}\xF3\x97\xCC]Uv&gt;]\xFE\x9C\xD9\x1C\x1C\x1C|#\x9Em(\xD5\xD1\xE3\x84iW\xBB\xA6\x9B\xF6\xB7\xFD\xD3\xDD;\xFC\xEB\x86\xE0\xE0\xE0\x9Bp\x91SS\xF8_\xDAK\x8F*\xA6\xDD5\xA3\"\xBF\xB6\xC0'88\xF8F\xBC;\xBEs\xB7j5t\xD7\xD8\x02\xC7\x93\\\x16\f\x8B*\xDB\xB5\xFB\x05\a\a\xDF\x89[6\x9F\xF2RS\b\xC7\xFE\xD6^\xAA\xE7\xBAa&lt;\x98N\xD4v\x17\x1C\x1C|+&gt;\xB2\xAAg\xA6\x1D{\xDE\xF3\xB5\xEF\xF4\xFC\xD3\xDDbW1}V3\v\x1C\x1C|/\xDE\xC5o\x15\xC9J\xC6\x8A|\xF5\xA2\xB2\xE5\xF4\xB8\xAE\x01J\xD5\x91\xC8\xC1\xC1\xC1\xF7\xE1\xFD*'\"z}\xEB\x00\x7F\x0EU\xCF\xEE\xF3DT\xDE\xAED~\x9B7\x04\a\a\xDF\x85G\x91lV?m\xE6\xEB\xDC\xF8\xE6\x1Db\xAD\x98\xBBZ\e\xCF\xD4])pp\xF0M\xB8\x8Ad\xFD\xD7\xC3O\xEDy\x83\xECd\x1C\xCBDe\xE4\xD1\xA9\xB2\xCB\xD2\x01\x0E\x0E\xBE\x0F\x17i\xB3\\\x8E]\xAD\xB4\xF5m4\x8A\xBBf\xEE:\xFA\x1C'\xC0\xC1\xC1\xB7\xE1\x9F.\xB8t\x86\x8Fq\e\xAB\xED\xAE\x16\x82G\xAC\x10\xDA\e\xDB\x87.488\xF8\xBF\xE3\xBA\x83\xD5\xB9\xB5\xC9\xCD\xD5`\x9C\xADu!\xAF\xBB\x1F\xA3\xDEN`\xF5\xA2\xC0\xC1\xC1w\xE3qA5\x95\xD6\x983+\xE8\xFB\xD8M\x19\xB9\x8F\x9DC\x04\a\a\xDF\x81g\xCC\xF6\xCC{~dSX\e\xDF\x8E\xF7\xD9\x90\xEA\xE4\xAE\xA4\r\x0E\x0E\xBE\x13\xCF\x99\x9E\x11\xAD\xA0\x9Fm\xDFQGg\x95]\x8D\xE2[\xFE\xFC\xBF\xB5\x05\x1C\x1C\xFC;&lt;\xAF_\xA3&amp;\xC5\x89{\xFDsC4\x85\xB3\x15lYe\xABy&lt;\x97\x8ECw\x00\a\a\xDF\x82\xABfV\xB78\x9BJU$[\xBE\xA7\x19o{\xD6\xE4j\n\x9BU\xFA\xCE\x87\x05\a\a\xDF\x86G\x94\x87\xAB\"9/\xB8\xBFmm\xF5\xCA'\x93\xB6\xD2r=Dm\x90\xC1\xC1\xC17\xE1\xB9Q\xADZ\xB8\x92\xF19^\xB6\x1E\xE5&gt;\xC6j\xD0\xBD\xA8\xE9\x82\x83\x83\xEF\xC3\xD5cJ2\xCE\x8C\xB2Zg\xBB\xF9\x94\xE9\xFB9\xAAg\x15sk\xBF\f\x0E\x0E\xBE\x13WS\xC9\x85\xF7\xF5jM\xF9\xAA\xAD\xD7\xD9\x17\xA8\xA6\xBD'hpp\xF0o\xF1\xAA\x94#\xE7FE\xAD\r\xAD\x96\x84K\xE6\xCE\xC8?|\xBCl\xB5\xF1\x10\xE0\xE0\xE0\xDB\xF0\xBC`\x85\xBFf\xE6\x05\xE3_\x972i+7\x1F\x9A\xA1v\xD5\xD8%\x83\x83\x83o\xC55\x9A\xCC\xD2\xB86\xBE\xEB\xEC\xCF\xFB]{\x9A\xD6\x00\xBF\x96\xD0\xE0\xE0\xE0\xDF\xE2\x1D\xD6qX\xAE\xBE\xE5\xD0N\xB7\e\xCA\x95\xD2\xE3qTo;88\xF8f\xFC\x12\xFE:vv{\xD8.7\xCC\xD6T\x7F\x98)K\xBF\xB4\xA1\xC0\xC1\xC1\xBF\xC4s\xFA\xA5\x84\xCE\xA1`\x8E\xDB\x8C\xD5`\xAC\v\xEB\x92\\\x03&gt;\xEC\xA0\xC1\xC1\xC1w\xE0\xF1\x9E\xE6y0\xC9\xCA\xB4\xCA\xC8\xFDN\xD5\xAAQ&lt;\xF6\xBC\xB9\x06\xF8\xA7\xF0\a\a\a\xFF\x0E\xCF\xEC\xEBu.\xCAj\xB5\xA1\xAE\xBD(e\xEEj9E\xF8\xFB\x87\x12\x1A\x1C\x1C\xFC[\xDC=#\xBA\xDF\xCE\xA4f\xF9\x8E'\xD6\x85L\xC1U8\xBBkFd\xF8\xC7xDpp\xF0]x\xBEX\x15\xE9\n\xF0\x97\xD7;j\x19\xF7\x9BYW\xBE\xBE\xE5#\xC6\tpp\xF0\xAD\xB8\xD9h E0\xD7\xF4$UV+\x0F\xE7\x87\xD6\x05\xCF\x12\xBA\xD6\x05pp\xF0]\xF8\xDC\xC1\xFAe\xDC\xB5y\xAD\xDC&lt;\eMUegn\xF6\x8F%488\xF8\x97x\xCC\xAC76w\e\xFB\xDB\xFC\xB9Nx\x87\xFA\x91\xCD\xA7\xE8;\xDD3\x83\x87z\x82\x83\x83o\xC5=v\xB0s\xE6\xADnx\xF3\xF1zG\xE1\x9FI{|\xBC\xF6\xB1\xC0\xC1\xC17\xE1\x15\xE0kt-\x9C\x01\xFE\xA8S\xDD\xA4:)\x9B\xD7&amp;wdspp\xF0m\xF8\b\\\xB39IY\xFA\xA8\x13]3{\x8D\xB9\xFB\xD3B\x00\x0E\x0E\xBE\r\xBF\xBC\x9D\xA9,\xEDYB\xC7\x0E\xB6\x86\x1EG\x89\xBC\xB2\xB9\x96\x8E\xF7\x1E\x1788\xF8Wx\x8D _^\xEA\xE4\xCCC\xC7\xEE\xF9-\xAB\xECK\e\xCA\xCC\xC0\xC1\xC1\xF7\xE2\x89\xEE\x0EfW-\\\xC1\xFC\xFAO\x10\xAE]\xEDOor\xC7Yxp\xF0}x\xFCP\xBA\x8D\xF1c\x19\xEAJ\xD5\x15\xF4vx?IW\xD4\x19\xFE\xB7\x87\xD6\x14pp\xF0M\xBCB=3\xED\xDDT[\xAF\x17\xB0\x01\xBD\xB9\xAF\xDF\xD6\xE8\xB9\xF0\xE0\xE0\xDB\xF1\x1C\xB9e\xCD6\x94\xEB\x86\xB1$\xC4]u\xC2:\xFC\xDB\x05\a\a\xFF\v&lt;H/(\xB2\xAF\x8EE\xE1\\Qn\xD5U\x8E\xA2;\xD6\x00mw\xC9\xC1\xC1\xB7\xE1\xEBO\x14\xC9\xBA j\xF1\xCB1\xBDb]gE\x9E\xB5\x1A\xD4\x89\x97\xF0\a\a\a\xFF\x0E\xCFQ\xC1\xBC\xBE\x99\xE2\xFD\x1C\xBB_\xB9\xB3x\xCE\x02{\x95\xDAYo\x83\x83\x83\xEF\xC3\xFFh\x80\x83\x83\x83\x83\x83\x83\x83\x83\x83\x83\x83\x83\x83\xBF\x8C\xFF\x00\xF0Q2\xB9\xD9\x12\xFF,\x00\x00\x00\x00IEND\xAEB`\x82\x00\x00\x00\x00\x00\x00\x00"
</pre>
<p>圧縮の展開に失敗するため、普通の Preview.app などでは見ることができませんでしたが、とりあえず Chrome に投げたらある程度の断片が拾えて、QRコードだったので、なるほど〜といいつつ画像をチームチャットに投げたところ誰かのアプリが良い感じに読んでくれました。</p>
<pre class=""><code class="EnlighterJSRAW" data-enlighter-language="generic">SECCON{SEMAPHORE_LINE_IS_THE_1ST_TELEGRAPH_SYSTEM_IN_THE_WORLD}</code></pre>
<p>7番目ぐらいに解けた気がします。これ、多分うまくやると自動分類できるんですが、それでもそこそこしんどい気がしますね。結局PNGは最後まで戻せるのかどうか……</p>
<p>普段 Web 系の人間なはずなのに全く分からなくてしんどいし困りますね。でもバイナリにも強くなりたいですね。やっていきましょう。</p>The post <a href="https://blog.monora.me/2016/12/seccon-2016-online-ctf-write-up/">SECCON 2016 Online CTF に参加しました (Write-up)</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1458</post-id>	</item>
		<item>
		<title>shotgun じゃなくて rerun を使おうという話</title>
		<link>https://blog.monora.me/2016/03/use-rerun-with-tmux-not-shotgun/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=use-rerun-with-tmux-not-shotgun</link>
		
		<dc:creator><![CDATA[きょんたん]]></dc:creator>
		<pubDate>Sat, 26 Mar 2016 19:32:48 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[rerun]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[tmux]]></category>
		<guid isPermaLink="false">http://blog.monora.me/?p=1351</guid>

					<description><![CDATA[<p>Ruby で Rack アプリケーションを書いているときに、コード変更したら自動的にサーバー再起動したいという話。 今までは shotgun でやっていたのだけれど、これは毎回リクエストする度に変更の有無に関係なくサーバ [&#8230;]</p>
The post <a href="https://blog.monora.me/2016/03/use-rerun-with-tmux-not-shotgun/">shotgun じゃなくて rerun を使おうという話</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></description>
										<content:encoded><![CDATA[<p>Ruby で Rack アプリケーションを書いているときに、コード変更したら自動的にサーバー再起動したいという話。</p>
<p>今までは <a href="https://github.com/rtomayko/shotgun" target="_blank" rel="noopener noreferrer">shotgun</a> でやっていたのだけれど、これは毎回リクエストする度に変更の有無に関係なくサーバーを立ち上げ直すので、遅いという欠点があった。<br />
副次的な問題として、<a href="https://github.com/charliesome/better_errors" target="_blank" rel="noopener noreferrer">better_errors</a> で REPL が無効になるという欠点があった。(レスポンスを返すとそのコンテキストを捨ててしまうから?)</p>
<p>ずっと前からどうにかならないかなーと思っていたのでググったら <a href="https://github.com/alexch/rerun" target="_blank" rel="noopener noreferrer">rerun</a> というものを見つけた。<br />
Rack とか関係なくもっと汎用的なやつで、ファイル変更検知してサーバー上げ直すぞ! みたいなプロダクトらしい。</p>
<p>入れたら下のような感じで使える。便利。</p>
<p><code>RACK_ENV=development rerun -- rackup -o 127.0.0.1<br />
</code></p>
<p>調子に乗って通知有効化するぞ! というノリで <a href="https://github.com/julienXX/terminal-notifier" target="_blank" rel="noopener noreferrer">terminal-notifier</a> を入れてみたらサーバーが上がらなくなった。何事かと思ったら tmux 上で使おうとすると一癖あるらしく、<a href="https://github.com/julienXX/terminal-notifier/issues/115" target="_blank" rel="noopener noreferrer">こういうIssue </a>が立っていたので適当に読んだら解決した。</p>
<p>要するに、<code>brew</code> なりなんなりで、<code>reattach-to-user-namespace</code> をインストールして、<code>.tmux.conf</code> に下を書き加えるという話。</p>
<pre>
set -g default-command "which reattach-to-user-namespace &gt; /dev/null &amp;&amp; reattach-to-user-namespace -l $SHELL || $SHELL -l"</pre>
<p>再起動に掛かる時間が体感で倍ぐらいになったけれど、<code>better_errors</code>使えることで圧倒的効率アップみたいなところがあるので、トータルで幸福度が向上した気がする。</p>The post <a href="https://blog.monora.me/2016/03/use-rerun-with-tmux-not-shotgun/">shotgun じゃなくて rerun を使おうという話</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1351</post-id>	</item>
		<item>
		<title>Sinatra Modular-Application で configure が上書きされる問題の対処</title>
		<link>https://blog.monora.me/2016/03/problem-about-overwritten-configure-in-sinatra-using-modular-application/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=problem-about-overwritten-configure-in-sinatra-using-modular-application</link>
		
		<dc:creator><![CDATA[きょんたん]]></dc:creator>
		<pubDate>Tue, 15 Mar 2016 20:35:15 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[sinatra]]></category>
		<guid isPermaLink="false">http://blog.monora.me/?p=1322</guid>

					<description><![CDATA[<p>Ruby の Siantra で、Modular-Application を書いていたら良く分からない挙動にぶち当たって気が付いたら朝になっていたのでメモ。 app.rb require_relative "hoge"  [&#8230;]</p>
The post <a href="https://blog.monora.me/2016/03/problem-about-overwritten-configure-in-sinatra-using-modular-application/">Sinatra Modular-Application で configure が上書きされる問題の対処</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></description>
										<content:encoded><![CDATA[<p>Ruby の <a href="http://www.sinatrarb.com/" target="_blank" rel="noopener noreferrer">Siantra</a> で、Modular-Application を書いていたら良く分からない挙動にぶち当たって気が付いたら朝になっていたのでメモ。</p>
<p>app.rb</p>
<pre class="EnlighterJSRAW" data-enlighter-language="ruby" data-enlighter-linenumbers="true">require_relative "hoge"

class App &lt; Sinatra::Base
  configure do
    disable :protection
  end

  use HogeRoutes
end
</pre>
<p>hoge.rb</p>
<pre class="lang:ruby" title="hoge.rb">class HogeRoutes &lt; Sinatra::Base
  get "/" do
     ...
  end
end
</pre>
<p>みたいな事をしていた。<br />
<code>disable :protection</code> をしているのにどうしても <code>Rack::Protection</code> が有効になるので、どうしてこうなるんだとあちこちのコードを追いかけたりした結果、<code>HogeRoutes</code> が <code>App</code> とは別にもう一度 <code>session, protections</code> 等のセットアップが行われるので、以下のように、 <code>use HogeRoutes</code> を <code>configure</code> より上に持ってくる必要があった。</p>
<p>app.rb</p>
<pre class="EnlighterJSRAW" data-enlighter-language="ruby" data-enlighter-linenumbers="true">require_relative "hoge"

class App &lt; Sinatra::Base
  use HogeRoutes

  configure do
    disable :protection
  end
end
</pre>
<p><code>HogeRoutes</code> 内の <code>configure</code> で <code>disable :protection</code> とやってもいいが、こうするとクラスが増えた際にその分だけ書かないといけなくて大変。セッションみたいなアプリケーション全体で統一的な設定を持つ部分は親の <code>App</code> でやって良いんじゃないかと思う。</p>The post <a href="https://blog.monora.me/2016/03/problem-about-overwritten-configure-in-sinatra-using-modular-application/">Sinatra Modular-Application で configure が上書きされる問題の対処</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1322</post-id>	</item>
		<item>
		<title>2016年1月あたりの今日このごろ</title>
		<link>https://blog.monora.me/2016/01/these-days-in-jan-2016/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=these-days-in-jan-2016</link>
		
		<dc:creator><![CDATA[きょんたん]]></dc:creator>
		<pubDate>Wed, 06 Jan 2016 17:25:45 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[雑記]]></category>
		<category><![CDATA[近況報告]]></category>
		<guid isPermaLink="false">http://blog.monora.me/?p=714</guid>

					<description><![CDATA[<p>こんばんは。 面白そうな事にどんどん手を出し続けた結果、日々忙しい生活を送っています。 ふと、季報的な物を書きたくなったので書きます。 10/27: monora rebuild 12/7: Adventar::List [&#8230;]</p>
The post <a href="https://blog.monora.me/2016/01/these-days-in-jan-2016/">2016年1月あたりの今日このごろ</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></description>
										<content:encoded><![CDATA[<p>こんばんは。<br />
面白そうな事にどんどん手を出し続けた結果、日々忙しい生活を送っています。</p>
<p>ふと、季報的な物を書きたくなったので書きます。</p>
<h4>10/27: <a href="https://monora.me" target="_blank" rel="noopener noreferrer">monora</a> rebuild</h4>
<h4>12/7: Adventar::List release</h4>
<h4>12/11: 某社に見学に行く / バイトを始める</h4>
<h4>12/14: <a href="https://monora.me" target="_blank" rel="noopener noreferrer">monora</a> improve</h4>
<h4>12/16: ネットワークスペシャリスト試験合格</h4>
<p><span id="more-714"></span></p>
<p>&nbsp;</p>
<h3><a href="https://monora.me">monora</a> rebuild / improve</h3>
<p>12月に一番力を入れたのがここ。</p>
<p>新デザインの構想は結構前からあって、ずっと <a href="https://dev.monora.me/labo/monora-feature/">laboの方</a> にはデザイン案が置いてあった。ファイル名を見るに 2014/5/18 に作ったっぽい。</p>
<p><figure id="attachment_947" aria-describedby="caption-attachment-947" style="width: 1920px" class="wp-caption alignnone"><img loading="lazy" class="alignnone size-full wp-image-947" src="https://blog.monora.me/wp-content/uploads/2016/01/monora-feature_140518-1417.png" alt="monora-feature_140518-1417" width="1920" height="1080" srcset="https://blog.monora.me/wp-content/uploads/2016/01/monora-feature_140518-1417.png 1920w, https://blog.monora.me/wp-content/uploads/2016/01/monora-feature_140518-1417-200x113.png 200w, https://blog.monora.me/wp-content/uploads/2016/01/monora-feature_140518-1417-320x180.png 320w, https://blog.monora.me/wp-content/uploads/2016/01/monora-feature_140518-1417-768x432.png 768w, https://blog.monora.me/wp-content/uploads/2016/01/monora-feature_140518-1417-640x360.png 640w" sizes="(max-width: 1920px) 100vw, 1920px" /><figcaption id="caption-attachment-947" class="wp-caption-text">2014/5/18 時点でのデザイン構想</figcaption></figure></p>
<p>確か Adobe Creative Cloud の学生プランに入って Illustrator が使い放題になったので、使い方を学ぶべく作ったというところ。<br />
ただ、この時はまだWebでこの見た目を HTML / CSS で再現するのは無理だと割りきっていて、いつかこのデザインが日の目を見ると良いな、という感じだった。</p>
<p>そこから1年半が経過して、ふと思い出したのが SVG 。<br />
<span style="line-height: 1.7;">HTML 5 もそろそろ普及してきて良い感じに使えるんじゃない? と思いつつ、ものは試しで Illustrator で SVG出力してみた。</span></p>
<p><strong>「うん、普通に表示できるね」</strong></p>
<p>というのがその時の率直な感想。実はこれ、1年前の時点でできたんじゃない? とか思うけれど気にしない。<br />
Illustrator は優秀で、それなりに読める SVG を吐いてくる。これは結構驚きだった。(コードジェネレータがまともなコードを吐いてくるとはあまり思っていない)</p>
<p>ただ、パスの部分は合成操作を多くしたせいか、結構長くてごちゃごちゃとしたパスが出力されていたので、その辺りも含めて一度全部書き直した。</p>
<p>もう1つ面白い発見があって、SVG の見た目の部分を html ファイル内に書くのがダサい!! と思っていたら、なんと CSS で書けることが発覚した。</p>
<p>http://www.w3.org/TR/SVG/styling.html#StylingWithCSS</p>
<p>6.6 Styling with CSS に書いてあって</p>
<pre class="EnlighterJSRAW" data-enlighter-language="css" data-enlighter-linenumbers="true">svg circle {
  fill: #3C241A;
  fill-opacity: 0.64;
  stroke: #3C241A;
  stroke-opacity: 0.64;
}
</pre>
<p>というように SVG の属性 を CSS で書ける。とても便利。<br />
問題はエディタがこういった仕様を知らないことで、手元の Sublime Text 3 では全く色が付かない……</p>
<p>そうして、これが</p>
<p><img loading="lazy" class="alignnone size-full wp-image-989" src="https://blog.monora.me/wp-content/uploads/2016/01/monora-v1.png" alt="monora-v1" width="1275" height="764" srcset="https://blog.monora.me/wp-content/uploads/2016/01/monora-v1.png 1275w, https://blog.monora.me/wp-content/uploads/2016/01/monora-v1-200x120.png 200w, https://blog.monora.me/wp-content/uploads/2016/01/monora-v1-320x192.png 320w, https://blog.monora.me/wp-content/uploads/2016/01/monora-v1-768x460.png 768w, https://blog.monora.me/wp-content/uploads/2016/01/monora-v1-640x383.png 640w" sizes="(max-width: 1275px) 100vw, 1275px" /></p>
<p>&nbsp;</p>
<p>こうなりました</p>
<p><img loading="lazy" class="alignnone size-full wp-image-990" src="https://blog.monora.me/wp-content/uploads/2016/01/monora-160107.png" alt="monora-160107" width="1275" height="764" srcset="https://blog.monora.me/wp-content/uploads/2016/01/monora-160107.png 1275w, https://blog.monora.me/wp-content/uploads/2016/01/monora-160107-200x120.png 200w, https://blog.monora.me/wp-content/uploads/2016/01/monora-160107-320x192.png 320w, https://blog.monora.me/wp-content/uploads/2016/01/monora-160107-768x460.png 768w, https://blog.monora.me/wp-content/uploads/2016/01/monora-160107-640x383.png 640w" sizes="(max-width: 1275px) 100vw, 1275px" /></p>
<p>自分でも感動した。めっちゃ良い。現代って感じがする。</p>
<p>元より v1 の時点でも corner-radius が正式に出る前から使っていたし、丸っこいデザインが好きで、そういうデザインをしたかったというのがあっただけに実際にブラウザに表示された時は感動した。まだまだWebで丸を全面的に使ったサイトというのは中々見ないし、文字の配置なんかもイケてると思う。</p>
<p>ただ、SVG による難点もいくつかある。例えば <code>&lt;foreignObject&gt;</code> を使ってHTMLの要素 (<code>&lt;p&gt;</code> とか) を使わないと幅を固定して複数行表示ができない。けれど、<code>&lt;foreignObject&gt;</code> は現状でサポートされていないブラウザもそれなりにあるので、<code>&lt;text&gt;</code>と<code>&lt;tspan&gt;</code>を併用して地道に座標を当てる対処も必要。<br />
ただ、今回は <a href="http://typesquare.com/service/" target="_blank" rel="noopener noreferrer">TypeSquare</a> という、無料で和文のWebフォントが使えるサービス (リュウミンや新ゴのようなすごいフォントがタダで使えるすごいサービス ) を使っているので、どの環境でも同じフォントでほぼほぼ同じに見える……はず……</p>
<p>12/14 には improve と題して<del>無駄な</del>機能を付けた。</p>
<p><div style="width: 620px;" class="wp-video"><!--[if lt IE 9]><script>document.createElement('video');</script><![endif]-->
<video class="wp-video-shortcode" id="video-714-1" width="620" height="564" preload="metadata" controls="controls"><source type="video/mp4" src="https://blog.monora.me/wp-content/uploads/2016/01/ecdce6eba666ffe33ce9ec576a9aed5e.mp4?_=1" /><a href="https://blog.monora.me/wp-content/uploads/2016/01/ecdce6eba666ffe33ce9ec576a9aed5e.mp4">https://blog.monora.me/wp-content/uploads/2016/01/ecdce6eba666ffe33ce9ec576a9aed5e.mp4</a></video></div></p>
<p>カーソルを乗っけると色が変わったりブラーが掛かったりする。モダンな感じに動くし良いんじゃないかなみたいなノリ。<br />
Material っぽく、カーソルを乗っけたところから色が変わると面白いかなと思ったけれど、結構実装がつらそうなので後回し。</p>
<p>今でも正しかったのか悩んでて、そのうち外すかも。<br />
(この記事を書きながら Firefox で検証しようとしたら、この変更のせいでまともに文字が描画されていないことに気が付いたのでブラーは無効化しました……)</p>
<p>背景はデザインを変更して少ししてから変えたもので、上の画像のものは大学に一眼レフをふらっと持っていって撮ったもの。<br />
背景にも地味ながらこだわっていて、もっとバリエーションを増やしていきたいなと思う。そして年も開けたしそろそろ差し替えたい。この辺りの話はまたいつか。</p>
<p>そんなこんなで結構良い感じのデザインをしたと勝手に思っている。コンテンツを増やしていきたいと切実に思う今日このごろ。</p>
<h3><a href="http://adventarlist.monora.me/2015/12/25" target="_blank" rel="noopener noreferrer">Adventar::List</a> release</h3>
<p>この記事が公開されているときには既にアドベントカレンダーは終わっているんですけど……<br />
2014年12月にリリースして、その後しばらく動いていたんですが最近またサーバー環境のあれこれでぶっ壊しまして、ほぼほぼ1から作り直しみたいなことをしました。<br />
ただ、今回はなんやかんやでクローラが上手く動かないし直そうにも忙しいしで困った。<br />
(今確認したら何故か今日の日付が表示されているし困った。後で直します。)</p>
<h3>某社へ見学に行った / バイトを始めた</h3>
<p>書いてある通りで、何の変哲もないです。<br />
見学に行ったつもりが仕事してました。何か前のバイトでも同じことをした気がする。学習してないですね。</p>
<p>業種としては自社開発のWebサービスの運営企業で、Wantedly にも載ってるような、いわゆるスタートアップというところです。僕は Wantedly 経由じゃないですけれど。</p>
<p>前からインフラに興味があって、たまたま中の人からお話を伺う機会があったというタイミングの良さもあり、インフラ関連の開発をさせて頂くことになった。<br />
これを書いてる時点ではDockerとかAWSとかそのあたりを弄っています。</p>
<p>いい椅子があって、壁で仕切られて無くて明るくて美味しいコーヒーが飲み放題でうんぬんかんぬんという、自分の想像するベンチャー像をまさに具現化したような存在でとても良い開発環境で作業をさせて頂いています。</p>
<p>近況は以下のとおりです。</p>
<blockquote class="twitter-tweet" data-width="550" data-dnt="true">
<p lang="ja" dir="ltr">某社にて、何も考えないで <a href="https://twitter.com/whywaita?ref_src=twsrc%5Etfw">@whywaita</a> っていう先輩と「マウントポイント? alice でいいんじゃない??」「ﾖｯｼｬ」とかやってたせいで 社内チャットに alice って単語が飛び交うのを観測している</p>
<p>&mdash; kyontan (@sukukyon) <a href="https://twitter.com/sukukyon/status/683996193932746752?ref_src=twsrc%5Etfw">January 4, 2016</a></p></blockquote>
<p><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></p>
<blockquote class="twitter-tweet" data-width="550" data-dnt="true">
<p lang="ja" dir="ltr"><a href="https://twitter.com/sukukyon?ref_src=twsrc%5Etfw">@sukukyon</a> アリスカータレットではない事を主張していこう</p>
<p>&mdash; why/橘和板 (@whywaita) <a href="https://twitter.com/whywaita/status/684060812017729536?ref_src=twsrc%5Etfw">January 4, 2016</a></p></blockquote>
<p><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></p>
<blockquote class="twitter-tweet" data-width="550" data-dnt="true">
<p lang="ja" dir="ltr"><a href="https://twitter.com/sukukyon?ref_src=twsrc%5Etfw">@sukukyon</a> 全く覚えてないけど、確かアリスとボブからだったと思うし、ついでにアリスゲームも関係あることにしよう</p>
<p>&mdash; why/橘和板 (@whywaita) <a href="https://twitter.com/whywaita/status/684061949378727936?ref_src=twsrc%5Etfw">January 4, 2016</a></p></blockquote>
<p><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></p>
<p>思いつきで名前を付けるのは良くないですね。意味のある名前を付けるよう心がけましょう。</p>
<p>ところで、前のバイトを退職したという事実は一切なくて、、むしろ新しく始めたこっちの方が勤務日数としても結果的な給料としても少なくなるはずです。(現状では)</p>
<p>気になるお給料については前の会社と同じ時給という感じにしてもらった。半年後、1年後となった時にどっちの方が高くなっているのかは個人的に興味深いところ。(今の時給は1000円台前半です。まさかこの歳でこんなに貰えるとは……)</p>
<p>前からいた会社の方では、最近はもっぱら iOS 開発を主にやっています。社外秘と書かれた紙を見るだけでワクワクするし、Objective-C という言語は知れば知る程賢い設計だなあと感動する。Swift にもそういうワクワクはあるのかな。</p>
<h3>12/16: ネットワークスペシャリスト試験合格</h3>
<p>ネスペに合格しました。これで、IPAの情報処理技術者試験は AP/ES/SC/NW を取ったことになります。</p>
<p>テクノロジ系だと、あと DB は取れると思いますが、今ひとつ興味が……<br />
マネジメント / ストラテジ に関しては全く歯が立たないですし、ひとまず IPA に関してはこのあたりで卒業したいかなというところ。<br />
NW は興味がある分野といえど勉強期間が短く詰め込み学習になったのもあって一番つらかった。</p>
<blockquote class="twitter-tweet" data-width="550" data-dnt="true">
<p lang="ja" dir="ltr">一番楽しい資格試験はエンベデッドシステムスペシャリストだって、わたし、なんどでも言えちゃいます！</p>
<p>&mdash; kyontan (@sukukyon) <a href="https://twitter.com/sukukyon/status/677722585090551808?ref_src=twsrc%5Etfw">December 18, 2015</a></p></blockquote>
<p><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></p>
<p>また3週間後に資格試験が控えている気がしますし、これを取ったらしばらく資格を取るのはやめたい。</p>
<p>&nbsp;</p>
<p>ではまた。</p>The post <a href="https://blog.monora.me/2016/01/these-days-in-jan-2016/">2016年1月あたりの今日このごろ</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></content:encoded>
					
		
		<enclosure url="https://blog.monora.me/wp-content/uploads/2016/01/ecdce6eba666ffe33ce9ec576a9aed5e.mp4" length="2431478" type="video/mp4" />

		<post-id xmlns="com-wordpress:feed-additions:1">714</post-id>	</item>
		<item>
		<title>SECCON 2015 Online CTF に参加しました (Write-up)</title>
		<link>https://blog.monora.me/2015/12/seccon-2015-online-ctf-write-up/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=seccon-2015-online-ctf-write-up</link>
		
		<dc:creator><![CDATA[きょんたん]]></dc:creator>
		<pubDate>Sun, 06 Dec 2015 17:56:25 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[CTF]]></category>
		<guid isPermaLink="false">http://blog.monora.me/?p=645</guid>

					<description><![CDATA[<p>CTF 完全初心者なのになぜか SECCON 2015 九州大会「Attack &#38; Defense」 というオンサイトCTFへ参加し、 -163125 点を獲得した kyontan です。 その節は本当に申し訳あ [&#8230;]</p>
The post <a href="https://blog.monora.me/2015/12/seccon-2015-online-ctf-write-up/">SECCON 2015 Online CTF に参加しました (Write-up)</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></description>
										<content:encoded><![CDATA[<p>CTF 完全初心者なのになぜか SECCON 2015 九州大会「Attack &amp; Defense」 というオンサイトCTFへ参加し、 -163125 点を獲得した kyontan です。<br />
その節は本当に申し訳ありませんでした。関係各位へお詫び申し上げます。</p>
<blockquote><p>15:57:20 MMA(kyontan) got -163215 points from &#8230;.</p>
<p><a href="http://pastebin.com/KTqNZ4Jf" target="_blank" rel="noopener noreferrer">http://pastebin.com/KTqNZ4Jf</a></p></blockquote>
<p>さて、今回は人生2回目のCTF大会である、SECCON  2015 Online CTF へ、学校の同級生である h-otter / @hogextend と共にチーム overflow として参加しました。</p>
<p>最終順位は 1200点 147位 でした。初心者なりには良くできたのではないでしょうか…… (<a href="http://score.quals.seccon.jp" target="_blank" rel="noopener noreferrer">http://score.quals.seccon.jp</a>)</p>
<p><img loading="lazy" class="alignnone size-full wp-image-647" src="https://blog.monora.me/wp-content/uploads/2015/12/seccon2015-ranking.png" alt="seccon2015-ranking" width="391" height="35" srcset="https://blog.monora.me/wp-content/uploads/2015/12/seccon2015-ranking.png 391w, https://blog.monora.me/wp-content/uploads/2015/12/seccon2015-ranking-200x18.png 200w, https://blog.monora.me/wp-content/uploads/2015/12/seccon2015-ranking-320x29.png 320w" sizes="(max-width: 391px) 100vw, 391px" /></p>
<p><span id="more-645"></span></p>
<p>自分が解いたのは、以下の通りです</p>
<ul>
<li>SECCON WARS 2015 (100)<br />
何かQRコードが見えるなという感じだったので、良く分からないままにとりあえず動画をダウンロードし、適当にQRが見えている部分のスクリーンショットをVLCで17枚ほど取って、ImageMagick で比較(明) 合成してみたら解けた。<br />
(参考: <a href="http://d-poppo.nazo.cc/blog/2014/04/imagemagick/" target="_blank" rel="noopener noreferrer">http://d-poppo.nazo.cc/blog/2014/04/imagemagick/</a>)</li>
<li>Unzip the file (100)<br />
既知ファイル2個を h-otter が見つけたものの、既知ファイルを圧縮したものを引数に与えるのを忘れていたっぽいので渡してみたら解けた。</li>
<li>Reverse-Engineering Android APK 1 (100)<br />
一番苦戦しました。<br />
apk を逆アセンブルしてソースを除いたら native で libcalc.so の <code>calc()</code> を呼んでいるところまでは分かったものの、どうやって呼ぶかと……<br />
x86 やら armeabi-v7a の so があったので、Raspberry Pi でビルドしてみたりするものの上手くいかず、結局 Android Studio を入れてアプリケーションを1から作って解くというかなりつらい解き方をした。<br />
他の人の Write-up を見た感じだと、<code>calc()</code> のバイナリを読めば 7 を返すことが一瞬で分かったらしい。なるほどつらい</li>
<li>Exec dmesg (300)<br />
問題の zip を展開したら iso があったのでとりあえず VirtualBox で起動。<br />
Tiny Core Linux なるものが起動するも、 <code>dmesg</code> コマンドがなくて怒られる。調べてみたら busybox 使ってることが分かったので、フルバイナリ落とせば行けるやろ! と busybox のバイナリを wget で落としてきて <code>dmesg</code> を叩いて終わり。<br />
300点……? という感じのさっくり感でした。うーん……</li>
<li>Last Challenge (50)<br />
換字式暗号です!! 1問目でハッシュのキーとバリューを逆向きに作るとかいう凡ミスをやらかしている間に h-otter に解かれましたが、今度はちゃんと解けました。</li>
</ul>
<p>QR puzzle (Nonogram) についてはソルバを持って来たりパーサでごにょごにょしたりして数時間粘るものの ソルバの精度が低い &amp;&amp; QRコードの認識精度が低い という二重苦に苦しめられ、最終的に全操作を自動化して寝て数時間放置するも、2000回 問題を試行して最大正解数が 22/30 とかいうことになっていたので完全に敗北しました。つらい</p>
<p>その他の感想としては、 h-otter が割と色々やってくれて強いな―って思ったみたいなのがあります。<br />
あと、@hogextend が QR puzzle (Windows) を手動で300問 9パズルを解いてフラグを得ていたのが印象的でした。お疲れ様でした。</p>
<p>初めてにしては頑張ったと思っていますが、同じサークルの先輩方のチームには完全敗北を喫したので頑張っていきたい。最強のQRソルバがあるんだよ〜〜などと言われまして、それは何処に……という感じです。</p>The post <a href="https://blog.monora.me/2015/12/seccon-2015-online-ctf-write-up/">SECCON 2015 Online CTF に参加しました (Write-up)</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">645</post-id>	</item>
		<item>
		<title>sinatra-activerecord で seed_fu を使ってみた</title>
		<link>https://blog.monora.me/2015/10/use-seed_fu-in-sinatra-with-sinatra-activerecord/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=use-seed_fu-in-sinatra-with-sinatra-activerecord</link>
		
		<dc:creator><![CDATA[きょんたん]]></dc:creator>
		<pubDate>Tue, 13 Oct 2015 19:02:52 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[ActiveRecord]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[sinatra]]></category>
		<guid isPermaLink="false">http://blog.monora.me/?p=617</guid>

					<description><![CDATA[<p>Sinatra で、sinatra-activerecord を使っているときに、$ rake db:seed すると、既に存在するレコードが重複登録される。 これ、とても一般的な問題で、 Rails だと、seed_f [&#8230;]</p>
The post <a href="https://blog.monora.me/2015/10/use-seed_fu-in-sinatra-with-sinatra-activerecord/">sinatra-activerecord で seed_fu を使ってみた</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></description>
										<content:encoded><![CDATA[<p>Sinatra で、<a href="https://github.com/janko-m/sinatra-activerecord" target="_blank" rel="noopener noreferrer">sinatra-activerecord</a> を使っているときに、<code>$ rake db:seed</code> すると、既に存在するレコードが重複登録される。</p>
<p>これ、とても一般的な問題で、 Rails だと、<a href="https://github.com/mbleigh/seed-fu" target="_blank" rel="noopener noreferrer">seed_fu</a> というのを使って解決したりするらしい。</p>
<p>Rails (ActiveRecord 4.x) で動くなら Sinatra (sinatra-activerecord) でも問題なく動くとおもいきや、<code>$ rake -T</code> しても <code>db:seed_fu</code> が表示されない……</p>
<p>ソースやらなんやら見ながら唸っていたら、どうも Rake のタスク追加を、 <a href="https://github.com/mbleigh/seed-fu/blob/master/lib/seed-fu/railtie.rb" target="_blank" rel="noopener noreferrer">Railtie を使ってやろうとしているところ</a>を発見した。<br />
どうやら Rails だと、初期化時にここのコードが走るらしいのだけれど、Sinatra にそんなものはないので当然タスクは追加されない。</p>
<p>というわけで、<code>Rakefile</code> にベタ書きしてみる。<br />
メインのアプリケーションソースが <code>./app.rb</code> にあるということになっています。(適宜書き換えてください)<br />
あと、なぜか <code>&lt;&lt;</code> が <code>&lt; &lt;</code> に置き換えられたので修正してください。</p>
<pre class="EnlighterJSRAW" data-enlighter-language="ruby" data-enlighter-linenumbers="true">namespace :db do
  desc &lt; &lt;-EOS Loads seed data for the current environment. It will look for ruby seed files in (settings.root)/db/fixtures/ and (settings.root)/db/fixtures/(settings.environment)/. By default it will load any ruby files found. You can filter the files loaded by passing in the FILTER environment variable with a comma-delimited list of patterns to include. Any files not matching the pattern will not be loaded. You can also change the directory where seed files are looked for with the FIXTURE_PATH environment variable. Examples: # default, to load all seed files for the current environment rake db:seed_fu # to load seed files matching orders or customers rake db:seed_fu FILTER=orders,customers # to load files from settings.root/features/fixtures rake db:seed_fu FIXTURE_PATH=features/fixtures EOS task :seed_fu =&gt; :environment do

    if ENV["FILTER"]
      filter = /#{ENV["FILTER"].gsub(/,/, "|")}/
    end

    if ENV["FIXTURE_PATH"]
      fixture_paths = [ENV["FIXTURE_PATH"], ENV["FIXTURE_PATH"] + "/" + settings.environment.to_s]
    end

    SeedFu.seed(fixture_paths, filter)
  end

  task :load_config do
    require "./app"
  end
end

Rake::Task["db:seed_fu"].enhance(["db:load_config"])

SeedFu.fixture_paths = [
  Pathname(settings.root).join("db/fixtures").to_s,
  Pathname(settings.root).join("db/fixtures/#{settings.environment}").to_s
]
</pre>
<p>コードとしては、<a href="https://github.com/mbleigh/seed-fu/blob/master/lib/tasks/seed_fu.rake" target="_blank" rel="noopener noreferrer">seed_fu の rakeファイル</a> を元に、<a href="https://github.com/janko-m/sinatra-activerecord/blob/master/lib/sinatra/activerecord/rake/activerecord_4.rb" target="_blank" rel="noopener noreferrer">sinatra-activerecord から、データベースの接続設定を拾ってくる部分</a>を参考にしたりした。</p>
<pre class="EnlighterJSRAW" data-enlighter-language="ruby" data-enlighter-linenumbers="false">Rake::Task["db:seed_fu"].enhance(["db:load_config"])
</pre>
<p>の部分がミソで、これでアプリケーションを通してデータベースに接続する必要がある。ここで2時間ぐらいハマった。</p>The post <a href="https://blog.monora.me/2015/10/use-seed_fu-in-sinatra-with-sinatra-activerecord/">sinatra-activerecord で seed_fu を使ってみた</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">617</post-id>	</item>
		<item>
		<title>non-root な環境で UTF-8 対応の nano をビルドする</title>
		<link>https://blog.monora.me/2015/10/build-nano-with-utf8-without-root/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=build-nano-with-utf8-without-root</link>
		
		<dc:creator><![CDATA[きょんたん]]></dc:creator>
		<pubDate>Mon, 12 Oct 2015 20:53:54 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[GNU nano]]></category>
		<category><![CDATA[Ubuntu]]></category>
		<guid isPermaLink="false">http://blog.monora.me/?p=604</guid>

					<description><![CDATA[<p>Ubuntu なレンタルサーバーで、 GNU nano を使おうとしたらそもそも nano が入ってなくて、適当にソースを拾ってきて野良ビルドしたら日本語が打てなくてつらくなった。 つらくなったので、--with-utf [&#8230;]</p>
The post <a href="https://blog.monora.me/2015/10/build-nano-with-utf8-without-root/">non-root な環境で UTF-8 対応の nano をビルドする</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></description>
										<content:encoded><![CDATA[<p>Ubuntu なレンタルサーバーで、 <code>GNU nano</code> を使おうとしたらそもそも <code>nano</code> が入ってなくて、適当にソースを拾ってきて野良ビルドしたら日本語が打てなくてつらくなった。<br />
つらくなったので、<code>--with-utf8</code> を付けてビルドしようとしたら、 <code>configure</code> で以下のエラーが出てつらくなって結構ハマったので備忘録。</p>
<pre>*** UTF-8 support was requested, but insufficient UTF-8 support was
*** detected in your curses and/or C libraries. Please verify that your
*** slang was built with UTF-8 support or your curses was built with
*** wide character support, and that your C library was built with wide
*** character support.
</pre>
<p>これを non-root な環境で以下の方法にて解決した。<br />
とてもシンプルではあるんだけど、 &#8211;enable-widec とか忘れるねん……</p>
<p>バージョンは執筆時点のものです。</p>
<pre>$ wget http://www.nano-editor.org/dist/v2.4/nano-2.4.2.tar.gz
$ rm nano-2.4.2.tar.gz
$ cd nano-2.4.2
$ apt-get source libncursesw5
$ cd ncurses-5.9-20140118
$ ./configure --enable-widec --prefix=$HOME --with-shared
$ make
$ make install
$ cd ../nano-2.4.2
$ ./configure --prefix=$HOME --enable-color --enable-multibuffer --enable-nanorc --enable-utf8
$ make
$ make install
</pre>
<h4>追記 (2015/10/14)</h4>
<blockquote class="twitter-tweet" width="550">
<p lang="ja" dir="ltr"><a href="https://twitter.com/sukukyon">@sukukyon</a> Gehirn RS2 Plus の明日のアップデートで nano と libncursesw5-dev をインストールします。明日のお昼までにこのアップデートが適用されます。</p>
<p>&mdash; Kohei YOSHIDA (@yosida95) <a href="https://twitter.com/yosida95/status/653926613772447745">October 13, 2015</a></p></blockquote>
<p><script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script></p>
<p>とのことなので、Gehirn RS2 では non-root でも何もしなくても nano が使えるようになるらしい。ありがたい……。</p>The post <a href="https://blog.monora.me/2015/10/build-nano-with-utf8-without-root/">non-root な環境で UTF-8 対応の nano をビルドする</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">604</post-id>	</item>
		<item>
		<title>Gehirn DNS を DDNS っぽく使えるようにする gddns2 を作った</title>
		<link>https://blog.monora.me/2015/10/wrote-gddns2-a-ddns-client-for-gehirn-dns/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=wrote-gddns2-a-ddns-client-for-gehirn-dns</link>
		
		<dc:creator><![CDATA[きょんたん]]></dc:creator>
		<pubDate>Mon, 12 Oct 2015 17:15:21 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[gddns2]]></category>
		<category><![CDATA[Gehirn DNS]]></category>
		<category><![CDATA[作った]]></category>
		<guid isPermaLink="false">http://blog.monora.me/?p=601</guid>

					<description><![CDATA[<p>皆さん Gehirn DNS 使ってますか? 僕は使ってます! Gehirn DNS というのは、エイリアスやらマイグレーションやら機能が充実している DNSサービスです。 Web インターフェースもモダンで結構使いやす [&#8230;]</p>
The post <a href="https://blog.monora.me/2015/10/wrote-gddns2-a-ddns-client-for-gehirn-dns/">Gehirn DNS を DDNS っぽく使えるようにする gddns2 を作った</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></description>
										<content:encoded><![CDATA[<p>皆さん Gehirn DNS 使ってますか? 僕は使ってます!</p>
<p><a href="https://www.gehirn.jp/gis/dns.html" target="_blank" rel="noopener noreferrer">Gehirn DNS</a> というのは、エイリアスやらマイグレーションやら機能が充実している DNSサービスです。<br />
Web インターフェースもモダンで結構使いやすいのですが、もちろん API も叩けるので CLI でアップデートできて便利。<br />
<small>ステマっぽいですが、使ったところで僕には1円も入りません……</small></p>
<p>そんな Gehirn DNS を、<a href="https://github.com/atpons/gddns" target="_blank" rel="noopener noreferrer">gddns</a> を使って DDNS っぽく使っていたのですが、Gehirn Infrastructure Service の開始に伴い API体型もガラッと変わりました。</p>
<p>新しい Gehirn DNS でも DDNS っぽく使いたいですよね。<br />
というわけで <a href="https://github.com/kyontan/gddns2" target="_blank" rel="noopener noreferrer">gddns2</a> を作りました。</p>
<p><span id="more-601"></span></p>
<p>gddns2、複数ゾーン/複数ドメイン使えて便利になった! みたいなのがあります。<br />
そのうち IPv6 対応もしたいところですね。</p>
<p>ちなみに、新しい Gehirin DNS ではリクエスト元の グローバルIP が取得できなくなったので、<a href="http://ipinfo.io" target="_blank" rel="noopener noreferrer">ipinfo.io</a> を使って取得しています。</p>
<p>Gehirn DNS、2円/日でとても安価なのですが、執筆時点(2015/10/13) ではプレビュー期間なので無料です。ぜひ使ってみてください。</p>The post <a href="https://blog.monora.me/2015/10/wrote-gddns2-a-ddns-client-for-gehirn-dns/">Gehirn DNS を DDNS っぽく使えるようにする gddns2 を作った</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">601</post-id>	</item>
		<item>
		<title>sigma.js に送った Pull Request が マージされた</title>
		<link>https://blog.monora.me/2014/10/sigma-js%e3%81%ab%e9%80%81%e3%81%a3%e3%81%9fpullrequest%e3%81%8c%e3%83%9e%e3%83%bc%e3%82%b8%e3%81%95%e3%82%8c%e3%81%9f/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=sigma-js%25e3%2581%25ab%25e9%2580%2581%25e3%2581%25a3%25e3%2581%259fpullrequest%25e3%2581%258c%25e3%2583%259e%25e3%2583%25bc%25e3%2582%25b8%25e3%2581%2595%25e3%2582%258c%25e3%2581%259f</link>
		
		<dc:creator><![CDATA[きょんたん]]></dc:creator>
		<pubDate>Thu, 09 Oct 2014 11:50:32 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Github]]></category>
		<category><![CDATA[sigma.js]]></category>
		<guid isPermaLink="false">http://blog.monora.me/?p=525</guid>

					<description><![CDATA[<p>sigma.js という便利なグラフ(グラフ理論の方)の描画ライブラリがあって、研究のGUI部分で使っていたらバグを踏んだという話。 グラフの描画領域をスクロールした時に、ノードをドラッグしようとすると座標がぶっ飛ぶとい [&#8230;]</p>
The post <a href="https://blog.monora.me/2014/10/sigma-js%e3%81%ab%e9%80%81%e3%81%a3%e3%81%9fpullrequest%e3%81%8c%e3%83%9e%e3%83%bc%e3%82%b8%e3%81%95%e3%82%8c%e3%81%9f/">sigma.js に送った Pull Request が マージされた</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></description>
										<content:encoded><![CDATA[<p><a title="Sigma js" href="http://sigmajs.org/" target="_blank" rel="noopener noreferrer">sigma.js</a> という便利なグラフ(グラフ理論の方)の描画ライブラリがあって、研究のGUI部分で使っていたらバグを踏んだという話。</p>
<p>グラフの描画領域をスクロールした時に、ノードをドラッグしようとすると座標がぶっ飛ぶという割りと深刻なバグなのだけれど、sigma.js のサンプルは全てページに全画面で描画されていたので今まで気が付かなかったんだと思う。</p>
<p>原因はブラウザの座標系の違い (pageX/Y と clientX/Y のズレ) だった。JavaScriptでブラウザの座標系なんて今まで意識したこともなかったせいで、原因を突き止めるのにかなり手間取ってしまった……</p>
<p><span id="more-525"></span></p>
<p>結果として、修正は以下の2行の変更で済んだ。</p>
<pre class="EnlighterJSRAW" lang="diff" data-enlighter-language="diff" data-enlighter-linenumbers="true">-  x = event.pageX - offset.left,
-  y = event.pageY - offset.top,
+  x = event.clientX - offset.left,
+  y = event.clientY - offset.top,
</pre>
<p>僕はこのコードが存在するもう一箇所(タッチデバイス向けのコードだった)にも修正をして、PR(Pull Request) を送ったのだけれど、これが問題だった。</p>
<p>送ってから数週間反応が無かったので、いつ Merge されるのかなと楽しみにしていたら、昨日 Issue に返信があって、「そのPRはタッチデバイスのピンチイン/アウト操作を破壊している」と突っ込まれ、………?! とびっくりしつつ、返信の検証コードを試したら確かにバグっていて、急いで元々の修正点1箇所だけを修正したPRを送信。</p>
<p><a title="Fix to drag nodes in scrollable page works properly. by kyontan · Pull Request #412 · jacomyal/sigma.js" href="https://github.com/jacomyal/sigma.js/pull/412" target="_blank" rel="noopener noreferrer">昨夜未明に無事 Merge されました。</a>よかったよかった。</p>
<p>OSS、こうして人のプロダクトに貢献出来るの良いな〜と思いますし、承認欲求も満たせて一石二鳥な感じがありますね。<br />
今後も貢献していきたい</p>
<p>なんとなくこの記事を書きながら、Issue の英語間違ってて恥ずかしいなこれーとかなっていた。恥ずかしい恥ずかしい</p>The post <a href="https://blog.monora.me/2014/10/sigma-js%e3%81%ab%e9%80%81%e3%81%a3%e3%81%9fpullrequest%e3%81%8c%e3%83%9e%e3%83%bc%e3%82%b8%e3%81%95%e3%82%8c%e3%81%9f/">sigma.js に送った Pull Request が マージされた</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">525</post-id>	</item>
		<item>
		<title>lldbの使い方備忘録</title>
		<link>https://blog.monora.me/2014/09/lldb%e3%81%ae%e4%bd%bf%e3%81%84%e6%96%b9%e5%82%99%e5%bf%98%e9%8c%b2/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=lldb%25e3%2581%25ae%25e4%25bd%25bf%25e3%2581%2584%25e6%2596%25b9%25e5%2582%2599%25e5%25bf%2598%25e9%258c%25b2</link>
		
		<dc:creator><![CDATA[きょんたん]]></dc:creator>
		<pubDate>Sun, 28 Sep 2014 06:41:49 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[lldb]]></category>
		<category><![CDATA[デバッガ]]></category>
		<guid isPermaLink="false">http://blog.monora.me/?p=507</guid>

					<description><![CDATA[<p>メモリ管理周りで色々ハマってたのだけど、普通にデバッガを使えばよかった。 Mac OSX だと、gdb より lldb を使う方が環境的に整ってて楽っぽい。LLVMさまさまだ。 LLDBの使い方（チュートリアル日本語訳） [&#8230;]</p>
The post <a href="https://blog.monora.me/2014/09/lldb%e3%81%ae%e4%bd%bf%e3%81%84%e6%96%b9%e5%82%99%e5%bf%98%e9%8c%b2/">lldbの使い方備忘録</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></description>
										<content:encoded><![CDATA[<p>メモリ管理周りで色々ハマってたのだけど、普通にデバッガを使えばよかった。<br />
Mac OSX だと、gdb より lldb を使う方が環境的に整ってて楽っぽい。LLVMさまさまだ。</p>
<blockquote><p><a href="http://cont0f.net/2014-04-lldb-tutorial-ja/" target="_blank" rel="noopener noreferrer">LLDBの使い方（チュートリアル日本語訳） | こん</a></p></blockquote>
<p>とりあえずここを読めばいいと思います。</p>
<p>以下は、上を読みながら実際にどのようにして作業を行ったかという流れのメモ。</p>
<p><span id="more-507"></span></p>
<p>まず、コンパイル時に -g オプションをつけてコンパイルすること<br />
(これによって変数名や関数名のようなデバッグ情報が埋め込まれる)</p>
<pre class="EnlighterJSRAW" data-enlighter-language="shell" data-enlighter-linenumbers="false">$ pgrep a.out</pre>
<p>なんかでプロセスのpidを取得して、</p>
<p>&nbsp;</p>
<pre class="EnlighterJSRAW" data-enlighter-language="shell" data-enlighter-linenumbers="false">$ lldb -p [pid]</pre>
<p>で対象プロセスにアタッチ</p>
<p>&nbsp;</p>
<pre class="EnlighterJSRAW" data-enlighter-language="shell" data-enlighter-linenumbers="false">(lldb) breakpoint set -n malloc_error_break</pre>
<p>とすると、mallocにまつわるエラーにブレークポイントがセットできる<br />
(その他のブレークポイント等は元記事を参照)</p>
<p>これを叩いた時に、メインプロセスの実行が止まったら</p>
<pre class="EnlighterJSRAW" data-enlighter-language="shell" data-enlighter-linenumbers="false">(lldb) c</pre>
<p>で再開出来る。(c は continue の省略コマンド)<br />
で、実行すると、ブレークポイントで自動的に lldb がスタックトレースを吐いて止めてくれる。</p>
<p>&nbsp;</p>
<pre class="EnlighterJSRAW" data-enlighter-language="shell" data-enlighter-linenumbers="false">(lldb) bt</pre>
<p>でスタックトレースが表示できる (bt = thread backtrace)</p>
<p>&nbsp;</p>
<pre class="EnlighterJSRAW" data-enlighter-language="shell" data-enlighter-linenumbers="false">(lldb) frame select [n]</pre>
<p>で、n番目のフレームに移動出来る (btで表示した #n にあたるもの)</p>
<p>&nbsp;</p>
<pre class="EnlighterJSRAW" data-enlighter-language="shell" data-enlighter-linenumbers="false">(lldb) frame variable</pre>
<p>とすると、そのフレームから見える変数が表示できる。</p>
<p>&nbsp;</p>
<pre class="EnlighterJSRAW" data-enlighter-language="shell" data-enlighter-linenumbers="false">(lldb) p [variable]</pre>
<p>とかすると、 valiable の値が表示できる。<br />
また、*, &amp;, -&gt;, [] みたいな演算子も使用可能</p>
<p>&nbsp;</p>
<pre class="EnlighterJSRAW" data-enlighter-language="shell" data-enlighter-linenumbers="true">(lldb) expr (int)printf("hoge")</pre>
<p>みたいにすると、 printf(&#8220;hoge&#8221;) の返り値を取得できる。<br />
ただし、返り値のキャストが必須のよう<br />
(普通にhogeと表示出来るらしいけれど、こちらの環境では上手くいかなかった)</p>The post <a href="https://blog.monora.me/2014/09/lldb%e3%81%ae%e4%bd%bf%e3%81%84%e6%96%b9%e5%82%99%e5%bf%98%e9%8c%b2/">lldbの使い方備忘録</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">507</post-id>	</item>
		<item>
		<title>Ubuntu 14.04 LTSでCUDA環境を整える</title>
		<link>https://blog.monora.me/2014/05/ubuntu%e3%81%a7cuda%e7%92%b0%e5%a2%83%e3%82%92%e6%95%b4%e3%81%88%e3%82%8b/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=ubuntu%25e3%2581%25a7cuda%25e7%2592%25b0%25e5%25a2%2583%25e3%2582%2592%25e6%2595%25b4%25e3%2581%2588%25e3%2582%258b</link>
		
		<dc:creator><![CDATA[きょんたん]]></dc:creator>
		<pubDate>Thu, 08 May 2014 15:46:22 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[CUDA]]></category>
		<category><![CDATA[GPU]]></category>
		<category><![CDATA[Ubuntu]]></category>
		<guid isPermaLink="false">http://blog.monora.me/?p=434</guid>

					<description><![CDATA[<p>最近組んだPCで環境構築をしていて、何故か物凄くハマったので記録。 以下、気を付けた方が良いと思った点です。 そもそもFreeBSDでCUDAをネイティブに扱うことは出来ないので辞めたほうが良さげ。(ハマった GUI環境 [&#8230;]</p>
The post <a href="https://blog.monora.me/2014/05/ubuntu%e3%81%a7cuda%e7%92%b0%e5%a2%83%e3%82%92%e6%95%b4%e3%81%88%e3%82%8b/">Ubuntu 14.04 LTSでCUDA環境を整える</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></description>
										<content:encoded><![CDATA[<p>最近組んだPCで環境構築をしていて、何故か物凄くハマったので記録。</p>
<p>以下、気を付けた方が良いと思った点です。</p>
<p><span id="more-434"></span></p>
<ul>
<li><strong>そもそも</strong>FreeBSDでCUDAをネイティブに扱うことは出来ないので辞めたほうが良さげ。(ハマった</li>
<li>GUI環境だと何度もコケたので、<strong>GUI環境は避ける方が良い</strong> (Ubuntu Server をおすすめします。</li>
<li><strong>apt-get</strong> でドライバ, CUDA Toolkitを入れるのはハマることが多いので、NVIDIAのサイトから<strong>.run</strong>ファイルを落とすのがおすすめです。</li>
<li><strong>nvidia-smi</strong> コマンドでグラボが認識しているか確認出来る。</li>
</ul>
<h4>参考リンク</h4>
<ul>
<li>ドライバ: <a title="NVIDIAドライバダウンロード" href="http://www.nvidia.co.jp/Download/index.aspx?lang=jp" target="_blank" rel="noopener noreferrer">NVIDIAドライバダウンロード</a></li>
<li>CUDA Toolkit (<span style="color: #000000;"><a title="Downloads | NVIDIA Developer Zone" href="https://developer.nvidia.com/cuda-downloads#linux" target="_blank" rel="noopener noreferrer">Downloads | NVIDIA Developer Zone</a>)</span></li>
</ul>The post <a href="https://blog.monora.me/2014/05/ubuntu%e3%81%a7cuda%e7%92%b0%e5%a2%83%e3%82%92%e6%95%b4%e3%81%88%e3%82%8b/">Ubuntu 14.04 LTSでCUDA環境を整える</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">434</post-id>	</item>
		<item>
		<title>Adventar::Listを作った</title>
		<link>https://blog.monora.me/2013/12/adventarlist%e3%82%92%e4%bd%9c%e3%81%a3%e3%81%9f/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=adventarlist%25e3%2582%2592%25e4%25bd%259c%25e3%2581%25a3%25e3%2581%259f</link>
		
		<dc:creator><![CDATA[きょんたん]]></dc:creator>
		<pubDate>Sun, 01 Dec 2013 12:39:47 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[AdventarList]]></category>
		<category><![CDATA[作った]]></category>
		<guid isPermaLink="false">http://blog.monora.me/?p=366</guid>

					<description><![CDATA[<p>12月になりました。アドベントカレンダーの季節ですね。 アドベントカレンダーといえば、去年はATNDを中心に行われているものが多かった気がするのですが、今年はAdventarというサイトが使われているものを多く見かけます [&#8230;]</p>
The post <a href="https://blog.monora.me/2013/12/adventarlist%e3%82%92%e4%bd%9c%e3%81%a3%e3%81%9f/">Adventar::Listを作った</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></description>
										<content:encoded><![CDATA[<p>12月になりました。<strong>アドベントカレンダー</strong>の季節ですね。<br />
アドベントカレンダーといえば、去年は<a title="イベント集客 告知 | 集客ならイベントアテンド" href="http://atnd.org/" target="_blank" rel="noopener noreferrer">ATND</a>を中心に行われているものが多かった気がするのですが、今年は<a title="Adventar" href="http://www.adventar.org/" target="_blank" rel="noopener noreferrer">Adventar</a>というサイトが使われているものを多く見かけます。<br />
Adventarというのは、その名の通り、アドベントカレンダーの作成, 記事の公開に特化したサービスで、TwitterやGithubアカウントを用いて簡単にアドベントカレンダーへの参加, 作成が出来ます。</p>
<p>ただ、このサービス、1つ気になったことがあります。</p>
<h3><strong>なんでアドベントカレンダー作るのはそんなに簡単なのに今日の記事一覧が見れないんだ!!</strong></h3>
<p>……何故でしょうか…… 今日公開された記事を5つ観ようとしたら、5つそれぞれのアドベントカレンダーのページを開き、そこから今日の日付のところまでスクロールし、リンクをクリックしないといけないのです……</p>
<p>これはまとめを作るしか無いなーと思いまして、作りました。</p>
<h3><a title="Adventer::List" href="http://adventarlist.monora.me/" target="_blank" rel="noopener noreferrer">Adventar::List</a></h3>
<p><span id="more-366"></span></p>
<p>※ちょこちょこ稼働させながらコード書き換えてるので500返りますがご愛嬌</p>
<p>超シンプルです。めいどいんSinatraです。<br />
最初はCGIで作っていて(何)、1ファイルで動いてミニマム感溢れていたのですが、あまりにも遅すぎたので途中でPassengerに変更しました。<br />
データはAdventarから持ってきたものを<a title="Nokogiri" href="http://nokogiri.org/" target="_blank" rel="noopener noreferrer">Nokogiri</a>でスクレイピングして、<a title="german/redis_orm - Github" href="https://github.com/german/redis_orm" target="_blank" rel="noopener noreferrer">redis_orm</a>を使って<a title="Redis" href="http://redis.io" target="_blank" rel="noopener noreferrer">Redis</a>に投げています。<br />
ただ、redis_ormの実装がアレなのか良く分かりませんが、異様にバグります。なんでや!!<br />
例えば、id=1なオブジェクトを検索したらid=2なものが返ってくるとか、find(:all, &#8230;)で取得したデータが何故か最後に突っ込んだデータだけとか…<br />
あまりにも残念すぎたので素直に<a title="DataMapper" href="datamapper.org" target="_blank" rel="noopener noreferrer">DataMapper</a>を使うべきだったと反省。</p>
<p>最後に:<br />
<a title="Amazon.co.jp: きょんたん: Wishlist" href="http://www.amazon.co.jp/registry/wishlist/10E3CDBHPY7IP" target="_blank" rel="noopener noreferrer">クリスマスプレゼントお待ちしております!</a></p>The post <a href="https://blog.monora.me/2013/12/adventarlist%e3%82%92%e4%bd%9c%e3%81%a3%e3%81%9f/">Adventar::Listを作った</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">366</post-id>	</item>
		<item>
		<title>開いているタブ数をツイートする Chrome Extension を作ってみた。</title>
		<link>https://blog.monora.me/2013/09/chrome-extension-tweets-number-of-opening-tabs/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=chrome-extension-tweets-number-of-opening-tabs</link>
		
		<dc:creator><![CDATA[きょんたん]]></dc:creator>
		<pubDate>Sat, 21 Sep 2013 15:37:46 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Chrome Extension]]></category>
		<category><![CDATA[Twitter]]></category>
		<category><![CDATA[作った]]></category>
		<guid isPermaLink="false">http://blog.monora.me/?p=318</guid>

					<description><![CDATA[<p>ふとした思いつきで作ってみた。 https://twitter.com/sukukyon/status/381401707759935489 https://twitter.com/sukukyon/status/381 [&#8230;]</p>
The post <a href="https://blog.monora.me/2013/09/chrome-extension-tweets-number-of-opening-tabs/">開いているタブ数をツイートする Chrome Extension を作ってみた。</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></description>
										<content:encoded><![CDATA[<p>ふとした思いつきで作ってみた。</p>
<p><a href=".page-template-archive-all-php #content div.post">https://twitter.com/sukukyon/status/381401707759935489</a></p>
<p><a href=".page-template-archive-all-php #content div.post">https://twitter.com/sukukyon/status/381401849338683394</a></p>
<p><span id="more-318"></span></p>
<p>Chrome Extension 、作るの面倒くさそうだなーという思い込みがあったのだけど、実際に試してみたらかなり簡単でした。</p>
<p>情報も充実してて、分からないことはググったら一発で解決したので、ふとした思いつきという微妙なモチベーションでも詰まらずに完成したわけですっ。</p>
<p>今更、作り方を説明などしても無駄な感じなので、参考になったサイトを2つだけ。</p>
<blockquote><p><a title="Chrome Extensions API リファレンス" href="http://dev.screw-axis.com/doc/chrome_extensions/">Chrome Extensions API リファレンス</a></p></blockquote>
<p>ただのリファレンスと言っては何だけれど、困ったことは大体ここを見れば良いと思う。</p>
<blockquote><p><a title="What are extensions? - Google Chrome" href="https://developer.chrome.com/extensions/index.html">What are extensions? &#8211; Google Chrome</a></p></blockquote>
<p>公式の解説ページ。リファレンスにもなっているけれど、チュートリアルだったり、各機能のサンプルが豊富にあったり。</p>
<p>単に自分が使えればいいやー程度の、そもそも公開する気なんてさらっさら無い拡張機能なので、セキュリティ周りとかを何も考えずに作ったら1時間で出来た。</p>
<p>それにしてもお手軽だなーと。</p>
<p>JavaScript やら HTML やらの基本知識さえあれば、そこそこの物は簡単に作れる気がする。ただ、既存の物は結構多いのでやはり<strong>新規性</strong>が…</p>
<p>とりあえず出来上がったものを置いておきますね。</p>
<p><a href="http://dev.monora.me/test/TabCount.crx">http://dev.monora.me/test/TabCount.crx</a></p>
<p>Chromeでそのままインストールしようとするとエラーが出るので、一旦ダウンロードしてから、設定-&gt;拡張機能 のところに ドラッグすればインストール出来る気がします。</p>The post <a href="https://blog.monora.me/2013/09/chrome-extension-tweets-number-of-opening-tabs/">開いているタブ数をツイートする Chrome Extension を作ってみた。</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">318</post-id>	</item>
		<item>
		<title>mod_mruby on FreeBSD</title>
		<link>https://blog.monora.me/2013/02/mod_mruby-on-freebsd/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=mod_mruby-on-freebsd</link>
		
		<dc:creator><![CDATA[きょんたん]]></dc:creator>
		<pubDate>Sun, 17 Feb 2013 09:31:21 +0000</pubDate>
				<category><![CDATA[FreeBSD]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[mod_mruby]]></category>
		<guid isPermaLink="false">http://blog.monora.me/?p=265</guid>

					<description><![CDATA[<p>mod_mrubyをFreeBSDで動かそうとして詰まるの修正点が変わってしまったのと、mod_mrubyが更新されてEvent MPMとWorker MPMでも動くようになったようなので再チャレンジしてみました。 Fr [&#8230;]</p>
The post <a href="https://blog.monora.me/2013/02/mod_mruby-on-freebsd/">mod_mruby on FreeBSD</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></description>
										<content:encoded><![CDATA[<p><a title="mod_mrubyをFreeBSDで動かそうとして詰まる" href="https://blog.monora.me/2012/12/mod_mruby%e3%82%92freebsd%e3%81%a7%e5%8b%95%e3%81%8b%e3%81%9d%e3%81%86%e3%81%a8%e3%81%97%e3%81%a6%e8%a9%b0%e3%81%be%e3%82%8b/">mod_mrubyをFreeBSDで動かそうとして詰まる</a>の修正点が変わってしまったのと、mod_mrubyが更新されてEvent MPMとWorker MPMでも動くようになったようなので再チャレンジしてみました。</p>
<p>FreeBSDでのmakeのやり方がまた変わってしまったので後述します。<br />
とりあえずベンチマークの結果から。</p>
<pre class="EnlighterJSRAW" data-enlighter-language="shell" data-enlighter-linenumbers="true">
$ cat test.txt
Hello!

$ cat test.rb
#!/usr/local/bin/ruby

print "Content-type: text/plainnn"
print "Hello"

$ cat test.mrb
Apache.rputs("Hello")
Apache.return(Apache::OK)
</pre>
<p>検証機のスペック: IBM ThinkCentre A55 (9636-A16)<br />
CPU: Core2 duo E6300@1.86GHz<br />
RAM: DDR2-SDRAM 1GB<br />
LAN: Broadcom Gigabit Ethernet<br />
Apache/2.2.23 (FreeBSD), mod_fcgid/2.3.6</p>
<p>Varnish(3.0.3)がリバースプロキシとして動いているので参考値であることをご了承ください。</p>
<p>abの条件は前回と同じく下記の通りで、3回計測して平均を取っています。</p>
<pre class="EnlighterJSRAW" data-enlighter-language="shell" data-enlighter-linenumbers="true">
$ ab -n 100000 -c 100
</pre>
<table>
<tbody>
<tr>
<th>Type</th>
<th>req/s</th>
</tr>
<tr>
<td>Plain Text</td>
<td>6318.693</td>
</tr>
<tr>
<td>Ruby 1.9.3p194(mod_fcgid)</td>
<td>5159.423</td>
</tr>
<tr>
<td><strong>mod_mruby</strong></td>
<td><strong>6700.153</strong> <del datetime="2013-02-17T12:15:11+00:00">4626.193</del></td>
</tr>
</tbody>
</table>
<p><del datetime="2013-02-17T12:15:11+00:00">な……何故か、FastCGIのrubyに負けてますが、このような結果となりました。</del></p>
<blockquote><p>
2013/2/17 21:15追記:<br />
mod_mrubyの作者である @matsumotory さんが<a href="https://twitter.com/matsumotory/status/303099603451015168" alt="Twitter / matsumotory: 最新のソースはthread_mutexにしたんだけど、それで ...">こんな事</a>を仰っていたので最新版をビルドし直して再測定しました。は、速い…
</p></blockquote>
<p>mod_mrubyはApacheのモジュールとかを書くのに面白く使えそうなので、そちらの道を模索してみたいなぁ……と</p>
<p>FreeBSDでmod_mrubyを使うためには、またちょこっと弄る必要があるみたいです。</p>
<pre class="EnlighterJSRAW" data-enlighter-language="shell" data-enlighter-linenumbers="true">
$ git submodule init && git submodule update
$ cd mruby
</pre>
<p>mruby本体のビルド設定に<strong>-fPIC</strong>を付ける。</p>
<pre class="EnlighterJSRAW" data-enlighter-language="shell" data-enlighter-linenumbers="true">
$ nano tasks/toolchains/gcc.rake
4: cc.flags = [ENV['CFLAGS'] || %w(-g -O3 -Wall -Werror-implicit-function-declaration -fPIC)]
</pre>
<p>makeではなく<strong>gmake</strong>を使う。</p>
<pre class="EnlighterJSRAW" data-enlighter-language="shell" data-enlighter-linenumbers="true">
$ rake
$ cd ..
$ ./configure
$ gmake && gmake install
</pre>
<p>この2点だけです。エラーが読めない人間には辛い……<br />
もう httpd.conf が mod_mruby を読み込むよう設定されているはずなので、 Apache を再起動させれば終わりです。</p>
<pre class="EnlighterJSRAW" data-enlighter-language="shell" data-enlighter-linenumbers="true">
$ httpd -k restart
</pre>The post <a href="https://blog.monora.me/2013/02/mod_mruby-on-freebsd/">mod_mruby on FreeBSD</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">265</post-id>	</item>
		<item>
		<title>mod_mrubyをFreeBSDで動かそうとして詰まる</title>
		<link>https://blog.monora.me/2012/12/mod_mruby%e3%82%92freebsd%e3%81%a7%e5%8b%95%e3%81%8b%e3%81%9d%e3%81%86%e3%81%a8%e3%81%97%e3%81%a6%e8%a9%b0%e3%81%be%e3%82%8b/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=mod_mruby%25e3%2582%2592freebsd%25e3%2581%25a7%25e5%258b%2595%25e3%2581%258b%25e3%2581%259d%25e3%2581%2586%25e3%2581%25a8%25e3%2581%2597%25e3%2581%25a6%25e8%25a9%25b0%25e3%2581%25be%25e3%2582%258b</link>
		
		<dc:creator><![CDATA[きょんたん]]></dc:creator>
		<pubDate>Fri, 21 Dec 2012 11:37:29 +0000</pubDate>
				<category><![CDATA[FreeBSD]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[mruby Apache mod_mruby]]></category>
		<guid isPermaLink="false">http://blog.monora.me/?p=230</guid>

					<description><![CDATA[<p>CombConfの発表が2日後に迫っているにも関わらず他の技術に手がでます。 組み込み向けのRubyであるmrubyをApacheに組み込めるようにした、mod_mrubyというものをFreeBSDで動かしてみようかと思 [&#8230;]</p>
The post <a href="https://blog.monora.me/2012/12/mod_mruby%e3%82%92freebsd%e3%81%a7%e5%8b%95%e3%81%8b%e3%81%9d%e3%81%86%e3%81%a8%e3%81%97%e3%81%a6%e8%a9%b0%e3%81%be%e3%82%8b/">mod_mrubyをFreeBSDで動かそうとして詰まる</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></description>
										<content:encoded><![CDATA[<p>CombConfの発表が2日後に迫っているにも関わらず他の技術に手がでます。</p>
<p>組み込み向けのRubyである<a title="mruby/mruby · GitHub" href="https://github.com/mruby/mruby">mruby</a>をApacheに組み込めるようにした、<a title="matsumoto-r/mod_mruby · GitHub" href="https://github.com/matsumoto-r/mod_mruby">mod_mruby</a>というものをFreeBSDで動かしてみようかと思って手を出したら大苦戦しました。</p>
<p>とりあえず動いたには動いたという状況ですが、簡単なメモとベンチマークを取ってみました。</p>
<blockquote><p>
<strong>2013/2/17追記</strong><br />
mod_mrubyの更新によって手順が変わりました⇒ <a title="mod_mruby on FreeBSD" href="https://blog.monora.me/2013/02/mod_mruby-on-freebsd/">mod_mruby on FreeBSD</a>
</p></blockquote>
<p>導入はmod_mrubyのページと同じようにやればいいのかと思いきや、makeでエラーを吐いてしまいます。</p>
<pre class="EnlighterJSRAW" data-enlighter-language="shell" data-enlighter-linenumbers="true">
$ make
make: illegal option -- -
usage: make [-BPSXeiknpqrstv] [-C directory] [-D variable]
        [-d flags] [-E variable] [-f makefile] [-I directory]
        [-j max_jobs] [-m directory] [-V variable]
        [variable=value] [target ...]
rake aborted!
Command failed with status (2): [make -C src --no-print-directory CC='gcc' ...]

Tasks: TOP =&gt; default =&gt; all
(See full trace by running task with --trace)
*** [libmruby.a] Error code 1

Stop in /root/mod_mruby.
</pre>
<p>どうもmrubyのRakefileがLinux向けのようで、makeをgmakeに書き換える必要があるようです。</p>
<pre class="EnlighterJSRAW" data-enlighter-language="shell" data-enlighter-linenumbers="true">
$ nano tmp/mruby/Rakefile
#MAKE = ENV['MAKE'] || 'make'
MAKE = ENV['MAKE'] || 'gmake'
</pre>
<p>mrubyは1回mod_mrubyをmakeをしないとRakefileが存在しないので注意です。</p>
<p>あとはWarningが出ますがとりあえずスルーして、make installすればApacheにモジュールが登録されます。<br />
あとはhttpd.confに、</p>
<pre class="EnlighterJSRAW" data-enlighter-language="shell" data-enlighter-linenumbers="true">
AddHandler mruby-script .mrb
</pre>
<p>と書き加えれば普通にmrubyファイルが動くはずなのですが……</p>
<p>自分の環境(Freebsd 9.1-BETA1 amd64, Apache/2.2.23 Event MPM)な環境では、httpdを起動した直後からCPUをバカ食いする上、リクエストに全く応答しなくなるという状況に陥ってしまい、解決策が分からなくなりました。<br />
そんなことをTwitterで呟いたら、mod_mrubyの作者である、<a title="人間とウェブの未来" href="http://blog.matsumoto-r.jp/" target="_blank" rel="noopener noreferrer">matsumoto-r</a>さんから</p>
<blockquote class="twitter-tweet" data-width="550" data-dnt="true">
<p lang="ja" dir="ltr"><a href="https://twitter.com/kyonfuee?ref_src=twsrc%5Etfw">@kyonfuee</a> 現状、きちんと対応しているのはpreformでworkerもeventも一応動くのですが、不安定です。preforkで試してもだめでしょうか？</p>
<p>&mdash; Ryosuke Matsumoto / まつもとりー (@matsumotory) <a href="https://twitter.com/matsumotory/status/282046980342022144?ref_src=twsrc%5Etfw">December 21, 2012</a></p></blockquote>
<p><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></p>
<p>という指摘を頂きました。試しに(FreeBSD 9.0 i386, Apache/2.2.22 Prefork MPM)な旧サーバーで試したところ、何も問題がないかのように動きました。<br />
どうもApache 2.2でEvent MPMをやるのはだめみたい……？</p>
<p><span id="more-230"></span></p>
<p>試しにどのくらい速いのか、mruby, FastCGIのRuby(mod_fcgid, 1.9.3p125), 静的ファイルの3つで比較してみました。</p>
<pre class="EnlighterJSRAW" data-enlighter-language="shell" data-enlighter-linenumbers="true">
$ cat test.mrb
Apache.rputs(&quot;Hello&quot;)
Apache.return(Apache::OK)
#!/usr/local/bin/ruby

$ cat test.rb
print &quot;Content-type: text/plainnn&quot;
print &quot;Hello!&quot;

$ cat test.txt
Hello!
</pre>
<p>検証機のスペック: <a title="ThinkCentre S50(8086-AGJ) - 製品仕様" href="http://support.lenovo.com/ja_JP/detail.page?LegacyDocID=SYP0-03184BF" target="_blank" rel="noopener noreferrer">IBM ThinkCentre 8086-AGJ</a><br />
CPU: Celeron D 330 2.66GHz<br />
RAM: DDR-SDRAM 1GB<br />
LAN: Gigabit Ethernet(Intel chip)</p>
<p>abの条件は下記の通り</p>
<pre class="EnlighterJSRAW" data-enlighter-language="shell" data-enlighter-linenumbers="true">
$ ab -n 100000 -c 100
</pre>
<p>結果:</p>
<ul>
<li>mruby</li>
</ul>
<p>Time taken for tests: 108.551 seconds<br />
Requests per second: <strong>921.23 [#/sec]</strong> (mean)<br />
Time per request: 108.551 [ms] (mean)<br />
Time per request: 1.086 [ms] (mean, across all concurrent requests)</p>
<ul>
<li>Ruby(FastCGI)</li>
</ul>
<p>Time taken for tests: 362.996 seconds<br />
<strong>Failed requests: 109</strong><br />
Requests per second: <strong>275.48 [#/sec]</strong> (mean)<br />
Time per request: 362.996 [ms] (mean)<br />
Time per request: 3.630 [ms] (mean, across all concurrent requests)</p>
<ul>
<li>txt</li>
</ul>
<p>Time taken for tests: 98.767 seconds<br />
Requests per second: <strong>1012.48 [#/sec]</strong> (mean)<br />
Time per request: 98.767 [ms] (mean)<br />
Time per request: 0.988 [ms] (mean, across all concurrent requests)</p>
<p>なんとmrubyが静的ファイルに迫る速度を出してました。すごい……</p>
<p><small>ちなみにmrubyが動かなかった方のメインサーバー(Core2 duo E6300@1.86Ghz, RAM512MB)ではRuby(FastCGI: mod_fcgid)で1857.93 [#/sec]とかいう値を叩きだしてました。</small><br />
後日メインのサーバーの方もPreforkにして検証してみようかと思います。<br />
いつになったらFreeBSD PortsにApache 2.4が来るのだろう……</p>
<p>そういえば、もう明後日に迫っていますが、<a title="CombConf" href="http://combconf.com/" target="_blank" rel="noopener noreferrer">CombConf</a>に参加します！<br />
内容は、「HTTPSを使わずに暗号化通信をしよう」でやる予定です。<br />
出来るの………？(まだ検証してない</p>The post <a href="https://blog.monora.me/2012/12/mod_mruby%e3%82%92freebsd%e3%81%a7%e5%8b%95%e3%81%8b%e3%81%9d%e3%81%86%e3%81%a8%e3%81%97%e3%81%a6%e8%a9%b0%e3%81%be%e3%82%8b/">mod_mrubyをFreeBSDで動かそうとして詰まる</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">230</post-id>	</item>
		<item>
		<title>DigitalArts プログラミングコンテスト2012に参加しました!</title>
		<link>https://blog.monora.me/2012/11/digitalarts-%e3%83%97%e3%83%ad%e3%82%b0%e3%83%a9%e3%83%9f%e3%83%b3%e3%82%b0%e3%82%b3%e3%83%b3%e3%83%86%e3%82%b9%e3%83%882012%e3%81%ab%e5%8f%82%e5%8a%a0%e3%81%97%e3%81%be%e3%81%97%e3%81%9f/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=digitalarts-%25e3%2583%2597%25e3%2583%25ad%25e3%2582%25b0%25e3%2583%25a9%25e3%2583%259f%25e3%2583%25b3%25e3%2582%25b0%25e3%2582%25b3%25e3%2583%25b3%25e3%2583%2586%25e3%2582%25b9%25e3%2583%25882012%25e3%2581%25ab%25e5%258f%2582%25e5%258a%25a0%25e3%2581%2597%25e3%2581%25be%25e3%2581%2597%25e3%2581%259f</link>
		
		<dc:creator><![CDATA[きょんたん]]></dc:creator>
		<pubDate>Sat, 24 Nov 2012 12:47:51 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[プログラミングコンテスト]]></category>
		<guid isPermaLink="false">http://blog.monora.me/?p=188</guid>

					<description><![CDATA[<p>タイトルの通りです。 DigitalArts Programming Contest 2012 なんとかA, B問題を解くことが出来ました。流れはこんな感じ。 http://twitter.com/kyonfuee/st [&#8230;]</p>
The post <a href="https://blog.monora.me/2012/11/digitalarts-%e3%83%97%e3%83%ad%e3%82%b0%e3%83%a9%e3%83%9f%e3%83%b3%e3%82%b0%e3%82%b3%e3%83%b3%e3%83%86%e3%82%b9%e3%83%882012%e3%81%ab%e5%8f%82%e5%8a%a0%e3%81%97%e3%81%be%e3%81%97%e3%81%9f/">DigitalArts プログラミングコンテスト2012に参加しました!</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></description>
										<content:encoded><![CDATA[<p>タイトルの通りです。<br />
<a title="DigitalArts Programming Contest 2012" href="http://www.daj.jp/company/recruit/contest/">DigitalArts Programming Contest 2012</a></p>
<p>なんとかA, B問題を解くことが出来ました。流れはこんな感じ。</p>
<p>http://twitter.com/kyonfuee/status/272311520388591616</p>
<p>長いでんがな……<br />
C問題は解けなかったです。時間足らず。</p>
<p>今回は初のRubyで挑戦してみました。getsとsplitとchompでどうにかなりそう？とか思いつつ、ARCで他人のRuby解答を見よう見まねでやってました。</p>
<p><span id="more-188"></span></p>
<h4>提出コード</h4>
<p><a title="A - C-Filter" href="http://digitalarts2012.contest.atcoder.jp/tasks/digitalarts_1" target="_blank" rel="noopener noreferrer">A &#8211; C-Filter</a><br />
見た瞬間に正規表現で解けそうだと思ったのでそのまんま。<br />
/aaa/だと&#8221;aaaa&#8221;にマッチしてしまうので、/^aaa$/にするようにして解決</p>
<pre class="EnlighterJSRAW" data-enlighter-language="ruby" data-enlighter-linenumbers="true">#!/usr/bin/ruby -Ku
input = gets.split

ng = []
num = gets.to_i
num.times { ng &lt; &lt; gets.chomp }

ng.map!{|v| v = Regexp.new("^" + v.gsub("*", ".") + "$")}
ng.each{|n| input.map!{|i| i =~ n ? i = "*" * i.length : i}}

input.length.times.each {|n| print input[n]; print " " if n != input.length}
puts
</pre>
<p>298Bytes(提出時から若干変更あり)</p>
<p><a title="B - Password" href="http://digitalarts2012.contest.atcoder.jp/tasks/digitalarts_2" target="_blank" rel="noopener noreferrer">B &#8211; Password<br />
最初は簡潔なコードにして書いていたつもりが、前述の通りひたすらにA問題に提出してWAを返されていたので焦りながら修正していたらこんなありさまに…<br />
でも最後のこのコードしか通らなかったり。本当に良く分からないミラクル。</a></p>
<p>Rubyではchar ⇒ intは &#8220;a&#8221;.ord, int =&gt; charは 96.chr みたいにやるらしい。へえ<br />
というのを利用して、後は普通のC言語でやるような感じで解いた。</p>
<p>後半のif out == input 以降が若干キモ？のようです。<br />
入力が&#8221;b&#8221;の時に&#8221;aa&#8221;を返したり、&#8221;zz&#8221;のときに&#8221;yza&#8221;を返すようにしてます。</p>
<pre class="EnlighterJSRAW" data-enlighter-language="ruby" data-enlighter-linenumbers="true">#!/usr/bin/ruby -Ku

hash = 0
input = gets.chomp
input.each_char {|s| hash += s.ord - 96}

if hash == 520 || hash == 1 #a, zzzzzzzzzzzzzzzzzzzz
  puts "NO"
  exit
end

out = ""
out += "z" * (hash / 26)
out += ((hash % 26) + 96).chr unless (hash % 26) == 0

if out == input
  if hash &lt; 26
    out = "a"
    out += (hash - 1 + 96).chr
  else
    out = "y"
    hash -= 25
    out += "z" * (hash / 26)
    out += ((hash % 26) + 96).chr unless (hash % 26) == 0
  end
end

puts out
</pre>
<p>484Bytes</p>
<h4>総評<br />
もう少し落ち着いたほうがいいと思う(4度の提出ミスに対して<br />
後はC言語みたいなコンパイラ言語が書けなくなってるくさいので、またそっちも書かないといけないような……<br />
そういえばJOI予選も控えてますし…(PCKはあと1問が5分という所で予選落ち)</h4>
<p>そして結構謎なのが、表彰式(1問以上解いたら参加出来る)の開始が12/3(月)の16時からということ。<br />
平日の16時とか参加出来る人が限られそうです……</p>
<p>かくいう僕も地理的には近いけれども時間的に無理ゲなので遅刻の旨を伝えた上で良さげなら参加します。</p>
<h4>(どうでも)いいこと</h4>
<p><a title="12/22 プログラミング生放送勉強会 第19回＠品川 参加受付中！ #pronama « プログラミング生放送" href="http://pronama.wordpress.com/2012/11/23/pronama-1-at-shinagawa/">12/22 プログラミング生放送勉強会 第19回＠品川 参加受付中！ #pronama « プログラミング生放送</a>参加するよ！<br />
<a title="第12回 日本情報オリンピック実施要領" href="http://www.ioi-jp.org/joi/2012/top.html">第12回 日本情報オリンピック</a>予選参加しますよ！</p>
<p>以上</p>The post <a href="https://blog.monora.me/2012/11/digitalarts-%e3%83%97%e3%83%ad%e3%82%b0%e3%83%a9%e3%83%9f%e3%83%b3%e3%82%b0%e3%82%b3%e3%83%b3%e3%83%86%e3%82%b9%e3%83%882012%e3%81%ab%e5%8f%82%e5%8a%a0%e3%81%97%e3%81%be%e3%81%97%e3%81%9f/">DigitalArts プログラミングコンテスト2012に参加しました!</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">188</post-id>	</item>
		<item>
		<title>Kuinでエラトステネスのふるい</title>
		<link>https://blog.monora.me/2012/08/kuin%e3%81%a7%e3%82%a8%e3%83%a9%e3%83%88%e3%82%b9%e3%83%86%e3%83%8d%e3%82%b9%e3%81%ae%e3%81%b5%e3%82%8b%e3%81%84/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=kuin%25e3%2581%25a7%25e3%2582%25a8%25e3%2583%25a9%25e3%2583%2588%25e3%2582%25b9%25e3%2583%2586%25e3%2583%258d%25e3%2582%25b9%25e3%2581%25ae%25e3%2581%25b5%25e3%2582%258b%25e3%2581%2584</link>
		
		<dc:creator><![CDATA[きょんたん]]></dc:creator>
		<pubDate>Sun, 26 Aug 2012 16:54:09 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Kuin]]></category>
		<guid isPermaLink="false">http://blog.monora.me/?p=168</guid>

					<description><![CDATA[<p>Kuin0.02が公開されたのでエラトステネスのふるいを使って素数を計算してみた。 Kuin0.02でコンパイル, 動作確認してます。 まだKuin用のシンタックスハイライトがない……… constに関するコンパイルエラ [&#8230;]</p>
The post <a href="https://blog.monora.me/2012/08/kuin%e3%81%a7%e3%82%a8%e3%83%a9%e3%83%88%e3%82%b9%e3%83%86%e3%83%8d%e3%82%b9%e3%81%ae%e3%81%b5%e3%82%8b%e3%81%84/">Kuinでエラトステネスのふるい</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></description>
										<content:encoded><![CDATA[<p>Kuin0.02が公開されたので<a title="エラトステネスの篩 - Wikipedia http://bit.ly/NU7jC4" href="http://ja.wikipedia.org/wiki/%E3%82%A8%E3%83%A9%E3%83%88%E3%82%B9%E3%83%86%E3%83%8D%E3%82%B9%E3%81%AE%E7%AF%A9" target="_blank" rel="noopener noreferrer">エラトステネスのふるい</a>を使って素数を計算してみた。</p>
<p>Kuin0.02でコンパイル, 動作確認してます。</p>
<p>まだKuin用のシンタックスハイライトがない………</p>
<p><strong>constに関するコンパイルエラー、Kuin0.021で修正されました。くいなちゃんに感謝です。 (2012/8/27 22:55)</strong></p>
<pre class="EnlighterJSRAW" data-enlighter-language="c" data-enlighter-linenumbers="true">{
  エラトステネスのふるい

  Author: きょんたん (@kyonline)
}

func Main()
  const N : int :: 10000000

  var isPrime : []bool :: @new [N]bool
  var Prime : []int :: @new [N]int
  var numPrime : int :: 0

  for i(0, N - 1)
    do isPrime[i] :: true
  end for

  do Prime[0] :: 2
  do numPrime :+ 1

  for i(3, N - 1, 2)
    if (!isPrime[(i - 1) / 2 - 1])
      continue i
    end if

    do isPrime[(i - 1) / 2 - 1] :: false
    do Prime[numPrime] :: i
    do numPrime :+ 1

    do Kuin@Dbg(i.ToStr())

    var j : int :: (i - 1) / 2 - 1 + i
    while (j &amp;lt; N)
      do isPrime[j] :: false
      do j :+ i
    end while

  end for

  do Kuin@Stop()
end func
</pre>The post <a href="https://blog.monora.me/2012/08/kuin%e3%81%a7%e3%82%a8%e3%83%a9%e3%83%88%e3%82%b9%e3%83%86%e3%83%8d%e3%82%b9%e3%81%ae%e3%81%b5%e3%82%8b%e3%81%84/">Kuinでエラトステネスのふるい</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">168</post-id>	</item>
		<item>
		<title>Supercon2012に参加します！</title>
		<link>https://blog.monora.me/2012/06/supercon2012%e3%81%ab%e5%8f%82%e5%8a%a0%e3%81%97%e3%81%be%e3%81%99%ef%bc%81/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=supercon2012%25e3%2581%25ab%25e5%258f%2582%25e5%258a%25a0%25e3%2581%2597%25e3%2581%25be%25e3%2581%2599%25ef%25bc%2581</link>
		
		<dc:creator><![CDATA[きょんたん]]></dc:creator>
		<pubDate>Fri, 29 Jun 2012 12:41:11 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Supercon2012]]></category>
		<guid isPermaLink="false">http://blog.monora.me/?p=77</guid>

					<description><![CDATA[<p>今日になってまさかの衝撃。 公式サイトには日付しか書かれていなかったりしてメールでの発表なのかな？とか思いながら12時になるもメールなし。 なるほど落ちたのかーと思ったころ、まさかの予選通過通知。 まさかのSuperco [&#8230;]</p>
The post <a href="https://blog.monora.me/2012/06/supercon2012%e3%81%ab%e5%8f%82%e5%8a%a0%e3%81%97%e3%81%be%e3%81%99%ef%bc%81/">Supercon2012に参加します！</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></description>
										<content:encoded><![CDATA[<p>今日になってまさかの衝撃。</p>
<p><a title="Supercomputing Contest 2012" href="http://new-web.gsic.titech.ac.jp/supercon/main/attwiki/index.php?Supercomputing%20Contest%202012" target="_blank" rel="noopener noreferrer">公式サイト</a>には日付しか書かれていなかったりしてメールでの発表なのかな？とか思いながら12時になるもメールなし。</p>
<p>なるほど落ちたのかーと思ったころ、まさかの予選通過通知。</p>
<blockquote class="twitter-tweet" width="550" lang="ja">
<p>まさかのSupercon2012予選通過です！東工大でお会いしましょう！</p>
<p>&mdash; きょんたんさん (@kyonfuee) <a href="https://twitter.com/kyonfuee/status/218623559478689792">2012年6月29日</a></p></blockquote>
<p><script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script></p>
<p>とりあえず<a title="Supercon2012予選問題を解いてみた" href="https://blog.monora.me/2012/06/supercon-2012-%e4%ba%88%e9%81%b8%e5%95%8f%e9%a1%8c%e3%82%92%e8%a7%a3%e3%81%84%e3%81%a6%e3%81%bf%e3%81%9f/">前の記事</a>にも書いてあるとおり、何でバグあるはずなのに通ったのかとか色々謎は残りますが…</p>
<blockquote class="twitter-tweet" width="550" lang="ja">
<p>Supercon2012、バグ死してる方多いのだけど、領域破壊してる自分のプログラムなんで通ったの…？</p>
<p>&mdash; きょんたんさん (@kyonfuee) <a href="https://twitter.com/kyonfuee/status/218666506878320640">2012年6月29日</a></p></blockquote>
<p><script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script></p>
<p>でも出場できるからには全力で頑張ります！</p>
<p>自分と先輩方2人で参加します。チーム名は後ほど…？</p>
<p><strong>チーム名は<em>hoge</em>になりました。よろしくお願いします。</strong>(2012.7.2 2:38追記)</p>The post <a href="https://blog.monora.me/2012/06/supercon2012%e3%81%ab%e5%8f%82%e5%8a%a0%e3%81%97%e3%81%be%e3%81%99%ef%bc%81/">Supercon2012に参加します！</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">77</post-id>	</item>
		<item>
		<title>Supercon2012予選問題を解いてみた</title>
		<link>https://blog.monora.me/2012/06/supercon-2012-%e4%ba%88%e9%81%b8%e5%95%8f%e9%a1%8c%e3%82%92%e8%a7%a3%e3%81%84%e3%81%a6%e3%81%bf%e3%81%9f/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=supercon-2012-%25e4%25ba%2588%25e9%2581%25b8%25e5%2595%258f%25e9%25a1%258c%25e3%2582%2592%25e8%25a7%25a3%25e3%2581%2584%25e3%2581%25a6%25e3%2581%25bf%25e3%2581%259f</link>
		
		<dc:creator><![CDATA[きょんたん]]></dc:creator>
		<pubDate>Sun, 24 Jun 2012 08:58:34 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Supercon2012]]></category>
		<guid isPermaLink="false">http://blog.monora.me/?p=52</guid>

					<description><![CDATA[<p>以前から、Superconの存在自体は知っていて、ずっと参加したいと思っていたのですが、ついに参加する機会を得ることが出来たので予選問題解きました。 が、まさかの応募する際の添付ファイルミスという目も当てられないミスを… [&#8230;]</p>
The post <a href="https://blog.monora.me/2012/06/supercon-2012-%e4%ba%88%e9%81%b8%e5%95%8f%e9%a1%8c%e3%82%92%e8%a7%a3%e3%81%84%e3%81%a6%e3%81%bf%e3%81%9f/">Supercon2012予選問題を解いてみた</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></description>
										<content:encoded><![CDATA[<p>以前から、<a title="Supercomputing Contest" href="http://www.gsic.titech.ac.jp/supercon/main/attwiki/" target="_blank" rel="noopener noreferrer">Supercon</a>の存在自体は知っていて、ずっと参加したいと思っていたのですが、ついに参加する機会を得ることが出来たので予選問題解きました。<br />
<strong>が</strong>、まさかの応募する際の添付ファイルミスという目も当てられないミスを……<br />
もしこれで本選通っていたら奇跡ですね。</p>
<p><small><br />
追記(2012/6/25):詳細の説明は私事により2週間ほど先になるかも……？<br />
コードが長いのは仕様です。期限日の午前4時に書いていたらこうなります。<br />
動的計画法とかそんな時間短縮を使う暇も知識もなかったのですし…<br />
全てが同じ文字のパターンに対しては一応関数を作って対処してます。<br />
ただ、|W|が短い場合の対策がほぼ皆無。</small></p>
<p>添付ファイルミスとは: 寝ぼけて<strong>&lt; </strong>と<strong>&lt; =</strong>を間違えたプログラムを送信した。</p>
<p>というわけでとりあえず修正したソースだけ置いておきます。<del>詳細は後ほど?</del></p>
<p><del></del><strong>多分書かない。というか書けない…… (2012.7.8追記)</strong><br />
<span id="more-52"></span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="c" data-enlighter-linenumbers="true">
/* SuperCon 2012 予選問題C用テンプレート(問C,スーパーコン予選問題 兼 1級認定問題 2012版)
・解答プログラムはこのテンプレートに従って作成すること.
・解答プログラムは1つのファイルで,チーム名.c という名前にすること.
・入力の方式は,あらかじめ入力ファイル(例:input_sample.txt)を作っ
ておき,実行時にファイル名を指定する方式です.
*/

#include &lt;assert.h&gt;
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;ctype.h&gt;
#include &lt;time.h&gt;

/* ↓以下の範囲は変更可能 */
#define TIME_LIMIT 59.5
#define MAX_LEN 10
#define MAX_V 100000

#define max(a,b) ( a &gt; b ? a : b )
#define min(a,b) ( a &gt; b ? b : a )

int isFront(char input[]);

void searchTree(int flag, int answerTemp, char inputStr[]);

void searchB (void);

int isTypeB(void);

int Sum(int flag);

int N_G = 0;
int v_G[1000];
char w_G[1000][10 + 1];
char W_G[10000 + 1];
clock_t start_G;

int answerTemp_G = 0,strLenTemp_G = 0;
/* ↑上記の範囲は変更可能 */

int main(int argc, char** argv){
int answer = -1; /* この変数に答(Vの最大値)を代入してください */
int N;
static int v[1000];
static char w[1000][10+1];
static char W[10000+1];
char* problem_file;
clock_t start, end;
FILE* fp;

int i;
char buf[0xffff];
char* p;

if(argc &lt;= 1){
fprintf(stderr, "Enter the input file.¥n");
exit(EXIT_FAILURE);
}

problem_file = argv[1];
fp = fopen(problem_file, "r");
if(fp == NULL){
fprintf(stderr, "Cannot open %s.¥n", problem_file);
exit(EXIT_FAILURE);
}

p = fgets(buf, 0xffff, fp);
assert(p != 0);

N = atoi(strtok(buf, " ¥n"));
assert(1 &lt;= N &amp;&amp; N &lt;= 1000);

p = fgets(buf, 0xffff, fp);
assert(p != 0);
p = strtok(buf, " ¥n");
strcpy(W, p);
assert(1 &lt;= strlen(W) &amp;&amp; strlen(W) &lt;= 10000);
for(p = W; *p; ++p){
assert(islower(*p));
}

for(i = 0; i &lt; N; ++i){
p = fgets(buf, 0xffff, fp);
assert(p != 0);
v[i] = atoi(strtok(buf, " "));
assert(-1000000 &lt;= v[i] &amp;&amp; v[i] &lt;= 1000000);
p = strtok(NULL, " ¥n");
strcpy(w[i], p);
assert(1 &lt;= strlen(w[i]) &amp;&amp; strlen(w[i]) &lt;= 10);
for(p = w[i]; *p; ++p){
assert(islower(*p));
}
}

fclose(fp);

start = clock();

/* ↓以下の範囲は変更可能 */

N_G = N;
strcpy(W_G, W);
for (i = 0; i &lt; N; i++) {
memcpy(w_G[i], w[i], sizeof(w[i]));
v_G[i] = v[i];
}
start_G = start;

if (isTypeB() == 0) {
searchB();
} else {
searchTree(0, 0, "");
}

answer = max(0, answerTemp_G);

/* ↑上記の範囲は変更可能 */

end = clock();
printf("%s, %f, %d¥n", problem_file, (double)(end - start) / CLOCKS_PER_SEC, answer);

printf("%s, %d¥n", problem_file, answer);
return 0;
}

/* ↓以下の範囲は変更可能 */

int isFront(char input[]) {

int ret = strncmp(input, W_G, strlen(input));

if (ret == 0) return 0;
if (ret &lt; 0) return 1;

return -1;
}
void searchTree(int flag, int answerTemp, char inputStr[]) {
int quit = 0, len, i;

char *tempStr;
tempStr = (char *)calloc(10000 + 1, sizeof(char));
strcpy(tempStr, inputStr);
len = strlen(tempStr);

for (i = flag; i &lt; N_G; i++) {

if(((double)(clock() - start_G) / CLOCKS_PER_SEC) &gt;= TIME_LIMIT) {
answerTemp_G = max(answerTemp_G,answerTemp); break;
}
memset(tempStr + len, 0, sizeof(char) * (10001 - len));

strcat(tempStr, w_G[i]);

switch (isFront(tempStr)) {
case -1: continue;
case 0:
answerTemp += v_G[i];

answerTemp_G = max(answerTemp, answerTemp_G);

flag = i + 1;
searchTree(flag, answerTemp, tempStr);
answerTemp -= v_G[i];

if (quit == 1) continue;
break;
case 1:
answerTemp += v_G[i];
flag = i;

answerTemp_G = max(answerTemp_G,Sum(flag + 1) + answerTemp);

quit = 1;
continue;
}
}
RET:
free(tempStr);
tempStr = NULL;
return;
}

void searchB (void) {
int AnsS = Sum(0), AnsL = AnsS, WLen = strlen(W_G);
int strLenS = strLenTemp_G, strLenL = strLenTemp_G;
int a = 0, b = MAX_LEN, c, d = MAX_V, e = MAX_V;

if (strLenTemp_G &lt;= WLen) { answerTemp_G = Sum(0); } else {
int i;
while (strLenS &gt; WLen &amp;&amp; strLenL &gt; WLen) {

for (i = 0; i &lt; N_G; i++) {
if (v_G[i] &gt; 0) {
c = strlen(w_G[i]);
a = max(a, c);
b = min(b, c);
}
}

for (i = 0; i &lt; N_G; i++) {
if (v_G[i] &gt; 0) {
c = strlen(w_G[i]);
if (a == c) d = min(v_G[i], d);
if (b == c) e = min(v_G[i], e);
}
}

strLenL -= a; AnsL -= d;
strLenS -= b; AnsS -= e;

}
if (strLenL &lt;= WLen) answerTemp_G = AnsL;
if (strLenS &lt;= WLen) answerTemp_G = max(answerTemp_G, AnsS);
}
return;
}

int isTypeB(void) {
char isSame = w_G[0][0];
int i,j = 0;

do {
for (i = 0; i &lt; strlen(w_G[j]) ; i++) if (w_G[j][i] != isSame) { return 1; }
} while ( ++j &lt; N_G );

return 0;
}

int Sum(int flag) {
int i, ret = 0;
for (i = flag; i &lt;= N_G; i++) if(v_G[i] &gt; 0) {
ret += v_G[i];
strLenTemp_G += strlen(w_G[i]);
}

return ret;
}
/* ↑上記の範囲は変更可能 */
</pre>
<p>まさか初投稿がこんな残念な記事になるとは…</p>The post <a href="https://blog.monora.me/2012/06/supercon-2012-%e4%ba%88%e9%81%b8%e5%95%8f%e9%a1%8c%e3%82%92%e8%a7%a3%e3%81%84%e3%81%a6%e3%81%bf%e3%81%9f/">Supercon2012予選問題を解いてみた</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">52</post-id>	</item>
	</channel>
</rss>
