<?xml version="1.0" encoding="UTF-8"?>
<feed version="0.3" xmlns="http://purl.org/atom/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="en">
  <title>YappoLogs</title>
  <link rel="alternate" type="text/html" href="http://blog.yappo.jp/yappo/" />
  <modified>2016-12-31T13:43:19Z</modified>
  <tagline>Yappo運営者のメモとか色々
blogって単語は好きぢゃ無いけどスクラッチ代わりに使います。
</tagline>
  <id>tag:blog.yappo.jp,2016:/yappo//1</id>
  <generator url="http://www.movabletype.org/" version="2.661">Movable Type</generator>
  <copyright>Copyright (c) 2016, Yappo</copyright>
  <entry>
    <title>2016年まとめ</title>
    <link rel="alternate" type="text/html" href="http://blog.yappo.jp/yappo/archives/000853.html" />
    <modified>2016-12-31T13:43:19Z</modified>
    <issued>2016-12-31T22:43:19+09:00</issued>
    <id>tag:blog.yappo.jp,2016:/yappo//1.853</id>
    <created>2016-12-31T13:43:19Z</created>
    <summary type="text/plain">会社のブログ書きました...</summary>
    <author>
      <name>Yappo</name>
      <url>http://i.yappo.jp/</url>
      <email>yappo+yappologs@shibuya.pl</email>
    </author>
    <dc:subject>perl</dc:subject>
    <content type="text/html" mode="escaped" xml:lang="en" xml:base="http://blog.yappo.jp/yappo/">
      <![CDATA[<p><a href="http://developers.linecorp.com/blog/ja/?p=3973">会社のブログ書きました</a></p>]]>
      
    </content>
  </entry>
  <entry>
    <title>ISUCON #6 参加してきた</title>
    <link rel="alternate" type="text/html" href="http://blog.yappo.jp/yappo/archives/000852.html" />
    <modified>2016-10-24T04:33:42Z</modified>
    <issued>2016-10-24T13:33:42+09:00</issued>
    <id>tag:blog.yappo.jp,2016:/yappo//1.852</id>
    <created>2016-10-24T04:33:42Z</created>
    <summary type="text/plain">やったことに関しては以下の動画を御覧ください。...</summary>
    <author>
      <name>Yappo</name>
      <url>http://i.yappo.jp/</url>
      <email>yappo+yappologs@shibuya.pl</email>
    </author>
    <dc:subject>music</dc:subject>
    <content type="text/html" mode="escaped" xml:lang="en" xml:base="http://blog.yappo.jp/yappo/">
      <![CDATA[<div>やったことに関しては以下の動画を御覧ください。</div>

<div>
<iframe src="https://live.line.me/r/channels/1033/broadcast/77434/embed" frameborder="0" scrolling="no" style="width: 600px; height: 450px; visibility: visible;"></iframe> <script src="https://scdn.line-apps.com/n/line_live/thirdparty/embed.js" async defer></script>
</div>

<div>
<iframe src="https://live.line.me/r/channels/1033/broadcast/77490/embed" frameborder="0" scrolling="no" style="width: 600px; height: 450px; visibility: visible;"></iframe> <script src="https://scdn.line-apps.com/n/line_live/thirdparty/embed.js" async defer></script>
</div>

<div>
<iframe src="https://live.line.me/r/channels/1033/broadcast/77551/embed" frameborder="0" scrolling="no" style="width: 600px; height: 450px; visibility: visible;"></iframe> <script src="https://scdn.line-apps.com/n/line_live/thirdparty/embed.js" async defer></script>
</div>

<div>
<iframe src="https://live.line.me/r/channels/1033/broadcast/77644/embed" frameborder="0" scrolling="no" style="width: 600px; height: 450px; visibility: visible;"></iframe> <script src="https://scdn.line-apps.com/n/line_live/thirdparty/embed.js" async defer></script>
</div>

<div>
<iframe src="https://live.line.me/r/channels/1033/broadcast/77741/embed" frameborder="0" scrolling="no" style="width: 600px; height: 450px; visibility: visible;"></iframe> <script src="https://scdn.line-apps.com/n/line_live/thirdparty/embed.js" async defer></script>
</div>

<div>
<iframe src="https://live.line.me/r/channels/1033/broadcast/77833/embed" frameborder="0" scrolling="no" style="width: 600px; height: 450px; visibility: visible;"></iframe> <script src="https://scdn.line-apps.com/n/line_live/thirdparty/embed.js" async defer></script>
</div>

<div>
<iframe src="https://live.line.me/r/channels/1033/broadcast/77929/embed" frameborder="0" scrolling="no" style="width: 600px; height: 450px; visibility: visible;"></iframe> <script src="https://scdn.line-apps.com/n/line_live/thirdparty/embed.js" async defer></script>
</div>
]]>
      
    </content>
  </entry>
  <entry>
    <title>LINE Notify で line command 作ると便利 </title>
    <link rel="alternate" type="text/html" href="http://blog.yappo.jp/yappo/archives/000851.html" />
    <modified>2016-09-30T16:05:09Z</modified>
    <issued>2016-10-01T01:05:09+09:00</issued>
    <id>tag:blog.yappo.jp,2016:/yappo//1.851</id>
    <created>2016-09-30T16:05:09Z</created>
    <summary type="text/plain"><![CDATA[インターネット見てたら LINE Notifyはテストとか時間のかかるコマンドを実行してちょっと席を外して休憩してる間に通知させるとかときに使うとめっちゃ便利かつ楽そうって思いました&mdash; 貴社の名は。 (@karupanerura) September 29, 2016 って書いてあるの見たので、試しに作ってみました。 動かすと以下の感じです。 LINE Notify さん、めっちゃ簡単で便利すぎないか？？？？！！ tweet みてから10分くらいでエントリ書き終わったくらいの手軽さ!...]]></summary>
    <author>
      <name>Yappo</name>
      <url>http://i.yappo.jp/</url>
      <email>yappo+yappologs@shibuya.pl</email>
    </author>
    <dc:subject>tech</dc:subject>
    <content type="text/html" mode="escaped" xml:lang="en" xml:base="http://blog.yappo.jp/yappo/">
      <![CDATA[インターネット見てたら<br><br>

<blockquote class="twitter-tweet" data-lang="en"><p lang="ja" dir="ltr">LINE Notifyはテストとか時間のかかるコマンドを実行してちょっと席を外して休憩してる間に通知させるとかときに使うとめっちゃ便利かつ楽そうって思いました</p>&mdash; 貴社の名は。 (@karupanerura) <a href="https://twitter.com/karupanerura/status/781410569148432384">September 29, 2016</a></blockquote> <script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

って書いてあるの見たので、試しに作ってみました。

<script src="https://gist.github.com/yappo/0488671ec5c6591a7ba8b9adaefcb158.js"></script>

動かすと以下の感じです。 LINE Notify さん、めっちゃ簡単で便利すぎないか？？？？！！ tweet みてから10分くらいでエントリ書き終わったくらいの手軽さ!

<img src="https://i.gyazo.com/ec7c5cef42428f35d22b7a832df5ab59.png">]]>
      
    </content>
  </entry>
  <entry>
    <title>ikachan with Yappocall for LINE BOT API Trial Account</title>
    <link rel="alternate" type="text/html" href="http://blog.yappo.jp/yappo/archives/000850.html" />
    <modified>2016-04-08T07:21:14Z</modified>
    <issued>2016-04-08T16:21:14+09:00</issued>
    <id>tag:blog.yappo.jp,2016:/yappo//1.850</id>
    <created>2016-04-08T07:21:14Z</created>
    <summary type="text/plain">LINE さんから Bot が作れる API がリリースされたということなのでikachanと昔なつかしYappocallの LINE 版を作ってみました。 実物はこちらhttp://yappocall.yappo.jp/ 初代 Yappocall は APNs で実装してましたが、今度は LINE を使ってるので僕からのお知らせが表示されてて双方向インタラクションな未来が来てる！ LINE の開発者画面で Bot の作成を行い必要な設定を済ませた後、 Bot 連携するために必要な情報をソースコードに書いて実行するだけで簡単に ikachan のような単純な Web API が設置出来ます。 ソースコードの設定以外にも必要な作業があって、作成した LINE Bot を友だちに追加してから API で利用する appname の登録を行い api_token を生成する必要があります。 ln.yappo を利用した bot...</summary>
    <author>
      <name>Yappo</name>
      <url>http://i.yappo.jp/</url>
      <email>yappo+yappologs@shibuya.pl</email>
    </author>
    <dc:subject>tech</dc:subject>
    <content type="text/html" mode="escaped" xml:lang="en" xml:base="http://blog.yappo.jp/yappo/">
      <![CDATA[<p>LINE さんから Bot が作れる API がリリースされたということなので<a href="http://blog.yappo.jp/yappo/archives/000760.html">ikachan</a>と昔なつかし<a href="http://blog.yappo.jp/yappo/archives/000750.html">Yappocall</a>の LINE 版を作ってみました。<p>

<p>実物はこちら<a href="http://yappocall.yappo.jp/">http://yappocall.yappo.jp/</a><br>
初代 Yappocall は APNs で実装してましたが、今度は LINE を使ってるので僕からのお知らせが表示されてて双方向インタラクションな未来が来てる！</p>

<p>LINE の開発者画面で Bot の作成を行い必要な設定を済ませた後、 Bot 連携するために必要な情報をソースコードに書いて実行するだけで簡単に ikachan のような単純な Web API が設置出来ます。<br>
ソースコードの設定以外にも必要な作業があって、作成した LINE Bot を友だちに追加してから API で利用する appname の登録を行い api_token を生成する必要があります。<br>
ln.yappo を利用した bot は以下の様なコマンドを受け付けているので、 add コマンドで appname の登録と api_token の取得が出来ます。 $SECRET は lnyappo.pl の中で設定した、連携時に使うパスワードのようなものです。知らない人には API の利用をさせないという安全弁です。
<pre>ln.yappo Help

1. add
  &gt; $SECRET add $yourAppName

2. delete
  &gt; $SECRET del $yourAppName

3. send message to callback url
  &gt; $SECRET send $yourAppName $message

4. list
  &gt; $SECRET list

5. help
  > $SECRET help</pre></p>

<p>appname と api_token を lnyappo.pl に設定すると本格的に利用可能になるので API を呼ぶでも良いですし、立ち上げた http server にアクセスすると簡単にメッセージを送るフォームが出てくるので、それを利用すると以下の様な感じで LINE にリアルでメッセージが届きます。<br>
<img src="https://i.gyazo.com/98beec0d6615a47fdb3c773f17a8c792.png"></p>

<p>これだけでもいいんですが ln.yappo には、LINE で発言したテキストを ln.yappo の Web UI で設定した callback url に送信する事が可能になってるので、より LINE らしいかたちの ikachan になりました。</p>

<p>たとえば<br>
<ul>
 <li>監視アラート</li>
 <li>Raspberry Pi から LINE にデータを送る</li>
 <li>外出先から Raspberry Pi にコマンドを送る</li>
 <li>ぎっはぶ連携</li>
 <li>LINE から Twitter にポストする</li>
 <li>ほかほか</li>
</ul>
といった活用が考えられます。<p>

<p>特に現状の制限だと、一人あたり1個の Bot しか作れないとのことなので、この ikachan を Hub にして各種システムと連携すると、効率的に LINE Bot で遊べる事でしょう。<br>
という理由もあって appname を登録して一人あたり複数の api_token を払い出し、複数の callback url を設定できる仕組みにしておきました。</p>

<p>ln.yappo を活用したサンプルとして Yappocall という、 Web 上で POST したメッセージを紐付けた人の LINE に送信する。 LINE から送信したお知らせを Web 上に表示するという簡単なアプリも書いてみたので参考にしてください。</p>

<p>ikachan は IRC ベースなので LINE 向けの Bot とは意識する場所が大きく違っていますが、差異に気をつければ古き好き IRC Bot 職人の皆様も簡単に LINE Bot がかけると思います。<br>
<ul>
 <li>IRC は irc server と常に接続し続けるが、 LINE は message が callback API に届く、 Bot からの送信は API を叩く</li>
 <li>IRC は channel 単位に送信すれば全員に送信できるが、 LINE は個別に送信する</li>
 <li>IRC はいきなり channel に送信しても問題ないが、 LINE だとトークの画面上で利用者の紐付け処理入れといたほうがよさそう</li>
 <li>というか ikachan 的なの作りたい時は、外の別システムから誰に送りたいかを安全よりな方向で設計しときたい</li>
 <li>IRC みたいに複数人に同報送信したい時は、複数人の api_token を管理しといて、送信したい人ぶん送っとけば良い</li>
</ul>
<p>


烏賊ソース<br>
<a href="https://github.com/yappo/ln.yappo">https://github.com/yappo/ln.yappo</a><br><br><br>

どうぞご利用下さい。]]>
      
    </content>
  </entry>
  <entry>
    <title>2015年振り返り #yapcasia</title>
    <link rel="alternate" type="text/html" href="http://blog.yappo.jp/yappo/archives/000849.html" />
    <modified>2015-12-31T14:18:05Z</modified>
    <issued>2015-12-31T23:18:05+09:00</issued>
    <id>tag:blog.yappo.jp,2015:/yappo//1.849</id>
    <created>2015-12-31T14:18:05Z</created>
    <summary type="text/plain">最後の YAPC::ASIA Tokyo 2015 にて 大規模でも小中規模サービスでも捗る microservices な Web サービスのつくりかた という内容で発表してきました。 また LT にて 廃止予定になった $^ENCODING に関する発表もしましたが、諸事情により資料は非公開です。 Have a Happy new year!...</summary>
    <author>
      <name>Yappo</name>
      <url>http://i.yappo.jp/</url>
      <email>yappo+yappologs@shibuya.pl</email>
    </author>
    <dc:subject>tech</dc:subject>
    <content type="text/html" mode="escaped" xml:lang="en" xml:base="http://blog.yappo.jp/yappo/">
      <![CDATA[<p>最後の YAPC::ASIA Tokyo 2015 にて <a href="http://yappo.github.io/talks/20150821-yapcasia2015-microservices/">大規模でも小中規模サービスでも捗る microservices な Web サービスのつくりかた </a>という内容で発表してきました。</p>
<p>また LT にて 廃止予定になった $^ENCODING に関する発表もしましたが、諸事情により資料は非公開です。</p>

<p>Have a Happy new year!</p>]]>
      
    </content>
  </entry>
  <entry>
    <title>LINE@ で俺の公式アカウントをはじめました</title>
    <link rel="alternate" type="text/html" href="http://blog.yappo.jp/yappo/archives/000848.html" />
    <modified>2015-02-20T10:30:19Z</modified>
    <issued>2015-02-20T19:30:19+09:00</issued>
    <id>tag:blog.yappo.jp,2015:/yappo//1.848</id>
    <created>2015-02-20T10:30:19Z</created>
    <summary type="text/plain">さいきん LINE@ というアプリ？みたいのが出てて、そこで公式アカウント的なのが作れるみたいなので作ってみました。 @yappo で LINE から検索すると登録できると思います。 僕のお得な情報とか配信していて盛り上がり始めてるので皆様ぜひぜひご登録を〜...</summary>
    <author>
      <name>Yappo</name>
      <url>http://i.yappo.jp/</url>
      <email>yappo+yappologs@shibuya.pl</email>
    </author>
    <dc:subject>foods</dc:subject>
    <content type="text/html" mode="escaped" xml:lang="en" xml:base="http://blog.yappo.jp/yappo/">
      <![CDATA[<p>さいきん LINE@ というアプリ？みたいのが出てて、そこで公式アカウント的なのが作れるみたいなので作ってみました。</p>

<p>@yappo で LINE から検索すると登録できると思います。</p>

<p>僕のお得な情報とか配信していて盛り上がり始めてるので皆様ぜひぜひご登録を〜</p>

<p><br />
<a href="http://line.me/ti/p/%40yappo"><img height="36" border="0" alt="友だち追加数" src="http://biz.line.naver.jp/line_business/img/btn/addfriends_ja.png"></a><br />
<img src="http://qr-official.line.me/L/6wVpaCHXt_.png"></p>]]>
      
    </content>
  </entry>
  <entry>
    <title>Mac + emacs + PlantUML でさくさく UML 職人</title>
    <link rel="alternate" type="text/html" href="http://blog.yappo.jp/yappo/archives/000847.html" />
    <modified>2014-11-26T10:43:35Z</modified>
    <issued>2014-11-26T19:43:35+09:00</issued>
    <id>tag:blog.yappo.jp,2014:/yappo//1.847</id>
    <created>2014-11-26T10:43:35Z</created>
    <summary type="text/plain">例えば ./uml/ に uml ファイルを置いておいて ./img/ に UML の画像ファイルを書き出すような環境の場合。JAVA_TOOL_OPTIONS=&quot;-Djava.awt.headless=true&quot; watcher --dir ./uml/ -- &apos;java -jar /foo/bar/plantuml.jar ./uml/*.uml &amp;&amp; open -g -a Preview ./img/*.png&apos;のようなコマンドをバックグラウンドで起動しとくと、編集作業の邪魔されずに .uml ファイルが保存されるたびに全自動で画像を生成して Preview.app で開いといてくれる。 開いといてくれるけど Preview.app にフォーカスが移動しないと window 中の画像は反映されないので注意。 そしてwatcher コマンドはみなさんが嫌いな Perl でできていて CPANから入手できます。...</summary>
    <author>
      <name>Yappo</name>
      <url>http://i.yappo.jp/</url>
      <email>yappo+yappologs@shibuya.pl</email>
    </author>
    <dc:subject>music</dc:subject>
    <content type="text/html" mode="escaped" xml:lang="en" xml:base="http://blog.yappo.jp/yappo/">
      <![CDATA[<p>例えば ./uml/ に uml ファイルを置いておいて ./img/ に UML の画像ファイルを書き出すような環境の場合。<pre>JAVA_TOOL_OPTIONS="-Djava.awt.headless=true" watcher --dir ./uml/ -- 'java -jar /foo/bar/plantuml.jar ./uml/*.uml && open -g -a Preview ./img/*.png'</pre>のようなコマンドをバックグラウンドで起動しとくと、編集作業の邪魔されずに .uml ファイルが保存されるたびに全自動で画像を生成して Preview.app で開いといてくれる。<br />
開いといてくれるけど Preview.app にフォーカスが移動しないと window 中の画像は反映されないので注意。</p>

<p>そしてwatcher コマンドはみなさんが嫌いな Perl でできていて <a href="https://metacpan.org/release/App-watcher">CPAN</a>から入手できます。</p>]]>
      
    </content>
  </entry>
  <entry>
    <title>#isucon 2014  に参加して暫定圏外になってきました</title>
    <link rel="alternate" type="text/html" href="http://blog.yappo.jp/yappo/archives/000846.html" />
    <modified>2014-09-29T10:36:12Z</modified>
    <issued>2014-09-29T19:36:12+09:00</issued>
    <id>tag:blog.yappo.jp,2014:/yappo//1.846</id>
    <created>2014-09-29T10:36:12Z</created>
    <summary type="text/plain">ISUCON4 の予選やってきました、最終スコアは37000位だったけど本戦足切りラインは45000くらいだと思うので残念でした。 チームメイトは、前回組んだ kamipo さんに加え新メンバー ar_tama さんと共に望みました。 役割としては kamipo: 司令塔権 middleware 以下全部担当 ar_tama: アプリ担当 yappo: アプリ担当 リポジトリはこちら https://github.com/kamipo/isucon4qualifier 開始前 大体の凡ミスはレギュレーション読まない事に起因するのが、過去の ISUCON の教訓だからひたすらレギュレーション読む。 お陰でリーダの遅刻を見逃した。 10:00-12:00 開始とともにトイレ。この間に kamipo さんが必要なインスタンスあげてログイン出来るようになってた。 うちのチームは1人/1インスタンスという構成で始めた。理由としては去年1インスタンスでやったせいで、気づかない間に環境壊されてたり各人が施した成果のベンチマークを回すのに待ち行列が発生して無駄だったから。 インスタンスを別ける事で他人に影響する事無くひたすら開発を進められた。 ちなみに基本的にサーバのコードは触らずに yappo/master branch に commit してくスタイルだった。 最初に isucon user で直接ログインしようとしたけど、鍵置いても直接はどうしても無理だったから2分くらいで諦めた。ログインし続ければいいだけだし。 そして、標準の...</summary>
    <author>
      <name>Yappo</name>
      <url>http://i.yappo.jp/</url>
      <email>yappo+yappologs@shibuya.pl</email>
    </author>
    <dc:subject>tech</dc:subject>
    <content type="text/html" mode="escaped" xml:lang="en" xml:base="http://blog.yappo.jp/yappo/">
      <![CDATA[<p>ISUCON4 の予選やってきました、最終スコアは37000位だったけど本戦足切りラインは45000くらいだと思うので残念でした。<br />
チームメイトは、前回組んだ kamipo さんに加え新メンバー ar_tama さんと共に望みました。<br />
役割としては</p>

<p>kamipo: 司令塔権 middleware 以下全部担当<br />
ar_tama: アプリ担当<br />
yappo: アプリ担当</p>

<p>リポジトリはこちら <a href="https://github.com/kamipo/isucon4qualifier">https://github.com/kamipo/isucon4qualifier</a></p>

<p><h4>開始前</h4></p>

<p>大体の凡ミスはレギュレーション読まない事に起因するのが、過去の ISUCON の教訓だからひたすらレギュレーション読む。<br />
お陰でリーダの遅刻を見逃した。</p>

<p><h4>10:00-12:00</h4></p>

<p>開始とともにトイレ。この間に kamipo さんが必要なインスタンスあげてログイン出来るようになってた。<br />
うちのチームは1人/1インスタンスという構成で始めた。理由としては去年1インスタンスでやったせいで、気づかない間に環境壊されてたり各人が施した成果のベンチマークを回すのに待ち行列が発生して無駄だったから。<br />
インスタンスを別ける事で他人に影響する事無くひたすら開発を進められた。<br />
ちなみに基本的にサーバのコードは触らずに yappo/master branch に commit してくスタイルだった。</p>

<p>最初に isucon user で直接ログインしようとしたけど、鍵置いても直接はどうしても無理だったから2分くらいで諦めた。ログインし続ければいいだけだし。<br />
そして、標準の ruby でベンチマークを回す。<pre>10:27 < Yappo> 01:26:52 type:score     success:6090    fail:0  score:1316</pre>だった。</p>

<p>その後に ruby を止めて perl を有効にしようとしたら、まさかの forman が死なないトラブルがあったので kill してから plackupしてベンチを取った。<pre>10:37 < Yappo> 01:35:55 type:score     success:7530    fail:0  score:1627</pre>Perlにするだけでスコアが上がった。<br />
workload 4とかにするだけで<pre>10:50 < ar_tama> score 3335いった</pre>でした。</p>

<p>ベンチのスコアを確認した後は、ブラウザで見たときの見た目重視っていうゆるふわルールあったのでちゃんとアプリを使ってみようとしたんだけど、ログインしてから何も出来ない！銀行なのにローン組むリンクすらマトモにうごかない！！！<br />
っていう挙動に不安になったので「いすこん銀行さん Safari でログインするとローン申し込めないんですが、それおっけーですか?」って質問したら問題ないって回答きてひと安心。<br />
<blockquote class="twitter-tweet" lang="ja"><p>ISUCON4 予選で一番心に残った不具合報告は「住宅ローンの申し込みができないのですが」</p>&mdash; Issei Naruta (@mirakui) <a href="https://twitter.com/mirakui/status/516256287391105024">2014, 9月 28</a></blockquote><br />
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script></p>

<p><br />
その後は benchmarker がどうなってるのかを一通り調べてて<pre>//*[@id='last-logined-at']<br />
//*[@id='last-logined-ip']<br />
//*[@id='notice-message']</pre>って書いてあるのを見つけた。たぶん「DOM を崩さない=このXPathで処理出来る事」だと理解した。<br />
もちろん input 要素や submit 周りの XPath も書いてあったので、ベンチマーク用の UA の時に表示する専用の HTML 返したら良いんだと思ったけど、そんなんおもろくないのでチームメンバーには黙ってた。</p>

<p>その後はテンプレートファイルを見る。<pre>11:06 < Yappo>     &lt;span class="hikaru-mozi"&gt;偽画面にご注意ください！&lt;/span&gt;<br />
11:06 < Yappo> これに釘付けだった<br />
11:06 < ar_tama> ｗ<br />
11:06 < Yappo> hiraku-mozi<br />
11:06 < ar_tama> hikaru-mozi!!<br />
11:06 < ar_tama> かわいい</pre>いいセンスしてたので余計な所で時間くってた。。</p>

<pre>11:08 < Yappo> [isucon@ip-10-127-131-242 ~]$ sudo zcat /var/log/nginx/access.log-20140926.gz | less
11:08 < Yappo> censored - - [26/Sep/2014:09:35:39 +0000] "GET /tmUnblock.cgi HTTP/1.1" 400 172 "-" "-"
11:08 < Yappo> censored - - [26/Sep/2014:10:27:58 +0000] "GET / HTTP/1.1" 200 2228 "-" "() { :;}; /bin/bash -c \x22echo testing9123123\x22; /bin/uname -a"</pre>ヒント探したつもりが全然品とじゃなかった案件もあった。。

<p>その後はベンチ走らせた時のログを集計して top page -> login -> エラーだったら top page に戻る/成功だったら mypage を表示 という固定的なアクセスしかない事を把握した。<br />
top page を開いた時に、必要な static file のリンク先を全部辿ってアクセスしにいく感じだった。<br />
css を gz 化して見たものの当たり前だけどスコア落ちた。これは CPU 食ってて逆効果だったのか md5 checksum が一致してないのかわからんかったけど、余計な事なのですぐにやめた。</p>

<p><br />
<h4>12:00-13:00</h4></p>

<p>ここらで作戦タイムしながらアプリのコードを読んでく。<br />
トラフィック的には / へのアクセスが支配的。 /login はクエリが重いので最後のボトルネックは /login 。そして /mypage の内容は実質 /login 時に取得したデータを使い回せる事を把握した。<br />
/ に関しては、ログイン失敗時のエラーメッセージを動的に埋め込んでいるが、実際は5パターンのエラーしかないので、何かしらの状態をクライアント側に保持させて nginx 側で振り分けすれば application が処理しなくても良いはず。<br />
/mypage に関しても /login 時に必要なデータを保持して nginx 側でレンダリングした方が早そう。</p>

<p>という結果を踏まえて、 benchmarker が任意の Set-Cookit を受け取って Cookie ヘッダで送ってくるかを調べ、それが可能である事を把握してから</p>

<p>1. 何も cookie が無い時に / へのアクセスがあったら nginx 側で静的コンテンツを返す<br />
2. ログイン失敗時には error=nanntara という cookie を送信するので、その cookie がついた / へのアクセスは cookie の内容を考慮して適切な静的コンテンツを返す<br />
3. ログイン成功したときは、最終ログイン情報を cookie に入れておくので、 nginx は cookie を元に ssi を使って /mypage のレンダリングをする</p>

<p>という、方針で動く事にした。</p>

<p>kamipo さんが nginx 周りの作業を全面的に行うあいだ、僕は暇になるので、自分は /login の重い処理を片付ける ar_tama さんは逆から攻めてく感じで /report 周りをやる感じになった。<br />
本来は /report はカリカリにチューニングする意味ないんだけど、高スコアが叩けるようになった時に /report の負荷が高過ぎてベンチマーク成立しないリスクもあるので、先回りで。</p>

<p><br />
<h4>13:00-15:00</h4></p>

<p>このアプリはログイン時に失敗すると失敗カウントが増えていって、閾値を越えるとそのアカウントがロックされる。または ip address が ban リストに入って、どのアカウントにもログイン出来ない。<br />
という仕組みが入っていたのですが、このログイン時に lock / ban をチェックする為のクエリが面倒いサブクエリで書かれていて index 使われてないので遅い。<br />
これをまずどうにかする為に<pre>CREATE TABLE IF NOT EXISTS `login_log` (<br />
  `id` bigint NOT NULL AUTO_INCREMENT PRIMARY KEY,<br />
  `created_at` datetime NOT NULL,<br />
  `user_id` int,<br />
  `login` varchar(255) NOT NULL,<br />
  `ip` varchar(255) NOT NULL,<br />
  `succeeded` tinyint NOT NULL,</p>

<p>  KEY (user_id),<br />
  KEY (ip),<br />
  KEY (succeeded, user_id),<br />
  KEY (succeeded, ip)<br />
) DEFAULT CHARSET=utf8;</pre>という感じで index つけたら、これだけで score:1668 -> score:10027 に上がっていた。</p>

<p>でも index を貼る前に考えてた戦略があったので、一旦この案は取り消しました。</p>

<p>index 貼ってもログイン処理で lock/ban されたかどうか調べるクエリが複雑になるので、それらのクエリが簡単になるように予め失敗回数をカウントするだけのテーブルを用意しました。<pre>CREATE TABLE IF NOT EXISTS `last_login_failure_count_user_id` (<br />
  `user_id` int NOT NULL UNIQUE,<br />
  `count` int<br />
) DEFAULT CHARSET=utf8;</p>

<p>CREATE TABLE IF NOT EXISTS `last_login_failure_count_ip` (<br />
  `ip` varchar(255) NOT NULL UNIQUE,<br />
  `count` int<br />
) DEFAULT CHARSET=utf8;</pre>そうすると、ログイン時に login_log テーブルと追加したテーブルに対して3回も insert クエリが走ってしまうので trigger を使ってクエリ数を減らしました。<pre>DELIMITER //<br />
CREATE TRIGGER login_log_insert AFTER INSERT ON login_log<br />
FOR EACH ROW<br />
BEGIN<br />
    IF NEW.succeeded = 1 THEN<br />
        DELETE FROM last_login_failure_count_user_id WHERE user_id=NEW.user_id;<br />
        DELETE FROM last_login_failure_count_ip      WHERE ip=NEW.ip;<br />
    ELSE<br />
        INSERT INTO last_login_failure_count_user_id SET user_id=NEW.user_id, count=1 ON DUPLICATE KEY UPDATE count=count+1;<br />
        INSERT INTO last_login_failure_count_ip SET ip=NEW.ip, count=1                ON DUPLICATE KEY UPDATE count=count+1;<br />
    END IF;<br />
END//<br />
DELIMITER ;</pre>また、 SELECT クエリが複数飛ぶのも点数下げるだけなので UNION でおまとめしてます。<pre>(<br />
        SELECT 'user_id' AS name, count AS count FROM last_login_failure_count_user_id WHERE user_id = ?<br />
      ) UNION (<br />
        SELECT 'ip', count FROM last_login_failure_count_ip WHERE ip = ?<br />
      )</pre>違うテーブルを UNION にまとめて結果を取り出すと、どの行が何のデータだかわからなくなるので1カラム目にラベルを入れておいて、それをプログラム側で成形してりようします。</p>

<p>ここら辺ずっと1並列でベンチ取ってたので、基本的にスコアが1万から変わらなくて辛かったけど次なる施策が控えてるので、このまま進んでた。</p>

<p><h4>15:00-16:00</h4></p>

<p>login 周りが一旦落ち着いたので、今度は /mypage で表示させるべきデータを /login で生成する作業に取りかかる。<br />
/mypage で出しているのは<b>前回</b>ログインした時の ip address とログイン日時。という事で /login 叩かれた時点の user_id の最近の成功したログインのテーブルからデータを取れば良いという事になる。<br />
ログイン履歴のテーブル(login_log)は、該当の user_id/ip address がいつログインしたか、それは成功したか失敗したか(succeededカラム)。という情報を入れてるので SELECT * FROM login_log WHERE succeeded=1 AND user_id=? ORDER BY id DESC みたいなクエリになるわけだけど、実は先ほど trigger の仕組みを作った時に<pre>CREATE TABLE IF NOT EXISTS `last_login_success_user_id` (<br />
  `user_id` int NOT NULL UNIQUE,<br />
  `login_log_id` bigint NOT NULL<br />
) DEFAULT CHARSET=utf8;</p>

<p>CREATE TABLE IF NOT EXISTS `last_login_success_ip` (<br />
  `ip` varchar(255) NOT NULL UNIQUE,<br />
  `login_log_id` bigint NOT NULL<br />
) DEFAULT CHARSET=utf8;</pre>というテーブルを作ってて<pre>DELIMITER //<br />
CREATE TRIGGER login_log_insert AFTER INSERT ON login_log<br />
FOR EACH ROW<br />
BEGIN<br />
    IF NEW.succeeded = 1 THEN<br />
        INSERT INTO last_login_success_user_id SET user_id=NEW.user_id, login_log_id=NEW.id ON DUPLICATE KEY UPDATE login_log_id=NEW.id;<br />
        INSERT INTO last_login_success_ip SET ip=NEW.ip, login_log_id=NEW.id                ON DUPLICATE KEY UPDATE login_log_id=NEW.id;<br />
        DELETE FROM last_login_failure_count_user_id WHERE user_id=NEW.user_id;<br />
        DELETE FROM last_login_failure_count_ip      WHERE ip=NEW.ip;<br />
    ELSE<br />
        INSERT INTO last_login_failure_count_user_id SET user_id=NEW.user_id, count=1 ON DUPLICATE KEY UPDATE count=count+1;<br />
        INSERT INTO last_login_failure_count_ip SET ip=NEW.ip, count=1                ON DUPLICATE KEY UPDATE count=count+1;<br />
    END IF;<br />
END//<br />
DELIMITER ;</pre>という定義を作っていたので、それを利用して<pre>FROM last_login_success_user_id JOIN login_log ON last_login_success_user_id.login_log_id=login_log.id WHERE last_login_success_user_id.user_id = ?</pre>のようなクエリを作っていた。<br />
もちろんこれも UNION でむりやり1クエリにまとめてたので<pre>(<br />
        SELECT 'user_id' AS name, count AS count, NULL AS ip, NULL AS created_at FROM last_login_failure_count_user_id WHERE user_id = ?<br />
      ) UNION (<br />
        SELECT 'ip', count, NULL, NULL FROM last_login_failure_count_ip WHERE ip = ?<br />
      ) UNION (<br />
          SELECT 'last', NULL, ip, created_at FROM last_login_success_user_id JOIN login_log ON last_login_success_user_id.login_log_id=login_log.id WHERE last_login_success_user_id.user_id = ?<br />
      )</pre>みたいにして取ってた。</p>

<p>そして、そろそろ素の file に session data を書いてるのも良く無さそうなので。 /dev/shm 以下に書くようにしてメモリの上に session data を置くようにした。<br />
ここで memcached 入れなかったのは、いきなり新規の daemon 突っ込もうとしてハマったら面倒、今まで1個のプロセスの中だけで session data の読み書きしてたのに突然別のプロセスに tcp socket 経由で処理するのは危険だしコンテキストスイッチやばそう。みたいな素人判断で安全にメモリ上に移行する方法を選びました。</p>

<p>この辺りまでは、ささいな typo でベンチマークがこける事はあったけど、それ以外の大きなトラブルは無く進んでた感じ。</p>

<p>ここで衝撃の事実<pre>15:42 < Yappo> flash まわり kamipo 先生がやってたけど、どうなんだろうw<br />
15:42 < ar_tama> ｗ<br />
15:42 <@kamipo> それは挫折しましたｗ<br />
15:42 <@kamipo> si<br />
15:42 < Yappo> w<br />
15:42 <@kamipo> し、使ってる / がめっちゃ速いから</pre> flash まわりってのは / とか /mypage を nginx でどうにかするって言ってたやつなんだけど、結局 ssi がうまく動かせなくて諦めてしまったっぽい。</p>

<p><h4>16:00-17:00</h4></p>

<p>という事で /mypage を nignx で処理する事は諦めたけど / は静的に返そうという話になった。<br />
僕は事前の準備でベンチマークは path が不一致だと加点しないが、 query string が url に付与されてても加点対象となる事実をしってたので、 /login でエラーになったら /?error=xxx にリダイレクトして nginx で query string を処理して、全ての / へのレスポンスを静的に返そう！という話になった。</p>

<p>16:30  すぎた辺りから、まだ nginx の設定出来ない感じだったので全員で nginx の設定調べだすことになった。</p>

<p>ここからが真のデスマーチが始まって、だれも / を静的に返す nginx.conf が書けないまま1時間がすぎてしまい。途中経過に名前出てこないまま終わるのだけは嫌だ！というリーダの叫びもあって17時前に3万ちょい越えのスコアを送信してギリギリ名前を刻む事だけは出来たけど暫く進まず。。</p>

<p><h4>17:00-17:40</h4></p>

<p>全員でnginxを調べだして30分がすぎて、このままだともうダメだ！ってなってた頃に、ようやく僕が nginx で動く設定が解ったので、設定を試してベンチを回す事ができた。<br />
まだ / だけ静的化しただけだったけど、すぐに error page を静的にする設定を入れて何とかベンチ通るようになった。<pre>17:39 < Yappo> 08:37:49 type:score     success:68790   fail:0  score:14859<br />
17:39 < Yappo> 08:39:27 type:score     success:159410  fail:0  score:34434</pre>上が1並列で下が5並列くらいだとおもう。</p>

<p>このくらいになると、まったく原因解らないけど僕のインスタンスだけが正しく動く環境になってました。<br />
去年の本戦も同じくらいの時刻にもあったのですが、今回も「<img src="http://i.gyazo.com/7bc8338e682afc5bab05feb8b246905b.png">もう最後の頼みの綱はやっぽさんだけや。。」って発言を頂いてしんみり。</p>

<p>結局、静的ファイル大作戦でスコアが1-2割上がったくらいでまだまだ足りんかった。</p>

<p><h4>17:40-18:00</h4></p>

<p>この後は悪あがきで Starman だったのを Starlet に入れ替えて workload を色々変えて試してみて、だいたい37000くらいのスコアで収束しそうだったので、天にも祈る気持ちでベンチマーク連打を他のメンバーにお願いして僕はトイレに行ってきました。<br />
そして帰ってきた頃に終了です。</p>

<p><h4>やり残した事</h4></p>

<p>みなさんお分かりでしょうが trigger 周りが無駄すぎるので、そこはもっと効率よくする予定で進んでたのですが、さすがは本番でトラブル多発で時間足りなくなって、まともな感じにする前に撃沈でした。<br />
最終的には MySQL の接続は /login のみで 1 write, 2 read クエリのみになってたけど、やはり /login での mysql 処理が支配的になってくるので users テーブルを全部 perl のコードに変換してクエリ数を減らす事もやりたかったです。<br />
最後の手段で、ベンチマークの User-Agent の時だけ必要最小限な HTML を返すという事をやって終了させる目標があったけど、それもやりきれず残念。</p>

<p>スタート時に使ってる midllware を使い続けてキャッシュ戦略も取らなかった割には良いスコアだったのでは？？？</p>

<p>kamipo さんとか ar_tama さんとか、なんもバリュー出せてない言ってたけど細かい所直したり バグ見つけてくれたり kernel 設定したり middleware の調整したり ami 提出の調整するのとかバリューでまくってたよ！！<br />
最初の戦略がちゃんと当たってれば、それこそすっごいバリューになってたし、今回は惜しい感じだっただけ！！<br />
僕最初と最後に別のバリューだしてたけど。。。</p>

<p><h4>反省点</h4></p>

<p>スタートダッシュをゆっくりしない。最初と最後くらいトイレに行かない。<br />
最後の静的ファイル返す時に Varnish 入れた方が良いと思ってたけど、普段やらない事を本番でやっちゃだめだという学びがありました。</p>

<p>こちらからは以上です。</p>]]>
      
    </content>
  </entry>
  <entry>
    <title>#isucon で、やらんかった事</title>
    <link rel="alternate" type="text/html" href="http://blog.yappo.jp/yappo/archives/000845.html" />
    <modified>2014-09-28T17:34:10Z</modified>
    <issued>2014-09-29T02:34:10+09:00</issued>
    <id>tag:blog.yappo.jp,2014:/yappo//1.845</id>
    <created>2014-09-28T17:34:10Z</created>
    <summary type="text/plain">書いてる人 ISUCON が始まる直前のエンジニアチューニングコンテストで、レギュレーションで「特定のディレクトリ以下のファイルを弄ったら失格。それ以外は自由」って競技があったので、特定のディレクトリ以外の htppd.conf をいじって documentroot を変更して、ぶっちぎりのスコアをたたき出したら、ぶっちぎりすぎたと言う理由で失格になってマジイラっと来た人間。 最初やった事 レギュレーションを良く読む テンプレートファイルを良く読む ベンチマーク実行する ベンチマークの User-Agent を見る 任意の Set-Cookie を返してもちゃんと処理するかどうか見る ログを awk ... | sort | unic -c |sort -r | more static file を.gz してファイル圧縮対応してる client かどうか試して無理なの確認する ベンチマークのバイナリを vim で開く strings ベンチマークのバイナリ...</summary>
    <author>
      <name>Yappo</name>
      <url>http://i.yappo.jp/</url>
      <email>yappo+yappologs@shibuya.pl</email>
    </author>
    <dc:subject>music</dc:subject>
    <content type="text/html" mode="escaped" xml:lang="en" xml:base="http://blog.yappo.jp/yappo/">
      <![CDATA[<h4>書いてる人</h4>

<p>ISUCON が始まる直前のエンジニアチューニングコンテストで、レギュレーションで「特定のディレクトリ以下のファイルを弄ったら失格。それ以外は自由」って競技があったので、特定のディレクトリ以外の htppd.conf をいじって documentroot を変更して、ぶっちぎりのスコアをたたき出したら、ぶっちぎりすぎたと言う理由で失格になってマジイラっと来た人間。</p>

<h4>最初やった事</h4>
<ul>
<li>レギュレーションを良く読む</li>
<li>テンプレートファイルを良く読む</li>
<li>ベンチマーク実行する</li>
<li>ベンチマークの User-Agent を見る</li>
<li>任意の Set-Cookie を返してもちゃんと処理するかどうか見る</li>
<li>ログを awk ... | sort | unic -c |sort -r | more</li>
<li>static file を.gz してファイル圧縮対応してる client かどうか試して無理なの確認する</li>
<li>ベンチマークのバイナリを vim で開く</li>
<li>strings ベンチマークのバイナリ</li>
<li>ベンチマークで定義してる XPath に対して、 fail する条件を確定させる</li>
</ul>

<h4>やらなかったこと</h4>
<ul>
<li>in memory storage(FAQみたらこれアウトなの確定してた)</li>
<li>公開されてる予選レギュレーション「レスポンス(HTML)のDOM構造」と「ブラウザで表示した際の見た目(問題ない範囲で)」と、実際のベンチマークバイナリから得た加点対象に最適な DOM 出力、そして実際の見た目で使用しうる User-Agent とベンチマークの User-Agent の差異を考慮した最短解</li>
<li>実際正しくレスポンス返しても誤差にしかならないもののレスポンスを捨てる行為</li>
<li>IS NOT NULL なレコード作らんだろ！っていって、それ省く事</li>
</ul>

<h4>やったことの一部</h4>
<ul>
<li>url の ? 以下が付与されてても加点に影響しない事を利用</li>
</ul>]]>
      
    </content>
  </entry>
  <entry>
    <title>超軽量 logger の logminimal っていう Java8 ライブラリ書いた</title>
    <link rel="alternate" type="text/html" href="http://blog.yappo.jp/yappo/archives/000844.html" />
    <modified>2014-07-15T08:13:17Z</modified>
    <issued>2014-07-15T17:13:17+09:00</issued>
    <id>tag:blog.yappo.jp,2014:/yappo//1.844</id>
    <created>2014-07-15T08:13:17Z</created>
    <summary type="text/plain">さいきんは空前の Java ブームの兆しが高まっているので、練習を兼ねてlogminimalっていうライブラリ書いてみました。 import static jp.yappo.logminimal.Log.*; public class Foo { public void var() { critf(&quot;crit log&quot;); warnf(&quot;warn log&quot;); infof(&quot;info log&quot;); debugf(&quot;debug log&quot;); critf(&quot;crit log %s&quot;, str); warnf(&quot;warn log %s&quot;, str); infof(&quot;info log %s&quot;, str); debugf(&quot;debug log %s&quot;, str); } }って感じで使えます！かんたん！...</summary>
    <author>
      <name>Yappo</name>
      <url>http://i.yappo.jp/</url>
      <email>yappo+yappologs@shibuya.pl</email>
    </author>
    <dc:subject>java</dc:subject>
    <content type="text/html" mode="escaped" xml:lang="en" xml:base="http://blog.yappo.jp/yappo/">
      <![CDATA[<p>さいきんは空前の Java ブームの兆しが高まっているので、練習を兼ねて<a href="https://github.com/yappo/java-logminimal">logminimal</a>っていうライブラリ書いてみました。</p>

<pre>import static jp.yappo.logminimal.Log.*;
public class Foo {
    public void var() {
        critf("crit log");
        warnf("warn log");
        infof("info log");
        debugf("debug log");
        critf("crit log %s", str);
        warnf("warn log %s", str);
        infof("info log %s", str);
        debugf("debug log %s", str);
    }
}</pre>って感じで使えます！かんたん！

<p>デフォルトの出力内容とかは以下のテストが通る感じの出力です。<pre>		assertEquals(LogTest.logResult, "[2014/06/10 18:19:20] [CRITICAL] log 0001 at jp.yappo.logminimal.LogTest.test(LogTest.java:35)");<br />
		warnf("%s %04d", "log", 1);<br />
		assertEquals(LogTest.logResult, "[2014/06/10 18:19:20] [WARN] log 0001 at jp.yappo.logminimal.LogTest.test(LogTest.java:37)");<br />
		infof("%s %04d", "log", 1);<br />
		assertEquals(LogTest.logResult, "[2014/06/10 18:19:20] [INFO] log 0001 at jp.yappo.logminimal.LogTest.test(LogTest.java:39)");<br />
		debugf("%s %04d", "log", 1);<br />
		assertEquals(LogTest.logResult, "[2014/06/10 18:19:20] [DEBUG] log 0001 at jp.yappo.logminimal.LogTest.test(LogTest.java:41)");</p>

<p>		critf("foo\nbar\rbaz\tblha");<br />
		assertEquals(LogTest.logResult, "[2014/06/10 18:19:20] [CRITICAL] foo\\nbar\\rbaz\\tblha at jp.yappo.logminimal.LogTest.test(LogTest.java:44)");</pre></p>

<p>ログの出力先は lambda で差し替えられます<pre>Log.setLogger((time, type, message, rawMessage, trace) -&gt; {<br />
			...<br />
		});</pre>みたいにすればいいですね。</p>

<p>1個の java file で作ってるのでコピペでつかえてべんり！</p>]]>
      
    </content>
  </entry>
  <entry>
    <title>MySQL Casual #6 で Groonga の話してきました #mysqlcasual</title>
    <link rel="alternate" type="text/html" href="http://blog.yappo.jp/yappo/archives/000843.html" />
    <modified>2014-07-15T07:21:56Z</modified>
    <issued>2014-07-15T16:21:56+09:00</issued>
    <id>tag:blog.yappo.jp,2014:/yappo//1.843</id>
    <created>2014-07-15T07:21:56Z</created>
    <summary type="text/plain">先週末 Oracle で開催された MySQL Casual #6 でBetter Groonga Replication という題名で Mroonga 使わずに Groonga のレプリケーション構成作って便利に使ってるよ！って話をしました。 普通に話したら Mroonga を使えってマジレス返されるので、なんで Mroonga を使わないで Groonga 単独で頑張ったかの理由などの話をしてたら時間かかりすぎたので9月に開催される Groonga のイベントでもうちょっと詳細の実装などを話そうとおもいましたまる...</summary>
    <author>
      <name>Yappo</name>
      <url>http://i.yappo.jp/</url>
      <email>yappo+yappologs@shibuya.pl</email>
    </author>
    <dc:subject>tech</dc:subject>
    <content type="text/html" mode="escaped" xml:lang="en" xml:base="http://blog.yappo.jp/yappo/">
      <![CDATA[<p>先週末 Oracle で開催された MySQL Casual #6 で<a href="http://yappo.github.io/talks/20140711-mysqlcasual6/">Better Groonga Replication</a> という題名で Mroonga 使わずに Groonga のレプリケーション構成作って便利に使ってるよ！って話をしました。</p>

<p>普通に話したら Mroonga を使えってマジレス返されるので、なんで Mroonga を使わないで Groonga 単独で頑張ったかの理由などの話をしてたら時間かかりすぎたので9月に開催される Groonga のイベントでもうちょっと詳細の実装などを話そうとおもいましたまる</p>]]>
      
    </content>
  </entry>
  <entry>
    <title>YAPC::Asia 2014 でトークしたい</title>
    <link rel="alternate" type="text/html" href="http://blog.yappo.jp/yappo/archives/000842.html" />
    <modified>2014-07-09T04:58:06Z</modified>
    <issued>2014-07-09T13:58:06+09:00</issued>
    <id>tag:blog.yappo.jp,2014:/yappo//1.842</id>
    <created>2014-07-09T04:58:06Z</created>
    <summary type="text/plain"><![CDATA[最近は他の言語とかの勉強をちょっとづつしてるんですが Java8 がでてぞんがい普通っぽくなったらしい Java を特に使ってみようと思って色々覚えようとしてるなかで、逆に Perl への気づきや学びやつらさあるところ等を発見する機会になったので、外から見た Perl という観点で Java For Perl Mongers というタイトルでトーク募集しています。 JPA の会長が #yapcasia にトーク応募している人、もう少しがんばってソーシャルボタン押してもらわないと今年は特に倍率高くてヤバい気がしてるのは俺だけか…&mdash; Daisuke Maki (@lestrrat) 2014, 7月 9 って言ってて危機感感じたので、僕しゃべりたいのでJava For Perl Mongersのページの中にあるソーシャルボタンでガンガン拡散してもらえると嬉しいです！ よろしくおねがいします！！！...]]></summary>
    <author>
      <name>Yappo</name>
      <url>http://i.yappo.jp/</url>
      <email>yappo+yappologs@shibuya.pl</email>
    </author>
    <dc:subject>perl</dc:subject>
    <content type="text/html" mode="escaped" xml:lang="en" xml:base="http://blog.yappo.jp/yappo/">
      <![CDATA[<p>最近は他の言語とかの勉強をちょっとづつしてるんですが Java8 がでてぞんがい普通っぽくなったらしい Java を特に使ってみようと思って色々覚えようとしてるなかで、逆に Perl への気づきや学びやつらさあるところ等を発見する機会になったので、外から見た Perl という観点で</p>

<p><a href="http://yapcasia.org/2014/talk/show/8f7ead9a-ebba-11e3-bd6d-c7a06aeab6a4">Java For Perl Mongers</a></p>

<p>というタイトルでトーク募集しています。</p>

<p>JPA の会長が</p>

<blockquote class="twitter-tweet" lang="ja"><p><a href="https://twitter.com/hashtag/yapcasia?src=hash">#yapcasia</a> にトーク応募している人、もう少しがんばってソーシャルボタン押してもらわないと今年は特に倍率高くてヤバい気がしてるのは俺だけか…</p>&mdash; Daisuke Maki (@lestrrat) <a href="https://twitter.com/lestrrat/statuses/486729797209296897">2014, 7月 9</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

<p>って言ってて危機感感じたので、僕しゃべりたいので<a href="http://yapcasia.org/2014/talk/show/8f7ead9a-ebba-11e3-bd6d-c7a06aeab6a4">Java For Perl Mongers</a>のページの中にあるソーシャルボタンでガンガン拡散してもらえると嬉しいです！</p>

<p>よろしくおねがいします！！！</p>]]>
      
    </content>
  </entry>
  <entry>
    <title>xlsx ファイルを git diff しやすくする為の天才的な wrapper script を書いた</title>
    <link rel="alternate" type="text/html" href="http://blog.yappo.jp/yappo/archives/000841.html" />
    <modified>2014-06-19T12:13:52Z</modified>
    <issued>2014-06-19T21:13:52+09:00</issued>
    <id>tag:blog.yappo.jp,2014:/yappo//1.841</id>
    <created>2014-06-19T12:13:52Z</created>
    <summary type="text/plain">皆さんはプロジェクトのリソースとしてエクセルの xlsx ファイルを使う事があると思います。 何てったって事務職の人ですら楽々使えるスーパー優れた UI なので、 web の管理画面とかを作り込むよりもエクセルでシート作ってもらってしまった方が早いケースも多いんです。現実の世界では。 で、普通の人は TSV にするだの CSV にしてもらうだのすると思うんですが、一方的にデータ貰うだけなら良いんだけど、相手とやり取りする時にはどうしても xlsx ファイル経由とかにしないと相手がこまる！やっぱりエンジニアのエは優しさのエだから相手に優しくしないとだめです。 で、 xslx ファイルでエンジニア以外の人とデータやり取りするとやっぱり、バージョン管理したくなるのが人情です。 でも xslx ファイルはバイナリファイルなので git diff とかが残念です。。。 って事で作っちゃいました。 https://github.com/yappo/p5-git-xlsx-textconv.pl xlsx2txt みたいなコマンドは結構あるけど、僕が作ったのは git diff した時に見やすさを重視してます。 だいたい下の画像のようになります。 シート名を行頭に持ってくるので複数のシートでもだいじょうぶです。 行名や列名を入れると行挿入で死ぬので入れてません。簡単ですね。 README.md の通りに install して .gitconfig を設定して...</summary>
    <author>
      <name>Yappo</name>
      <url>http://i.yappo.jp/</url>
      <email>yappo+yappologs@shibuya.pl</email>
    </author>
    <dc:subject>tech</dc:subject>
    <content type="text/html" mode="escaped" xml:lang="en" xml:base="http://blog.yappo.jp/yappo/">
      <![CDATA[<p>皆さんはプロジェクトのリソースとしてエクセルの xlsx ファイルを使う事があると思います。<br />
何てったって事務職の人ですら楽々使えるスーパー優れた UI なので、 web の管理画面とかを作り込むよりもエクセルでシート作ってもらってしまった方が早いケースも多いんです。現実の世界では。</p>

<p>で、普通の人は TSV にするだの CSV にしてもらうだのすると思うんですが、一方的にデータ貰うだけなら良いんだけど、相手とやり取りする時にはどうしても xlsx ファイル経由とかにしないと相手がこまる！やっぱりエンジニアのエは優しさのエだから相手に優しくしないとだめです。</p>

<p>で、 xslx ファイルでエンジニア以外の人とデータやり取りするとやっぱり、バージョン管理したくなるのが人情です。<br />
でも xslx ファイルはバイナリファイルなので git diff とかが残念です。。。</p>

<p>って事で作っちゃいました。</p>

<p><a href="https://github.com/yappo/p5-git-xlsx-textconv.pl">https://github.com/yappo/p5-git-xlsx-textconv.pl</a></p>

<p>xlsx2txt みたいなコマンドは結構あるけど、僕が作ったのは git diff した時に見やすさを重視してます。<br />
だいたい下の画像のようになります。</p>

<p><img src="https://camo.githubusercontent.com/64754274ec3ea639d5b2b4f6f1d71fb8ce1a93b0/687474703a2f2f742e636f2f35457069364e58485a35"></p>

<p>シート名を行頭に持ってくるので複数のシートでもだいじょうぶです。<br />
行名や列名を入れると行挿入で死ぬので入れてません。簡単ですね。</p>

<p>README.md の通りに install して .gitconfig  を設定して プロジェクトの .gitattributes を設定すればすぐに使えます。</p>

<p>僕の用途だと1行に意味がある感じのシートだからわりとこれで良いけど、列と行を特定したセルにそれぞれ意味があるなら行列を1行で区切る感じの出力にしたら便利でしょう。</p>

<p><h4>その他</h4></p>

<p>折角だけど git merge も全自動で良い感じにするラッパー書きたかったけど git には良い感じに merge warpper script を指定出来なかったようだ。。</p>

<p>あと .xlsx って実は zip file で中身は XML だったから shell だけで解決させようと思ってたんだけど、データ構造わりと面倒くて諦めた。</p>

<p>もし Perl とか使うだけで発狂するような方がいたら Ruby に移植するなりお好きにしてください。その場合のライセンスも好きに設定していいです。</p>

<p>enjoy!<br />
</p>]]>
      
    </content>
  </entry>
  <entry>
    <title>\s is space character, and includes &apos;no-break space(0xA0)&apos;.</title>
    <link rel="alternate" type="text/html" href="http://blog.yappo.jp/yappo/archives/000840.html" />
    <modified>2014-06-09T13:35:37Z</modified>
    <issued>2014-06-09T22:35:37+09:00</issued>
    <id>tag:blog.yappo.jp,2014:/yappo//1.840</id>
    <created>2014-06-09T13:35:37Z</created>
    <summary type="text/plain">perl -E &apos;my $x = pack &quot;C&quot;, 160; $x = &quot;A${x}B&quot;; say(join &quot;,&quot;, unpack &quot;C*&quot;, $x); $x =~ s/\s//; say(join &quot;,&quot;, unpack &quot;C*&quot;, $x)&apos; 65,160,66 65,66 perl -E &apos;my $x = &quot;ム&quot;; say(join &quot;,&quot;, unpack &quot;C*&quot;, $x); $x =~ s/\s//;...</summary>
    <author>
      <name>Yappo</name>
      <url>http://i.yappo.jp/</url>
      <email>yappo+yappologs@shibuya.pl</email>
    </author>
    <dc:subject>perl</dc:subject>
    <content type="text/html" mode="escaped" xml:lang="en" xml:base="http://blog.yappo.jp/yappo/">
      <![CDATA[<pre>perl -E 'my $x = pack "C", 160; $x = "A${x}B"; say(join ",", unpack "C*", $x); $x =~ s/\s//; say(join ",", unpack "C*", $x)'
65,160,66
65,66</pre>

<pre>perl -E 'my $x = "ム"; say(join ",", unpack "C*", $x); $x =~ s/\s//; say(join ",", unpack "C*", $x)'
227,131,160
227,131</pre>

<p>160 = 0xA0</p>

<p>UTF8 string に対して、うっかり byte data に対して s/\s// とかすると 0xA0 を使っている UTF8 string が broken どす。</p>

<p>\s is space character, and includes 'no-break space'.</p>]]>
      
    </content>
  </entry>
  <entry>
    <title>LINE Developer Meetup in Fukuoka #4 でしゃべってきた</title>
    <link rel="alternate" type="text/html" href="http://blog.yappo.jp/yappo/archives/000839.html" />
    <modified>2014-06-04T07:16:21Z</modified>
    <issued>2014-06-04T16:16:21+09:00</issued>
    <id>tag:blog.yappo.jp,2014:/yappo//1.839</id>
    <created>2014-06-04T07:16:21Z</created>
    <summary type="text/plain">LINE株式会社という会社が月イチでdeveloper meetupを福岡でやっている、ついては第四回目でしゃべってくるがよい、ということになったので、いってきた。わーい博多だ。 http://yappo.github.io/talks/20140528-linedm04/ 話題はどうしようかと思ったけど、普通に自分のお仕事で考えている話すか、ということでエンジニアの考え方の概要、どういう考え方で働けばいいのか、実務でどうかの話もからめてひと通りやった。30分の予定が40分近い話になってしまった。 もうちょっとコードレベルの話とかでも良かったんだけど、もう一人の資料みたらそういう感じだったので逆ばりして、意識高いだけのなんちゃってエンジニアっぽい感じのふわっとした話をしてみました。 こんな話でよかったかなあと思ったけど、懇親会で「バッチスクリプト動かす時に勇気居るの共感した」しかもお仕事で！ という人に何人も話しかけてもらったりもして、それなりに興味を持ててもらえる話ができたのかなという気はした。参加者も登録数(定員いっぱい40人)くらいは実際に来場されてたらしい。よかったよかった。 来月以降はまた全然違う方向の技術の話をしに別の人が行くと思うので、今回の話がまったく楽しめなかったという方も、これに懲りずに参加してもらえると良いのではないかと思います。 雑感 死ぬほどうビールを飲んだので1泊のうちの出費がほとんどなかった。福岡は魅力的な場所だが長期滞在したらサイフだいじょうぶそう。 冗談は置いておいても、U/Iターン採用みたいのもやるらしいし福岡良い所だから移住して働くでも良いと思うんじゃないのかな？ あと、今回の話をよりちゃんとコード書ける人レベルに落とし込んだ話を YAPC::Asia 2014 でやります。...</summary>
    <author>
      <name>Yappo</name>
      <url>http://i.yappo.jp/</url>
      <email>yappo+yappologs@shibuya.pl</email>
    </author>
    <dc:subject>music</dc:subject>
    <content type="text/html" mode="escaped" xml:lang="en" xml:base="http://blog.yappo.jp/yappo/">
      <![CDATA[<p>LINE株式会社という会社が月イチでdeveloper meetupを福岡でやっている、ついては第四回目でしゃべってくるがよい、ということになったので、いってきた。わーい博多だ。</p>

<p><a href="http://yappo.github.io/talks/20140528-linedm04/">http://yappo.github.io/talks/20140528-linedm04/</a></p>

<p>話題はどうしようかと思ったけど、普通に自分のお仕事で考えている話すか、ということでエンジニアの考え方の概要、どういう考え方で働けばいいのか、実務でどうかの話もからめてひと通りやった。30分の予定が40分近い話になってしまった。</p>

<p>もうちょっとコードレベルの話とかでも良かったんだけど、もう一人の資料みたらそういう感じだったので逆ばりして、意識高いだけのなんちゃってエンジニアっぽい感じのふわっとした話をしてみました。</p>

<p>こんな話でよかったかなあと思ったけど、懇親会で「バッチスクリプト動かす時に勇気居るの共感した」しかもお仕事で！ という人に何人も話しかけてもらったりもして、それなりに興味を持ててもらえる話ができたのかなという気はした。参加者も登録数(定員いっぱい40人)くらいは実際に来場されてたらしい。よかったよかった。</p>

<p>来月以降はまた全然違う方向の技術の話をしに別の人が行くと思うので、今回の話がまったく楽しめなかったという方も、これに懲りずに参加してもらえると良いのではないかと思います。</p>

<p><b>雑感</b><br />
死ぬほどうビールを飲んだので1泊のうちの出費がほとんどなかった。福岡は魅力的な場所だが長期滞在したらサイフだいじょうぶそう。</p>

<p>冗談は置いておいても、U/Iターン採用みたいのもやるらしいし福岡良い所だから移住して働くでも良いと思うんじゃないのかな？</p>

<p>あと、今回の話をよりちゃんとコード書ける人レベルに落とし込んだ話を YAPC::Asia 2014 でやります。</p>]]>
      
    </content>
  </entry>

</feed>