<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>tech.kayac.com - KAYAC engineers&apos; blog</title>
    <link rel="alternate" type="text/html" href="http://tech.kayac.com/" />
    <link rel="self" type="application/atom+xml" href="http://tech.kayac.com/atom.xml" />
    <id>tag:tech.kayac.com,2010-04-29:/2</id>
    <updated>2013-04-22T02:03:42Z</updated>
    
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type 5.01</generator>

<entry>
    <title>2013年の新卒研修と社内ISUCONやりました - (2) ISUCON死闘編</title>
    <link rel="alternate" type="text/html" href="http://tech.kayac.com/archive/2013isucon.html" />
    <id>tag:tech.kayac.com,2013:/2.255</id>

    <published>2013-04-22T01:48:29Z</published>
    <updated>2013-04-22T02:03:42Z</updated>

    <summary>技術部新卒研修担当の fujiwara です。 前回の記事「2013年の新卒研修と社内ISUCONやりました - (1) 研修編」に引き続き、新卒研修の最後を飾るイベント、社内ISUCONについて詳しく振り返ります。 社内ISUCONとは レギュレーションはこちらです。 各チーム1台ずつ使用できる仮...</summary>
    <author>
        <name>fujiwara-shunichiro</name>
        
    </author>
    
    
    <content type="html" xml:lang="ja" xml:base="http://tech.kayac.com/">
        <![CDATA[<p>技術部新卒研修担当の fujiwara です。</p>

<p>前回の記事<a href="http://tech.kayac.com/archive/2013training.html">「2013年の新卒研修と社内ISUCONやりました - (1) 研修編」</a>に引き続き、新卒研修の最後を飾るイベント、社内ISUCONについて詳しく振り返ります。</p>

<h2>社内ISUCONとは</h2>

<p><a href="https://github.com/kayac/newbie-training/tree/master/isucon/README.md">レギュレーションはこちら</a>です。</p>

<ul>
<li>各チーム1台ずつ使用できる仮想マシン上で、お題のアプリケーションを動作させる</li>
<li>外部からベンチマークを行って処理できたリクエスト数をスコアとする</li>
<li>アプリケーション、OS、ミドルウェアなど、どのようなチューニングを行ってもよい</li>
<li>ベンチマークスクリプトはデータの整合性をチェックするロジックが組み込まれており、アプリケーションとして不整合を起こしていることを検出するとFAIL(スコアなし)</li>
<li>10:00〜17:00 までの作業中には適宜ベンチマークを実行できる</li>
<li>作業終了後の最終計測でのスコアが高いものが優勝 (FAILしたら失格。17:00以前までのスコアは考慮しない)</li>
</ul>

<p>参加したのは2013新卒8名が2名ずつで4チーム、先輩は10名を5チームに編成し、合計9チームです。</p>

<p>お題のアプリケーションはいわゆる nopaste (gistのようなもの) です。ユーザ登録、ログイン機能を備えており、投稿と★を付ける機能はログインした状態でないと使えません。サイドバーには最新投稿が100件まで並んでいます。</p>

<p><a href="/assets_c/2013/04/nopaste-191.php" onclick="window.open('/assets_c/2013/04/nopaste-191.php','popup','width=600,height=387,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"><img src="/assets_c/2013/04/nopaste-thumb-480x309-191.png" width="480" height="309" alt="nopaste.png" class="mt-image-none" style="" /></a></p>

<p><a href="https://github.com/kayac/newbie-training/blob/master/webapp/NoPaste/">ソースコードは一式公開しています</a></p>

<p>ログイン機能があるため、セッション管理が必要になるところが過去2回の本家 ISUCON とは異なるところでしょうか。</p>

<p>新卒チームは昨日まで実際に作成していたアプリケーションをベースに作業できる上、実行するサーバ環境も研修中の実習で使用していたもののため、先輩チームよりは内部の把握に有利です。これはハンデですね。</p>

<h2>死闘の始まり</h2>

<p><a href="/assets_c/2013/04/isucon-opening-194.php" onclick="window.open('/assets_c/2013/04/isucon-opening-194.php','popup','width=1024,height=332,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"><img src="/assets_c/2013/04/isucon-opening-thumb-480x155-194.jpg" width="480" height="155" alt="isucon-opening.jpg" class="mt-image-none" style="" /></a></p>

<p>10:00 から本家ばりのオープニングムービーに引き続きレギュレーション説明が行われ、各チームは作業を開始します。</p>

<p>1チームのみ、運営の不手際で仮想マシンに30分ほどログインできない事案がありましたが、これは優勝候補の一角「チーム kameda (handlename, kenjiskywalker)」だったのでハンデということでひとつ勘弁していただきたく…</p>

<p>ベンチマークは CIツール <a href="https://github.com/ukigumo">Ukigumo</a> (に少し手を入れたもの) で実行し、スコアを一覧して表示できるようにしていました。</p>

<p><a href="/assets_c/2013/04/isucon-ukigumo-197.php" onclick="window.open('/assets_c/2013/04/isucon-ukigumo-197.php','popup','width=600,height=501,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"><img src="/assets_c/2013/04/isucon-ukigumo-thumb-480x400-197.png" width="480" height="400" alt="isucon-ukigumo.png" class="mt-image-none" style="" /></a></p>

<h2>新卒の一撃</h2>

<p>競技開始から2時間ほど経過した12時過ぎ、新卒チーム ganbaru (MacoTasu, ichinose) がここまでの最高スコア 13,000 over を叩き出し、先輩チームに動揺が走ります。初期スコアは200程度ですので、この時点で60倍以上の高速化をしたことになります。</p>

<p><a href="http://macotasu.hatenablog.com/entry/2013/04/12/233500">社内isuconを終えて - Maco_Tasuの技術ブログ</a>によると、この時点でサイドバーで大量に飛ぶクエリの書き換えとindex追加、nginxで静的ファイルをさばくなどのチューニングが行われていたようです。</p>

<h2>デッドヒート</h2>

<p>なかなかどのチームもブレイクスルーを起こせないまま、しかし着実に先輩チームはスコアを伸ばしていきます。</p>

<p>チーム beer (soh335, Konboi) が 15時前に 20,000 に到達、同じく先輩のチーム kameda と fugu (macopy, 9re) がそれを追いかけます。</p>

<p>しかし午前中に会場の空気を震撼させた  ganbaru が 16:25 に 23,000 超えでトップを奪還、激しいデッドヒートを繰り広げる展開となりました。</p>

<h2>部長、動く</h2>

<p>終了まであと1時間を切る激闘のさなか、2年目のtkuchikiとコンビを組み、あえて自分はコードを書かずにサポートに徹していた部長 syoji がここで満を持して動きます。</p>

<p><a href="/assets_c/2013/04/isucon-irc-200.php" onclick="window.open('/assets_c/2013/04/isucon-irc-200.php','popup','width=478,height=100,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"><img src="/assets_c/2013/04/isucon-irc-thumb-480x100-200.png" width="480" height="100" alt="isucon-irc.png" class="mt-image-none" style="" /></a></p>

<p>しかし詰んだ。</p>

<h2>終演</h2>

<p>17:00 の競技終了直前、どのチームも作業をしてはベンチマークを繰り返し、計測ホストでは最大4並列でベンチマークが実行され、5分間の平均トラフィックは500Mbpsを超えました。</p>

<p>ここまでトップを争っていたチーム beer は終了直前に FAIL を連発し、焦りを隠せません。対して新卒の ganbaru は最後 16:55 に 22,774 を記録して首位に立ち、そのまま計測終了。</p>

<p>これはまさかの新卒チームの勝利か。入社2週間の新卒に叩きのめされた先輩の威厳はどうなる。</p>

<h2>最終計測</h2>

<p>競技終了後、最終計測に入ります。</p>

<p>公平を期すため全マシンを一回再起動。運営側がDBを初期データにリセットし、その後各チームが初期化の手作業を行うことはできますが、ベンチマークは実行できません。</p>

<p>そして、競技中のスコアは、最終計測には全く加味されません。</p>

<p>これまでどれだけ FAIL していても、最終計測で成功してスコアを残せばそれが採用。ここまでどれだけ中間スコアが高くても、最終計測で FAIL したら失格、スコアなし。それが ISUCON です。</p>

<p>計測中には、運営側からどんなチューニングをやった？というアンケートなどを行っていました。</p>

<h2>結果発表</h2>

<p><strong>優勝 team: beer (SCORE 25,133.4)</strong></p>

<p>終了直前にFAIL連発して危ぶまれていた beer でしたが、最終計測を見事にpassして優勝です！</p>

<p>一方、勝利を8割方手中にしたと思われた ganbaru はFAILで失格。2013新卒チームは残念ながら全チームが FAIL でスコアなしという結果に終わりました。</p>

<p>あとから聞くところによると ganbaru はデータリセット後の初期化処理をミスしたそうですが、本番でミスをしないのも仕事をする上での実力のうちですね。</p>

<p>最終結果は以下のようになりました。先輩チームは最終的にはきっちりスコアを出して上位に食い込むあたり、さすがに実戦で鍛えられた力を感じます。</p>

<pre>
   team     | status  |  score     | members
------------|---------|------------|----------------------------------
beer        | SUCCESS | 25,133.4   | soh335 Konboi
kameda      | SUCCESS | 24,125.33  | handlename kenjiskywalker
fugu        | SUCCESS | 21,768.46  | macopy 9re
syoji       | SUCCESS |  7,623.68  | tkuchiki syoji
ganbaru *   | FAIL    | 19,914.95  | MacoTasu ichinose
ky          | FAIL    |  9,078.29  | tei-you chen-xiao
p_shake *   | FAIL    |  8,806.17  | keishake p_chin
chinatown * | FAIL    |    687.39  | m0t0k1ch1 piyon
gumma *     | FAIL    |    616.7   | gs hosono
* は2013新卒チーム

以下参考記録
------------|---------|------------|----------------------------------
reference   | SUCCESS | 53,977.37  |
acidlemon   | SUCCESS | 24,235.15  |
</pre>

<h2>講評</h2>

<p>今回の社内 ISUCON の出題では、最初に提供される<a href="https://github.com/kayac/newgrad/blob/master/public/webapp/NoPaste/app.psgi.reference">リファレンス実装</a>には意図的にかなり無駄な処理が含まれています。研修の一環ということもあり、特に罠らしい罠は仕掛けていません。初期スコアは200 (1分間のHTTPリクエスト数) 程度ですが、</p>

<ul>
<li>DBに適切にindex追加</li>
<li>サイドバーで100回のループ中に都度発行されるクエリを JOIN に書き換える</li>
</ul>

<p>だけで 13,000 程度のスコアに到達できるような出題になっています。
つまり、ここまで到達できればほぼ合格点、という水準がスコア 13,000 以上ということになります。</p>

<p>優勝争いはそのあたりを確実にクリアした上で、サイドバーのレンダリングが重いのを部分的に cache するなどの方策を適切に入れることができるか、というのが焦点になったようです。</p>

<p>優勝チームのblogエントリは以下です。おめでとうございます！</p>

<ul>
<li><a href="http://soh335.hatenablog.com/entry/2013/04/13/182200">社内 isucon に参加 - soh335 memo</a></li>
<li><a href="http://konboi.hatenablog.com/entry/2013/04/15/170219">社内ISUCONに参加した。 - Konboi&#39;s Memo</a></li>
</ul>

<h2>(おまけ) 優勝チームの2倍のスコアを出す方法</h2>

<p>出題者(fujiwara)はこのアプリを火曜日の夜中に書き、水曜にテストを書き、木曜にベンチマーククライアントを書いて金曜に本戦を行った関係で、どこまでスコアを伸ばせるかを事前に追い込むことができていませんでした。</p>

<p>ベンチマーククライアント側の限界を確認するために、nginx で <code>return 200</code> するだけのサーバに対して負荷を掛けて、最高100,000程度まで到達できることを確認したのみです。</p>

<p>ということで、競技中に自分もリファレンス実装からどこまでスコアを伸ばせるかチャレンジしていました。</p>

<p>結果、優勝チームの約2倍、53,000のスコアを記録することができましたが、これはベンチマーク計測でどのような整合性チェックをしているか(=どのようにすればチェックをかいくぐれるか) を把握していたからできた手法という感があります。</p>

<p>チェッカーはログインした上で投稿や★をPOSTし、その結果がサイドバーなどに1秒後に反映されているかどうか見てくるのですが、ログインしていないで単に負荷を掛けるだけのクライアントではそのチェックが緩い、という特性を利用します。</p>

<p>具体的には、varnish をフロントに置き、以下のような設定をしました。</p>

<ul>
<li>GET 以外は application に pipe (キャッシュしないでそのまま返す)</li>
<li>Cookieに plack_session=[a-f0-9] が含まれている場合 (ログインしてセッションが維持されている) は application に pipe</li>
<li>それ以外は静的ファイルまたは application へ lookup (キャッシュする)</li>
</ul>

<p>しかし、キャッシュ可能な画面でもアプリケーションは Cookie を発行してそれをベンチマーククライアントが維持してしまい、結果 Cookie の有無だけではログイン状態を判別できないという(出題意図にない) 実装が競技中に判明してしまったため、急遽必要ない Set-Cookie ヘッダを削除して Cache 可能にする Plack::Middleware を書くことになりました。</p>

<p>スコアが出せたのは終了13分前。出題者としては優勝チームのスコアに負けるわけにはいかず、相当ギリギリの戦いでした…</p>

<p><a href="https://github.com/kayac/newbie-training/blob/master/isucon/benchmark.md">ベンチマーククライアントと動かしかたについても公開しています</a>
ので参考まで。</p>

<h2>まとめ</h2>

<p>新卒研修の最後に2013新卒 vs 2012新卒でバトルしたらおもしろいんじゃない？というぐらいのネタで開催することになった社内 ISUCON ですが、参加者の誰に聞いても楽しい(ただしFAILしたチームは悔しい) という、非常に充実したイベントになりました。</p>

<p>普段の仕事ではいろんなしがらみがあって同一条件で競うことはなかなかできないわけですが、そういう事情を一切排除して、公平な条件でガチでぶつかり合うというのはとても楽しいことですね。</p>

<p>みなさんも是非開催してみると想像以上に面白いのでは、と思います。</p>

<p># ただし、出題者はかなり胃が痛い思いをする可能性がありますのでお気を付けください</p>
]]>
        

    </content>
</entry>

<entry>
    <title>2013年の新卒研修と社内ISUCONやりました - (1) 研修編</title>
    <link rel="alternate" type="text/html" href="http://tech.kayac.com/archive/2013training.html" />
    <id>tag:tech.kayac.com,2013:/2.254</id>

    <published>2013-04-22T01:45:00Z</published>
    <updated>2013-04-22T01:45:46Z</updated>

    <summary>4月になり、新人が入ってくる季節になりました。技術部新卒研修担当の fujiwara です。 これまで弊社技術部では特に技術部としての研修というものを行っていなかったのですが、今年は何かやりたいねということで人事部に7日間確保してもらい、主に acidlemon と2人で新卒8人に研修をすることにな...</summary>
    <author>
        <name>fujiwara-shunichiro</name>
        
    </author>
    
    
    <content type="html" xml:lang="ja" xml:base="http://tech.kayac.com/">
        <![CDATA[<p>4月になり、新人が入ってくる季節になりました。技術部新卒研修担当の <a href="http://www.kayac.com/team/fujiwara-shunichiro">fujiwara</a> です。</p>

<p>これまで弊社技術部では特に技術部としての研修というものを行っていなかったのですが、今年は何かやりたいねということで人事部に7日間確保してもらい、主に <a href="http://www.kayac.com/team/kawazoe-masatoshi">acidlemon</a> と2人で新卒8人に研修をすることになりました。</p>

<p>研修の資料などは GitHub でプライベートリポジトリを作って作業しており、それをまとめたものを GitHub上で <a href="https://github.com/kayac/newbie-training">kayac/newbie-training</a> として公開しています。</p>

<p>どのような内容にするかは事前に昨年度の新卒を含めたエンジニア陣で(社内勉強会でビールを飲みながら)話し合い、</p>

<ul>
<li>現場で実務に追われてしまうと身につきにくい基礎的な内容</li>
<li>コードを書ける人は多いけどLinuxサーバの操作は不慣れな人が多いので、そのあたりを底上げする内容</li>
</ul>

<p>をメインに構成してみました。また、7日目の最終日には社内 ISUCON (Webアプリケーション高速化コンテスト) を行い、昨年度の新卒を含む先輩エンジニアとガチで戦うイベントも用意しました。</p>

<hr />

<p>詳細はリポジトリの方を見ていただくとして、ざっと内容を説明します。</p>

<h2>1日目 <a href="https://github.com/kayac/newbie-training/tree/master/install.md">環境構築・インストール作業</a></h2>

<p>手元のマシンに今後使うであろうソフトウェアの環境を整備してもらいます。Macの人は homebrew などを利用して直接、Windowsの人は VirtualBox で Linux VM を立ててそこにインストールという形を取りました。</p>

<p>社内で <a href="http://boxen.github.com/">boxen</a>のようなものがあればいいのですが、ないので手動で設定してもらいましたがこれで時間を使うのももったいないので何とかしたいところですね。</p>

<p>また、研修中の日報は各自、リポジトリに適当なフォーマット(markdownの人が多数)でcommitしてもらうようにしました。</p>

<p>社内にIRCチャンネルも用意し、GitHubにコミットがあった場合に IRC hook で通知するようにも設定してあります。</p>

<h2>2日目 <a href="https://github.com/kayac/newbie-training/tree/master/server">severspecとChefによるサーバ構築実習</a></h2>

<p>1人に1台ずつKVMの仮想マシンを配布し、そのサーバをセットアップする実習です。
最近はサーバの構成管理に Chef を利用しているため、慣れてもらうのも目的です。</p>

<p><a href="http://serverspec.org/">serverspec</a> を利用し、事前に作成したテストを通るようにセットアップを行ってもらいます。サーバ構築もテストする時代ですね。</p>

<ul>
<li>まず serverspecが通る状態へ手動でセットアップ (メモを取る)</li>
<li>通ったらVMをrollbackして初期状態へ戻す</li>
<li>今度はChefでレシピを書いてserverspecを通す</li>
<li>それが通ったらもう一度 rollback</li>
<li>まっさらな状態から Chef recipe を適用し、テストを通るかどうか確認</li>
</ul>

<h2>3日目 <a href="https://github.com/kayac/newbie-training/tree/master/perl">Perl</a></h2>

<p>自社サービスのサーバサイドアプリケーションは Perl がメインのため、最低限 Perl の読み書きができてもらいたいということで Perl に1日あてました。</p>

<p>テキストには、はてなさんが公開されている <a href="https://github.com/hatena/Hatena-Textbook/blob/master/oop-for-perl.md">Perl によるオブジェクト指向プログラミング</a> を利用させていただきました。大変充実したテキストでありがたかったです。</p>

<h2>4日目 <a href="https://github.com/kayac/newbie-training/tree/master/webapp/simple">HTTP・WebApp</a></h2>

<p>Webに携わるエンジニアとして、HTTPはどのようなものなのかを理解することは大変重要です。
ブラウザやWebサーバを単に扱っているだけでは把握しづらい HTTP の生の通信を扱ってもらいます。</p>

<ul>
<li>各自構築したサーバ上で ngrep を使用してパケットキャプチャ
<ul>
<li>HTTPで何が流れているのかを見る</li>
</ul></li>
<li>telnet で手で HTTP を喋って HTTP client になる</li>
<li>nc -l で手で応答を返す HTTP サーバになる</li>
<li>PSGI を生で使った Web Application を作る</li>
<li>それを Amon2::Lite に移植してフレームワークの威力を実感する</li>
</ul>

<h2>5日目 <a href="https://github.com/kayac/newbie-training/tree/master/#410-dbdbwebapp">RDBMS・DBを使ったWebApp</a></h2>

<p>データストアとしては最近はいわゆる NoSQL も多いとはいえ、基本的には MySQL を利用しているのでそれの基礎の基礎です。</p>

<p>まず mysql コンソールで操作し、次に Perl + DBI で MySQL を使う演習を行いました。
ここまではセキュリティについて基本的には触れていませんでしたが、外部からの入力を不適切に扱うことでSQL injectionという脆弱性に繋がる話もします。</p>

<p>また、昨日作ってもらった PSGI を直接使う WebApp のコードを見ながら講評をし、実は全員が HTML escape を行わないことによる XSS を作ってしまっていたことにも触れました。</p>

<p>その後、最終日の ISUCON に向けての課題アプリケーション(ログイン機能付きnopaste) の雛形に、実装とテストを追加して仕上げてもらう課題に移ります。</p>

<h2>6日目 <a href="https://github.com/kayac/newbie-training/tree/master/webapp/NoPaste">フレームワークを使ったWebApplicationの作成とテスト</a></h2>

<p>前日に引き続き、Amon2 を使用した nopaste アプリの実装とテスト。</p>

<p>明日の ISUCON にむけて、現在本番で動いているサービスはどのようなサーバ構成になっているのかの講義も行いました。参考 : <a href="http://tech.kayac.com/archive/post_1.html">カヤック流ソーシャルアプリの作り方 インフラ編</a></p>

<h2>7日目 <a href="https://github.com/kayac/newbie-training/tree/master/isucon#isucon">社内ISUCON</a></h2>

<p>いよいよ最終日。</p>

<p>新卒8人を2人ずつで4チーム、先輩エンジニアは技術部長から2012新卒まで10人参加したのでこれも2人ずつで5チーム、計9チームを編成し、昨日までに作成した nopaste アプリケーションを題材にどれだけリクエストを捌けるかのベンチマークで勝敗を競う『社内ISUCON』を開催しました。</p>

<p>ちなみに本家 ISUCON については<a href="http://blog.livedoor.jp/techblog/archives/cat_60289063.html">こちらのblogなどをご覧ください</a></p>

<p>……というところで、次のエントリ<a href="http://tech.kayac.com/archive/2013isucon.html">「2013年の新卒研修と社内ISUCONやりました - (2) ISUCON死闘編」へ続きます！</a></p>
]]>
        

    </content>
</entry>

<entry>
    <title>#24 「Unityでコルーチンも単体テストしよう」 tech.kayac.com Advent Calendar 2012</title>
    <link rel="alternate" type="text/html" href="http://tech.kayac.com/archive/merry_christmas_2012.html" />
    <id>tag:tech.kayac.com,2012:/2.245</id>

    <published>2012-12-24T14:33:00Z</published>
    <updated>2012-12-24T14:39:19Z</updated>

    <summary>みなさんこんばんは。今年の2月に入社してWeb業界というものがよくわからないままiPhoneアプリ開発やらnode.jsでサーバ開発やらPerlでサーバ開発やらC#でUnity開発やらをやっていたら年が暮れかかっていた@acidlemonです。 もともと私はC++が専門で、SIerの業界にいたのでし...</summary>
    <author>
        <name>acidlemon (kawazoe-masatoshi)</name>
        
    </author>
    
    
    <content type="html" xml:lang="ja" xml:base="http://tech.kayac.com/">
        <![CDATA[<p>みなさんこんばんは。今年の2月に入社してWeb業界というものがよくわからないままiPhoneアプリ開発やらnode.jsでサーバ開発やらPerlでサーバ開発やらC#でUnity開発やらをやっていたら年が暮れかかっていた<a href="https://twitter.com/acidlemon">@acidlemon</a>です。</p>

<p>もともと私はC++が専門で、SIerの業界にいたのでしかたなくJavaもやっていたという感じだったのですが、Web業界に転職してみたらC++でプログラムを書く人がほぼいなかったということで、今年だけで新規に4言語も手をつけていて環境の激変っぷりに自分でも驚いています。</p>

<p>さて、24日間にわたってお送りしてまいりました<a href="http://tech.kayac.com/archive/techkayaccom_advent_calendar_2012.html">tech.kayac.com Advent Calendar 2012</a>も今日が最終日。2日目にしていきなり<a href="http://tech.kayac.com/archive/2_techkayaccom_advent_calendar_2012.html">JavaScriptでおっぱいが動き始めた</a>時はどうなることかと思いました。しかし、振り返ってみると<a href="http://tech.kayac.com/archive/5gitddl_techkayaccom_advent_calendar_2012.html">DDLをGitで管理</a>したり、<a href="http://tech.kayac.com/archive/10_2012proclet.html">Procletで開発中のミドルウェアの立ち上げを超簡単に</a>したりといった開発を効率よく進めるためのイノベーションや、<a href="http://tech.kayac.com/archive/18_techkayaccom_advent_calendar_2012.html">5年前から続いているWebサービスを時間と技術革新の流れに合わせて</a>いったり、<a href="http://tech.kayac.com/archive/cs.html">ユーザの行動ログを可視化してカスタマーサポートを効率化</a>したりといった、運用を効率よく進めるためのイノベーションなのがありましたね! いやーすごい。</p>

<p>昨日の<a href="http://hokkaido.pm.org/">Hokkaido.pm</a>のため22〜24日は北海道に行っていたため遅めのアップロードとなりましたが、最終日のアドベントカレンダーいってみましょうー(よくわからないテンションになっています)。</p>

<h2>本題</h2>

<p>最初にも書きましたが最近はPerlでサーバを書きつつC#でUnityクライアントの通信部分を書くという二足のわらじ(?)のような生活をしております。</p>

<p>で、Perlは単体テストしやすい言語なので大変感動しているのですが、C#/Unityとなるとなかなか苦痛な感じです。私のプロジェクトにはフロント専門のUnityチームがいるので、私は通信部分とモデル部分のみ書いています。つまり表示部分を全く書かずにロジックだけのコードを書いているため、単体テストを書くのはやはり必須。とりあえず世間的にはUnityの単体テストするなら<a href="http://wiki.unity3d.com/index.php?title=SharpUnit">SharpUnit</a>だよねみたいなノリになっているようなのですが、通信部分をテストするにはこれもなかなかつらいものがありました。</p>

<p>というのも、SharpUnitは非同期実行(コルーチン実行)をサポートしておらず、同期実行できるメソッドしかテストできないんです。まぁサーバから来たJSONをパースしてクラスオブジェクトを組み立てるところは同期実行なので別によいんですが、通信が絡む部分はUnityEngine.WWWを使う必要があるためどうしてもコルーチンを実行してyield returnでゆっくり待つ必要が出てきます。</p>

<p>「通信部分なんて単体テストの範疇じゃないじゃん、サーバ側のテストでやれよ」というご意見もごもっともなのですが、だからといってサーバに接続出来ないときのエラー等をテストしないわけにも行かないので、そういうところはクライアント側でちゃんとテストする必要があります。それを自動化したかったわけですね!</p>

<h2>SharpUnitを改造したよ</h2>

<p>ということで、今回はSharpUnitを改造してコルーチンのテストもできるようにしました。</p>

<p><a href="https://github.com/mgants4/SharpUnit">オリジナルのソースがgithubに上がっている</a>ようなのでとりあえず<a href="https://github.com/acidlemon/SharpUnit">forkして改造したものをgithubにあげています</a>。</p>

<p>大枠の使い方(Unity上での動かしかた)についてはあんまり変わっておりません。以下の記事が大変参考になります。というか私がまず最初に動かして動作チェックをしたときにこれを参考にさせていただきました。ありがとうございます。</p>

<ul>
<li><a href="http://blogs.yahoo.co.jp/nanashi_hippie/53071189.html">Unity SharpUnitって単体テストツール使ってみた</a></li>
</ul>

<p>とりあえずUnity側で必要な作業は、テスト時に動かすシーンに対してTestRunnerというGameObjectを追加して、そこに<code>Unity3D_TestRunner.cs</code>と<code>Unity3D_TestSuite.cs</code>をアタッチする感じになります。</p>

<p><a href="/assets_c/2012/12/de253cf0f17bb921094b9e8ebc8f0ccb-188.php" onclick="window.open('/assets_c/2012/12/de253cf0f17bb921094b9e8ebc8f0ccb-188.php','popup','width=1083,height=295,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"><img src="/assets_c/2012/12/de253cf0f17bb921094b9e8ebc8f0ccb-thumb-480x130-188.png" width="480" height="130" alt="2012_24_img.png" class="mt-image-none" style="" /></a></p>

<p>さてオリジナルのSharpUnitとの差分ですが、具体的には以下のような点を改造しています。</p>

<ul>
<li>従来のTestCaseの使用感は変更せず、それとは別にIEnumeratorを戻り値とする関数をテストできるUnityTestCaseクラスを追加</li>
<li>TestCaseクラスからITestCaseインタフェースを分離</li>
<li>TestSuiteクラスを使うのはやめて、Unity3D_TestSuiteクラスを追加。ITestCaseを実装しているTestCaseクラスとUnityTestCaseクラスの両方に対応(ファイルはそのまま残しています) </li>
</ul>

<p>改造理由についてちょっと触れておくと、TestCaseクラスはコルーチン実行できないテストフレームワークなので、これを元にコルーチンを実行できるUnityTestCaseクラスを作りました。Suite側でTestCaseとUnityTestCaseの両方を同じように扱えるようにするため、UnityTestCase側のインタフェースをITestCaseに分離し、TestCaseをそれに適応するようにTestResultを受け取る部分のインタフェースを変更しています。</p>

<p>これでTestSuiteでTestCaseとUnityTestCaseを同じように扱えるようになったのですが、そもそもTestSuiteからテストケースのコルーチンを実行するにはTestSuite自体がMonoBehaviorを継承してGameObjectとしてシーンにアタッチできるようになっている必要があるため、TestSuiteをベースにUnity3D_TestSuiteクラスを作ってGameObjectとして利用できるようにしています。</p>

<p>C++脳の私はこの辺の再実装は多重継承使ってやればいいじゃーんと思ってたんですが、C#には多重継承の仕組みがなかったのでてっとり速くコピペですませてしまっています。コレ書いててmix-in的なことをやればよかったんじゃねって今思いました。</p>

<h2>どんな感じでつかうの?</h2>

<p>そもそもSharpUnitを使ったことがある人はこの記事読んでも「へー」くらいで終わるかと思うんですが、Unityで単体テストとかやんねーだろ的な人もいるかと思いますので、具体的な例をこちらに書きます。</p>

<p>たとえば、こんなクラスがあったとしましょう。</p>

<pre><code>class Plan {
    private string _Title;
    private string _Text;
    public string Title { get { return _Title; } }
    public string Text { get { return _Text; } }

    // コンストラクタ
    public Plan(string title, string text) {
        _Title = title;
        _Text = text;
    }
}
</code></pre>

<p>このオブジェクトをテストするとなるとこんなコードを書きます。</p>

<pre><code>using SharpUnit;

public class PlanTestCase : TestCase {
    public override void SetUp() {
    }

    public override void TearDown() {
    }

    [UnitTest]
    public void TestConstructor() {
        // ふつうに作る
        Plan val1 = new Plan("Christmas", "Let's play tennis!");

        Assert.Equal(val1.Title, "Christmas", "title ok");
        Assert.Equal(val1.Text, "Let's play tennis!", "text ok");

        // 本文がぬるぽ
        Plan val2 = new Plan("Christmas", null);
        Assert.Equal(val2.Title, "Christmas", "title ok");
        Assert.Null(val2.Text, "text is null ok");
    }
}
</code></pre>

<p>ここまでは既存のSharpUnitで可能でした。ここからが問題で、かなり誰得感はありますがPlanをインターネットから取ってきて作るファクトリクラスがあったとしましょう。まーUnityでやる必要性はないですがサンプルなのでそんなもんです。</p>

<pre><code>using UnityEngine;

class InternetPlanFactory {
    private Plan _Plan;
    public Plan Plan { get { return _Plan; } }

    // 特定のURLにアクセスし、1行目をタイトル、2行目をテキストとしてオブジェクトを生成
    public IEnumerator PlanFromUrl(string url) {
        WWW www = new WWW(url);
        yield return www;

        if (www.error) {
            // ノープランだ
            _Plan = null;
        } else {
            // 適当にPlanつくる
            string[] lines = www.text.Split('\n');
            string title = lines[0];
            string text = lines.Length &gt; 1 ? lines[1] : "";

            _Plan = new Plan(title, text);
        }
    }
}
</code></pre>

<p>このファクトリクラスをテストするならまぁ大体この2ケースでしょうか(ホントは1行しかなかったときのテストもしたいですね)。</p>

<ul>
<li>ふつうにうまくいった</li>
<li>接続出来なかったり404とかのエラーが返ってきたりした</li>
</ul>

<p>が、このファクトリクラスのメソッドはコルーチン実行して結果が帰ってくるのを待たないとちゃんとテストできません。そこで、今回使ったUnityTestCaseを使います。</p>

<pre><code>using SharpUnit;

public class InternetPlanFactoryTestCase : UnityTestCase {
    private InternetPlanFactory factory;
    public override void SetUp() {
        factory = new InternetPlanFactory();
    }

    public override void TearDown() {
        factory = null;
    }

    [UnitTest]
    public IEnumerator TestPlanFromUrlOk() {
        // 普通にうまくいきそうなパターン
        Unity3D_TestSuite runner = GameObject.Find("TestRunner").GetComponent&lt;Unity3D_TestSuite&gt;();
        yield return runner.StartCoroutine(factory.PlanFromUrl("http://www.example.org/example.txt"));

        try {
            Assert.NotNull(factory.Plan, "plan is not null ok");
            Assert.NotNull(factory.Plan.Title, "plan has title ok");
            Assert.NotNull(factory.Plan.Text, "plan has text ok");
        } catch (TestException e) {
            MarkAsFailure(e);
            yield break;
        }

        DoneTesting();
    }

    [UnitTest]
    public IEnumerator TestPlanFromUrlError() {
        // ダメっぽそうなパターン
        Unity3D_TestSuite runner = GameObject.Find("TestRunner").GetComponent&lt;Unity3D_TestSuite&gt;();
        yield return runner.StartCoroutine(factory.PlanFromUrl("http://www.example.org/error.txt"));

        try {
            Assert.Null(factory.Plan, "plan is null ok");
        } catch (TestException e) {
            MarkAsFailure(e);
            yield break;
        }

        DoneTesting();
    }

}
</code></pre>

<p>さていくつか普通のTestCaseと違う点が出てきました。1つめはテスト関数の戻り値がIEnumeratorになってることですね。テストを走らせる呼び出し元が <code>yield return StartCoroutine(testMethod);</code> というような感じで呼び出しますのでこれに対応できるようにIEnumeratorにします。これによりテスト関数の中でyield returnを使えるようになるというわけですね。</p>

<p>2つめはAssertをtryで囲んでいることです。普通のTestCaseであればAssertでTestExceptionが飛んだら呼び出し元がcatchしてよしなにエラーレポートしてくれるところなんですが、C#にはtry-catchブロックの中にyield returnを書けないという制限があります。まぁ複雑になるしそれで正解だと思います。が、それによりテストを走らせる呼び出し元でcatchする作戦が使えませんので、テスト関数の中でちゃんとtry-catchして、catchしたらUnityTestCaseが持ってるMarkAsFailure関数でTestExceptionが発生したことをマークしておきます。呼び出し元はyield returnからコルーチンが帰ってきたらTestExceptionがセットされているかをチェックしています。</p>

<p>3つめはStartCoroutineの呼び出し方です。テストはコルーチンとして実行する必要があるのですが、コルーチンとして実行するにもロジックしかないメソッドのためGameObjectがありません。そこで、テストを走らせるためにシーンに追加したGameObjectからUnity3D_TestSuiteクラスのコンポーネントを取得して、こいつをコルーチンランナーとして活用しています。</p>

<p>あとDoneTesting()っていうのを呼んでいるのはPerlでテストを書いている人にはおなじみの<code>done_testing</code>ですね。IEnumeratorな関数である以上適当に途中にyield breakを書いてしまうとそこでテストを中断出来てしまい、テストが全部走らないままパスしたように見えてしまうことがありますので、それの対策にDoneTesting()を呼ばないとFailする機構をいれておいたというところです(まぁあってもなくてもいいとは思いますが、趣味で入れてしまったものです)。</p>

<h2>まとめ</h2>

<p>かけ足で紹介してきましたUnityでも使えるテストフレームワークSharpUnitの改造版、私はC#歴が浅いため結構これで満足しちゃっているのですが、もし「こうしたらもっと使いやすくなると思う!」などありましたらコメントいただければとおもいます。</p>

<p>それでは皆さん、よいクリスマス、そしてよい新年をお迎えください。カヤック技術部のアドベントカレンダーを購読いただきありがとうございました!</p>
]]>
        

    </content>
</entry>

<entry>
    <title>#22 カジュアルに乱数を使う方法とその注意点</title>
    <link rel="alternate" type="text/html" href="http://tech.kayac.com/archive/22.html" />
    <id>tag:tech.kayac.com,2012:/2.253</id>

    <published>2012-12-23T10:20:13Z</published>
    <updated>2012-12-23T10:22:01Z</updated>

    <summary>この記事はtech.kayac.com Advent Calendar 2012の22日目です。 @songmuです。ゲーム作ったりしてると、乱数が必要になってきますがそれについて書きます。 多くの人にとっては当たり前の話も多く出てくるかと思いますがご容赦ください。間違ってる記述があった場合は突っ込...</summary>
    <author>
        <name>matsuki-masayuki</name>
        
    </author>
    
    
    <content type="html" xml:lang="ja" xml:base="http://tech.kayac.com/">
        <![CDATA[<p>この記事は<a href="http://tech.kayac.com/archive/techkayaccom_advent_calendar_2012.html">tech.kayac.com Advent Calendar
2012</a>の22日目です。</p>

<p><a href="https://twitter.com/songmu">@songmu</a>です。ゲーム作ったりしてると、乱数が必要になってきますがそれについて書きます。</p>

<p>多くの人にとっては当たり前の話も多く出てくるかと思いますがご容赦ください。間違ってる記述があった場合は突っ込みください。</p>

<h2>擬似乱数とは何か</h2>

<p>計算機は単体では厳密な意味での乱数を生成することができません。実際には一様に分布する乱数の集合を算術的に求めている場合がほとんどです。</p>

<p>その乱数の集合は以下を満たす必要がありますが、そういう小難しいことは偉い人に任せて、巨人の肩に乗って解決してしまえば良いでしょう。</p>

<ul>
<li>偏りがなく一様に分布している</li>
<li>途中の出力から未来が予測しづらい</li>
<li>高速に算出できるか</li>
</ul>

<h2>つまり？</h2>

<p>色々な疑似乱数生成法がありますが、多くの場合、 <strong>馬鹿でかい乱数の循環リストがある</strong> と考えるとわかりやすいです。</p>

<p>例えばメルセンヌ・ツイスタの場合、2^19937-1という途轍もない長さの周期(乱数列)を持っています。</p>

<p>もちろん、そんな馬鹿でかい配列はメモリ上には持てないので、計算して求める必要があります。</p>

<p>昔のゲームだとメモリやプログラムサイズの制約のため、255くらいの長さの乱数列を決め打ちで持ったり、すごく単純な計算で乱数列を表現していたりするようです。</p>

<h2>乱数の初期化</h2>

<p>その循環リストのどの位置から数字を取り出し始めるかを決めることが乱数の初期化です。</p>

<p>その初期位置の決定に使う数値をシードと言ったりします。乱数の種ですね。</p>

<p>例えばPerlでは組み込みの乱数の初期化に <code>srand()</code> を使います。以下をターミナルで実行してみてください。</p>

<pre><code>% perl -E 'srand(1);say rand;say rand;'
0.0416303447718782
0.454492444728629
</code></pre>

<p>この場合は、1をシードにして乱数を初期化しています。何度実行して同じ結果が返ってくるはずです。</p>

<h2>乱数の初期化のジレンマ</h2>

<p>じゃあ、この乱数のシードはどうやって決めるんだという話になります。</p>

<p>もちろんシードはランダムに与えたい。ただ、ランダムに与えるには乱数を使う必要がある。鶏と卵みたいな話です。</p>

<p>エポック秒とマイクロ秒とプロセスIDあたりをうまいこと撹拌してそれをシードにするみたいな話もあります。</p>

<p>ただ、それだとエントロピーが少なく初期値があまり分散しない上、予測されやすいという問題も出てきます。</p>

<p>なので、環境が提供している擬似乱数生成器を利用して、それをシードとするのが好ましいです。</p>

<p>Linuxの場合、/dev/randomというものがあります。これはキーボード入力等をもとに作られたエントロピプールから乱数を生成する優れものになっています。</p>

<p>ただ、エントロピプールが空の場合は、乱数を返せず、処理をブロックしてしまいます。
そのへんをうまいことや仕組みとして、/dev/urandomという乱数生成器が準備されています。
そこまでセキュアな要件が必要じゃない場合はこちらを利用すれば十分です。</p>

<p>細かい話はWikipediaの/dev/randomの項でも読んでください。</p>

<h2>Perlの組み込み乱数</h2>

<p>ちなみにperlの場合、<code>srand()</code>を引数なしで呼び出すと、/dev/urandomからシードを生成してくれます。(/dev/urandomが使える環境の場合)</p>

<p>しかも、<code>rand</code>が初回に呼ばれた時に、<code>srand</code>を暗黙的に呼び出して乱数の初期化までやってくれます。すごい！カジュアル！</p>

<p>じゃあ、ここまでの話は必要なかったんやーとかいうと、そういうわけでもありません。</p>

<h2>forkの罠</h2>

<p>割と注意しなければならないのは、forkした場合に親の乱数シードを使ってしまうという問題です。
以下のような場合です。</p>

<pre><code>#!/usr/bin/env perl
use 5.014;
use warnings;
use utf8;

use Parallel::ForkManager;

rand; # 親プロセスで乱数が呼ばれると同時にシードも決定される

my $pm = Parallel::ForkManager-&gt;new(3);
for my $i (1..12) {
    $pm-&gt;start and next;

    say "$$ :". rand; # 同じ値が出続ける！！！

    $pm-&gt;finish;
}
</code></pre>

<p>この場合はちゃんと子プロセス側で、乱数を初期化してやる必要があります。</p>

<pre><code>#!/usr/bin/env perl
use 5.014;
use warnings;
use utf8;

use Parallel::ForkManager;

rand;

my $pm = Parallel::ForkManager-&gt;new(3);
for my $i (1..12) {
    $pm-&gt;start and next;

    srand; # ちゃんと子プロセスで初期化する！！！
    say "$$ :". rand; # OK

    $pm-&gt;finish;
}
</code></pre>

<p>forkされる場所に直接手を入れられない場合などのために、POSIX::AtForkを使う手もあります。</p>

<pre><code>#!/usr/bin/env perl
use 5.014;
use warnings;
use utf8;

use POSIX::AtFork;
POSIX::AtFork-&gt;add_to_child(sub { srand }); # magic!!!

use Parallel::ForkManager;

rand;

my $pm = Parallel::ForkManager-&gt;new(3);
for my $i (1..12) {
    $pm-&gt;start and next;

    say "$$ :". rand; # OK

    $pm-&gt;finish;
}
</code></pre>

<h2>シードを固定することのメリット</h2>

<p>シードを固定することにはメリットもあります。</p>

<p>規則性があるということは再現性があるということです。</p>

<p>乱数ジェネレータを同じシードで初期化すれば常に同じ結果が出るということです。</p>

<p>以下の例ではMath::Random::MTを使っていますが、常に同じ結果が出るはずです。</p>

<pre><code>#!/usr/bin/env perl
use 5.014;
use warnings;
use utf8;

use Math::Random::MT;
my $rand_gen = Math::Random::MT-&gt;new(10); # 10をシードにして初期化

say $rand_gen-&gt;rand;
say $rand_gen-&gt;rand;
say $rand_gen-&gt;rand;

__DATA__
0.771320643136278
0.298761158483103
0.020751946605742
</code></pre>

<p>これは何らかのシミュレータを動かす場合には非常に有用です。シードを記録しておけば、何度実行しても同じ結果が得られるからです。</p>

<p>ゲームのリプレイデータファイルなんかにも、その時に使われた乱数のシードが記録されていたりするそうです。</p>

<h2>メルセンヌ・ツイスタ</h2>

<p>メルセンヌ・ツイスタは、非常に周期が大きく、乱数も均等に分布していて、かつ計算も早いという優れものの擬似乱数アルゴリズムです。そのPerl実装がMath::Random::MTです。</p>

<p>ちょっと複雑な乱数ジェネレータを作りたい場合は、これを使っておけば十分です。</p>

<p>ただ、規則性を持った疑似乱数であることには変わりないので、単体では暗号化技術にはなりませんし、当然のことながら匿名化技術ではありません。</p>

<h2>結論</h2>

<p>ということでPerlにおける乱数生成のベタープラクティスは以下の様な感じです。</p>

<ul>
<li>Math::Random::MTを使う</li>
<li>シードの生成はsrand()を使う</li>
<li>forkした場合は、乱数を初期化するのが吉。POSIX::AtFork使うと捗る</li>
</ul>
]]>
        

    </content>
</entry>

<entry>
    <title>#23 「欲しい情報に素早くアクセスするためのたくさんの方法」tech.kayac.com Advent Calendar 2012</title>
    <link rel="alternate" type="text/html" href="http://tech.kayac.com/archive/23_techkayaccom_advent_calendar_2012.html" />
    <id>tag:tech.kayac.com,2012:/2.252</id>

    <published>2012-12-22T23:30:00Z</published>
    <updated>2012-12-22T23:27:04Z</updated>

    <summary>速さは強さ。 tech.kayac.com Advent Calendar 2012の23日目です。 @handlenameです。 クリスマス前の3連休なのに野郎オンリーでジムを冷やかしに行く予定しかありません。うける。 普段使っている、様々な情報に素早くアクセスする方法を紹介します。 アプリケーシ...</summary>
    <author>
        <name>nagata-hiroaki</name>
        <uri>http://blog.handlena.me</uri>
    </author>
    
    <category term="adventcalendar2013" label="AdventCalendar2013" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="chrome" label="chrome" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="emacs" label="emacs" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="mac" label="mac" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="ja" xml:base="http://tech.kayac.com/">
        <![CDATA[<p>速さは強さ。</p>

<p><a href="http://tech.kayac.com/archive/techkayaccom_advent_calendar_2012.html">tech.kayac.com Advent Calendar 2012</a>の23日目です。
<a href="https://twitter.com/handlename">@handlename</a>です。
クリスマス前の3連休なのに野郎オンリーでジムを冷やかしに行く予定しかありません。うける。</p>

<p>普段使っている、様々な情報に素早くアクセスする方法を紹介します。</p>

<h2>アプリケーションを素早く起動する (Spotlight)</h2>

<p>Mac限定のはなし。</p>

<p>Quicksilvel、LaunchBar、Butlerなどの
ランチャーアプリを使っていたこともありましたが、
SSDなMacbookAirになってからはSpotlightが爆速なので
全てこれで済ませてしまっています。</p>

<p>候補が多すぎると鬱陶しいので、
検索対象をアプリケーションとシステム環境設定に絞って使っています。</p>

<h2>アプリケーションを素早く切り替える (Spark)</h2>

<p>こちらもMac限定のはなし。</p>

<p>アプリケーションの切り替えにいちいちCmd+Tabを使っていては、
「エディタは3番目にあるからTabを3回押して…」と、無駄な思考が入ってしまいます。
アプリケーションの切り替えごときにいちいち頭を使っていられないので、
Sparkというツールでワンストロークで切り替えられるようにしています。</p>

<ul>
<li><a href="http://www.shadowlab.org/softwares/spark.php">http://www.shadowlab.org/softwares/spark.php</a></li>
</ul>

<p>設定画面。</p>

<p><img alt="spark.png" src="/advent-calender-2013-23/spark.png" width="839" height="603" class="mt-image-none" style="" /></p>

<p>エディタ(Emacs)・ターミナル(iTerm2)・ブラウザ(Chrome)の三種の神器と、
よく使うアプリケーションいくつかを登録しています。</p>

<p>起動していなければ起動、していればアクティブにしてくれるので
なにも考えずにキーを押せばお目当てのアプリケーションにたどり着くことができます。</p>

<p>(画像中で使われているキーに違和感を感じるかもしれませんが、
dvorak配列だとすべて右手で押せる位置にあるのです)</p>

<h2>IRC/tmuxのウィンドウを素早く切り替える (canything)</h2>

<p>弊社typesterのブログ記事を参照。</p>

<ul>
<li><a href="http://unknownplace.org/memo/2012/03/26/1/">http://unknownplace.org/memo/2012/03/26/1/</a></li>
</ul>

<p>IRCでどんなにたくさんのチャンネルにjoinしていても、
tmuxでどんなにたくさんのウィンドウを開いていても、
一瞬で目的のチャンネルにたどり着けます。</p>

<p>tmuxのウィンドウを開くときは次のようなコマンドを作って使っています。
新しいウィンドウを開くのはたいていsshコマンドを使うときなので、
特別扱いしてホスト名をウィンドウ名として使うようにしています。</p>

<pre><code>#!/bin/sh

name=$1

if test $name = "ssh"; then
    name=$2
fi

tmux new-window -n $name "$*"
</code></pre>

<h2>ディレクトリ履歴を素早く絞り込む (zaw)</h2>

<p>以前はこういう無理矢理な感じのエイリアスを登録していたのですが、</p>

<pre><code>alias cda='cd `pushd | tr " " "\n" | sed -e "s/~/\/Users\/handle/" | canything`'
</code></pre>

<p>zawというものを知ってからはこちらを使っています。</p>

<ul>
<li><a href="https://github.com/zsh-users/zaw">https://github.com/zsh-users/zaw</a></li>
</ul>

<p>詳しくはREADME参照。
ディレクトリ履歴以外にも様々なことをanythingなインターフェイスで絞り込み&amp;実行できます。</p>

<h2>emacs上で素早く絞り込む (helm.el)</h2>

<p>anything派生のhelmを使ってます。</p>

<ul>
<li><a href="https://github.com/emacs-helm/helm">https://github.com/emacs-helm/helm</a></li>
</ul>

<p>このあたりが便利。</p>

<table>
<tr><td>helm-show-kill-ring</td><td>キルリングの履歴を絞り込む</td></tr>
<tr><td>helm-c-moccur-occur-by-moccur</td><td>バッファ内検索にマッチしたものを絞り込む</td></tr>
<tr><td>helm-for-files</td><td>バッファ・バッファ履歴・カレントディレクトリなどからファイルを絞り込む</td></tr>
<tr><td>helm-git-find-files</td><td>gitプロジェクト内のファイルを絞り込む</td></tr>
<tr><td>helm-imenu</td><td>バッファ内の関数を絞り込む</td></tr>
<tr><td>helm-M-x</td><td>emacsのコマンドを絞り込む</td></tr>
</table>

<p>.emacs以下のファイルはgithubにpushしてあるので、
具体的な設定方法はそちらを参照してください。</p>

<ul>
<li><a href="https://github.com/handlename/dot-emacs/blob/master/dot.emacs.d/inits/40_helm.el">https://github.com/handlename/dot-emacs/blob/master/dot.emacs.d/inits/40_helm.el</a></li>
</ul>

<h2>でバッファ内を素早く移動する (ace-jump-mode.el)</h2>

<p>emacs上でhit-a-hint的なカーソル移動を実現します。</p>

<ul>
<li><a href="https://github.com/winterTTr/ace-jump-mode">https://github.com/winterTTr/ace-jump-mode</a></li>
</ul>

<p>README中にリンクのあるデモを見てみましょう。
どういう機能なのか、よくわかります。</p>

<ul>
<li><a href="http://dl.dropbox.com/u/3254819/AceJumpModeDemo/AceJumpDemo.htm">http://dl.dropbox.com/u/3254819/AceJumpModeDemo/AceJumpDemo.htm</a></li>
</ul>

<h2>Chromeのタブを素早く切り替える (chrome-anything)</h2>

<p>調べ物をしているときはタブを大量に開くことが多いので、
目的のタブに素早く切り替えられるように拡張をつくりました。</p>

<ul>
<li><a href="https://github.com/handlename/chrome-tab-anything">https://github.com/handlename/chrome-tab-anything</a></li>
</ul>

<p>こんな感じの表示が出て、インクリメンタルにタブを絞り込めます。</p>

<p><img alt="chrome-anything.png" src="/advent-calender-2013-23/chrome-anything.png" width="678" height="498" class="mt-image-none" style="" /></p>

<p>拡張機能にショートカットを設定しておくと
キーボードがから手を離さずにタブ切り替えができます。</p>

<h2>Chromeからスマホに素早くテキストを送る (chrome-post-it)</h2>

<p>以前、弊社の<a href="http://nakamap.com">ナカマップ</a>というサービスの公開APIを使って、
おなじく弊社の<a href="http://im.kayac.com">im.kayac</a>というサービスと同じような
手軽にプッシュ通知を送るサービスをつくりました。</p>

<ul>
<li><a href="https://im.handlena.me">https://im.handlena.me</a></li>
</ul>

<p>この自作のサービスを使って、
Chromeからスマホに簡単にテキストを送ることができる拡張機能をつくってみました。</p>

<ul>
<li><a href="https://github.com/handlename/chrome-post-it">https://github.com/handlename/chrome-post-it</a></li>
</ul>

<p>インストールするとコンテキストメニューに「post to nakamap」という項目が追加されて、
im.handlena.meで登録した中マップのチャットグループに
選択したテキストを送ることができます。</p>

<p><img alt="post-it.png" src="/advent-calender-2013-23/post-it.png" width="632" height="150" class="mt-image-none" style="" /></p>

<p>im.kayacでは開けないURLも、ナカマップで受け取ればその場で開けます。
ナカマップAPI便利。</p>

<h2>おわり</h2>

<p>最終日は北海道より愛をこめて、<a href="https://twitter.com/acidlemon">@acidlemon</a>さんがお送りします。
お楽しみに。</p>
]]>
        

    </content>
</entry>

<entry>
    <title>#21 「CS対応にマジ便利!! 行動ログ閲覧ツール &quot;伊右衛門&quot; の話」 tech.kayac.com Advent Calendar 2012</title>
    <link rel="alternate" type="text/html" href="http://tech.kayac.com/archive/cs.html" />
    <id>tag:tech.kayac.com,2012:/2.251</id>

    <published>2012-12-21T08:20:35Z</published>
    <updated>2012-12-21T09:24:11Z</updated>

    <summary>こんにちは、@hisaichi5518 です。 今年のクリスマスこそは、彼女とイチャイチャしながら有意義に過ごしたかったので、こういうのを作ったりしましたが、女の子から告白される気配がありません。クソが。 CS対応 と 行動ログ閲覧ツール「伊右衛門」 CSとは、カスタマーサポートの事で、 CS対応は...</summary>
    <author>
        <name>hisaichi5518</name>
        
    </author>
    
    
    <content type="html" xml:lang="ja" xml:base="http://tech.kayac.com/">
        <![CDATA[<p>こんにちは、<a href="http://twitter.com/hisaichi5518" target="_blank">@hisaichi5518</a> です。<br />
今年のクリスマスこそは、彼女とイチャイチャしながら有意義に過ごしたかったので、<a href="http://blog.hisaichi5518.com/entry/2012/11/10/003301" target="_blank">こういうの</a>を作ったりしましたが、女の子から告白される気配がありません。クソが。</p>

<h2>CS対応 と 行動ログ閲覧ツール「伊右衛門」</h2>

<p>CSとは、カスタマーサポートの事で、<br />
CS対応は、ユーザーさんのお問い合わせの調査の事をここでは指します。</p>

<p>例えば、ソーシャルゲームを運営していると「アイテムを使ってないのになくなっている！」なんてお問い合わせはよくあると思います。<br />
そういう時にアイテムを使ったログが残っていなかったり、検索しにくかったら大変な事になります。</p>

<p>なのでカヤックは、fluentdとMongoDBを使ってユーザーさんの行動ログを保存しています。<br />
その行動ログをブラウザで見えるようにしたのが、伊右衛門です。<br />
→ <a href="https://github.com/hisaichi5518/iyemon" target="_blank">https://github.com/hisaichi5518/iyemon</a></p>

<p>この伊右衛門を使えば「そのアイテムはこの時間に使ってます」っていうのがすぐ分かったり、使っていなかった場合はバグだ！というのがすぐ分かって、マジ便利！！！！！！！という事です。</p>

<h2>セットアップ & 立ち上げる</h2>

<p>Perlを使っています。やっぱりPerlは可愛い。</p>

<pre>
$ git clone git@github.com:hisaichi5518/iyemon.git
$ cd iyemon
$ cpanm --installdeps .
$ cp common.sample.pl common.pl
$ cat common.pl
{
    'MongoDB::Connection' => {
        host       => 'localhost',
        port       => 27017,
        database   => 'test',
        collection => 'test',
    },
    boostrap => {
        web => ['-p' => 50004],
    },
}
$ vi common.pl # MongoDB::Connectionの設定をよしなに設定する
$ cat common.pl
{
    'MongoDB::Connection' => {
        host       => 'localhost',
        port       => 27018,
        database   => 'test2',
        collection => 'test2',
    },
    boostrap => {
        web => ['-p' => 50004],
    },
}
$ ./boostrap
</pre>

<p>これでhttp://localhost:50004/にアクセスすれば見えるようになります。</p>

<h2>作った時の話</h2>

<h3>MongoDB</h3>

<p>ウッ、MongoDB.pm</p>

<pre>
# これはちゃんとログが取得できる
my @logs = $mongo->find({uid => 1});
# これだとログが取得できない！！！！１
my @logs = $mongo->find({uid => "1"});
</pre>

<p>というのがあって、ハゲるかと思いました。<br />
なので<a href="https://github.com/hisaichi5518/iyemon/blob/master/lib/Iyemon/Web.pm">頑張っています</a>。</p>

<h3>DateTime</h3>

<p>DateTime使った事がなかったんですが、MongoDB.pmでは必須だったので使ってます。<br />
今では、ぼくもDateTimeにどっぷり！！！！！！１?(^o^)／</p>

<h3>Kossy</h3>

<p>元々は違うフレームワークで書いていたんですが、<br />
エエイ！使いにくいわ！書き換えてやる！って事で昨日書き換えました。</p>

<p>Kossyは、 GrowthForecastやHRForecastに使われているフレームワークです。<br />
簡単なアプリを作るのにすごい便利なのでオススメです。</p>

<p>そのKossyに書き換えた事で、導入もしやすくなりました。</p>

<h2>まとめ</h2>

<p>伊右衛門があるとCS対応が非常に捗るのでオススメ！！！！！！！！！！！！！！！！！<br />
そんなわけで伊右衛門の紹介でした〜</p>

<p><a href="https://github.com/hisaichi5518/iyemon">https://github.com/hisaichi5518/iyemon</a></p>

<p>明日は <a href="http://twitter.com/songmu">@songmu</a> さんです！楽しみ！！！１１</p>]]>
        
    </content>
</entry>

<entry>
    <title>#20 まさか、Cocos2d-x 使っているのに C++ 書いてるわけないよね？</title>
    <link rel="alternate" type="text/html" href="http://tech.kayac.com/archive/20_snmp.html" />
    <id>tag:tech.kayac.com,2012:/2.236</id>

    <published>2012-12-19T15:00:00Z</published>
    <updated>2012-12-19T17:36:46Z</updated>

    <summary>Unity ではプラグイン開発専門の @Gemmbu です。 みなさん Cocos2d-x で開発してますよね？ 当然のことながら Cocos2d-x で開発する際は Lua/JavaScript で開発していますよね？ Q. Lua/JavaScript で開発すると何がうれしいの？ A. スマー...</summary>
    <author>
        <name>kameda-kyosuke</name>
        
    </author>
    
    
    <content type="html" xml:lang="ja" xml:base="http://tech.kayac.com/">
        <![CDATA[<p>Unity ではプラグイン開発専門の <a href="http://twitter.com/Gemmbu">@Gemmbu</a> です。</p>

<p>みなさん <a href="http://www.cocos2d-x.org">Cocos2d-x</a> で開発してますよね？</p>

<p>当然のことながら Cocos2d-x で開発する際は Lua/JavaScript で開発していますよね？</p>

<h2>Q. Lua/JavaScript で開発すると何がうれしいの？</h2>

<p><strong>A. スマートフォンの開発サイクルを高速化できます</strong></p>

<p>スマートフォンの開発サイクルって通常以下のフローを回しますよね</p>

<ol>
<li>コーディング</li>
<li>ビルド</li>
<li>実機/シミュレータへ転送</li>
<li>テスト</li>
</ol>

<p>このうち、開発の本質でない部分を Lua/JavaScript を使うことでさくっと省くことができます。</p>

<p>Lua/JavaScript を使用した場合のフローは</p>

<ol>
<li>コーディング</li>
<li>実機/シミュレータへ転送（修正したスクリプトのみ）</li>
<li>テスト</li>
</ol>

<p><strong>ビルドがなくなった！！</strong>。また、実機/シミュレータへ転送もスクリプトファイルのみになりました。
ゲーム等画像及び音声の多いものを作っている場合は、コード以外のリソースの転送がほとんどなのでスクリプトファイルだけの転送になるのは嬉しいですよね。</p>

<h2>Q. じゃあ、どうやるの？</h2>

<p><strong>A. Android は SD カードに書き込んで、それを読み出すようにちょっと修正するだけ</strong></p>

<pre><code>---- &lt;PROJECT_ROOT&gt;/Classes/AppDelegate.cpp ----

/* Lua スクリプトの読み込み先を SD カードからに変更する */
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
    const char *pLuaFile = "/mnt/sdcard/genius.lua";    /* 環境に合わせたパスに変更する */
    CCString *pstrFileContent = CCString::createWithContentsOfFile(pLuaFile);
    if (pstrFileContent)
    {
        pEngine-&gt;executeString(pstrFileContent-&gt;getCString());
    }
#endif
</code></pre>

<p>上記のように修正して</p>

<pre><code>$ adb push genius.lua /mnt/sdcard/genius.lua
</code></pre>

<p>でスクリプトを更新したら、アプリを再起動するだけ。簡単ですね。
SDカードのパスをちゃんとするなら、jni で以下のようなコードを書きましょう</p>

<pre><code>/* android.os.Environment */
typedef struct {
    jclass klass;
    jmethodID get_external_storage_directory;
} android_os_environment_class;

/* java.io.File */
typedef struct {
    jclass klass;
    jmethodID get_path;
} java_io_file_class;

static void get_sdcard_path(JNIEnv* env, char* dst)
{
    android_os_environment_class environment_class;
    java_io_file_class f_class;
    jobject f;
    jstring j_path;
    const char* n_path;
    environment_class.klass = env-&gt;FindClass("android.os.Environment");
    environment_class.get_external_storage_directory
        = env-&gt;GetStaticMethodID(environment_class.klass,
                                 "getExternalStorageDirectory",
                                 "()Ljava/io/File;");

    f_class.klass = env-&gt;FindClass("java.io.File");
    f_class.get_path = env-&gt;GetMethodID(f_class.klass,
                                        "getPath",
                                        "()Ljava/lang/String;");

    f = env-&gt;CallStaticObjectMethod(environment_class.klass,
                                    environment_class.get_external_storage_directory);

    j_path = (jstring) env-&gt;CallObjectMethod(f, f_class.get_path);
    if(j_path != NULL){
        n_path = env-&gt;GetStringUTFChars(j_path, NULL);
        strcpy(dst, n_path);
    }

    env-&gt;ReleaseStringUTFChars(j_path, n_path);
    env-&gt;DeleteLocalRef(j_path);
    env-&gt;DeleteLocalRef(f_class.klass);
    env-&gt;DeleteLocalRef(environment_class.klass);
}
</code></pre>

<h2>Q. じゃあ、SD カードが使えない iOS はどうやるの？</h2>

<p><strong>A. iTunes からファイルを転送します</strong></p>

<h2>Q. めんどいよ</h2>

<p><strong>A. じゃあ、iOS に curl から post して</strong></p>

<p><a href="https://github.com/KAMEDAkyosuke/simple-post-server">simple-post-server</a> を使えば curl からファイルを post できます。</p>

<p>iOS のプロジェクトに移動して simple-post-server を追加します。</p>

<pre><code>$ git submodule add git@github.com:KAMEDAkyosuke/simple-post-server.git &lt;PROJECT_NAME&gt;/ios/external/simple-post-server
</code></pre>

<p>また、simple-post-server は <a href="https://github.com/joyent/http-parser">http-parser</a>に依存しているため、以下を行います</p>

<pre><code>$ cd &lt;PROJECT_NAME&gt;/ios/external/simple-post-server
$ git submodule init
$ git submodule update
</code></pre>

<p>xcode の Build Phases の Compile Sources に以下を追加します。</p>

<ul>
<li><code>&lt;PROJECT_NAME&gt;/ios/external/simple-post-server/body-parser.c</code></li>
<li><code>&lt;PROJECT_NAME&gt;/ios/external/simple-post-server/http-parser-helper.c</code></li>
<li><code>&lt;PROJECT_NAME&gt;/ios/external/simple-post-server/intlist.c</code></li>
<li><code>&lt;PROJECT_NAME&gt;/ios/external/simple-post-server/simple-post-server.c</code></li>
<li><code>&lt;PROJECT_NAME&gt;/ios/external/simple-post-server/stringlist.c</code></li>
<li><code>&lt;PROJECT_NAME&gt;/ios/external/simple-post-server/external/http-parser/http_parser.c</code></li>
</ul>

<p>サーバの起動と、post されたファイルの保存のコードを書きましょう。</p>

<pre><code>---- &lt;PROJECT_NAME&gt;/ios/AppController.mm ----

/* ポストしたファイルを保存する */
static void simple_post_server_callback(post_content_t* post_content){
    NSArray *documentDirectories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentDirectory = [documentDirectories lastObject];

    NSString *path = [documentDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%s", post_content-&gt;filename]];
    NSData *content = [NSData dataWithBytes:post_content-&gt;body
                                     length:strlen(post_content-&gt;body)];
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSError* error = nil;
    if([fileManager fileExistsAtPath:path]){
        [fileManager removeItemAtPath:path error:&amp;error];
        if(error != nil){
            NSLog(@"%@", [error description]);
        }
    }
    [fileManager createFileAtPath:path
                         contents:content
                       attributes:nil];
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    /* サーバの起動 */
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
    dispatch_async(queue, ^{
        start_server(8080, simple_post_server_callback);
    });
    ...
</code></pre>

<p>ファイルの保存はよくあるコード。サーバの起動もわずか 4 行。簡単ですね。</p>

<p>あとは android の場合と同様に読み込む先のスクリプトパスを変更すればいいだけ。</p>

<p>ファイルの転送を便利にするために以下のようなスクリプトを書くといいですね。</p>

<pre><code>---- post_all.sh ----
#!/bin/sh

HOST=$1

for filepath in *.lua; do
    HOGE="curl -F file=@$filepath http://$HOST:8080"
    echo $HOGE
    $HOGE
done
</code></pre>

<p>スクリプトの編集が終わったら以下のコマンドで一気に転送しましょう</p>

<pre><code>$ ./post_all.sh &lt;your_ios_ip_address&gt;
</code></pre>

<h2>Q. iOSでスクリプト簡単に転送できるようになったけど、エラーログってどうやってみるの？</h2>

<p><strong>A. <PROJECT_NAME>/libs/cocos2dx/platform/ios/CCCommon.mm を書き換えましょう</strong></p>

<p>具体的には以下のようにログ出力に NSLog を使用するようにしましょう。</p>

<pre><code>void CCLog(const char * pszFormat, ...)
{
    char szBuf[kMaxLogLen];

    va_list ap;
    va_start(ap, pszFormat);
    vsnprintf(szBuf, kMaxLogLen, pszFormat, ap);
    va_end(ap);
    NSLog(@"%s", szBuf);
}
</code></pre>

<p>xcode につながなくても <a href="http://support.apple.com/kb/DL1465?viewlocale=ja_JP">iPhone構成ユーティリティ</a> 使えば見られるのはご存知ですよね。</p>

<h2>Q. パフォーマンスは？</h2>

<p><strong>A. 弊社のアプリを手元で適当に移植した際は問題なし</strong></p>

<p>いざとなったら C/C++ で書けばいいし。</p>

<h2>まとめると</h2>

<ul>
<li>Cocos2d-x で C++ だけで書いているのはもったいないよ。</li>
<li>Android は SD カードで簡単にスクリプトだけの更新ができるよ。</li>
<li>iOS は面倒だから curl からの post を受け取れるサーバを書いたよ。みんな使ってね。</li>
<li>パフォーマンス困ったら C/C++ で書けばいいから心配しなくてもいいんじゃない？</li>
</ul>

<p>明日はマヤ暦によると人類滅亡の日です。
人類滅亡が先か<a href="https://twitter.com/hisaichi5518">@hisaichi5518</a>さんの記事が公開されるのが先か楽しみですね。</p>
]]>
        

    </content>
</entry>

<entry>
    <title>#19 「iOS6のカスタムUIAcitivityのつくりかた」 tech.kayac.com Advent Calendar 2012</title>
    <link rel="alternate" type="text/html" href="http://tech.kayac.com/archive/19_ios6uiacitivity_techkayaccom_advent_calendar_2012.html" />
    <id>tag:tech.kayac.com,2012:/2.250</id>

    <published>2012-12-19T07:00:00Z</published>
    <updated>2012-12-20T01:14:19Z</updated>

    <summary>突然ですが、tech.kayacの読者の皆様方におかれましては、自社でWebサービスを運営している方、及びそのサービスのクライアントとしてのネイティブiOSアプリをリリースされている方はかなり多いのではないのでしょうか。 そんな独自サービス／アプリを、もっと多くの人に使ってもらえるきっかけとなる（か...</summary>
    <author>
        <name>tsutsumi-shuichi</name>
        
    </author>
    
    
    <content type="html" xml:lang="ja" xml:base="http://tech.kayac.com/">
        <![CDATA[<p>突然ですが、tech.kayacの読者の皆様方におかれましては、自社でWebサービスを運営している方、及びそのサービスのクライアントとしてのネイティブiOSアプリをリリースされている方はかなり多いのではないのでしょうか。</p>

<p>そんな<strong>独自サービス／アプリを、もっと多くの人に使ってもらえるきっかけとなる（かもしれない） UIActivity という iOS 6 の新機能</strong>について書かせていただきます。</p>

<p>あ、申し遅れました、入社３年目にして初めて投稿する、ツツミ（<a href="https://twitter.com/shu223">@shu223</a>）と申します。ひたすらiOSアプリをつくり続けております。</p>

<h2>UIActivityとは？</h2>

<p>iOS 6 から入った、こんなやつです。</p>

<p><a href="/assets_c/2012/12/uiactivity1-179.php" onclick="window.open('/assets_c/2012/12/uiactivity1-179.php','popup','width=792,height=1488,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"><img src="/assets_c/2012/12/uiactivity1-thumb-200x375-179.png" width="200" height="375" alt="uiactivity1.png" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></a></p>

<p>FacebookやTwitterに投稿したり、テキストをメールで送信したり、写真アプリに画像を保存したりと、とにかく<strong>アプリやサービス連携の総合受付</strong>みたいなUIです。</p>

<h2>実装は超カンタン</h2>

<p>この UI、UIActivityController というクラスを使って実装するのですが、超カンタンです。</p>

<pre><code>- (IBAction)pressBtn {
    UIActivityViewController *activityView = [[UIActivityViewController alloc] initWithActivityItems:@[@"投稿するテキスト"]
                                                                               applicationActivities:@[]];    
    [self presentViewController:activityView animated:YES completion:nil];
}
</code></pre>

<p>こんな感じで、なんと<strong>たったの２行</strong>で UIActivityController を表示できてしまいます。</p>

<p>「Twitter投稿の実装が簡単になった！」と iOS 5 時代に大歓迎された TWTweetComposeViewController とそんなに実装量が変わらないので、私はここ最近はほぼ確実に UIActivity を入れています。</p>

<h2>拡張もカンタン</h2>

<p>そんな便利な UIActivity ですが、さらに便利なことに、カスタムUIActivityをつくって UIActivityViewController に追加することができるのです。</p>

<p>たとえば、<a href="https://github.com/alextrob/ARChromeActivity">ARChromeActivity</a> という OSS を使うと、UIActivityViewController に Chromeアプリで URL を開くためのアイコンが追加されます。</p>

<p><a href="/assets_c/2012/12/uiactivity3-182.php" onclick="window.open('/assets_c/2012/12/uiactivity3-182.php','popup','width=320,height=310,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"><img src="/assets_c/2012/12/uiactivity3-thumb-200x193-182.png" width="200" height="193" alt="uiactivity3.png" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></a></p>

<p>で、このカスタムUIActivityの追加がまたラクなのです。</p>

<p>たとえば ARChromeActivity を追加したい場合に、上述したコードに追加するコードは1行だけ。</p>

<pre><code>ARChromeActivity *chromeActivity = [[ARChromeActivity alloc] init];
</code></pre>

<p>これを、UIActivityController を初期化する際の applicationActivities 引数に渡してやると、</p>

<pre><code>UIActivityViewController *activityView = [[UIActivityViewController alloc] initWithActivityItems:activityItems
                                                                           applicationActivities:@[chromeActivity]];
</code></pre>

<p>これだけの変更で Chrome アプリとの連携機能が実現するという優れものです。</p>

<h2>カスタムUIActivityのつくりかた</h2>

<p>やっと本題です。</p>

<p>このカスタムUIActivityをつくるのもけっこう簡単なので、独自サービス／アプリをお持ちの方は、<strong>マイUIAcitvityをつくって Github などで公開しておけば、他の開発者が自分のアプリのUIActivityControllerに組み込んでくれる</strong>かもしれません。</p>

<p>つまり、カスタムUIActivityを公開しておくことで、連携アプリが増え、独自サービス／アプリのアクティブ率向上につながる可能性があります。</p>

<p>というわけで、弊社のグループチャットサービス『ナカマップ』のUIActivityをつくってみたので、その際の実装手順を紹介させていただきます。</p>

<p>リポジトリはこちら。（デモアプリつき） <br />
<a href="https://github.com/shu223/SHNakamapActivity">SHNakamapActivity</a></p>

<p>チャット投稿用のカスタムURL Schemeを1つたたくだけの、最小構成です。</p>

<h3>1. アイコンを用意する</h3>

<p>周囲を透過にする必要があります。透過にしないとどうなるか、どんな画像を用意すればよいかは、<a href="http://hirakiuc.blogspot.jp/2012/09/uiactivity.html">こちらの記事</a>が画像付きでわかりやすいです。</p>

<p>今回は、僕の拙いFireworksスキルで無理やり透過にしたので、こんなのが入っています。</p>

<p><a href="/assets_c/2012/12/NakamapActivityIcon@2x~ipad-173.php" onclick="window.open('/assets_c/2012/12/NakamapActivityIcon@2x~ipad-173.php','popup','width=110,height=110,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"><img src="/assets_c/2012/12/NakamapActivityIcon@2x~ipad-thumb-55x55-173.png" width="55" height="55" alt="NakamapActivityIcon@2x~ipad.png" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></a></p>

<p>緑っぽい色がついてる部分も、iOS側で UIActivity っぽく処理されます。</p>

<p>ちなみにサイズは</p>

<ul>
<li>43x43</li>
<li>86x86</li>
<li>55x55</li>
<li>110x110</li>
</ul>

<p>の4種類入れてあります。</p>

<h3>2. UIActivity を継承したクラスを新規作成</h3>

<p>UIActivity を継承したクラスを新規作成します。今回はヘッダファイルは新規作成時のままとくにいじりません。</p>

<h3>3. UIActivityのメソッドをオーバーライド</h3>

<p>下記を参考に、サービス／アプリに合わせてよしなにオーバーライドしてください。</p>

<pre><code>- (NSString *)activityType {
    return @"com.kayac.nakamap";
}

- (UIImage *)activityImage {
    return [UIImage imageNamed:@"NakamapActivityIcon.png"];
}

- (NSString *)activityTitle {
    return @"Nakamap";
}

- (BOOL)canPerformWithActivityItems:(NSArray *)activityItems {
    for (id activityItem in activityItems) {
        if ([activityItem isKindOfClass:[NSString class]]) {
            return YES;
        }
    }
    return NO;
}

- (void)prepareWithActivityItems:(NSArray *)activityItems {
    for (id activityItem in activityItems) {
        if ([self openNakamapWithItem:activityItem]) {
            break;
        }
    }
}
</code></pre>

<h3>4. 連携処理を実装</h3>

<p>サービス／アプリとの連携処理を実装します。サービスならAPI、アプリならURL Schemeを呼びます。（アプリ内のフレームワークとかを呼び出すUIActivityもあります）</p>

<p>SHNakamapActivity では、prepareWithActivityItems: で呼んでいる openNakamapWithItem: のところで、ナカマップのチャット用 URL Schemeをたたいています。</p>

<pre><code>- (BOOL)openNakamapWithItem:(id)item {
    NSURL *url = [NSURL URLWithString:@"nakamap://chat"];
    NSString *urlStrWithItem = [NSString stringWithFormat:@"nakamap://chat?message=%@", item];
    NSURL *urlWithItem = [NSURL URLWithString:urlStrWithItem];
    [[UIApplication sharedApplication] openURL:urlWithItem];
    return YES;
}
</code></pre>

<p>（上記コードは簡単化のため各種チェック処理は省いています）</p>

<h3>できあがり！</h3>

<p>呼び出し側はこんな感じで、</p>

<pre><code>SHNakamapActivity *nakamapActivity = [[SHNakamapActivity alloc] init];
UIActivityViewController *activityView = [[UIActivityViewController alloc] initWithActivityItems:@[@"投稿テキスト"]
                                                                           applicationActivities:@[nakamapActivity]];
[self presentViewController:activityView animated:YES completion:nil];
</code></pre>

<p>これでナカマップ連携機能がUIActivityControllerに追加されました！</p>

<p><a href="/assets_c/2012/12/uiactivity2-176.php" onclick="window.open('/assets_c/2012/12/uiactivity2-176.php','popup','width=792,height=1488,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"><img src="/assets_c/2012/12/uiactivity2-thumb-200x375-176.png" width="200" height="375" alt="uiactivity2.png" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></a></p>

<p>アイコンタップでナカマップアプリが起動し、グループのチャット画面へ移動すると、チャット入力欄に投稿テキストが自動入力されます。（ナカマップが未インストールの場合はAppStoreを開きます）</p>

<h2>カスタムUIActivityをまとめたリポジトリ</h2>

<p>Dropbox、Instagram、LINEといった著名サービスの UIActivity は、すでにちらほら Github で公開されはじめているので、それらを集めたリポジトリをつくりました。詳細は下記記事をご覧ください。</p>

<p><a href="http://d.hatena.ne.jp/shu223/20121127/1354017518">たった1行でWebサービスと連携！UIActivity のまとめリポジトリをつくりました</a></p>

<h2>その他のiOS6の機能</h2>

<p>iOS 6 には UIActivity 以外にもイノベーティブな新機能がたくさんあります。そんな iOS6新機能のサンプルコード／ライブラリをまとめた記事がこちら。</p>

<p><a href="http://d.hatena.ne.jp/shu223/20120923/1348355900">iOS 6 新機能のサンプルコード／ライブラリのまとめ22個</a></p>

<h2>まとめ</h2>

<p>個人ブログの宣伝などを交えつつ、カスタム UIActivity の実装方法についてご紹介させていただきました！</p>

<p>明日は<a href="https://twitter.com/Gemmbu">@Gemmbu</a>さんの記事です。お楽しみに！</p>
]]>
        

    </content>
</entry>

<entry>
    <title>#18 「サービスの負債を減らしましょう」tech.kayac.com Advent Calendar 2012</title>
    <link rel="alternate" type="text/html" href="http://tech.kayac.com/archive/18_techkayaccom_advent_calendar_2012.html" />
    <id>tag:tech.kayac.com,2012:/2.247</id>

    <published>2012-12-18T06:30:00Z</published>
    <updated>2012-12-18T06:41:54Z</updated>

    <summary>こんにちは、入社4年目にして初投稿する、あきひと(@takihito)です。 このエントリーは tech.kayac.com Advent Calendar 2012 の18日目の記事になります。 今年の12月で5周年を迎えた某サービスの運用開発をしています。自分が関わり始めてからは4年ほどです。 ...</summary>
    <author>
        <name>takeda-akihito</name>
        
    </author>
    
    
    <content type="html" xml:lang="ja" xml:base="http://tech.kayac.com/">
        <![CDATA[<p>こんにちは、入社4年目にして初投稿する、あきひと(<a href="http://twitter.com/takihito">@takihito</a>)です。</p>

<p>このエントリーは <a href="http://tech.kayac.com/archive/techkayaccom_advent_calendar_2012.html">tech.kayac.com Advent Calendar 2012</a> の18日目の記事になります。</p>

<p>今年の12月で5周年を迎えた某サービスの運用開発をしています。自分が関わり始めてからは4年ほどです。
その間にサービスの成長に伴い溜まった負債を減らす方法をいくつか紹介したいと思います。
（テーマは「2012年のマイイノベーション」ですが特に気にせず書かせて頂きます）</p>

<h3>カプセル化</h3>

<p>リリース時にコントローラにベタ書きしてしまったコード、開発速度や納期を優先するとよくあります。
このままでは単体テストも書きにくく、品質や機能拡張の障害にもなります。こんな時にはカプセル化をしましょう。</p>

<p><a href="/assets_c/2012/12/advent_calendar_2012_18_fig1-150.php" onclick="window.open('/assets_c/2012/12/advent_calendar_2012_18_fig1-150.php','popup','width=766,height=407,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"><img src="/assets_c/2012/12/advent_calendar_2012_18_fig1-thumb-480x255-150.png" width="480" height="255" alt="advent_calendar_2012_18_fig1.png" class="mt-image-none" style="" /></a></p>

<p>ベタ書きしたビジネスロジックを上図のようなModelクラスを新たにつくって、移し閉じ込めてしまいまいます。
これでコードの見通しも良くなり、単体テストもしやすくなりました。
別のアプリケーション(スマホ/ガラケー)からも重複している処理を呼び出せるようになります。負債の一本化ですね。</p>

<h3>並行稼動</h3>

<p>長期運用をしていくと当初用意したしたサーバーリソースでは足りなくなってくることがあります。</p>

<p>たとえばWebアプリケーションがJobQueue経由でWrokerに画像ファイル等を保存させるような場合</p>

<ul>
<li>保存先のストレージが容量不足になりそう</li>
<li>潤沢な 新ストレージに移行させたい</li>
<li>サービスは止めたくない </li>
</ul>

<p>といったことが起きてきます。
そのような時には新ストレージに保存するNew Workerを用意し並行稼動させます。</p>

<p><a href="/assets_c/2012/12/advent_calendar_2012_18_fig2-153.php" onclick="window.open('/assets_c/2012/12/advent_calendar_2012_18_fig2-153.php','popup','width=454,height=463,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"><img src="/assets_c/2012/12/advent_calendar_2012_18_fig2-thumb-480x489-153.png" width="240" height="245" alt="advent_calendar_2012_18_fig2.png" class="mt-image-none" style="" /></a></p>

<p>並行稼動している間に旧ストレージから新ストレージにデータを移していきましょう。
データの移行が完了したら、プロキシサーバーからの参照先を新ストレージに切り替えます。
完全移行後も旧システムを暫く動かし、切り戻し出来るようにしておくと安心ですね。
ファイルベースの管理からS3やKVSなどに移行させる時などにも有効です。これで返済期限が伸びました。</p>

<h3>疎結合</h3>

<p>単体のアプリケーションに入れていた仕組みを外部に出すことで依存関係を整理し、保守性を高めることができます。</p>

<p>IPアドレスを利用してSPAM対策を行う例になります。</p>

<p><a href="/assets_c/2012/12/advent_calendar_2012_18_fig3-156.php" onclick="window.open('/assets_c/2012/12/advent_calendar_2012_18_fig3-156.php','popup','width=305,height=324,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"><img src="/assets_c/2012/12/advent_calendar_2012_18_fig3-thumb-480x509-156.png" width="240" height="255" alt="advent_calendar_2012_18_fig3.png" class="mt-image-none" style="" /></a></p>

<p>Webアプリケーションから外部のSPAM IP リスト(API)に直接アクセスしチェックを行うようにしていました。
チェックしたIPはKVSに一時保存し次回からはKVSを参照するような仕組みになっています。
ただ問題がないわけではなく</p>

<ul>
<li>IP をチェックする箇所がサービス上に複数ある</li>
<li>SPAMerはIPや手法を頻繁に変えてくる</li>
<li>外部のSPAM IP リスト(API)とは非同期に連携したい</li>
</ul>

<p>といったことがあります。SPAM IP を管理する仕組みはWebアプリケーションから切り離したほうが良さそうです。</p>

<p>そこでシステム構成を以下のように変更しました。</p>

<p><a href="/assets_c/2012/12/advent_calendar_2012_18_fig4-159.php" onclick="window.open('/assets_c/2012/12/advent_calendar_2012_18_fig4-159.php','popup','width=432,height=380,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"><img src="/assets_c/2012/12/advent_calendar_2012_18_fig4-thumb-480x422-159.png" width="240" height="211" alt="advent_calendar_2012_18_fig4.png" class="mt-image-none" style="" /></a></p>

<p>外部のSPAM IP リストとの連携やSPAM IPを判定するロジックをWebアプリケーションから切り離し、新たにSPAM IP Serverを立てて移しています。
今後はSPAM IP Serverを保守していけば良いので、Webアプリケーションの肥大化を防ぐことにもつながります。他のサービスやアプリケーションとも連携を取りやすくなり、効率的にSPAM対策が行えるようになりそうです。</p>

<p>SPAM IP Serverは<a href="http://search.cpan.org/~cindy/Memcached-Server/">Memcached-Server</a>を使ってつくりました。
お手軽にmemcachedプロトコルのサーバーをつくることができ、WebアプリケーションからのIPチェックもgetでチェックするようにしています。面倒な仕事は外部に投げてスッキリ！</p>

<h3>名前</h3>

<p>コードの混乱により、上であげたような大鉈を振るうことができない場合には
メソッド名やマジックナンバーを見直すだけでも十分効果があります。</p>

<pre><code>sub dec24 {
    my $self = shift;
    return 'メリークリスマス';
}
</code></pre>

<p>dec24だと流石にわかりにくいので（自分にはわからないので）</p>

<pre><code>sub merry_xmas {
    my $self = shift;
    $self-&gt;dec24()
}
</code></pre>

<p>としてmerry_xmasでも呼べるようにしましょう。
（人によってはtsuraiの方が分かりやすいかもしれません）</p>

<p>ハードコードしてしまったマジックナンバーも</p>

<pre><code> use constant {
     XMAS_EVE =&gt; 24,
     XMAS =&gt; 25,
 };
:
if ( $day == XMAS_EVE || $day == XMAS ) {
    return '定時で帰って酒飲むぞ！！';
}
</code></pre>

<p>としておくだけで分かりやすくなります。窓口が<s>カワイイ子に</s>代わるだけで、解決したりするものです。</p>

<h2>まとめ</h2>

<p>開発から運用フェーズとなると、モチベーションの維持が難しくなる時もあるかと思います。</p>

<p>先に伸ばしがちな仕事は、午前中の意思が枯渇していない時間にやったり（意思は消耗品）
新しい技術は管理画面や直接サービスと関係ない箇所に投入して様子をみるなどして
触れておくと良いかもしれませんね。</p>

<p>借金（負債）を減らして気持よく新年を迎えたいものです。</p>

<p>明日は、<a href="http://twitter.com/shu223">@shu223</a>さんの記事です、お楽しみに！</p>
]]>
        

    </content>
</entry>

<entry>
    <title>#17「並列処理はGCD! 」tech.kayac.com Advent Calendar 2012</title>
    <link rel="alternate" type="text/html" href="http://tech.kayac.com/archive/17_cgd_techkayaccom_advent_calendar_2012.html" />
    <id>tag:tech.kayac.com,2012:/2.248</id>

    <published>2012-12-17T06:55:37Z</published>
    <updated>2012-12-17T11:40:23Z</updated>

    <summary>はじめまして！iOSのプログラム書いたり、perlを書いたりと色々している@Maco_Tasuです。 このエントリは tech.kayac.com Advent Calendar 2012 の17日目の記事です。 この2012年は、卒業制作関係でIllustratorを使ったり、企画をひたすら考えた...</summary>
    <author>
        <name>shiga-makoto</name>
        <uri>http://makotoshiga.com</uri>
    </author>
    
    
    <content type="html" xml:lang="ja" xml:base="http://tech.kayac.com/">
        <![CDATA[<p>はじめまして！iOSのプログラム書いたり、perlを書いたりと色々している<a href="http://twitter.com/Maco_Tasu">@Maco_Tasu</a>です。</p>

<p>このエントリは <a href="http://tech.kayac.com/archive/techkayaccom_advent_calendar_2012.html">tech.kayac.com Advent Calendar 2012</a> の17日目の記事です。</p>

<p>この2012年は、卒業制作関係でIllustratorを使ったり、企画をひたすら考えたりと多様多種に渡る仕事をした年だったなと思います。</p>

<p>今年のAdvent Calenderのテーマが<strong>「私の中のマイイノベーション」</strong>ということで、今年、今更ながら知った<a href="https://developer.apple.com/library/mac/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html">GCD</a>についてご紹介したいと思います。</p>

<h2>GCD</h2>

<p>GCDとは正式名称が grand central dispatchというものでiOS4から導入されたマルチスレッドプログラミングを実現するための技術です。</p>

<p>このGCDが導入される以前からiOSではperformSelectorやNSThreadなどのマルチスレッドプログラミングの方法がもちろんありました。しかし、これらの方法を実現するには少し煩わしいと感じるようなコードを書かなければいけませんでした。</p>

<p>ですが、GCDでは次のコードだけでマルチスレッドプログラミングを実現できます。</p>

<pre><code>dispatch_queue_t mainDispatchQueue = dispatch_get_main_queue();
dispatch_queue_t globalDispatchQueueDefault
  = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_async(globalDispatchQueueDefault, ^{
    //ここで長時間かかる処理・重い処理を記述

    dispatch_async(mainDispatchQueue, ^{
     //メインスレッドで実行させる処理

    });
});
</code></pre>

<p>このコードについて簡単に説明すると</p>

<pre><code>dispatch_async(globalDispatchQueueDefault, ^{
</code></pre>

<p>このコードでバックグラウンドスレッドに処理を走らせて</p>

<pre><code>dispatch_async(mainDispatchQueue, ^{
</code></pre>

<p>このコードでメインスレッドに処理を走らせています。</p>

<p>すごく簡単ですね！</p>

<p>このGCDを利用することでマルチスレッドを誰もが簡単に実装できるようになりました！</p>

<p>GCDを利用するシチューエーションはいくつも考えられますが</p>

<p>私の場合はバックグラウンドでサーバとの通信をし、メインスレッドでローディングを表示させる時などに使用しています。</p>

<p><a href="/assets_c/2012/12/IMG_2087-thumb-480x852-162-163.php" onclick="window.open('/assets_c/2012/12/IMG_2087-thumb-480x852-162-163.php','popup','width=480,height=852,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"><img src="/assets_c/2012/12/IMG_2087-thumb-480x852-162-thumb-320x568-163.png" width="320" height="568" alt="adventCalender2012-12-17.PNGのサムネール画像" class="mt-image-none" style="" /></a></p>

<p>↑みたいな感じですね。</p>

<p>iOS4で導入されたこの技術をiOS6がでた今更になって騒ぎ始めてしまいましたが、なんだかんだ今年の私にとってイノベーティブな技術でした！</p>

<h2>おまけ</h2>

<p>私は卒業研究を２つしていてそのうちの１つで、仲間と共に<a href="http://meglue.com/">meglue</a>という旅の思い出共有サービスを制作していました。
iPhone・Android共に2013/01/25に同時リリースですので、是非ダウンロードよろしくお願いします！</p>

<h2>明日は</h2>

<p>明日は<a href="https://twitter.com/takihito">@takihito</a>さんです！お楽しみに！</p>
]]>
        

    </content>
</entry>

<entry>
    <title>#16 「moshは確かにイノベーション」 tech.kayac.com Advent Calendar 2012</title>
    <link rel="alternate" type="text/html" href="http://tech.kayac.com/archive/16_advent_calender_2012.html" />
    <id>tag:tech.kayac.com,2012:/2.242</id>

    <published>2012-12-16T14:20:00Z</published>
    <updated>2012-12-16T14:36:21Z</updated>

    <summary>初めまして。HTMLファイ部兼ダーツ部のkubota(@kubosho_)です。 最近はAndroidブラウザーのレンダリングエンジンの気持ちになりながら仕事をしています。 このエントリーはtech.kayac.com Advent Calendar 2012 16日目の記事です。 Vimまじイノベ...</summary>
    <author>
        <name>kubosho_</name>
        
    </author>
    
    <category term="adventcalendar2012" label="AdventCalendar2012" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="mosh" label="mosh" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="ja" xml:base="http://tech.kayac.com/">
        <![CDATA[<p>初めまして。HTMLファイ部兼ダーツ部の<a href="//www.kayac.com/team/kubota-shota">kubota</a>(<a href="//twitter.com/kubosho_">@kubosho_</a>)です。<br />
最近はAndroidブラウザーのレンダリングエンジンの気持ちになりながら仕事をしています。</p>

<p>このエントリーは<a href="//tech.kayac.com/archive/techkayaccom_advent_calendar_2012.html">tech.kayac.com Advent Calendar 2012</a> 16日目の記事です。</p>

<h1>Vimまじイノベーション</h1>

<p>さて、テーマが「私の中のマイイノベーション 2012」ということで、今年はいろいろとイノベーションがあったのですが、その中でもイノベーションだったのが「Vim」でした。</p>

<p>元々Emacs派だったのですが、弊社HTMLファイ部の部長である<a href="//twitter.com/edo_m18">@edo_m18</a>に「Vimいいよいいよ」と<s>洗脳</s>おすすめされた結果、Vimを使い出して今では8:2くらいの割合でVimを多く使っています。</p>

<p>しかし、それよりももっとイノベーションを起こしたものが昨日できました。<br />
それが<a href="//mosh.mit.edu/">mosh</a>です。</p>

<h1>moshまじイノベーション</h1>

<p>元々は<a href="//twitter.com/typester">@typester</a>の<a href="//tech.kayac.com/archive/2012.html">#14 「2012年 私の中のマイイノベーション」tech.kayac.com Advent Calendar 2012</a>の記事を見て、</p>

<p>「なんだか良さげだし試しにインストールしてみるかー」</p>

<p>と軽い気持ちで、インストールしてみて使ってみたのですが、結果として日頃SSHに対して感じていた不満点が解消されて、「moshまじイノベーション！」と1人で盛り上がってました。</p>

<h1>moshの特徴</h1>

<p>自分がなぜmoshがイノベーションかと思ったか。<br />
思うきっかけになった特徴を、<a href="//d.hatena.ne.jp/karasuyamatengu/20120411/1334092521">mosh: MITからモバイル時代のSSH代替品 - karasuyamatenguの日記</a>の記事から引用すると、以下の2つです。</p>

<blockquote>
  <p>・遅いリンクでもローカルエコーにより快適<br />
  ・断続的な接続でも平気</p>
</blockquote>

<p>では、1つずつ書いていきます。</p>

<h2>遅いリンクでもローカルエコーにより快適</h2>

<p>よくあるのが、ネット接続が遅い環境だとリモートサーバーにSSHで接続した場合、打ち込んだコマンドがなかなか反映されずザ・ワールド状態になってしまうことです。</p>

<p>しかしmoshの場合は、とりあえずコマンドは打てて、リモートサーバー上に反映されていない箇所は下線が引かれます。
「なんのコマンドを打ち込んだか画面に反映されないから分からない！」ということがなくなり、とても快適になりました。</p>

<h2>断続的な接続でも平気</h2>

<p>例えば、電車内でリモートサーバーにつないで何か作業をするということもあると思います。
そんな時に、電車がトンネルなどに入って接続が切れると再接続になってしまったり、最悪の場合接続した画面のままフリーズしてしまうこともあります。</p>

<p>しかしmoshの場合は、ネット接続が復活した時に、再接続の手間がなく何事も無かったかのようにそのままリモートサーバーで作業ができます。</p>

<p>さすがプロトコルとアプリケーションを同時に作ってしまっただけあって、これだけでもイノベーションすぎます。MITすごい。</p>

<h1>moshのインストール</h1>

<p>さてべた褒めしてきたmoshですが、「そんな事言ってもインストールが大変なんでしょ？」と思っている人もいると思います。</p>

<p>実際、自分がmoshをインストールするときに色々と調べたのですが、git cloneして、./configureして、makeして…と面倒なインストール方法しか最初見つからなかったため、インストールを一瞬諦めかけました。</p>

<p>しかし冷静に<a href="//mosh.mit.edu/">公式サイト</a>を見てみると、自分がさくらのVPSにインストールしているDebian バージョン6.0.6(squeeze)であれば、backportsというのを追加するだけでaptitudeでインストールできるようになりました。</p>

<p>具体的な方法としては以下の通りです。</p>

<h2>ローカル側</h2>

<p>自分はMac OS X Lion + Homebrewという環境なので、以下のコマンドをターミナル上から実行します。</p>

<pre><code>brew install mobile-shell
</code></pre>

<p>これだけで、ローカル側は終わりです。</p>

<h2>リモート側</h2>

<h3>sources.listにbackports追加</h3>

<pre><code>sudo vim /etc/apt/sources.list
</code></pre>

<p>おもむろにsources.listを開き、最後の行あたりに以下の行を追加します。</p>

<pre><code>deb http://backports.debian.org/debian-backports squeeze-backports main
</code></pre>

<h3>update &amp;&amp; install</h3>

<p>追加し終えたらパッケージのアップデートを行います。</p>

<pre><code>sudo aptitude update
</code></pre>

<p>アップデートが終わったら、moshをインストールします。</p>

<pre><code>sudo aptitude install mosh
</code></pre>

<p>インストールが終わり接続テストと行きたい…ところですが、ポートをUDP 60000:61000を開けてやらないと、Ctrl-^でキャンセルしない限り永遠に接続待ちの状態になってしまいます。<br />
なので、iptablesの設定でポートを開放します。具体的には以下のような感じです。</p>

<pre><code>sudo vim /etc/iptables/rules

# moshのために以下の行を追記
-A INPUT -p udp -m udp --dport 60000:61000 -j ACCEPT
</code></pre>

<p>これでリモート側の準備は完了です。</p>

<h1>moshを使う</h1>

<p>SSHで接続する場合「ssh example.com」とコマンドを打って実行すると思います。</p>

<p>moshの場合でもそれは変わりなく、sshの部分をmoshとして「mosh example.com」とするだけです。<br />
これだけでmoshが使えます。まじイノベーション。</p>

<h2>ちょっと待って！俺SSHのポートも変えてるしユーザー名も違うのにしてSSH接続してるよ！＞＜</h2>

<p>そんなあなたでも大丈夫。以下のようにするだけです。</p>

<pre><code>mosh --ssh="ssh -p ポート -l ユーザー名" example.com
</code></pre>

<p>これでポートを変え、かつユーザー名も違う名前で接続していた場合でも、問題なくmoshが使えます。<br />
まじイノベーション。</p>

<h1>まとめ</h1>

<ul>
<li>ネットワークが遅かったり不安定でも、問題なくリモートサーバーに繋げっぱなしにできる</li>
<li>なので、対応がいつどこで起きるかわからないインフラの人に向いてるかも</li>
<li>インストールも割と簡単</li>
<li>SSHの接続ポートを変えたり、ユーザー名を違うものにしてSSH接続していても対応できる</li>
</ul>

<p>明日は<a href="//twitter.com/Maco_Tasu">@Maco_Tasu</a>の記事です。お楽しみに！</p>
]]>
        

    </content>
</entry>

<entry>
    <title>#15 「人体錬成に近いものの仕方、もしくはhubotの使い方」tech.kayac.com Advent Calendar 2012</title>
    <link rel="alternate" type="text/html" href="http://tech.kayac.com/archive/15_hubottechkayaccom_advent_calendar_2012.html" />
    <id>tag:tech.kayac.com,2012:/2.243</id>

    <published>2012-12-15T16:00:00Z</published>
    <updated>2012-12-15T16:04:44Z</updated>

    <summary>どう？　蕎麦の巻き方の練習してる？　ずるってる？  どうもマコピーです。最近はふぐおじさんになったりフードファイターにされそうになったり大変です。   さて、このAdvent Calendarですが、着々とクリスマスに向かって続々と記事が書かれていってあと11日。  さきほど所用で街に出かけましたが...</summary>
    <author>
        <name>taniwaki-makoto</name>
        
    </author>
    
    <category term="adventcalendar2012" label="AdventCalendar2012" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="ja" xml:base="http://tech.kayac.com/">
        <![CDATA[<p>どう？　蕎麦の巻き方の練習してる？　ずるってる？ <br />
どうも<a href="http://twitter.com/mackee_w">マコピー</a>です。最近はふぐおじさんになったりフードファイターにされそうになったり大変です。  </p>

<p>さて、このAdvent Calendarですが、着々とクリスマスに向かって続々と記事が書かれていってあと11日。 <br />
さきほど所用で街に出かけましたが、なるほど、世間はクリスマス色ですね、つらぽよ。  </p>

<p>つらいし誰もかまってくれないし、<a href="http://twitter.com/hisaichi5518">@hisaichi5518</a>くんには「めんどくせぇ！」って言われるし、外も寒くなってきたので、一人でもさみしくないようにIRCのボットを作ってみようと思います。 <br />
とはいえ、IRCのボットで彼女を作るとか二番煎じもいいところなので、そういうことはしません。 <br />
淡々とボットを作ってなんとかイノベーションに紐づけてみようと思います。</p>

<h2>hubotって</h2>

<p><a href="http://hubot.github.com/">HUBOT</a>  </p>

<p>CoffeeScriptで作られたボットのフレームワークです。node.js上で動き、npmから入れることが出来ます。 <br />
また、JSは書いたことあるけれどCoffeeScriptの文法がよくわからないという方もJavaScriptで書くことができます。 <br />
とりあえず何らかの方法でnode.jsを入れてください。 <br />
僕はnodebrewからinstall-binaryで入れました。環境によっては入りませんが、brewしないので速いです。 <br />
以下はMac OS X Lionで作業を行いました。  </p>

<pre><code>$ npm install hubot -g
</code></pre>

<p>これでhubotコマンドが使えるようになります。 <br />
あとこれだけではIRCの発言に応答したりは出来ないのでhubot-ircを入れましょう。これはアダプターと呼ばれるもので、単体では標準入出力しか扱えないhubotをIRCでやり取りできるようにさせるものです。 <br />
いろいろ試して気づいたのですがnpmに上がっているhubot-ircではIRCの接続にSSLを使っている場合に起動時にコケるようです。githubに上がっているバージョンだとうまくいったのでそれを入れてしまいます。  </p>

<pre><code>$ git clone https://github.com/nandub/hubot-irc
$ npm install hubot-irc -g
</code></pre>

<p>さて、準備は整ったのでボットのためのディレクトリを作ります。ここでは<a href="http://ja.wikipedia.org/wiki/%E6%8E%A2%E5%81%B5%E3%82%AA%E3%83%9A%E3%83%A9_%E3%83%9F%E3%83%AB%E3%82%AD%E3%82%A3%E3%83%9B%E3%83%BC%E3%83%A0%E3%82%BA%E3%81%AE%E7%99%BB%E5%A0%B4%E4%BA%BA%E7%89%A9#Genius4">kokorochan</a>とします。</p>

<pre><code>$ mkdir kokorochan
$ cd kokorochan
</code></pre>

<p>これからはkokorochanディレクトリでの作業となります。
さらに、ボットの動作を記述するためのスクリプトを置くフォルダを作ります。</p>

<pre><code>$ mkdir -p node_modules/hubot-scripts/src/scripts
</code></pre>

<p>スクリプトを作っていきます。まずはkokorochanにkokorochanと呼びかけた場合の動作を記述します。</p>

<pre><code>$ vim node_modules/hubot-scripts/src/scripts/kokorochan.coffee
module.exports = (robot) -&gt;   
    robot.hear /kokorochan.*/i, (msg) -&gt;
        msg.send msg.message.user.name + ': ' + 'こころちゃんゆーな！'
</code></pre>

<p>これだけです。robot.head /正規表現/, callback という形式でIRC上の発言に対する挙動を記述していきます。 <br />
robot.respond /正規表現/, callbackという形式もあります。これはkokorochan: ほげほげ と呼びかけた場合にのみ反応するときに使います。 <br />
この場合はkokorochanと呼びかけられた場合に「こころちゃんゆーな！」と返すようです。kokorochanと呼ばれたくないようですね。
respondじゃなくてhearを使うのは伏線です。 <br />
callbackにはResponseオブジェクトが渡ってくるのでそこに生えているmsg.sendというメソッドで返答します。これはhubot-irc(IRCアダプター)だけではなく、他のアダプターを使った場合も一緒です。</p>

<p>さて、準備が整ったところで試してみましょう。 <br />
入るIRCサーバやチャンネル設定は環境変数で渡します。この際なのでシェルスクリプトで書いちゃいましよう。</p>

<pre><code>#!/bin/sh
export HUBOT_IRC_ROOMS="#yokohama" # チャンネル名
export HUBOT_IRC_SERVER="irc.xxxx.com" # IRCサーバ
export HUBOT_IRC_PORT=6667 # IRCサーバのポート
export HUBOT_IRC_PASSWORD="milyhomes" # IRCサーバのパスワード
export HUBOT_IRC_USESSL="true" 
export HUBOT_IRC_SERVER_FAKE_SSL="true" # 自己証明証明書を使う場合はtrue

hubot -a irc -n kokoro -d
</code></pre>

<p>先ほどの伏線を回収しますが、kokoroという名前でログインするようにします。<a href="http://ja.wikipedia.org/wiki/%E6%8E%A2%E5%81%B5%E3%82%AA%E3%83%9A%E3%83%A9_%E3%83%9F%E3%83%AB%E3%82%AD%E3%82%A3%E3%83%9B%E3%83%BC%E3%83%A0%E3%82%BA%E3%81%AE%E7%99%BB%E5%A0%B4%E4%BA%BA%E7%89%A9#Genius4">明智小衣</a>は明智小衣であって小衣ちゃんではないので。 <br />
hubotの引数を説明すると、</p>

<ol>
<li>-a irc 使うアダプタ名 省いたら標準入出力を使います</li>
<li>-n kokoro ボットの名前 respondで反応するときの名前はこれ</li>
<li>-d Webサーバの起動はしない。有効化するとWebAPIでボットの挙動を操作するなどのスクリプトが書けますが今回は使いません</li>
</ol>

<p>さらに、先ほど書いたスクリプトを有効化するために、hubot-script.jsonというのを書きます。</p>

<pre><code>$ vim hubot-scripts.json
["kokorochan.coffee"]
</code></pre>

<p>さてやっと起動する瞬間がやって来ました。たちあげてみます。</p>

<pre><code>$ sh kokorochan.sh
</code></pre>

<p>そうするとおもむろに立ち上がってチャンネルにインしてきます。</p>

<pre><code>00:00 kokoro has joined (~nodebot@)
00:00 macopy: kokorochan
00:00 kokoro: macopy: こころちゃんゆーな！
</code></pre>

<p>なんどでもやってくれます。</p>

<pre><code>00:00 macopy: kokorochan
00:00 kokoro: macopy: こころちゃんゆーな！
00:00 macopy: kokorochan
00:00 kokoro: macopy: こころちゃんゆーな！
00:00 macopy: kokorochan
00:00 kokoro: macopy: こころちゃんゆーな！
</code></pre>

<p>はあ、小衣ちゃん。。。心が温まる。。。 <br />
続いて小衣ちゃんのIQを聞いてみましょう。噂によると小衣ちゃんのIQは1300にも達するそうです。先ほどのスクリプトに追加してみます。</p>

<pre><code>$ vim node_modeules/hubot-scripts/src/kokorochan.coffee
iqlist = [1300, 13e3, 13e4, 13e9, 13e10, 13e11, 1400, 14e4, 14e5, 14e9, 14e11, 14e16, 14e20, 14e52, 14e-13, 14e-20, 14e56, 14e68]

module.exports = (robot) -&gt;
    robot.respond /iq$/i, (msg) -&gt;
        if (iqlist.length isnt 0)
            iq = iqlist.shift()
            msg.send iq.toString(10)
        else
            msg.send '1300'
</code></pre>

<p>再び立ち上げ直して kokoro: iqと呼びかけると</p>

<pre><code>00:00 macopy: kokoro: iq
00:00 kokoro: 1300
00:00 macopy: kokoro: iq
00:00 kokoro: 13000
00:00 macopy: kokoro: iq
00:00 kokoro: 130000
00:00 macopy: kokoro: iq
00:00 kokoro: 13000000000
00:00 macopy: kokoro: iq
00:00 kokoro: 130000000000
00:00 macopy: kokoro: iq
00:00 kokoro: 1300000000000
00:00 macopy: kokoro: iq
00:00 kokoro: 1400
00:00 macopy: kokoro: iq
00:00 kokoro: 140000
00:00 macopy: kokoro: iq
00:00 kokoro: 1400000
00:00 macopy: kokoro: iq
00:00 kokoro: 14000000000
00:00 macopy: kokoro: iq
00:00 kokoro: 1400000000000
00:00 macopy: kokoro: iq
00:00 kokoro: 140000000000000000
00:00 macopy: kokoro: iq
00:00 kokoro: 1.4e+21
00:00 macopy: kokoro: iq
00:00 kokoro: 1.4e+53
00:00 macopy: kokoro: iq
00:00 kokoro: 1.4e-12
00:00 macopy: kokoro: iq
00:00 kokoro: 1.4e-19
00:00 macopy: kokoro: iq
00:00 kokoro: 1.4e+57
00:00 macopy: kokoro: iq
00:00 kokoro: 1.4e+69
00:00 macopy: kokoro: iq
00:00 kokoro: 1300
00:00 macopy: kokorochan
00:00 kokoro: macopy: こころちゃんゆーな！
</code></pre>

<p>さすが小衣ちゃんや、天才美少女なだけある。。。
という感じでございます。小衣ちゃんのIQは最終的に14<a href="http://ja.wikipedia.org/wiki/%E7%84%A1%E9%87%8F%E5%A4%A7%E6%95%B0">無量大数</a>までいくみたいですね。 <br />
他の機能としてhubotはBrainという機能を使ってRedisサーバに情報を貯めこんでおくこともできるようです。npmに上がっている、hubot-scriptsというモジュールを入れると様々なサンプルスクリプトが使えるので試してみてください。</p>

<p>参考:
<a href="http://blog.fumiz.me/2012/08/05/hubot-irc-bot-script/">hubotスクリプトの書き方とサンプル集</a> <br />
<a href="http://d.hatena.ne.jp/anatoo/20120204/1328368042">github社製ボットフレームワーク、hubotをIRCボットとして導入した話(修正あり</a> <br />
<a href="http://fukayatsu.github.com/2012/12/03/jotei-advent-calendar/">hubot jotei > 女帝 Advent Calendar 2012(3日目)</a>  </p>

<p>ではではー。 <br />
次はダーツ部部長の――</p>

<h2>アカンアカン、自分イノベーションしたけれど、自分だけや</h2>

<p>ちょっとこれだとほんとひどいので、最近の僕のhubotの使い方を紹介します。  </p>

<h3>例えばあなたは運用兼開発エンジニア</h3>

<p>弊社のソーシャルゲームのサーバサイドエンジニアは大抵の場合、運用も兼ねており、本番化作業や運用中でサーバ関連の問題が起こった場合の担当もしております。 <br />
僕も例外ではなく、さらにチームのサーバサイドエンジニアの数が少ないためあっぷあっぷしてしまうときがあります。 <br />
そんな時に小衣ちゃ……じゃなかった、hubotにがんばってもらいましょう。 <br />
僕の案件の開発環境でマスタデータを流し込みたい時、今までは僕がサーバに入っていちいちコマンドを叩かなければなりませんでした。 <br />
hubotを使えばその代わり叩くなんてこともできます。</p>

<pre><code>00:00 &lt;macopy&gt; kokoro: master import item
00:00 &lt;kokoro&gt; よいしょ♪
00:00 &lt;kokoro&gt; はいったー
00:00 &lt;macopy&gt; kokorochan: ありがとう
00:00 &lt;kokoro&gt; こころちゃんゆーな！
</code></pre>

<p>中身は以下のようにコマンドを実行しているだけです。</p>

<pre><code>fs = require('fs')
exec = require('child_process').exec

basePath = '/path/to/home/'

module.exports = (robot) -&gt;
    robot.respond /master import (.*)$/i, (msg) -&gt;
        tableName = msg.match[1]
        filename  = basePath + 'csv/' + tableName + '.csv'
        msg.send 'よいしょ♪'
        fs.exists filename, (exists) -&gt;
            if exists
                loadFromCsv filename
            else
                msg.send 'くうきよめー(csv not found)'

        loadFromCSV = (filename) -&gt;
            loadCommand = 'perl -I ' + basePath + 'lib ' + basePath + 'scripts/load_master_data.pl ' + filename
            exec loadCommand, {}, (error, stdout, stderr) -&gt;
                if error != null
                    msg.send 'くうきよめー(load failed)'
                else
                    msg.send 'はいったよー'
</code></pre>

<p>ボットを開発サーバ上に(もしくはSSHなどで開発サーバにログイン出来る環境)置けば可能です。 
さらにnode.jsなのでコマンドを取りこぼすことはありません。 <br />
IRCに入ってれば使える気軽なコマンド環境を用意することでいろいろ楽になると思います。事故るとヤバイところでは使いませんが。 <br />
こういうときは管理画面を作るのが一般的ですが、この方法のメリットはIRCに実行したログが残ることです。 <br />
幸いなことに僕の案件ではディレクターさんもIRCに入っていただいているので管理画面ではなくとりあえずhubotでやるという感じです。  </p>

<p>実はまだこいつは先週こっそり開発していて先ほど完成したばっかりなので来週投入します。開発上のボトルネックが解消されたらいいですね。  </p>

<p>次はダーツ部部長の<a href="http://twitter.com/kubosho_">@kubosho_</a>さんです。ちなみに僕は自称副部長です。</p>
]]>
        

    </content>
</entry>

<entry>
    <title>#14 「2012年 私の中のマイイノベーション」tech.kayac.com Advent Calendar 2012</title>
    <link rel="alternate" type="text/html" href="http://tech.kayac.com/archive/2012.html" />
    <id>tag:tech.kayac.com,2012:/2.241</id>

    <published>2012-12-14T06:19:45Z</published>
    <updated>2012-12-14T09:09:30Z</updated>

    <summary>@kenjiskywalker 氏に「2012年 私の中のマイイノベーション」について記事を書けと脅されながらこのエントリを書いております。 振り返ってみると今年もいろいろイノベーティブな出来事があったので思い出せる範囲でまとめてみようかとおもいます。 GNU screen から tmux に移行し...</summary>
    <author>
        <name>Daisuke Murase (typester)</name>
        
    </author>
    
    
    <content type="html" xml:lang="ja" xml:base="http://tech.kayac.com/">
        <![CDATA[<p><a href="http://twitter.com/kenjiskywalker">@kenjiskywalker</a> 氏に「2012年 私の中のマイイノベーション」について記事を書けと脅されながらこのエントリを書いております。</p>

<p>振り返ってみると今年もいろいろイノベーティブな出来事があったので思い出せる範囲でまとめてみようかとおもいます。</p>

<h2>GNU screen から tmux に移行した</h2>

<p>screenとくらべるとtmuxはなかなかベンリでイノベってますね。</p>

<ul>
<li><a href="http://unknownplace.org/memo/2012/03/26/1/">tmux + irssi + canything で Anything 風チャンネル切り替えする</a></li>
<li><a href="http://unknownplace.org/memo/2012/03/27/1/">tmux で pbcopy</a></li>
</ul>

<p>みたい記事を書いてたみたいです。意外ととあんまり書いてなかったですね！</p>

<h2>mosh を使い始めた</h2>

<p>ssh のかわりにいくつかの環境で <a href="http://mosh.mit.edu/">mosh</a> を利用し始めました。</p>

<p>僕は MacBook Air 一つでいろいろなところで作業をするのですが、ssh だと移動するたびに接続し直しになって面倒だし、
とくに移動中に作業したりする時には、電波が弱い場所やトンネルなどで圏外になるたびに再接続をする必要があり、非常にストレスがたまります。</p>

<p>その点 mosh ではどこに移動してもつなぎっぱなし（のように見える）で、シームレスに作業の続きができるため非常に捗ります。</p>

<p>mosh にかんしては社内でベンリーベンリー騒いでたくらいでとくに記事を書いてはなかったようです。</p>

<h2>Redis を使い始めた</h2>

<p><a href="http://redis.io/">Redis</a> というKVSをつかいはじめました。</p>

<p>単純なKVSとしてももちろんつかえるのですが、いろいろなデータ構造をオンメモリで高速にあつかえるため、
向いている作業をまかせると既存のアプリケーションを非常に高速化できたりします。</p>

<p>ISUCONで優勝してきたりもしました。</p>

<ul>
<li><a href="http://unknownplace.org/memo/2012/11/07/1/">Redis布教活動報告 ISUCON 編</a></li>
</ul>

<p>また、いろいろなデータ型があってそれに対応するコマンドも多くあるので、
単純に使うとしてもどの使い方が効率的なのか？ ということを考えるのがパズル的で楽しいところも Redis をつかっていて楽しいところですね。</p>

<h2>GitDDL まじイノベーティブ</h2>

<p>git をつかった開発では各人がカジュアルに作業ブランチをきって作業するため、
それぞれがそこでデータベース定義を変更したりするとたいへんつらいことになってしまいます。</p>

<p>そこで、データベーススキーマ自体もgitで管理しちゃえばいいんじゃないの？ ってなことでうまれたモジュールが <a href="http://search.cpan.org/dist/GitDDL/">GitDDL</a> です。</p>

<p>これを使用すると branch を切り替えた際に、もしテータベース定義が変更されていると差分を git をもとにつくって、よしなに ALTER 文を発行してくれるものです。
これは本当にイノベーティブなのですが、説明するのが非常に面倒なので隣の席の人のエントリを参照ください。</p>

<ul>
<li><a href="http://tech.kayac.com/archive/5gitddl_techkayaccom_advent_calendar_2012.html">GitDDLまじイノベーティブ</a></li>
</ul>

<h2>まとめ</h2>

<p>他にもあった気がしますがとりあえず今思い出せるのはこんな感じですね。</p>

<p>どれもいまとなってはかかせないツールですね。
さわったことないなーってものがありましたらぜひお試しくださいませ！</p>

<p>明日は<del>フードファイター</del>マコピー氏です。</p>
]]>
        

    </content>
</entry>

<entry>
    <title>#13 「iPhone女子にもAndroid女子にも同時にモテる！Cocos2d-Xを使ってみた」tech.kayac.com Advent Calendar 2012</title>
    <link rel="alternate" type="text/html" href="http://tech.kayac.com/archive/13_iphoneandroidcocos2d-x.html" />
    <id>tag:tech.kayac.com,2012:/2.239</id>

    <published>2012-12-13T11:03:25Z</published>
    <updated>2012-12-13T11:59:31Z</updated>

    <summary>こんばんは、ゆるふわiOSプログラマの@Keita_Shiyaです。 このエントリはtech.kayac.com Advent Calendar 2012 13日目の記事です。 Cocos2d-Xという、クロスプラットフォーム開発が可能なオープンソースのフレームワークがあるんですが、 それを使うとな...</summary>
    <author>
        <name>shiya-keita</name>
        
    </author>
    
    <category term="adventcalendar2012" label="AdventCalendar2012" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="ja" xml:base="http://tech.kayac.com/">
        <![CDATA[<p>こんばんは、ゆるふわiOSプログラマの<a href="http://twitter.com/Keita_Shiya">@Keita_Shiya</a>です。</p>

<p>このエントリは<a href="http://tech.kayac.com/archive/techkayaccom_advent_calendar_2012.html">tech.kayac.com Advent Calendar 2012</a> 13日目の記事です。</p>

<p>Cocos2d-Xという、クロスプラットフォーム開発が可能なオープンソースのフレームワークがあるんですが、
それを使うとなんとiPhoneとかAndroidとか、あとwindows8とかのアプリもつくれるようになりそうなすごいヤツなんです。
先日、個人リリースのiOSアプリ<a href="https://itunes.apple.com/jp/app/id474786620?mt=8">『殴ればいい』</a> を、その<a href="http://www.cocos2d-x.org/">Cocos2d-X</a>を使ってAndroid対応してみたので、その際に参考にしたサイト等々をまとめてみようとおもいます。</p>

<p>でもまずは！</p>

<h2>つくったもの</h2>

<p><img src="https://lh4.ggpht.com/EIOrGgT6Jcn3hObtSPCg4_ykvxDhNumC-HS9sOOvkG4b1WN_HrwFvTGL1caIOFxwQQ=w124" alt="Smaller icon" title="" /></p>

<p><a href="https://play.google.com/store/apps/details?id=com.keitashiya.Beatanyway">こちら</a>になります。</p>

<p>ばしばし殴ってストレス解消できるカジュアルゲームになっております。たぶん。</p>

<p>ブラウザを開いたり、結果をツイートしたりといったAndroidにアクセスする機能も（おそらく）問題なく実装できました。</p>

<h2>参考にしたサイトなど</h2>

<h4>Java環境構築(Mac版) Eclipseのインストール Tech Fun.cc  <a href="http://techfun.cc/java/mac-eclipse-install.html">http://techfun.cc/java/mac-eclipse-install.html</a></h4>

<p>EclipseやandroidSDKをインストール・シミュレータの設定等をしてHellowWorldするまで。</p>

<h4>cocos2d-x入門 - kambayashiの日記  <a href="http://kambayashia.hatenablog.com/entry/20120725/1343188855">http://kambayashia.hatenablog.com/entry/20120725/1343188855</a></h4>

<p>Cocos2d-Xのxcodeプロジェクトテンプレートをインストール。</p>

<h4>Cocos2D-X for iOS and Android: Getting Started  <a href="http://www.raywenderlich.com/11283/cocos2d-x-for-ios-and-android-getting-started">http://www.raywenderlich.com/11283/cocos2d-x-for-ios-and-android-getting-started</a></h4>

<p>Android NDK等々をセットアップして、Cocos2d-XのプロジェクトをiPhone、Androidシミュレータ両方でHelloWorld。
ここが抜群にめんどくさかったです。</p>

<p>ここさえクリアすれば、あとは実装です。楽しいところです。
僕は<a href="http://www.amazon.co.jp/C-%E3%81%AE%E7%B5%B5%E6%9C%AC-%E6%A0%AA-%E3%82%A2%E3%83%B3%E3%82%AF/dp/4798108936">C++の絵本</a>とかを読みながらやりました。</p>

<p>そして完成したらあとは</p>

<h4>Androidアプリのアプリアイコンを設定する方法 - あらきんぐのAndroidアプリ開発ブログ</h4>

<p><a href="http://araking0.blog.fc2.com/blog-entry-23.html">http://araking0.blog.fc2.com/blog-entry-23.html</a></p>

<p>アイコンを設定したり</p>

<h4>Cocos2d-x | AdMob Integration with Cocos2d-x for Android</h4>

<p><a href="http://www.cocos2d-x.org/boards/6/topics/13233">http://www.cocos2d-x.org/boards/6/topics/13233</a></p>

<p>広告(admob)も設定してみたりして、</p>

<h4>Smart Gadget Laboratory: Android実機でHello Worldと画面キャプチャ - Hello world and Capture screen on the Android device - <a href="http://smartgadgetlaboratory.blogspot.jp/2011/02/androidhello-world-hello-world-and.html">http://smartgadgetlaboratory.blogspot.jp/2011/02/androidhello-world-hello-world-and.html</a></h4>

<p>スクリーンショットをとって、</p>

<h4>AndroidアプリのAndroid Marketへの公開方法 | mucchinのAndroid戦記 <a href="http://android.roof-balcony.com/market/market/">http://android.roof-balcony.com/market/market/</a></h4>

<p>Androidマーケットで公開！しました。</p>

<hr />

<p>思ってた以上にめんどくさいやら情報が少ないやらで大変でしたが、いろんなプラットフォームでアプリ開発ができるのはわくわくします！！！</p>

<p>明日はカヤックが世界に誇るスーパーエンジニア、<a href="https://twitter.com/typester">@typester</a>さんです。
世界に誇れるスーパーエントリを書いてくださるとおもいます！</p>

<p>楽しみ！！！！！！！！！！</p>
]]>
        

    </content>
</entry>

<entry>
    <title>#12 チームでgitを使い始めてよかった！</title>
    <link rel="alternate" type="text/html" href="http://tech.kayac.com/archive/12_git.html" />
    <id>tag:tech.kayac.com,2012:/2.240</id>

    <published>2012-12-12T16:46:30Z</published>
    <updated>2012-12-12T16:46:35Z</updated>

    <summary>こんばんわ、1年ぶりの投稿になります。せい（@shin1rosei）です。 キライな言葉は「面白法人なんだから面白いことしろよ」と言われることです。 自分は真面目一本で生きてきて大して面白い人間ではないので辛くなります。 このエントリはtech.kayac.com Advent Calendar 2...</summary>
    <author>
        <name>sei</name>
        
    </author>
    
    
    <content type="html" xml:lang="ja" xml:base="http://tech.kayac.com/">
        <![CDATA[<p>こんばんわ、1年ぶりの投稿になります。せい（<a href="http://github.com/shin1rosei">@shin1rosei</a>）です。
キライな言葉は「面白法人なんだから面白いことしろよ」と言われることです。
自分は真面目一本で生きてきて大して面白い人間ではないので辛くなります。</p>

<p>このエントリは<a href="http://tech.kayac.com/archive/techkayaccom_advent_calendar_2012.html">tech.kayac.com Advent Calendar 2012</a> 12日目の記事になります．</p>

<p>テーマは「私の中のマイイノベーション２０１２」ということで、
今年を色々振り返ってみってみて、かなり地味な内容になりますが、一番効果が高かったなーと感じる「チームでgitを使い始めたこと」をお話したいと思います。</p>

<h2>使い始めるまで</h2>

<p>今まで自分が関わっていたプロジェクトは（小学生と言われるの覚悟で）subersionを使うのが一般的で、
gitの恩恵にあやかりたいプログラマは"git-svn"を使っていました。</p>

<p>ただ、次のような問題点がありました。</p>

<ul>
<li>projectが巨大になるとgit svnが重すぎてツライ</li>
<li>svn switchが満足に扱えるいいGUIアプリがないため、プログラマー以外branchの切り替えができず、他職種は都度checkoutを強いられてツライ</li>
<li><a href="https://twitter.com/typester">@typester</a>にdisられてチームのモチベがダウンしてツライ</li>
</ul>

<p>そこで、gitを本格的にチームで運用することを決定しました。</p>

<p>結果的に見て一番大変だったのは「他職種の制作陣の開発環境にgitの環境を整える」ことでした。制作陣の各環境にgitの環境を整えるのですが、ターミナルもあまり触ったことがないという人がほとんどなので、鍵の生成から、gitのツールの利用方法までをレクチャーしました。</p>

<p>なかには（さっき鍵作ったばかりなのに）「パスフレーズ忘れちゃったんですけど」みたいなことを言われちゃったりもしますが、そこを笑って許してあげる度量が必要です（自分にはその度量はありませんでした）。</p>

<p>gitのbranchの切り替えやpull, push, commitの理解などは最近は下記のとてもわかりやすいスライドもあったりして、自分の想定よりもスムーズに導入できたなと感じております。</p>

<p><a href="http://www.slideshare.net/kotas/git-15276118">こわくないgit</a></p>

<h2>利用しているツール</h2>

<h3>SourceTree</h3>

<p>基本的にプログラマー陣はコマンドラインのgitを使っていますが、それ以外の職種はほぼ<a href="http://www.sourcetreeapp.com">SourceTree</a>を使っています。</p>

<p><img src="http://www.sourcetreeapp.com/img/screenshots/st_feature_diff.png" width="567" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></p>

<p>gitの導入を決めたのも、このツールの完成度が高く、しかも無料（ユーザ登録は必要）で使えたためと言っても過言ではありません。
Macのsubersionクライアントにありがちなsvn switchできなかったり挙動が不安定だったりということもありません。</p>

<h3>tig</h3>

<p>ターミナル上でもうちょっとカジュアルにgitのlogやdiffを確認したいというときは<a href="http://jonas.nitro.dk/tig/">tig</a>を使っています。</p>

<p>デプロイ用のサーバにもインストールしておくと現在本番反映されている内容が瞬時に確認できるので重宝してます。</p>

<p><a href="http://subtech.g.hatena.ne.jp/secondlife/20101114/1289736508">コンソールから使える git ブラウザ、tig が超便利</a></p>

<h2>IRCとの連携</h2>

<p>弊社では一昨年くらいからIRC熱が徐々に高まって、IRCでの情報共有を活発化しようという動きがあります。</p>

<p>現在のプロジェクトでは主だったところでは下記の2つをIRCで共有してます。</p>

<ul>
<li>gitへのpush</li>
<li>本番環境へのデプロイ</li>
</ul>

<p>基本的にはどちらも弊社で運用しているircに投稿するnopasteへそれぞれPOSTしてるというシンプルなものです。IRCを利用していなくてもメールなどでこのような情報が流れると情報共有がスムーズにできて素晴らしいですね。</p>

<p>gitへのpushはgitのpost-receiveで下記のスクリプトを実行するようにしてます。</p>

<pre>
#!/bin/sh

export LANG=ja_JP.UTF-8

# IRC channnel
CHANNEL="#channel"

read IN

OLD=`echo ${IN} | cut -d ' ' -f 1`
NEW=`echo ${IN} | cut -d ' ' -f 2`
REF=`echo ${IN} | cut -d ' ' -f 3`

git rev-list $NEW ^$OLD --reverse | while read COMMITID
do
    MSG=`git --no-pager log -1 --format='%an committed "%s"' $COMMITID`
    DIFF=`git show $COMMITID`

    curl --data-urlencode "summary=${MSG}:${REF}" --data-urlencode "text=${DIFF}" --data-urlencode "channel=${CHANNEL}" --data "notice=1" http://xxxx.kayac.com/nopaste
done
</pre>

<p>出力例</p>

<pre>
commit 85b8dcd18c703f156a7408dd17e23529e52189aa
Author: dummy user %lt;dummy-user@kayac.com%gt;
Date:   Wed Dec 12 10:17:57 2012 +0900

    count access num of quiz link

diff --git a/root/tmpl/common/footer.mt b/root/tmpl/common/footer.mt
index 5bff66d..691be9e 100644
--- a/root/tmpl/common/footer.mt
+++ b/root/tmpl/common/footer.mt
@@ -18,7 +18,7 @@
 %lt;nav id="js-embed-content"%gt;
     %lt;!--%lt;h1 class="name"%gt;MENU%lt;/h1%gt;--%gt;
 ? if (models('Schema::Event')-%gt;current) {
-    %lt;div class="specialBnr"%gt;%lt;a href="%lt;?= link_for('/special_practice_event') ?%gt;" onclick="javascript:_gaq.push(['_trackPageview', '/special_practice_event']);"%gt;VS戸成高校%lt;/a%gt;%lt;/div%gt;
+    %lt;div class="specialBnr"%gt;%lt;a href="%lt;?= link_for('/special_practice_event') ?%gt;" onclick="javascript:_gaq.push(['_trackPageview', '/event_banner_cnt']);"%gt;VS戸成高校%lt;/a%gt;%lt;/div%gt;
 ? }
     %lt;ul class="menu"%gt;
         %lt;li%gt;%lt;a href="%lt;?= link_for('/shop') ?%gt;"%gt;購買部%lt;/a%gt;%lt;/li%gt;
</pre>

<p>本番環境へのデプロイ時にはデプロイスクリプトの最後尾で下記のスクリプトを実行するようにしてます。</p>

<pre>
#!/usr/bin/env perl

use 5.12.0;

use strict;
use warnings;
use utf8;

use FindBin::libs;

use Try::Tiny;
use LWP::UserAgent;
use Getopt::Long qw/GetOptions/;

use DateTime;
use Git::Repository;
use Path::Class qw(dir);

GetOptions(\%ARGV, qw/
  dry-run
/);

my $now  = DateTime->now(time_zone => 'Asia/Tokyo');
my $home = dir('/home/app/sites');
chdir $home;

my $history_file = $home->subdir(qw/data/)->file('deploy_history.txt');
unless (-e $history_file->stringify) {
    $history_file->touch;
}
my $deploy_history    = $history_file->slurp;
my @deploy_histories  = split /\n/, $deploy_history;

my $warning_comment   = shift @deploy_histories;
my $last_deploy       = $deploy_histories[0];

my ($date, $last_rev) = split /\s+/, $last_deploy;

my $git_repo  = Git::Repository->new(work_tree => $home);
my $rev       = $git_repo->run('log', '--pretty=format:"%h"', '-1');
$rev =~ s/\"//g;

my $diff_stat = "";
if ($last_rev) {
    $diff_stat = $git_repo->run('log', "$last_rev..$rev", "--stat");
}

if (!$ARGV{'dry-run'}) {
    say 'post np.';

    my $ua = LWP::UserAgent->new(agent => 'deployhook');
    my $np_url = 'https://xxxxx.kayac.com/np';
    my $res = $ua->post($np_url, [
        channel => '#dummy-chann',
        summary => "deploy rev $rev",
        text    => $diff_stat,
    ]);
    die $res->content unless $res->code == 302;
}
else {
    say $diff_stat;
}


if (!$ARGV{'dry-run'}) {
    say 'update deploy_history';
    my $next_history = "$now $rev";
    my $fh = $history_file->openw;
    $fh->print(join "\n", ($warning_comment, $next_history, @deploy_histories));
}


say 'done';

</pre>

<p>出力例</p>

<pre>
commit 42189e4dfff430efa9afe7e7c52a1a888d6c815e
Author: xxxxxx <xxxxxxxx@kayac.com>
Date:   Wed Dec 12 10:35:10 2012 +0900

    change method of get link click count

 root/tmpl/default/member_top.mt |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

commit 85b8dcd18c703f156a7408dd17e23529e52189aa
Author: xxxxx <xxxxxxx@kayac.com>
Date:   Wed Dec 12 10:17:57 2012 +0900

    count access num of quiz link

 root/tmpl/common/footer.mt      |    2 +-
 root/tmpl/default/member_top.mt |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

</pre>

<h2>最後に</h2>

<p>gitに移行してみて感じたのは、一番大きいのはbranchの切り替えがスムーズになったことにより、
プログラマの効率ももとより、他職種とのやり取りの効率も上がったことですね。
「このbranchにあれをコミットしておいて」みたいなやり取りが以前よりも円滑できるようになりました。</p>

<p>苦労に対して得るものは大きかったので臆せずやるべきだったと感じてます。</p>

<p>とはいえSourceTreeなくしてここまでうまくいかなかっただろうなーということで、
結局一番伝えたいことはSourceTree++ってことです。</p>

<p>明日は若手バリスタのホープ<a href="https://twitter.com/keita_shiya">@Keita_Shiya</a>のお話です。お楽しみに！</p>
]]>
        

    </content>
</entry>

</feed>
