

http://perl-users.jp/articles/advent-calendar/2011/
http://atnd.org/events/22657
今年もやってきました。アドベントカレンダーの季節が!
アドベントカレンダーは特別なものです。たとえるなら図書館、公園、あるいは知の神殿のようなものです。私たちが考えたり、学んだり、知識を交換しあったりできる場所です。
既に5トラックの応募が始まってます!まだまだ席に余裕がありますので Perl に関わってる方は是非参加しましょう。
アドベントカレンダーを開始したとき、そこに広告バナーを設置し営利企業にすることもできたでしょう。しかし、私は別の道を選びました。私たちは、書き込みシステムのスリム化に努め、小さな組織であり続けています。私たちは使命を果たします。努力の無駄づかいはしません。
もしこれを読んでいる方々全員から1エントリずつの寄稿をいただけるならば、この参加者募集活動は一年に一日で済むでしょう。しかし、寄稿していただけるだけの余裕や心づもりが誰にでもあるとは限りません。それでもいいのです。というのも、充分な数の方々が毎年寄稿を決意してくださるからです。
このアドベントカレンダーを守り、維持していくため、1エントリ、1.5エントリ、2エントリなど、できる範囲でのご寄稿を考えてみていただければと思います。
よろしくお願い申し上げます。
Perl-users.jp創設者 大沢Yappo和宏

かんそうぶろぐかけってことなので、ぶくますうがのびるきょうこのたいみんぐでこうかいします。
ここのついきはげつようあさなんですが、あっとうてきにつかれててしゅっしゃできるかわからないくらいかいふくしてないのです。
なんか、こうしたほうがいいんじゃね?とか書いてるけどスルー推奨です。
なんか優等生トーク(内容ではなくて枠の使い方そのもの)ばっかりよりも、少し型を崩した時のほうが理解を深める事もあるんじゃないかなーと思ってた所で、makamakaさんのゲームのデモをやってるトークは本当に良かった。(まったくみにいってないけど!)
伝えたい目的によっては、壇上の机の前に突っ立ってるより効率よく伝える方法が他にもあるかもしれないので、ちょっと考えてみるといいかもしれない。資料の朗読をしてるだけだと後でスライド見れば良いやってことになりかねないしね。
そう言った意味では、何かしらのデモンストレーションがあると良い。takesakoさんのLTなんか殆どデモだったけどとても伝わりやすくて面白かった。
僕も大講堂の後ろの方までwiiフィットもって走ってデモしたり、講堂の前席にいるhoriigureiruとかにミサイルぶつけたりするデモをやっておこられましたね。
特にスピーカーがあまりに移動すると録画カメラで追いきれないって言われるw
とはいえ一番重視すべきなのは、リアルに交通費つかって、激安という程でもない程度の参加費を払って、時間をめいっぱいつかって、裏トラックを見るのを諦めて、わざわざ自分のセッションにやって来て頂いた方々を最大限尊重すべきなので、動画撮影班とかはあんまり気にしなくてよいのです。まぁみんな好き勝手にやり過ぎてたら本気で怒られそうだけどw
謝罪しない、最初から言い訳しない。自分の発表に自身が無かったり納得がいかなくても、謝ったり自身ないですとか言っちゃ駄目です。せめて「はじめてなのでやさしくしてね」くらいにしときましょう。これはほうぼうのプレゼン入門テキストに書いてある基本です。ただしネタの一環でやるぶんには除く。
本物の自己紹介は要らない。たかだか5分の枠で自己紹介とか本気で時間の無駄ですやめましょう。もしかしたら知らないかもしれないですが、最近のテクノロジーはすごくて、あなたの名前と発表タイトルがgihyo.jpとかに掲載されます。そしてここからのてくのろじいがもっとすごくて、gihyo.jpに乗ってる名前を検索するとあなたのプロフィールが解ります。
ただし、コミュニティなんかの成果報告とか例外だし、ほかにも例外はあるけど純粋なる技術LTで自己紹介は無駄なのは有名な話ですね。これかいてて気づいたけど僕は本トラックですら自己紹介わすれてました。
あとmayumineさんのLTは自己紹介自体がネタの重要な要素になってて面白かったので、ああいうのも別腹とおもっとります。
短時間だし慣れてないと緊張して頭が飛んでしまうこともあると思うので、一番主張したい事だけ神に書いて、キーボードの上に置いとくと、いざという時たすかるかもしれませんね。
資料作成やDan the dan-kaiとかで忙しくてあんまり見れてませんでした。
obraの話は面白くて割と聞いておりました。
スピーカーに対してはもっともっと絡んだほうがいいかなーと思いました。基本的に事前に準備終えていないスピーカーは、発表前までは資料作りに忙しくて、発表後は開放感で満載で他の人と積極的に絡んだりすることを忘れ勝ちなので、目当ての人がいたら積極的に話しかけるといいです。
ただしPC開いて寡黙になにかやってたら声かけちゃ駄目、集中途切れさせて嫌われるだけです。PCみないでたたずんでたりぼーっとしてるスピーカーは大抵「来週の晩ご飯ローテーション」「おなかすいた」「YAPC中に取り溜めてたアニメの消化スケジュール」などを考えているだけなので遠慮しないで大丈夫です。
たとえ他の人と談笑している時でも、大抵のケースでは別にYAPCじゃなくても話せる相手と話してるだけなので唐突に混ざりにいってもOKです。
まぁ唐突に混ざりにいっといて単なる自己紹介されてもイラっと来る人とかいそうなので(obraとかは平気だけど)、何かしらの話しかける相手の成果物に対する質問や感想や意見等を考えてから声をかけると、話してる事を中断して真剣に話を聞いてもらえます。
スピーカーは自分の成果物を普及しにやってくる生物なので、そういった話をしてくれる人に対するプライオリティが一番高いのです。
運が良ければ、談笑してた相手の人とかも話に参加してくれるかもしれないしね。
突発イベント的なあれはもうちょっといっぱいあったほうが面白いかとおもった。やるほう大変だけど餃子のあれてきなのだったらそんなに大変でもなかろうし、運営の治外法権でかってにやっておけばよいw
ちょっと巻き込む範囲が大きくなりそうだったり、事前にやりたい事があったら予め運営に伝えとくのは鉄の掟。僕も Perl Hackers Hub とかいう取材陣やら、商業誌に乗せる写真をパシャパシャ取りまくるような、とても厄介な事をやろうとしてたので、事前に怪鳥と941さんには情報を押し付けておいたので、トラブルなくおわりました。
なんか余ったうまい棒を入り口に運び出すミッションがあったらしいんですが、待っててくれてました。
そういう事前アナウンスなしに突発でやると大抵炎上するし、やってる途中で「だれの許可得て出店してるんじゃ」的な黒い関係者さんがやって来ちゃうかもしれないですからね。
善行だからいいでしょ。的に放置しとくとそれが悪行になったりもしますよ。この言ってる意味解らない人はUOを100年くらいROMっててください。
いままで、スピーカーの資料作成の憩いの場だったので、そのノリでみんな資料書いちゃってたのが結果的に失敗だった。受付の裏のスペースに椅子とか電源タップならべて、作業してるだけの人を押し込むような事が出来てたらスイーツエリアで談笑するひとふえたのかなー
あの黙々と作業してる空気感だと喋ってると悪い気になってしまうw
下関.pm で、ふぐとくるまえび食べるやくそくした。仙台.pmによんでアピールした。長屋.pmの偉い人にもあぴった。
二日目とか雨降ったりしてたのに、なんだかんだで天気が持ちこたえてくれて芝生に30人くらいあつまってばか騒ぎしたり飲み会で真面目にエンジニアらしい話してたりRJBS問いつめたりして、お祭り感がちゃんと引き継がれててとてもよかったです。今年は余裕ないだろうと思ってカメラ持ってこなかった。
来年はよくしらんけど、東京とか飽きてるのでどっか他の場所でやったらいいとおもう。多分集客大変だし参加者もだいぶ減るから色々たいへんだろうけど。頑張って!
アイドルに食べ物差し入れても食べてもらえないという現象を疑似体験出来たのも良かった。
あと、買って来たシューマイを食べたおっさんたちは一人100円な。

前回からPHPとかJavaScriptとかしかやってないから何も無いよなーと思いつつ、とりあえずWeb+DB PRESSの話でもしようと思って応募してたんだけど、急に Perl とかやるようになったので急遽LT二本応募とかしましたとさ。
死霊一覧はこちら http://yappo.github.com/
どんなにblogが発達しようとも、雑誌が無くなってしまおうとも、プロの編集者を通した技術的な出版物というものは大事です。このセッションは、その間口を広げようとするのを目的としました。
前日まで本当にスライドどうしようか良いアイデアが無かったんだけど、発表として伝えたい事は「誰でもこういう事できるんだよ。みんなもやりなよ。」っていうのだったので、年末に発売される回のサプライズな企画の紹介から始まって軽く背景の説明をしておいて残りの時間で会場内に居る関係者を招集して、何も特別な事なんか無いんだよ感を重視して、それぞれの話をしてもらいました。
セッション(この回はあくまでもトークとは言わない)の性質上、エンジニアが得する成果物の発表は無理ゲーなのですが、執筆する事に二の足を踏んでいる人の背中を押せたらいいなと思って、だいぶゆるふわざっくばらんに進行しました。
無茶ぶりで前に出て来てもらった人には、本当に事前に何も話していなかったのでgdgdっていた模様ですが(僕はinaoさんにマイク渡したらdanさんを呼びに外出てて、様子を知らない)、僕は事前に様々なパターンを入念にシミュレーションしてから挑んでいたので上手くまとめられたんじゃないかと思っています。
YAPC - Yet Anthor Perl Conference - Conference - 会議
「会議のはずなのに、授業のように一方通行のセッションだけってのもあんまり面白くないよなー」、「海外のカンファレンス(osdc.twしかいってないけど)、プレゼン中に観衆から発言が飛び出してきて、そこから議論が始まっていって最終的にスピーカーがまとめてオチをつけたりするよなー」「日本ってそういうのやってないよなー」って言うもやもやが頭に合った所に、前夜祭の帰りにロックスターが「日本人ってスライド詰めすぎだよね。もっとゆったりしてもいいのに」的な事を言っていたので、こういう方向性に決まりました。
本当はBOFっぽい感じにもってくつもりだったんだけど、時間が足りなかったのであきらめました。
xaicon-san, nekokak-san, kazeburo-san, dan-san, inao-san無茶ぶり引き受けて頂いて有り難うございました。
AnySan, ikachan を遂に shipit しましたよ。の話と、 ikachan の紹介を LT しました。
うちのプロジェクトのなかで、入社してから皆で作っていた開発環境等が良い感じになったので、他のプロジェクトの同僚向けのプレゼン。
基本的には小さなツールをいっぱい作って UNIX 的に作って行ったら良い感じになったよー。こういうツールがあって便利だよーみたいな話をしました。
LTの割にボリューム多過ぎたのでだいぶ割愛しましたが、要点だけ話せたかなと思います。
続きは社内でやると、僕ぺーぺーで色々ししょうありそうなんで、soozyconとかshibuya.pmで発表したいなーと思います。
唐突にスイーツエリアを占拠して、12月に発売される予定のPerl連載記事用の公開座談会を開催しました。Perl Hackers Hubという名前の通り、折角世界中からPerl Hackerが集まるのでどうにかして出演して欲しいという思いが去年からあったのですが、去年は連載一回目だしlestrratさんもYAPCの運営的に余裕無さそうだから諦めて、今年はなんか行けそうだからxaicronにdanさんに出演交渉依頼を依頼して快諾してもらえたので、開催する運びとなりました。
普段商業誌のインタビューとかって閉じられた空間で開催されるイメージなんですが、今回は会場のタイムテーブル抑えて誰でも参加可能な感じに仕上げてみました。時折野次が入る等なかなか面白い事になったんじゃないかなーと思うのですが、基本僕は裏方でうろちょろしてたので何話してたのか把握してません!
いつかは将来的には海外の方にも参加してもらいたいなーと思っていて、こんなに速く実現するとは夢にもおもいませんでした。
参加者が「obra, rjbs, mlehmann, sartak, gugod, dankogai, tokuhirom, xaicron」と Perl HackerどころかPerl Core Hackerが集まってしまいましたね。
座談会の最後にはサプライズな発表もありました。詳しくは12月末発売のWeb+DB PRESSにて、全ては @mandy_44 の頑張りにかかっている!11乞うご期待。
参加者もろもろの予定の合間を縫った結果、tsucchi-san, motemen-sanの発表枠を直前で移動して頂きました。お二方のご協力、ほんとうに有り難うございました。

たまたまhttp://twitter.com/kazeburo/status/103842813548040192を見かけたのでネタで作ってみただけのコード。
https://github.com/yappo/p5-Plack-Middleware-ErrorpageRedirectloopDefence
今回のリクエストが前回みてたURLと同じなのに関わらず、エラーページを返しちゃう場合にブラウザ側でのコンテンツの更新を抑止する為のmiddleware。
サンプルはhttps://github.com/yappo/p5-Plack-Middleware-ErrorpageRedirectloopDefence/blob/master/sample.psgiみたいなかんじ。
普通にplackupした時に http://localhost:5000/ok にアクセスすると3秒毎にリロードが発生しますが、 http::/localhost:5000/error とかにアクセスすると、リロードが一回しか行われないのが解るとおもいます。
エラーページを表示しているのに、自分自身をリロードする事になってしまう理由は色々考えられますが、エラーページを何回もリロードする意味は無いよねと思って作ってみただけです。
マジレスすると

皆さんは、日々のお仕事の中で様々なバッチ処理やデプロイツールまたはCIツールを動かすと思います。
一般的なネット系のエンジニアは仕事のコミュニケーション手段として IRC を用いているというのが有名ですが、これらバッチ処理の処理状況等を普段の生活環境である IRC に流せたら便利です。
実際に前の会社では、 deploy tool, ci tool, etc batch script の処理結果を社内 IRC channel に通知するような物を hirose31 さんが作ってくれて、とても便利でございました。
とはいえ、各種スクリプトが独自に IRC server に繋ぎに行く事は大げさですし、バッチが走る都度 join/part されたらうざいです。
そこで前の会社では、 IRC server につながりっぱなしなサーバを立てて置いて、 iDC などのインフラからいつでも何処でも IKC を使ってメッセージを送ると指定したチャンネルにメッセージを投げてくれると言う便利な物がありました。
実際自分が担当していないプロジェクトでも、今現在他のサービスでどんな作業が行われてるかをリアルタイムで把握出来るのは、その会社で働いている上でとても役に立つ事が多いです。
狙いとしては、こうした簡単に通知を行うインフラが整う事で、気軽に各種処理状況が共有出来るようになる事により、今まで何かの処理スクリプトを叩いて IRC とかで手作業で結果報告していたような類いの要件も、全自動化される事により飯が捗るといった事を期待しています。
実際 deploy tool とかに仕込んどくだけでもだいぶ便利ですけどね。
と言うような事をもんもんと思っていたのでさっき作りました。
https://github.com/yappo/p5-App-Ikachan
依存モジュールも、 AnyEvent, Plack, Twigyy, AnySan 程度で且つ、実際は1つの小さいスクリプトファイルなので扱いやすいとは思います。
(とはいえ AnySan が github にしかなくて install 面倒いので、そろそろ CPAN にうpりますが。。。)
使い方もとても簡単で
$ ikachan -S irc_server_address -N nickname[ -K irc_server_password][ -P irc_server_port]という形でサーバを立ち上げるだけです。
$ ikachan -h http_host -p http_portといったオプションも利用可能です。
チャンネルに入るには
$ curl -F channel=\#catalyst-ja http://localhost:4979/joinが使えます。
チャンネルを抜けるには
$ curl -F channel=\#catalyst-ja http://localhost:4979/leaveが使えます。
チャンネルにポストするには
$ curl -F channel=\#catalyst-ja -F message=こんにちわこんにちわ! http://localhost:4979/noticeが使えます。
ikachan はどのチャンネルに join したか等の情報をストレージに保存しないので、一度プロセスを殺したら、まえ入っていたチャンネルが解らなくなります。( http://localhost:4979/channel_list の内容をバックアップしとけばいいけど )
なので、 notice コマンドを送る時には join コマンドを一緒に送る事をお勧めします。
$ curl -F channel=\#catalyst-ja http://localhost:4979/join $ curl -F channel=\#catalyst-ja -F message=こんにちわこんにちわ! http://localhost:4979/notice
ikachan を操作するプロトコルは HTTP なので、様々な言語や環境で扱いやすいんじゃないかなと思います。ので、これを機に是非お試し下さい。
作って早々、 kazeburo さんに社内サーバに設置してもらって、作り途中の開発支援ツールに導入して便利になった予定です!
作った後に、まったく同じ事をする kan さんが作った App::donburi の存在に気づいたのですが、ちょっとおおがかりだし founder が irc 使わない会社に転職したりで、やっぱり知ってても使わなかったと思った。

Perl 終了時のゴミ回収フェーズに入ってるかどうかを調べるモジュール。
くわしくはhttp://perl-users.jp/expert_perl/hentai_modules.htmlでも見ればおk。
一番したに貼付けたサンプルコードを見ると、きっちり END フェーズの後にフラグが立ってるのがわかる。
しかし、 do と normal の実行順序が違うのが気になった。これは do ブロックの中に文を追加すると想定通りの実行順になるので、 perl 側でなんか最適化してるのかなーとかおもた。
ので B::Deparse さんの出番だとおもったけど https://gist.github.com/1145662よーわからん。
あ、 perl 5.14.1

Mac OS X 10.7 から普通に💩💩💩💩💩
などの絵文字が取り扱えるようになりましたので Encode::JP::Mobile で扱えるのかどうか調べたらいいのかなと思ったのでメモ。
このへん kawanet さんが詳しそう。

最近あたらしい Perl の環境を作って LWP を入れて https なページにアクセスしようとしたら
LWP will support https URLs if the LWP::Protocol::https module is installed.って言われてビビるかもしれません。
それは https 対応するモジュールが別ですと李に分離されたためです。
そういう時は迷わずLWP::Protocol::httpsを入れればいいです。

今話題の、お前のリアルな行動履歴はJobs様に筒抜けの件ですが、sugyan++ するだけでiPhoneのトラッキングファイル抽出作ってもらったので、それつかってiPhoneの移動履歴をGoogle Mapでストリーミングするツール書いたよ。
https://github.com/yappo/iPhoneTracker
適当に動かしてSafariとかで開いてください。
全部再生し終わったらプロセス殺してあげ直すとかそういうので。
s/Wifi/Cell/ にすると基地局をプロットします。デフォルトはWifiアンテナの位置なのでより精密です。
彼女の電話をハックするネタが前の飲み会で話題になっていて、いつかやりたいなーと思っていたのですが、遂に出来てよかった^^
ちなみに私のはこんな感じでした。


もともとはヌーブラアプリを作るためにiPhoneの開発環境を作ったのですが、ちょっと気が向いてim.kayackみたいなのを作ってみました。
im.kayack使えば良いじゃんって話もありますが、着信音を僕の好きな音とか声とかにしたかったので作ったのです。
通知の時にならす時には、hoge.appを作った時に一緒にコンパイルされてないと駄目なんです。
同時にコンパイルされちゃってさえいれば、通知するサーバ側の都合で音声を選べるという感じ。
yappocallは何かというと、YappoのiPhoneに好きな音声と共に秘密のメッセージを送れる超便利サービスです。
http://seiitaishougun.com/iphone/yappocall.cgi
で、いつでもどこでも好きな時に僕宛に秘密のメッセージを送れます。
人生相談、ピザの注文、プロポーズまで幅広くお使い下さい。
すでに、ランチのお誘い、ワインのお誘い、ごじます、おススメマッサージ店のご紹介、地震速報、新入社員の愚痴、AKBのセンターはtokuhiromがなるべきというご提案、挿入持ってくる、じゃーん!、おごれアピールなど多種多様のcallを受けております。
なんでこのエントリを核期になったかというと
これ仕組みしりたいです・・・
仕組みはiPhoneのAPIでRemote Push Notifiyとかそういう仕組みが用意されてるので、頑張って実装して下さい。
そんな頑張んなくてもPush通知使いたい!ってAPIを叩くと自動的にappleのサーバに問い合わせて、その端末に紐づいた Device Token を引数にどっかのメソッドが delegate されて呼ばれるので、そこで好きなように device token をサーバ側に持ってくれば良いだけですね。
簡単です。
サーバーの方はとっても簡単で yappocall.cgi を用意して、 worker.pl をローカルで実行させるだけです。
Apple の Server に通知を送りつける専用プロセスが必要なのが面倒ですが、短時間に接続するとbanされる可能性もあるってtypesterのお兄さんが言っていたのでsocketを使い回してbanを防ぐ作戦をしています。
CGI と Worker の間の通信は今大人気の MessagePack を使ってるので安心高速ですね!
残念なのは Net::APNS::Persistent は、 socket 切れたら放置される実装になってるので、直すのも面倒なので前回の通知処理から30分以上たってたら socket 繋ぎ直すようにしてあります。
烏賊ソース

おれなんかだいぶ昔からふぇいすぶうkしてるんだけど、皆さんはいまさらブームらしいですね。
いままで真面目にふぇぃすびっくのAPIとかそういうの触ってなかったんですが触ってみたついでに、shipitしたらFacebookにお知らせするやつ書きました。
http://frepan.org/~yappo/ShipIt-Step-Facebook-0.01/
https://github.com/yappo/p5-ShipIt-Step-Facebook
基本的にはhanekomuのShipIt::Step::Twitterのコピーとなっております。
違うのはpostするurlにfrepanを指定できる位。
postするWallとかも変更できるので、CPANおーさーの皆様は自分のファンページにでも向けて通知すると良いんじゃないでしょうかね?
てかレガシーな方のAPIだと、uid変えればファンページに直接投稿できるのにGraph APIだと
kazuhiro osawa => Yappoみたいな事になって嫌な感じなんだけど誰かしりませんか!?APIリファレンス見ても出来なさそうなんですけど。。。
あと良く判らないのは、access_tokenを取るために僕が作ったアプリケーションのApplication IDをaccess_token作るツールに埋め込んであるんだけど、それってやっていいのかな?という。
この使い方だとapp keyもapp secretも使わないで済むんだけどそれでいいの?とか。
あと、なんかふぁんぺーじに25人以上はいるとパーマリンクつくれるらしいんで入って下さい

HTML5 から offline application を作るための強力な機能として application cache が追加されています。
これのキャッシュを制御する方法としては、専用の manifest ファイルを書かなければいけないんですが、手で書くのもだるいし専用コマンド作るのも打つのもだるいので
$ make html5manifestってコマンド叩いたら htdocs 以下を勝手に探索して manifest ファイルを作ってくれる物をこしらえました。
http://frepan.org/~yappo/HTML5-Manifest-0.02/
http://frepan.org/~yappo/Module-Install-HTML5Manifest-0.01/
そのうちCPANにも登録されます。
ディレクトリの中から対象となるファイルを集めて来て manifest ファイルを作るための HTML5::Manifest というモジュールと、 HTML5::Manifest と Makefile の繋ぎ込みをしてくれる Module::Install::HTML5Manifest というモジュールの二本立てにしました。
HTML5::Manifest 単体の使い方は、きっとだれかが PSGI な middleware 書くだろうから今回は省略しておいて Makefile.PL での使い方をさらっと説明します。
POD に書いてあるのであんまり言う事ないですが
html5_manifest
make_target => 'hoge',
htdocs_from => 'htdocs',
manifest_skip => 'html5manifest.skip',
generate_to => 'example.manifest',
with_gzfile => 1, # create .gz file
network_list => [qw( /api /foo/bar.cgi )],
use_digest => 1,
;
とかして使います。
make_target は Makefile のターゲットを変更します。この例だと
$ make hogeで manifest ファイルを作るって事。
htdocs_from は、どのパスを起点にしてキャッシュするファイルのリストを作成するかを指定します。
普通に document root を指定するべきですね。
manifest_skip は、 htdocs_from で指定したパスをトラバースする時に、無視するファイルパターンを記述してあるファイルを指定します。
MANIFEST.SKIP と同じ役割です。
generate_to は、実際に作られた manifest ファイルを保存する先です。
with_gzfile は、真の値を渡すと generate_to と共に .gz ファイルも作成します。
manifest ファイルが、そこそこの大きさになったときに .gz 化してサーブする事を想定しています。
network_list は、 manifest ファイルの NETWORK セクションにそのまま書き出されるリストです。 NETWORK セクションについてはググれ。
use_digest は、キャッシュ対象のファイル全部の MD5 チェックサムを manifest ファイルの中に書き込みます。
ファイル構成がかわらなくても、どれかのファイルの内容が変更になったらチェックサムが変わるので「manifestファイルが更新されたら、キャッシュを更新する」という application cache の仕様を満たす事が出来ます。
手で、一々バージョン番号ふったり make html5manifest した日時を自動的にいれるとか面倒ですよね。
HTML5 っていう名前空間は、仕様の名前を使ってるから問題無いという判断。だれだって HTML::HTML5 とかタイプしたいと思う人なんかいないし。
ということで Perl で HTML5 をやっている方はお試しください。

FizzBuzz問題程度30byte以内で解かないと、今時はYahoo!Japanすら満足に入社できないそうなので、課題提出しておきます。
皆さんご存知の通りPerlを使えば1byteもコードを書かずにFizzBuzz問題が解けてしまいます。
今日現在のバージョンのPerlでは、何かしらの方法でAcme::FizzBuzzモジュールをインストールします。奇遇にも最近新しいバージョンが出ました。
インストールしたら、今度は
export PERL5OPT="-MAcme::FizzBuzz"としておまじないをかけます(bash shellの時)。他の環境でのおまじないについてはTAKESAKO @ Yet another Cybozu Labs: FizzBuzz - Golf Challengeを参考にして下さい。
準備が整ったら0バイトのコードを用意してPerlで処理します。
今回はエディタ起動するのが面倒なのでechoコマンドで代用です。
echo '' | perl
なんということでしょう。30byte未満でFizzBuzzのコードが書けてしまいました。
やふーの事ですからPerlがだめっていうかもしれません!
そうだったらシェルすくりぷとで30byte未満で書く方法を実装しました!
curl http://bp.to/yahoo.txt27byteで問題解けましたね!
マジレスすると、途方も無い苦労をかけてAcme::FizzBuzzをPerlに標準で添付されるモジュールにしてしまえば
use Acme::FizzBuzzという18byteのコードで本当に実現してしまうんですけどねー

こっちが本題なんだけど、わざわざブラウザ開いて Pikuboream とか見てるのだるいんで AnySan と Cocoa::Growl つかって pikubo に写真投稿した tweet があったらリアルタイムに growl で表示するやつ書いたし。
https://github.com/yappo/p5-AnySan/blob/master/eg/pikubo-growler.pl
Growl の通知アイコンに撮影した写真を設定して、 growl をクリックすると URL をブラウザで開いてくれる優れもの。growlを見るだけでどんな写真がうpされてるかわかっちゃう。
System Perl に依存して、必要なモジュールを全部詰め込んで PikuboGrowler.app として、出したかったけど全自動で consumer_key とか token を取る方法が良くわからないのでおあずけ中。
FriendFeed に pikubo.me な tweet を全部流してそっちを見ればいいのかなx。。。
コードは以下の感じ。単純ですね!

表題の通り Groonga さんの Perl バインディングかき始めてます。
Groonga とは senna の後継検索エンジンで、サーバとかついてるんですが Groonga for Perl では libgroonga のバインディングを作ってく感じになるので、 Groonga のサーバとか叩くような物は提供しません。
https://github.com/yappo/p5-Groongaでやってます。
libgroonga を直接叩く事によって Groonga の Ruby バインディングで提供されてるような特定のキーワードに対してマークアップするフィルタのような事も簡単に作れます。
rroonga での tag_keys を Perl に移植すると以下のような感じになります。
Groonga に対する入出力はバイトストリームにする感じです。
ノーマライズ処理がまだうまく動いてないどうすればいいんだroge.
ちなみに、まだパトリシアトライを弄る部分しか実装されてないので、他の機能が欲しいと言う方は是非パッチ送って下さい。
大昔に Rast の Perl バインディング書いてた時は、 XS 書くのが辛かったんですが今だと Module::Install::XSUtil やら XS::Object::Magic のお陰でめちゃんこ楽に書けるようになってますね。
数少ない優良なバインディング案件ですので、皆さん是非開発に参加してください。

なんかの時に、お勧めの growl を扱うモジュールの話をした時に、最近の俺の macbook pro では Mac::Growl が入らなくなって悲しいって話をしてたら typester さんが Cocoa::Growl を作ってくれました。
Objective-C をそのまま XS module 化しててイカすんですが、さらに AnyEvent のイベントループを cocoa のイベントループを使うようにする AnyEvent::Impl::NSRunLoop なんてのまで作っちゃって、
これを使うと growl の通知をクリックしたイベントとかを Perl 側でハンドリング出来ちゃったりして面白そうだけど使いどころ良くわからなかったので、 AnySan で繋いでる irc チャンネルに yappo って含む発言があったら growl で通知して、それをクリックすると irc の方に click って発言する bot を書いてみました。
なんか俺の事を話題にしてるけど返事する暇無いけど、その発言俺みたから!ってのを伝えたい用途に使えると思います!
ちなみに Cocoa::Growl はアイコン画像対応が終わったら shipit されるそうです。
追記:もちっと実用的に friend feed の cpan を流し続ける growler も書いときました。

だいぶ報告が遅れましたが、11月27日に福岡の博多でFUkuoka.PM #18が開催されて、なんと幸運にも招待していただいたので発表しに行ってきました。
事の経緯としてはYAPC::Asia 2010の飲み会でフラグを立てたところ、あれよあれよという真に招待して頂いて何とただで行く事ができました。
なんでただで行けたかというとJPAの新しい試み第1号に選んで頂けたおかげです。
今後も遠方に派遣するような試みを可能な限りJPAでやっていくそうなので「この地方のPerlの催しに行ってみたい!」「この人を呼んで合いたい!喋りたい!喋らせたい!」という方々はJPAに一声かけるか騒ぐかしてみると良いかと思います。
JPAだけの負担だけでは無くて、参加者の方々からも宿代をカンパしていただく形を取っているので、皆さんに感謝しなければなりません。
想像の通りですが、技術的なトレンドとかは地域のギャップなんかは少なくて、主目的は人と人が顔合わせてわいわい話していける部分が重要だなーとおもいました。
遠距離だからこそ料理屋とかでフリーダムに話すのが大事かなと。
宴会の場でも真面目なディスカッションとかしてたんですが、まー美味しいのを飲み食いして心の壁を無くしておけばいざオンラインとかでガチンコの討論する場面になった時に、遠慮しないで相手の懐に踏み込んだ討論がし易くなるので、そういったのも大事かもなーという
なんか吉岡さんの日記みたいでやになったのでこの辺で割愛。
Fukuoka.PMの全体的な印象は、参加者全員がdankogaiだな。と。
どういう事かというと、皆さんとても良く質問がでる。で、そのままディスカッションに突入する。
斜め上の質問とかもなく的を得たディスカッションになっているので、まるで海外のカンファレンスに来てるかのようでした。
このへんは関東人は真似するべきですね。
まー14時スタートで18時前くらいにおわって、そのまま宴会コースという余裕のありすぎるスケジュールというのも影響してそうですがw
質問のしやすさはカンファレンスのゆったり具合に関係してるかなと思ったのは昨日のshibuya.pmの発表者がshibuya.pmにしては珍しくゆったりしてたというのがヒントになりそうだけど、それは別の話。
プライマリPMはShibuya.PMだと思っていて、セカンダリPMとしては僕はよくYokohama.PMに遊びにいっているのですが、Fukuoka.PMの印象としてはだいぶYokohama.PMよりですね。単純にそれは参加人数が学校のクラスメイトと同等以下の規模感というのと、お互いの参加者同士が何となく皆知り合い感があるからだとおもいます。
前もcanadieさんのOkayama.PM人集まらない問題を書いたけども、規模感と参加者同士の距離感は一つのテーマとしておいておきましょう。
今回の発表は、Web+DB PRESSで連載しているFicia周りのWebUIネタの総編集版とFiciaで気づいたPerl周りの話をしてきました。
Perl周りの話はちょっと古い話題なんですが参考としてどうぞ。
http://yappo.github.com/talks/20101127-fukuoka.pm18-webui/
1次会はもつ鍋を食べていて、遠距離恋愛してる人に言われるまでもつ鍋が博多の名物だとしりませんでした!!!
博多は豚骨ラーメンと高菜と明太子の街だとおもってましたサーセン><
で、ビール飲みながらもつ鍋つついてたんですが、今度は2次会では美味しい焼酎がでるバーに移動して飲み易い焼酎ばっかり飲んでおりました。
で、ホテルのチェックイン時刻を24時に設定してたので、とりあえずチェックインだけしてとんぼ返りで合流して3次会の店へ。
あんまり覚えてないけどわんこそば的に出てくるつけ麺が死ぬ程上手くて無限ラーメンしてました。
で、記憶があやふやなまま26時前にホテルにもどって気づいたらた貴花田親方に激似のおっさんがベットの上で僕の上に乗ってたけど、それは別の話。
で、気づいたら朝10時前で二日酔いでフラフラになりながらホテルから博多駅に行って、地下鉄で呉服町までいって次のルートで博多駅まであるいてきました、
そして、そのままタクシーで空港まで行って帰宅です。帰りの飛行機で羽田の滑走路が使用禁止になって30分くらい大島の上を旋回したのは良い思いで。
ということで、lestrratさんならびにFukuoka.PMの皆様有り難うございました!本来の目的未達成なのでまた行きます!あとHokkaido.PMでスキーとミョウバンぬきの生ウニ食い放題したいです!

もう12月まで1週間切っちゃうのでさっさとatnd募集開始しましたよ。
公開場所はいつも通りのよていで、記事の投稿の仕方はまだ決まってないけど、書きたい事がある人は登録だけしとけば、あとはどうにかなると思います。
今年はadvent calendarのようなものを出版の世界にも持っていったし、良い記事が沢山あつまるので、他の言語や他の業界の人も真似するとよいです!
去年は本編とは別にORMのトラックもありましたが、今年も「Acme Trackやりたい!」「Win32 Track」やりたい!
とかの、特化型のカレンダートラックやりたい人がいれば一緒にやれば良いと思います。
心当たりのある人は、#perl-casual@chant.freenode.net やら twitter あたりで叫びましょう。
個人的には出版関係者トラックとかやってほしいです。
今年はコーヒー一杯でマーケティングしてもらうので、きっと全トラック埋まる事でしょう。
じゃぁはりきってまいりましょう

ほんっと奇遇なんですけど。ちょうたまたまなんですけど。AnySanにFriendFeed対応した所に。いや本当に偶然なんですけど。
最新 CPAN モジュールをつぶやく Twitter BOT を書いた - punitanのメモっていうエントリを見たので。
ほんと、超偶然なんですけどAnySanでもFriendFeedをリアルタイムで処理出来るようになっちゃってたので、ほんと偶然だけど。
なので、CPAN - FriendFeedからリアルタイムでデータを取ってきてTwitterで呟くbotを書いてみました。
たまたま、AnySan::Provider::Twitterでも、streaming apiを使わないモードとかを実験的に付けたので(偶然ですけど)、無駄なストリーミングAPIの接続もしません。
AnySan使えば、cpan botやりつつperlismてきなボットも1個のプロセスで実現出来そうです。
いや、偶然って恐いですね。

日本語の文章をzenrize(全裸化)するAcme::Zenraっていうのを作ったを見たので、折角なのでAnyEvent::IRC::Clientを直で使ってる部分をAnySanで書き換えました。
生で使ってる時と比べると、AnySanを使うとよりbot本体のコードを書くことに注力できる事がわかるとおもいます。(まだまだAnySanでのAPIの洗練は必要だけど)
let's enjoy irc hacking!

今年もPerl Monger共の日頃の行いが良いお陰で、天候が悪い中雨は降らずに事故も無く無事に終われてとてもよかった!
YAPCといえばカンファレンスなので講演を聞くだけの会とも思われそうなんですが、YAPCとは国際的なカンファレンスであり日本国内からも遠路はるばる参加している方も沢山います。
って事で、ちょっと座ってるのに疲れちゃったりしたら外に出て知らない人とおしゃべりするのも良いかと思いますね。共通の話題はあるので困る事は無い筈です。
かく言う自分は、二日目とか土曜日だし天気も良い事があって王将でいっぱい餃子買ってきてスーパーでビールしこたま買って餃子カンファレンスしてました。
芝生ではOkayama.PMのcanadieさんと初対面で色々話してたんですが「人が8人しか集まらないのが悩みなんです」って言ってたので「世界中のPerl Mongers見ると多い方だし、活動内容も居酒屋に集まってperlの話してる所いっぱいあるから、なんの問題も無い!むしろOkayama.PMで150人とか集まったら恐いっしょ!なのでマイペースに頑張って下さい!」っていう、ネット越しだと誤解されて炎上しそうなギリギリの話とかも気軽にできたりしました。もちろん酒はいって勢いあるってのもあるけど!
あーあと、芝生以外にも良い場所を見つけて発表前のacotieを捕まえて数千円握らせてビール買ってきてもらって(すっごいキレてたけど)、みんなで飲んでましたね。
acotieの発表後に丁度ビールが切れてたので、また捕まえて買ってきてもらうという(with @sugyan @kyanny)、というお三方はビール買ってきてくれて本当に有り難うございました。とくに刺身さんはビール飲まない人なのに。。。
なんというか、自分の発表が全部終わってフリーダムに無限ビールしてたわけですが、皆さんの感想でもYAPCは祭りだ!って感想が出てる通り祭りを楽しむために延々とみんなにビール渡して盛り上がっとりました。
お祭り騒ぎではあるけども、皆節度守って喧嘩も無く終わられて本当によかったです。
真面目に講演聞きに来た人、真面目に運営してる人に取っては良い迷惑だったかもしれないですが、目くじら立ててる人とかもいなかったっぽいので、こういう物事を本気で楽しめる人達の輪がPerlの魅力なんだと再認識できました。
コードだけではなく人が重要なファクターなんですね。Perlが好きなのはPerlに関わる人込みなんだな。と。
一日目の二次会はdragon3などFukuoka.pmの面々と相席になったくせにグロッキーしててマトモな会話すら出来なくて本当もうしわけ無かったのですが、perlやってればいつかまた合えるので、そんなに気にしない事にしました!
なんかJPA会長が福岡釣れてってくれるフラグ立ててる事ですし!
なんだかんだで嬉しいのは、お前の作ったの使ってるよ!とか言ってくれる事で、@kuzuhaが初日の芝生で使ってるよ!といってくれてました。もちろん初日はグロッキーで(以下略
本編発表後では@monjudohさんが声かけてくれて「連載の最初の話とか良かったよ!」とか言ってくれて嬉しかったですね。とくにWEB+DB PRESSの連載は読んでる人が直接感想を伝えてきてくれる機会がなかなか無いので貴重でした。
そういえば。ごく一部で女性参加者ふやしょう!とかネタで話してた人がいたけど、マジレスするとYAPCが「ガールズ(笑)せっしょん☆」とか「今年のLTからドラ娘がいます!」とかやり出したら参加する気うせるなーと思うしだい。
コードとか書く上で何の訳にもたたない性差を持ち出してうんたらするなんて論理的に考えて意味のない事だし、そんな事で怒るとか青筋の無駄だから、YAPCでは良くわからん事はやらないで欲しいすなーと思っとります。
ちんこついてない人の参加比率が高い所行きたかったり、女としてチヤホヤしてほしいなら合コンでも言ってやがれってこった。「女だから手加減してね☆」とか言う馬鹿は顔も見たくない。※
そのへんは、この界隈の人は良い意味で女の人のエンジニアを特別扱いする事が嫌いな人だらけなので問題無いとおもいますが。
全員の名前を出すと長くなりすぎるので、@941さんそして運営側の皆さん、発表者の皆さん、参加者の皆さん有り難うございました。
そしてすでにhttp://yapc.asia/では来年の計画が動こうとしています。
see you next YAPC
あ、自分の発表について書くの忘れてた。。。
本編の話は、JSTAPdの使い方について話しました。
今まで20分talkばっかりでいっつも時間足りなくて駆け足になってたのを反省して40分にしました。
だいぶ時間が余りそうだからおまけを用意していたんですが、結局おまけなしで40分で終わった感じでした。
誰かが20分とかじゃなくて、せっかくだから40分で応募すべきとか言ってたんですが、すっごい軽い話題でもない限りは40分にしといた方がいいと思った秋。
http://yappo.github.com/talks/20101016-yapcasia2010-jstapd/
IRC/Twitterを使ったメッセージ系のアプリケンーションを、書くサービスの処理を抽象化して簡単に書くためのフレームワークです。
irc botやらtwitter botなどが簡単にかけます。そしてirc/twitterを組み合わせたbotやら、AnyEvent なので他のネットワーク処理などと組み合わせて夢膨らむ。
http://yappo.github.com/talks/20101015-yapcasia2010-lt/
例えばTwitter IRC Gatewayとかこんなに簡単にかけます。
http://github.com/yappo/p5-AnySan/blob/master/eg/tig-for-anysan.pl
hackathonにて、発表時とちょっと実装変わってしまったんですが、もう少しして落ち着いたらちゃんとアナウンスする予定です。
はっかそんといえば、、、話が長くなるので、hackathonの時の写真込みのアルバムでも見てくださいです。
http://yappo.ficia.com/pl/album/A6E027E6-D9AF-11DF-A14C-378C2C411CC7
じゃ、そういうことでまた!

Shibuya Perl Mongersテクニカルトーク#14での僕の文の発表資料です。
http://github.com/yappo/shibuyapm-stream
動かすためにはAnySanが必要で、ここから取得出来ます。
http://github.com/yappo/p5-AnySan
当日バグバグだった部分はもろもろ治ってます。
デフォルトではshibuyapmでtwitter searchした結果をストリーミングするんですが、引数を与える事で任意のキーワードでストリーミングできます。
$ perl shibuya-stream.pl perl
背景画像がだいぶグレーな感じなんですが、あそこのプロジェクタの環境でやると、このくらいグレーじゃないと白くなりすぎて文字が見にくくなるんですよね。
IIJのサブスクリーンで出す機会がある人は参考にして下さい。
という事でShibuya.PM #14お疲れさまでした。

報告が遅くなりましたが、OSDC.tw 2010でJSTAPdの発表をしてきました。基本的にスライドは日本語無いですが、本編の方は日本語で発表してきました。やっぱり中文はtypoだらけだったようです。
この発表に併せて、JSTAPdももろもろ改善されております。まだCPANの方は古いままですがgithubに上がってる方ではHTTP::EngineからPlack+Twiggyに変更となってます。
既存の仕組みではtestが全て完了されてるかどうかをserverがわに数msec置きに問い合わせまくっているという仕様だったのですが、Twiggyを使ってtestが終了したかどうかを確認するHTTPセッションをlongpollで一つだけ張っておいて、テストが終了しだいresponseを返すという事をするようにしたので余計な負荷をかけないで済んでる感じです。その他のサーバにリクエスト投げつけまくる系の物をlong pollするようにしてあります。
あとは jstapd -n した時に作成されるテストのテンプレートファイルの構造を見直して、デフォルトでは*.t, *.html, *.jsとファイルを別けるようにしてあります。
ちょっと、まだ仕様が変わるかもですが、もうすこし落ち着いてからドキュメントをupdateしてCPANに0.02をあげたいと思ってるところです。
初めて海外で発表するのに、スライド事前準備してないどころか前日に迷子になって深夜徘徊するとかありえないですね!

FiciaがEye-Fiからのアップロードに対応したついでに、Eye-Fiからの受け口がGR2プロトコルなんで折角なんでGR2プロトコルしゃべってFiciaにアップロード出来るスクリプト書いてみたよ。
使い方は簡単なんですが、最初にFiciaからEye-Fiアップロード用のトークンを取る必要があるんですが、それは写真アップロードする所

の中に「Eye-Fiでアップロード」ってのが追加されてるので、そこクリックして「次へ」ってやってくと「パスワード」っていうハッシュっぽい文字列が出るので、これをコピーしときます。
そのパスワードをFICIA_EYEFI_PASSWORD環境変数にセットして
$ perl ./ficia-eyefi-uploader.pl アップロードしたい画像ファイル.jpgってするとアップロードされるはずです。
一点注意点としては、一度あげたファイルは二度とあげられないくらいです。
この辺は専用クライアントとかだと出来るんですがEye-Fi経由だと出来ないし、そもそもEye-Fiでは二度送信するユースケースが無いのでしょうがないです。
画像削除してもあげられないので注意してください。なんでかっていうといらない写真消したつもりなのにsyncしたら消した画像がまたuploadされてたらイラっとくるでしょ?
この例だと、画像一枚しかあげられないんですが肝心なのはOreOre::FiciaUploadByGR2に処理が入ってるんで、ディレクトリ丸ごとアップロードとか直ぐに作れると思うす。
もっとデーモン的なのがいいよーって人はhirose31さんのdoumekiとか使っとけば良いんじゃないのかなーと思います。
スクリプトは以下の通り。

ふとしたきっかけでPHPのリファレンスマニュアルにある関数と同等の機能をPerlで実装するにはどうするか?といったリファレンスを作るプロジェクトを始めました。
PHP使いの人がPerlを弄る時に「PHPのこれPerlでどうやれば良いんだ!」といった要望や、ごく普通のPerl使いの人が「これどうやって書けば良いのかな?」って時に使うcookbook代わりに使える事を想定しています。
ドキュメント管理にはgithubhttp://github.com/yappo/docs-php-funcref-in-perlを使い、ドキュメントのビューワーとしてwikihubWikiHub :: php-funcref-in-perl :: READMEを使っています。
書いて欲しいと思った人にはあらかたコラボレータ入れてるので、ドキュメント充実させたいと思ったらすぐにprivate repoをcloneして書けると思います。「俺入って無いし書きたいよ!」って人が居たら言ってもらえればコラボレータ追加します。
別にforkしてpull requestでもいいんですが、面倒なんでコラボにぶっ込みたい所。
書き方などはREADMEを読んでください。
今のところ書いてる人はPerl側の人間が多いので、もしPHPな人で気になった人が居たら参加してもらったら嬉しいなーとは思う所。なんかそのほうが完成度高くなりそう。
この形に落ち着くまでcodereposにしたりnim+perl-usersとか色々やってたんですが、miyagawa伝説とwikihubでの見た目が奇麗とsyntax highlightした時の組み込み関数にphp.netやperldoc.perl.org等にリンクされて便利ってのがwikihub採用の決め手でした。
とりあえず環境もろもろはいつも通り僕が用意したんですが、4000を越えるPHPの関数群のテンプレートファイルをyusukebeが用意してくれました。
ってことでどうぞよろしくです。

スケート頑張りすぎて足首が痛いYappoですみなさまウインタースポーチュしてますか?
本日kumofsが公開されたので、折角なので Data::Model から kumofs を実際にどうつかっているかを紹介しようかとおもいます。
kumofs については 分散Key-Valueストア「kumofs」を公開しました! - 古橋貞之の日記 を Data::Model::Driver::Memcached については dann さんによる Data::Model::Driver::Memcachedで超効率データ保存 - JPerl Advent Calendar 2009 を別途参照すると良いでしょう。
では実際に kumofs をつかった場合のスキーマ定義を下記に貼ります。
ちなみに、それらしいような定義をしてますが全部フィクションです。本当に。
Data::Model::Driver::Memcached のインスタンスを作る所で、 Cache::Memcached::Fast のインスタンスを指定する所で、3つのオプションを渡しています。
一つ目が、 serializer => 'Default', で、 Cache::Memcached 標準の直列化手段をつかわずに Data::Model::Driver::Memcached 標準の直列化手段を利用します。
即ち MessagePack を使った直列化を施します。 Data::Model で必要な MessagePack のコードは Pure Perl で内部的に実装されているのですが、実用的にするには Data::MessagePack をインストールしておくと、そっちを使って高速に直列化してくれます。
二つ目は、strip_keys => 1, です。
通常の方法だと、 primary key も KVS の Value として直列化してストレージに格納しようとするのですが、 KVS だったら既に Key のほうに値が入っているべきで、この重複が無駄なので削除して直列化します。
例えば、上記のコードを使った場合に以下のようなデータ構造だった場合に
{
file_id => 'dankogai',
media_type => 1,
client_type => 5,
is_broken => undef,
},
file_id の項目を delete して、下記のような構造にしてから直列化します。
{
media_type => 1,
client_type => 5,
is_broken => undef,
},
三つ目としては ignore_undef_value です。
これは何をする物かと言うと、カラムの値が undef だった場合は、その項目を DELETE してから直列化します。
そして lookup などで kumofs から Data::Model の Row オブジェクトに戻す時点で、直列化されてるデータにカラムのデータが無ければ value が undef だったと解釈をして復元するのです。
今回の例では、画像が壊れてた時だけ kumofs のストレージサイズが増加します。
上ので書いたデータ例に適用すると下記の用に is_broken が削除されて kumofs に格納されます。
{
media_type => 1,
client_type => 5,
},
ユースケースとしては、稀にフラグを立てる必要があるんだけど、フラグ立って無いレコードに対してもディスク容量を消費するのが嫌だ!という時に使えます。
SQL だと、別途 file_broken 的なテーブルを作って JOIN すれば済む話でしょう。
あいにく kumofs では JOIN 出来ないので、このような時は別の Key-value にデータを突っ込まないといけません。
そうすると GET する時のクエリの数が倍になったりするのでトレードオフしてどっちにするか選ばなきゃいけなくなるんですが、 ignore_undef_value を使っとけば、必要な時に必要なだけストレージを使いつつ GET する時のクエリ数も増えないので良い感じになるんです。
細かいこと言うと SQL で別テーブル使って JOIN するよりかは空間効率やらなんやらは良いと思うすけど。特に比較検証してないんでこれ以上はやめとくす。
今度は model 定義部分をみてみましょう。ポイントは二つあります。
一つ目は schema_options model_name_realname => 'f_m'; です。
これは、 memcached protocol の key の所に入れる model namespace を短縮するのに使います。
例えば key=file_id が 'dankogai' だとして、 schema_options model_name_realname が指定されてない場合は、このコード例では
kumofsfile_meta:dankogaiという key で kumofs に SET します。
kumofsf_m:dankogaiと短縮された key になります。
二つ目は schema_options column_name_rename の所です。
これは直列化する直前で Key を任意の値に変換してから直列化をかけます。
Data::Model 標準のシリアライザの MessagePack では、数値をとても効率よく直列化してくれるので、 media_type だとかいう長ったらしい key name を 2 とか言う数値に変換してしまいます。
2 とかという小さい値だと直列化後も1バイトしか容量食わなくて嬉しいんです!
実際、上のほうで書いてるデータ例だと以下の用になります。
{
2 => 1,
3 => 5,
},
とんでもなく圧縮出来ている事がお分かり頂けますか。
MessagePack の specをみても解るとおり、15要素以下の HASH に1バイト、 7bit 以下の unsigned int では1バイトの容量しかかからないので、上記の圧縮後の value は5バイトという驚異的なサイズとなって kumofs の value に格納されます。
今日は kumofs 公開したということで、 Data::Model からだったらどう使えるか、どう使うかという視点で書いてみました。
Data::Model 側で用意してるオプションを使い切る事により、プログラムコードは書き易く、かつ空間効率を驚異的に高めて利用出来る事が解ったかと思います。
もちろん Data::Model::Driver::Mecached は kumofs 専用という訳でなく Tokyo Tyrant やらなんやらでも利用できますので、機会があればお試しください。
まぁ、もちろんこんなレイヤ介さずに直接使えばいいって話も出てきそうですがね。
あわせて読みたい:YappoLogs: KVSでORマッパーを使うという事

twitterにでも書いて終りにしようと思ったけど140文字じゃ無理なんで。
Mooseの欠点やら利点やらMouseがどうだとかは今更感過ぎて割愛するし、下手な抽象的な表現も面倒なんでしない。
あなたが、再利用性の高いライブラリを作りたい場合はMooseを使うべきではない。
なぜならMooseはフレームワークだからであるからだ。
たとえ有用な再利用性の高いライブラリを作ったとしても、Mooseというフレームワークに依存してしまっては、あなたの有用なライブラリを選択してもらえない事もあるだろう。
誰かが小さいスクリプトを書くために、あなたが書いた有用なライブラリを使う事で楽が出来るとする、だがMooseというフレームワークに依存したばっかりに、その有用なライブラリの後ろに控えるものの大きさに臆して選択してくれないかもしれない。
もちろんMooseを使わなければ生産性が格段に落ちるだろう。メンテナンスも大変になるだろう。Mooseを使わないことによるペナルティの代わりに誰からも利用されるライブラリの作者になれると言うことだ。素敵だろ。
じゃぁCPANへ上げるライブラリはMooseを使うなってことか?いいや違う。
何度も言うがMooseは生産性を恐ろしく高める、だがしかし再利用性の高いライブラリでは使うべきでないと言っただけだ。
例えば App::* 名前空間のコードでは積極的に使っても良いだろう、Catalystだってそうだ。
え?Catalystは再利用性の高いライブラリじゃないか!だって?いいや、Catalystはとても有用なフレームワークだ。Catalystの中だけで世界が閉じているのだ。
そう、Mooseを使う場面と使わない場面と言うのは、書こうとしているコードがそのコードの世界で閉じたものなのか、または閉じないものなのか。そういった基準を見るという視点があると良いのではないだろうか。
例えばDBICなんかは閉じた世界でないのでMooseに依存するべきでは無い。
たとえばDBI.pmがMooseに依存してたらどうする?
HTTP::Engineは?うーん微妙だ。
Plack何かは閉じた世界では無いので使うべきでは無い。
じゃぁFeyはどうだ、、、、うーんMooseをたくさん使うという世界に閉じた中で使うと言う点ではありなんじゃないか?
繰り返すがMooseを使わないべきとは言っていない。良く考えて使うべきだと言っているのだ。

Plack処女喪失したての金曜日の天使ですおげんきですか。
Plack::Middleware::Debug を使って Debug のメニューを消したときって

みたくなってなんか邪魔なので、端っこにどかすCSSを適用するMiddleware書いてみた。
やりたい事としては、アプリとは関係ないファイルの管理をしないで PM::Debug のcssだけを置換して使いたいって事。
Plack::Middleware::Debug は、必要なjsやらcssをshareディレクトリ以下に入れて自分の好きなように書き換えて使えるんですが、それやるとアプリ以外にファイル管理しなきゃいけないので面倒なのでやりたくないというワケ。
上のコードを app.psgi に入れとくと

な感じになってくれました。
とりあえず目的は達成。
この
builder{
enable {
my $app = shift;
sub { $app->(@_) };
};
sub {};
};するような使い方ってMiddlewareって呼んでもいいものなかしら?
< miyagawa> middleware でいいですよとの事。

だいぶ前に作って放置してたんですが、そこそこCPANに上げられる感じにはしてあったので年末の倉庫整理をかねて CPAN にあげました。 http://github.com/yappo/p5-Object-InterfaceType
Goではクラス定義で云々するんじゃなくて、interfaceで定義されてるメソッド群をすべて実装されてたらOKといった感じなんですが、まぁいわゆるduck typingできればおkみたいな感じですね。
Perlの世界では if ($foo->can('bar') && $foo->can('baz')) みたいなコードで duck type可能かを調べるんですが、見た目がごちゃごちゃしがちになるので、Goのinterface type的な感じのものをPerlの世界に持ってきました。
if ($obj->can('read') && $obj->can('seek') && $obj->can('close')) {
なんてコードを
if ((interface_type [qw/ read seek close /])->($obj)) {
という感じで書き換えられます。
my $is_filehandle = interface_type [qw/ read seek close /];
if ($is_filehandle->($obj)) {
やら
interface_type filehandle =>[qw/ read seek close /];
if (is_filehandle($obj)) {
なんて書き方もできます。
canばっかり呼ばれてるコードって見たこと無いのですが、そういうコードはすっきりとかけるようになるんじゃないでしょうか。
コンセプトは夢の中で思いついて起きて1時間くらいで実装した。

ちょっと前のacotiethoneの時にlestrrat++さんがドキュメントを英訳してくださったのでCPANにアップロードしました。
http://search.cpan.org/dist/JSTAPd/
それなりに頑張って日本語でもドキュメント書いたので、lestrratさんが気に留めて使う気になって英訳してくださったんだとおもいます。
おかげでCPANへリリースすることもできました。
テストも重要ですがドキュメントも重要ですね。

依存モジュールの管理を実際のコード内で行う為にあったら便利そうなモジュールを思いついたので思いつきのまま CPAN にアップロードして advent calendar に書きました。
http://perl-users.jp/articles/advent-calendar/2009/hacker/25.html
たぶん、 advent calendar で紹介されたモジュールの中で一番新米なんじゃないかと思います。
あとは casual track が完走すれば JPerl Advent Calendar 2009 は全部完走となります。
今から寿司がたのしみです^^

一昨年書いた『あなたがRuby on Railsを使わない10の理由』を書いたら、おおむね好評とともに読んでもらえたみたいで(ほんとかー?)うれしい限り。実際あのあとも記事の影響ってわけじゃないと思うけどRoR使ってくれた人もたくさんいるし、ますます広まってきているみたいでこれも私設営業の人としてはとてもうれしい。
略
(例によって書きかけなので今後もいろいろ変わったりするかも)
まあ上でああいったけどやはりCPAN Moduleであることそのものの価値ということにまずは言及しておく。
いまのPerlはまぎれもないCPAN Moduleベースの言語なのだ。それ自体は実のところ単なる偶然の産物なんだけど。でもさまざまに紆余曲折あってCPAN Moduleベースになったおかげで、Perlが得た恩恵はとても大きい。
Perlはその根幹はCPAN Moduleであるということは、CPAN Moduleの四半世紀の歴史がはぐくんできた膨大な蓄積をPerlも同様に備えているということだ。おかげでプログラマだったらPerlがどんな挙動をするかというのはだいたい想像がつくわけ。
この項、あとで書く
あなたが何かの分野で世界第三位の位置に立つことを考えて欲しい。思った以上に道のりが険しいという事が誰でも想像がつくであろう。
しかし、そんなただの人が世界で三番目の位置に立てる分野がある。そうData::Modelのユーザとしてなら世界第三位のヘビーユーザーになれるチャンスがあるのだ。
現在Data::ModelのヘビーユーザはYappoとtokuhiromしか居ない。ここにあなたの名前が連ねるのだ。
どうだい魅力的ではないか?
え、DBIx::Skinnyがいいって?ありゃ駄目だ。nekokakを始めとしてモバイルファクトリーの全社員が使ってい。あなたはモバイルファクトリーの社員数を数えられるか?
それにyusukebeやnekoyaやnihenやnobuなんとかやmixiの連中まで唾をつけてやがる。
そんな手垢のついたものばっかり使ってるから君は世界三位の位置にいつまでたってもつけないんだよ。
それが、Data::Modelを使えばチャンスが巡ってくる。どうだい?簡単だろう。
それに今ならAdvent Calendar期間中で使い方のドキュメントが揃って来てるしね。
http://perl-users.jp/articles/advent-calendar/2009/data-model/
この記事を書いている私はもともとCDBIファンだったんだけど、いまのData::Modelは古き良きCDBIが持っていたcultureと、DBICが持っていたcultureの両方を備えたこれ以上はないほど魅力的なORMになっている。ある意味、CDBIよりもCDBIらしいと思う。この業界の先端を走っている人全員ではないけれど、かなり多くの人はData::Modelを使っているし、これからますます増えてくると思う。

ガイアックスさんのご好意で会場提供された hackathone の成果として Module::Setup 0.07 を shipit する事ができたので、当日担当だった Advent Calendar に Module::Setup の紹介と新要素紹介を行いました。
Module::Setup でらくらくモジュール作成 - JPerl Advent Calendar 2009
実に14月ぶりくらいのメジャーリリースで、様々な機能が追加されています。
おもに flavor 開発者にとって便利な物が大量投入されてます。
他にも Ark などの helper script をより便利に作れる Helper support 機能が投入されてます。
一般向けとしては XS flavor が追加されており、多分 id:gfx がよりモダンな flavor にしてくれることでしょう。
そしてようやく GitHub flavor も投入されました。スケルトン作るときに GitHub のリポジトリセットしたり git remote の設定を自動でやってくれたりします。
お望みとあれば、出来立てのスケルトンをそのまま git push してくれますがそんな変態はいないでしょうか。
ということで Module::Setup をご利用ください。
ガイアックス++
# 最初は本気で東小金井に行きかけたのはないしょのつぼみ

http://goo.gl/ ってのが巷では始まっていますが、まだ勝手に tinyurl を作れないようなので
簡単に http://goo.gl/hoge な tinyurl を作る WWW::Shorten::Google ってモジュールを書きました。
http://github.com/yappo/p5-WWW-Shorten-Google
CPAN には、各種 tinyurl を使って url を短くするための統一インタフェイスとして WWW::Shorten ってのがあるので、それの流儀にしたがって作りました。

という事で始まりました。
http://perl-users.jp/articles/advent-calendar/2009/
gfxさんがまとめてくれたPerl界隈のAdvent Calendarの便利リンク集も有るので便利です!
今回はトラックが二つに別れた事の他にDBIx::SkinnyとData::Modelのトラックが出来てるのに気づくかと思います。
これは、本来予定されていたものでは無くて、今回のJPerl Advent Calendar 2009は結構便利に書ける仕組みだったので、便乗して開始したといういきさつです。
Advent Calendar書く為の準備をする必要が特にないので参入障壁が低いと言う事ですね。
何が言いたいかというと、もし何かのテーマでPerl Advent Calendarをやってみたい!って人は気軽に始めると良いですよ。という事。
$ git clone http://git.coderepos.org/share/websites/jperl-advent-calendar-2009.git/ $ cd jperl-advent-calendar-2009 $ cp -r data/data-model data/anatano-track # data/anatano-track の中のファイルを諸々書き換える # s/data-model/anatano-track/ みたいな事とか # trackの名前変えたりとか $ $EDITOR data/anatano-track/\d+.txt して、内容書く $ git add data/anatano-track # 必要だったら .nim とか data/index.html とか data/base.html も追加しとくと良いよ $ git push
本当は今回GitHub Pagesを使うとかいう話があったんですが、コラボレータ追加作業が面倒という事で特に手間がないCodeRepos使うと言う話になった。
あとnimいいですね、全トラックのRSSをまとめたRSSとか作るのもPlagger使わないでnimだけで作れる。

YAPC 2009 (Yet Anther jPerl advent Calendar 2009) という事で、Data::Mode用のトラックを作りました。
http://perl-users.jp/articles/advent-calendar/2009/data-model/
あまりにも文書としてまとまってない Data::Model のドキュメントを増やすチャンスですね!
ちなみに全部書ききったら、別途kanさんに寿司奢ってもらうつもりです。

Data::ObjectDriverをDISってる人の話題が三周目に突入した今日この頃ですが皆さんは何をDISってますか?Yappoです。
JavaScript にもテストツールが色々とあると思うんですが、 Ajax アプリの XHR リクエストとかも含めてラクチンにテストできるツールが見つからなかったので JSTAPd というツールを作りました。
http://github.com/yappo/JSTAPd
名前の通りテスト結果はTAPで出力してるのでproveコマンドとかを使ってPerlの作法でテストできます。
ブラウザの連携の設定をすれば prove -v foo/hoge.t とかをコマンドで打ち込めば勝手にブラウザ立ち上げてテストコード実行してブラウザ閉じて結果をコンソールに吐いてくれます。
もちろんデーモンとして常駐化できるので複数のOS&ブラウザを使って自動的にテストするなんて構成も取れるでしょう。
1テスト1ファイルにまとめて書く事が出来て、実際にテストに関係するJavaScript, HTML, Server APIのコードを書くだけですむようになっています。
JSコードのテストを細かくサクサク量産できる事を目標にしてます。
文章で説明を呼んでもいまいちピンと来ないと思いますので、実際にJSTAPdを使っている所のデモンストレーション動画を撮ったのでご覧下さい。
あと、日本語でチュートリアルも作ったので細かい内容についてはそっちを参照してください。
http://yappo.github.com/JSTAPd/tutorial/ja.html
文法エラーとか補足しきれなかったりまだまだ細かい所がかゆいんですが徐々にまともにしてくつもりなので乞うご期待。

Careless you doing "perl Makefile", then you take many error messages.
Your trouble will be solved if the polyglot technology is used.
# Example Makefile
irst_labe: length
X;$Y=Z;
dummy_label: length
0;
print "perl world\n";
$x = <<'END_OF_MAKEFILE='
length:
echo "make world"
END_OF_MAKEFILE=
actually, this code is works on perl and make command.
$ perl Makefile perl world
$ make echo "make world" make world
Makefile is processible into Makefile.PL polyglot by perl code shown below.
perl Makefile.PLをperl Makefileと打ち込まんでエラーメッセージを出しちゃうドジっ娘さんは沢山いらっしゃるとおもいます。
そんな悩みを解決すべくperl Makefileと打ち込んでもexec $^X, 'Makefile.PL'を実行してくれるMakefileのsnipetを作りました。
規則名をlabelとして扱わせて、その次にperlの構文のlengthをぶち込み、セミコロン必要な所は何故かGNU makeでX;$Y=Z;が通ったので、それでごまかしてlengthの規則名を定義してmakeで実行させる規則を作りつつ。perlで実行された時にはlengthの規則の定義部分は$xにぶち込まれるようにしてあるという具合です。(説明めんどう
ExtUtils::MakeMakerにパッチあてれば良い感じになりますか?
GNU Make 3.81 で確認済み
thanks to tokuhirom and takesako

it is useful to what? i don't know.
my $path = 'foo/bar/baz'; Class->$pathとかAUTOLOADで普通に受け取れたから、オブジェクトも送れるんじゃないかと思って書いてみた。反省しない。

thanks many ideas from yusukebe, mattn, miyagawa.
I created a streaming response support for HTTP::Engine. it was a too easy hack.
example here
[ゆ]: multipart/mixedなストリームをPlack/PSGIでpushする みて、HTTP::Engineの上で動くかと思ったけど全然動かなかったので、HTTP::Engine側で対応して動くようにしました。
http://github.com/yappo/fast-twitter-stream
IO::Handle::Utilで作った$fhをHTTP::Engine::Response->new( body => io_from_getline sub {} )しただけだと、Content-Lengthが無いとエラーになってしまってbackend interfaceに渡せなかったんですね。
なんで、PSGIみたくバックエンド側でストリーミング的なコンテンツが扱えるinterfaceの時はContent-Length無しでも通るようにしました。
で、出来たのが以下のコードです。オリジナルと殆ど同じです。
use strict;
use warnings;
package FastTwitterStream;
use Coro;
use Coro::Channel;
use Coro::AnyEvent;
use AnyEvent::Twitter::Stream;
use HTTP::Engine::Response;
use IO::Handle::Util qw(io_from_getline);
use Encode;
my $username = $ENV{TWITTER_USERNAME};
my $password = $ENV{TWITTER_PASSWORD};
my $boundary = '|||';
my $streamer;
my %queue;
my $count = 0;
sub request_handler {
my $req = shift;
if ( $req->path eq '/push' ) {
my $now = ++$count;
$queue{$count} = Coro::Channel->new;
$streamer ||= AnyEvent::Twitter::Stream->new(
username => $username,
password => $password,
method => 'filter',
track => 'twitter',
on_tweet => sub {
$_->put(@_) for values %queue;
},
);
my $body = io_from_getline sub {
my $tweet = $queue{$now}->get;
if( $tweet->{text} ){
return "--$boundary¥nContent-Type: text/html¥n" .
Encode::encode_utf8( $tweet->{text} );
}else{
return '';
}
};
return HTTP::Engine::Response->new(
headers => {
'Content-Type' => qq{multipart/mixed; boundary="$boundary"},
},
body => $body,
);
}
if ( $req->path eq '/' ) {
return HTTP::Engine::Response->new( body => html() );
}
};
sub html {
my $html = <<'HTML';
<html><head>
<title>Server Push</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.1/jquery.min.js"></script>
<script type="text/javascript" src="/js/DUI.js"></script>
<script type="text/javascript" src="/js/Stream.js"></script>
<script type="text/javascript">
$(function() {
var s = new DUI.Stream();
s.listen('text/html', function(payload) {
$('#content').prepend('<p>' + payload + '</p>');
});
s.load('/push');
});
</script>
</head>
<body>
<h1>Server Push</h1>
<div id="content"></div>
</body>
</html>
HTML
return $html;
}
package main;
use HTTP::Engine;
use Plack::Builder;
my $engine; $engine = HTTP::Engine->new(
interface => {
module => 'PSGI',
request_handler => ¥&FastTwitterStream::request_handler,
},
);
builder {
enable "Plack::Middleware::Static",
path => qr{¥.(?:png|jpg|gif|css|txt|js)$},
root => './static/';
sub { $engine->run(@_) };
};
ブラウザから"http://localhost:8080/"にアクセスすると、もの凄い勢いでつぶやきが追加されていくのが分かるかと思います。しかも切断していないのでかなり高速です。
お試しの効果には個人差があります。multipart/mixedとこのDiggライブラリの組み合わせ、いいですね。というわけで、元ネタになったyusukebeさん、Plackでpush配信の仕方を教えてくれたmiyagawaさんありがとうございました。
Enjoy!

I shipped HTTP::Engine 0.03. Interface::PSGI is enclosed from this time.
async server became easy by PSGI.
use strict;
use warnings;
use HTTP::Engine;
use Plack::Loader;
my $he1 = HTTP::Engine->new(
interface => {
module => 'PSGI',
request_handler => sub {
HTTP::Engine::Response->new( body => 'plack 1' );
},
},
);
my $he2 = HTTP::Engine->new(
interface => {
module => 'PSGI',
request_handler => sub {
HTTP::Engine::Response->new( body => 'plach 2' );
},
},
);
Plack::Loader->load('AnyEvent', port => 18081)->register_service(sub { $he1->run(@_) });
Plack::Loader->load('AnyEvent', port => 18082)->register_service(sub { $he2->run(@_) });
AnyEvent->condvar->recv;Interface::PSGI を同梱した HTTP::Engine 0.03 をリリースしました。
思う所があって、PSGI対応周り以外にももすこし機能追加しようかなという気分になってきました。

Today I created a good wrapper for request body upload HTTP::Request.
this module is use few memory on file upload. also too big file.
http://search.cpan.org/dist/HTTP-Request-StreamingUpload/
http://github.com/yappo/p5-HTTP-Request-StreamingUpload
DESCRIPTION
HTTP::Request::StreamingUpload is streaming upload wrapper for HTTP::Request. It could be alike when $DYNAMIC_FILE_UPLOAD of HTTP::Request::Common was used. However, it is works only for POST method with form-data. HTTP::Request::StreamingUpload works on the all HTTP methods. Of course, you can big file upload using few memory by this wrapper.SYNOPSIS
my $req = HTTP::Request::StreamingUpload->new(
PUT => 'http://example.com/foo.cgi',
path => '/your/upload.jpg',
headers => HTTP::Headers->new(
'Content-Type' => 'image/jpeg',
'Content-Length' => -s '/your/upload.jpg',
),
);
my $res = LWP::UserAgent->new->request($req);
LWPとか使って大きなファイルアップロードするときは$HTTP::Request::Common::DYNAMIC_FILE_UPLOAD使ってアップロードするとメモリに優しくアップロードできるってのは有名ですが、あれってform-dataの時しかやってくれないので、例えばPUTメソッドでデッカいファイル送りたい時には使えません。
HTTP::Request->new( PUT => $uri, $headers, sub { read $fh, my $buf, 1978; $buf } )とか書けば出来るんですが、毎回書くのもうっとおしいので、同じ事をHTTP::Request::StreamingUpload->new( PUT => $uri, headers => $headers, fh => $fh )で出来るようにしたんです。
Content-Length を入れない場合は LWP::UserAgent の中で使ってる LWP::Protocol::http が chunked で送ってくれるので、予め送りたいサイズが解らない場合でも安心して使えます。

PSGIなServerはsendfileを扱う時にどうするかのメモ。
以上が、基本的なsendfileを使を行うときのパターンになる。
また、response headerにX-Sendfileなどの任意のヘッダが入っていて、その中にファイルパスが入っていれば、そのファイルパスを元にしてsendfileするのはServer実装者の自由である。
が、アプリの設定したヘッダはむやみに弄るべきではないので、後述するMiddleware等が設定したpsgix.sendfileを使うべき。だし、そもそも->pathとかをduck typeして取った方が奇麗だ。
というか、好き勝手にやればよい。と言うのがだいたいのsendfile扱うときの定石かな。
多分psgix.sendfileを最優先に使えば良いと思うけど。
たぶんMiddlewareがX-Sendfileなどをpsgix.sendfileに突っ込む等の方向性になるんじゃないか、まだ良くわかんない。
nginx embed perl は、今のところ $r->sendfile($path) しか提供されてなんだけど$r->sendfile_by_fd($res->[2]->fileno)とか出来るようにするつもりです。

AneEvent二日目なので plagger irc bot的に使えるのを書いてみた。
http://github.com/yappo/perl-anyevent-irc-message-proxy
POEってのはIKCっていう便利なRPC的に便利に使えるのが有るんですが、まぁplagger irc bot的なのにはそんな大げさの物も要らないので、jsonでデータ送ったらその中身をirc serverにNOTICEで出してくれるのを書いてみた。
そもそもjsonにしなくても良いんだけど、jsonの中に発言したいchannelとか指定出来るように拡張する時とかのためですね。
このくらいだと別に直でAnyEventのコード書いても良い感じすなー
plaggerのそれとはコードも比べ物にならない程適当なんですが、似たような処理をAnyEventで書くとこんなにすっきりするんだなぁ。と思いましたですね。ハイ

そろそろAnyEventでもやってみようと思ったので
いわゆるIOまわりの面倒を色々便利にやってくれる君。イベントベースなIOと言うよりかはevent queueなIOみたいな捉え方するとすんなり。
read/writeの処理はqueue的な感じで登録できるの。
->push_read() で、どんどんqueueにreadイベントを登録してく。fhがreadableになったらread queueがどんどん処理されるってわけ。
->unshift_read() だと、queueの先頭に突っ込んでく。
そう、まさしくperlのarrayへのpush/unshiftそのもの。AnyEvent::Introを読むとその辺の命名に関する思いが読める。
->push_write() だと、writeイベントを登録してく。writeできるようになるとどんどんfhにデータが送られる。
もしかしたらこれの対としてunshift_writeが出来るとか出来ないとか。
eventベースなのでpush_readとかしてもfhの都合考えないですぐにレスポンスが帰ってくる。
もしエラーとかタイムアウトをハンドリングしたければon_timeoutやらon_errorなどにハンドラ渡せ。
->on_drain() なんてのもある、排水溝。write bufferが空っぽになったら呼び出されるの。
空っぽの排水溝に汚物という名のdataをpush_writeしまくるか、汚物が無くなったらpush_shutdownしてsocketという排水溝を閉じてしまうかは好きにすれば良い。
こんだけ解ってればPlack::Impl::AnyEvent読むのは苦労しないよ。
つづく

まだ終わってないですが発表資料等。
1日目の Data::Model の資料は
http://yappo.ficia.com/pl/album/1E8DF4EE-9DB6-11DE-B1EE-7BD1A805B909
2日目の LT nginx に突いての資料は
http://yappo.ficia.com/pl/album/9509705E-9EAA-11DE-ADEA-3624873069EA
一応テキスト版を置いてあります。
http://github.com/yappo/talk-yapcasia2009/tree/master
なお LT で発表した nginx with memcached は
http://github.com/yappo/ngninx-ngx_http_memcachep_module/tree/master
にて。
Plack::Impl::Nginx に関しては
http://github.com/yappo/p5-Plack-Impl-Nginx/tree/master
nginx 本体にパッチいります
Yet Another Another Conference として、東工大の中の芝生で
1日目: MySQLカンファレンス
2日目: 画像配信サービスカンファレンス
が開催されました。
特に2日目は、無茶な呼び出しにも関わらずお集りいただきありがとうございました。
詳しい事は後で書く予定かも。。。。
写真等は
前夜祭http://yappo.ficia.com/pl/album/71902ED4-9D5F-11DE-AC2C-90D36E373816
1日目http://yappo.ficia.com/pl/album/BD7137E4-9DF0-11DE-8BEA-3624873069EA
2日目http://yappo.ficia.com/pl/album/850F7D50-9EAB-11DE-8946-7BD1A805B909
でみれます。
ハッカソンが終わって家に帰るまでYAPCなので、まだまだこれから。。。

HTTP::Engineは、ちょっとした一枚スクリプトをサーバ化する便利な利用方法がありますが、それをPSGI実装向けにやってくれるアプリを昨日の帰りの電車の中で書きました。
http://github.com/yappo/App-Ksk/tree/master
使い方は簡単で、下記のようなスクリプトを書いて
package KskExample::Sample1;
use strict;
use warnings;
sub handler {
my($class, $ksk, $req) = @_;
my $body = qq{
<h1>Welcome To Ksk World.</h1>
you request uri is @{ [ $req->uri ] }.<br />
};
my $res = $ksk->psgi_response_class->new({ status => 200, body => $body });
$res->header( 'content-type' => 'text/html' );
$res;
}
1;
$ ksk.pl scriptname.plもちろんPSGI実装は差し替え可能で次の用にするとAnyEventを使ってサーバを上げます。
package KskExample::AnyEvent;
use strict;
use warnings;
use Plack::Impl::AnyEvent;
sub ksk_init {
+{
psgi_setup => sub {
my $handler = shift;
my $ae1 = Plack::Impl::AnyEvent->new(port => 18081);
$ae1->psgi_app($handler);
$ae1->run;
my $ae2 = Plack::Impl::AnyEvent->new(port => 18082);
$ae2->psgi_app($handler);
$ae2->run;
},
run_finalizer => sub {
AnyEvent->condvar->recv;
},
};
}
sub handler {
my($class, $ksk, $req) = @_;
my $body = qq{
<h1>Welcome To Ksk World.</h1>
you request uri is @{ [ $req->uri ] }.<br />
};
my $res = $ksk->psgi_response_class->new({ status => 200, body => $body });
$res->header( 'content-type' => 'text/html' );
$res;
}
1;
PSGI実装の入れ替え可能という事は別にPlackなんか使いたく無いぜ!派の人も psgi_setup をちゃんと書けば実装の選択は可能です。
ちなみにrequest classとしてPlack::Requestを、response は Plack::Response を使っていますが、これも差し替え可能で
Another::Request->new($env);や
my $psgi_res = Another::Response->finalize;という感じのインターフェィス要件を満たしてくれる、他のPSGI対応Req/Resクラスに差し替える事も可能です。
ついでにハンドラー周りのクラスも差し替えられるけどオマケです。
という事で快適なPSGIライフをお過ごしください。

PSGI自体がまだまだ流動的なので、落ち着くまでHTTP::Engine::Interface::PSGIを作ってお茶を濁す事にするよ。
PlackX::Request も HTTP::Engine のそれとは大きく違う感じになったし、そもそもMoose/Mouse/Any::Moose使わなくしちゃったし。
なんか流れ的にもHTTP::Engineはもう使わないでPSGI実装とかを使う流れにもなりそうなんで、あんまやりすぎても無駄な感じだから静観する方向で。

昨日のHTTP::Engineは死なないよってのは間違いじゃないけど、プロジェクト的には老後生活に入る方向になってました。
仕様は PSGI になり、 Interface 実装は PSGI 実装に、 Request の実装は PlackX::Request に移る方向性っぽいです。
具体的に言うと PSGI の実装を Interface レイヤで使って、Request部分を PlackX::Request を使うラッパーという形になります。
本来の HTTP::Engine も Interface の部分からデータを受け取って Request オブジェクトを作って、アプリケーションのコールバックを呼んで
アプリケーションから帰って来たResponseオブジェクトを受け取って、それをWebサーバに戻すんですが、これをこれから
PSGI実装からPSIGプロトコルのデータ受け取って、 PlackX::Request を extends した HTTP::Engine::Request でくるんでアプリケーションに渡して、アプリケーションは HTTP::Engine::Response で返すんで、それを PSGIプロトコルに変換してPSGI実装に返す感じになります。
本来のHTTP::Engineのコアとやる事はあまり変わり無いです。
PlackX::Request は、すでに HTTP::Engine を元にして作ってあります。
http://github.com/yappo/p5-PlackX-Request/tree/master
で、PSGIは仕様の名前であって実装は別になるので、エンドユーザはPSGI実装を自由に選ぶ感じになります。
最初の内はPlackを使って行く予定です。

HTTP::Engine は元々
・各種Webサーバに依存した処理がWAF毎に分散してるのをまとめたい!
・Request/Responseも共通化したい!
という所からスタートしたプロジェクトな訳ですが、今回PSGIが始まる事によって前段の部分をPSGIに委譲して、Req/Resの共通化は今まで通りありますよと言う話。
今回のPSGIは「HTTP::EngineのInterfaceのレイヤとReq/Resのレイヤが絡み付いてて良く無いんで、良い感じに分離したいよね」という所から始まった感じ。
結局はPSGIは仕様なので、それを実装するのはHTTP::Engineの内部になるかもしくはRack的な物を外に作ってやるかという事になるけど(後者の方向)、HTTP::Engineの内部でPSGIと既存のRequest/Response/handlerの吸収を行うので、利用者側からしたら意識する必要は無いです。
なにが良くなるかというとHTTP::Engineのデペロッパにとってのコードの見通しが良くなるのと、真の意味でのWSGIをPerlが手に入れるという事ですね。
利用者側の視点では、HTTP::EngineがPSGIの実装を選べると言うのも選択肢が広がって良いのではないでしょうか。
例えばmod_psgiとかいうapacheモジュールが出たとしたら、HTTP::Engineが直接mod_psgiと繋げるなんて事が出来る訳ですね。mod_perl強すぎで必要性あんま無いけど。
既存のHTTP::Engineを受け入れにくいプロジェクトでも、良さげなPSGI実装の上でアプリを書けるので嬉しい事も多いでしょう。
ここまで読んで頂ければ解りますが、表題の答えは No ですね。

最近「国産のHTTP::Engine」のような文章を立て続けに見たので、HTTP::Engineは国産なのかどうかを考えてみたけどやっぱり国産じゃないんですよね。
そりゃディストリ作り出してメンテやりだしたのは日本人だけども、コードベースはCatalystだしMoose化の際にはnothingmuchの多大なる貢献があったし、大元のアイデアはPythonからの物だしで、そんなに国産と言う思いは無かったり。
だってさ、Pugsが台湾産だなんて言いかた聞かないでしょ?強いて言えばPerlコミュニティ産ってのがしっくりくるなという感じ。
中の人が日本語ばっかり使うから日本人が使うには気軽で良いという点くらいしかないんだけど、それって全体で見ると利点でなくて英語の情報が余りにも少なすぎてあんま良く無いなと思ってる所なんだけど、日本語ですらドキュメント書けてない困ったちゃん状態。
Ruby(以下省略

eyefiで上げまくる生活をした後にiPhotoに残ってる古い写真も上げようと思ったらeyefiで上げ済みの写真も上がっててバビった今日この頃皆様いかがお過ごしでしょうか。
iPhotoに取り込まれた写真はExif情報を追加するといったことが一般的に知られていますが、実際にどんなデータが追加されてるかを見てみました。
材料:iPhoto通してない写真 1枚
iPhoto通した同じ写真 1枚
下記のスクリプト
use strict;
use warnings;
use Image::ExifTool ':Public';
my $eyefi = ImageInfo(shift);
my $iphoto = ImageInfo(shift);
while (my($k, $v) = each %{ $eyefi }) {
my $iphoto_v = delete $iphoto->{$k};
my $is_changed = 0;
if (ref($v) eq 'SCALAR') {
if (ref($iphoto_v) eq 'SCALAR') {
$is_changed = 1 unless $$v eq $$iphoto_v;
} else {
$is_changed = 1;
}
} elsif ($v ne $iphoto_v) {
$is_changed = 1;
}
next unless $is_changed;
printf "key: %s¥n eyefi: %s¥n iphoto: %s¥n", $k, $v, $iphoto_v;
}
print "¥niPhoto's append data¥n";
while (my($k, $v) = each %{ $iphoto }) {
printf " %s => %s¥n", $k, $v;
}
さぁ実行しましょう
key: FileName eyefi: eKHPjLGE3hGDx7EShzBp6g.jpg iphoto: DLQpgnuI3hGrj3qvqAW5CQ.jpg key: FileModifyDate eyefi: 2009:08:09 15:54:57+09:00 iphoto: 2009:08:14 11:38:11+09:00 iPhoto's append data CMMFlags => Not Embedded, Independent ConnectionSpaceIlluminant => 0.9642 1 0.82491 ProfileCMMType => appl ProfileDescription => Camera RGB Profile ProfileID => 0 DeviceModel => GreenMatrixColumn => 0.35332 0.67441 0.09042 ChromaticAdaptation => 1.04788 0.02292 -0.0502 0.02957 0.99049 -0.01706 -0.00923 0.01508 0.75165 BlueTRC => SCALAR(0x8356ec) RedTRC => SCALAR(0x8d5f84) ProfileClass => Input Device Profile BlueMatrixColumn => 0.15662 0.08336 0.71953 PrimaryPlatform => Apple Computer Inc. RedMatrixColumn => 0.45427 0.24263 0.01482 ProfileDescriptionML => Camera RGB Profile ProfileVersion => 2.2.0 RenderingIntent => Perceptual ProfileCreator => appl ProfileFileSignature => acsp DeviceManufacturer => appl ProfileCopyright => Copyright 2003 Apple Computer Inc., all rights reserved. ProfileDateTime => 2003:07:01 00:00:00 GreenTRC => SCALAR(0x8d60c8) DeviceAttributes => Reflective, Glossy, Positive, Color ColorSpaceData => RGB MediaWhitePoint => 0.95047 1 1.0891 ProfileConnectionSpace => XYZファイル名が違うのはImage::ExifToolの都合ですが、最終変更日が変更されてプロファイルやら何やらが追加されましたね。
メタデータ変わったら違う画像になるのか、それとも画像自体が同じなら同じファイルなのかとかそういう話もありますが今日はこの辺で。
ちなみに元画像はここから落とせます

このところ、MySQL と KVS と ORM 関連のエントリをいろいろ書いていますが、それは、スケールアウト可能で、かつ、インフラの人に怒られないアプリケーションを、今まさに作っている、という理由があるからです。
ただ、ブログエントリだとどうしても細切れになるので、一連のモジュールやプログラムを組み合わせて、どうやってスケールするインフラと繋げる部分を作るのかという話を YAPC::Asia 2009 でさせていただくことにしました。
YAPC::Asia 2009 は9月10日(木)と11日(金)の2日間、東京工業大学大岡山キャンパスで開催されます。今日からチケット販売も始まったので、興味のある方はお越しいただければ、と思います。
YAPC::Asia 2009
Key Value Store with O/R Mapper: YAPC::Asia 2009 - Sep 10-11 in Tokyo, JAPAN

DBD::mysql は mysqld との接続が切れたら自動的に繋ぎ直す機能があるのですが、 Data::Model の reuse_dbh 機能を作るにあたりとてもはまりました。というようなエントリの建設予定地です。

The task which I have about cpan modules is as follows
The project into which I am putting power now.>

ケイレキ.jpの中でケイレキ.jpに招待して欲しい人を呼びかけても絶賛スルーされてるYappoです。さて今回は今巷で大人気のKey Value StorageでORマッパーを使う事についてお話するのじゃ。
一般的にORマッパーとはオブジェクトとリレーショナルデータベースをマッピングする為の仕組みの呼び名だと言うのは知られている所です。はい、そうするとKVSってのはハッシュデータベースであるわけなのでおかしいですね。今回の話はData::Model::Driver::Memcachedを使う事を前提としてるので問題が無いのです。なぜなら「data/object mapper」とか書いてあるから。
いわゆるPerlなORマッパーってのは行データをHASHで管理します。それはRDBが一般的に表形式でデータを管理しているからなんだと思います。なんでKVSをオブジェクトにマッピングするなら他の方法でも良いかもしれませんが、Data::Modelは異種ストレージでも同じインターフェィスで使えるようにする。例えば最初はSQLiteで動かすけどあとあとTokyoTyrantに乗せ替えるみたいな事をやる時にアプリケーションをほぼ変更無しで乗せ替えを可能にするといった事を考えて作ってあります。
厳密に言うとwhereとかindexとか使うクエリ使ってしまったら今のところ駄目ですけども。。。
本題に入るけども、先ほどリリースしたData::ModelからDriver::Memcachedを大幅に強化して各種KVSへデータを保存するのに有利な仕組みをいくつか追加しました。Driver::Memcachedはmemcached protocolに対応したサーバもしくは、Cache::Memcachedと互換なインターフェィスをストレージとして利用します。素のmemcached以外の物で使ってもらう事を考えてますが、データの生存期間に合わせてそのへんは選べば良いと思います。僕も特定のデータだったらmemcachedの方に突っ込んでるし。
Data::Modelはmemcachedのkeyにテーブルを含めます。
またinstall_modelでkeyとして定義されたkeyの値もふくまれます。
例えば「test_table」 という名前のテーブルで、keyに「1」があるレコードだとmemcachedのkeyとして「test_table:1」というkeyになります。
ただし、これだとtest_tableという名前は人間にはわかり易いけどスペース効率的によろしく無いケースもあるでしょう。
そういった時は
install_model test_table => schema {
schema_options model_name_realname => 't';
};という設定を仕込む事で、$model->set( test_table => { k => 1 } )という書き方のままで、memcachedのkeyには「t:1」という省スペースなkeyが使われます。
これも、思想としてはテーブル名変換と同じで、memcachedのvalueにはカラム名を含むハッシュを保存するため、カラム名を短縮形式に変換すると省スペースになります。
install_model simple => schema {
schema_options model_name_realname => 's';
key 'id';
column 'id';
column 'name';
column 'nickname';
schema_options column_name_rename => {
id => 1,
name => 2,
nickname => 3,
};
};数値にすると、後述するMessagePackでのシリアライズで有利になるのですし、ここのカラム名の所はとにかく小さくしとかないと大量のレコードを保存した時のコストが馬鹿にならないのです。
KVSはたいがい行データのkeyカラムをkey/valueのkeyとして保存しておくので、シリアライズされたvalueのなかにkeyの値が入ってると重複して無駄なので、シリアライズするハッシュ要素からkeyのデータを取り除きます。
lookup/getした時は、検索するのに使ったkeyから行データを復元する感じです。
普通にmemcached使ってるなら$memcached->add( $key, { k => 'v' })みたいにしてオブジェクト突っ込めば良いんだけど、この場合サーバがあるFLAGを保存するようにしないとgetする時に上手く動かなかったりします。風の噂でTokyoTyrantがそのまんまだと使えないとか聞きました。
こういった事を解消する為に、シリアライザを自由に変更出来るようにしました。Cache::Memcached::Fastでもシリアライザ変更出来るけども、全然別のモジュール使うときを考えてData::Modelのレイヤでシリアライズする感じです。
my $driver = Data::Model::Driver::Memcached->new(
memcached => Cache::Memcached::Fast->new({ servers => [ { address => "localhost:11211" }, ], }),
serializer => 'Default', # default is L<Data::MessagePack> or messagepack minimum set for Data::Model
);という感じでデフォルトでMessagePackのフォーマットを使って直列化しています。MessagePackはサイズ効率よくシリアライズができるようで、上記のカラム名変換機能で数値カラム名に変換するとMessagePackのFixNumという超省スペースなデータが使われるため、とても効率が良くなります。
Cache::Memcached::Fast標準で使われるStorableだとバージョンの差異でデシリアライズとか出来なくなってはまるときもあるのですが、MessagePackだと当面そういった事も無いでしょう。
実装のし易さやユーザの選択が出来るように、これらの要素はバラバラに設定するようになってますが、基本的に全てのオプションを全部使う事でKVSにとっても嬉しいデータを作り出すようになっています。
シリアライズ以外の要素は、その効果がとてもわかり易いですが、シリアライズの部分もStorableを使ったよりもサイズがコンパクトになります。
例えば
install_model bookmark => schema {
schema_options model_name_realname => 'b';
key 'id';
column 'id' => int => { unsigned => auto_increment => 1 };
column 'user_id';
column 'url_id';
column 'bookmark_at';
schema_options column_name_rename => {
id => 1,
user_id => 2,
url_id => 3,
bookmark_at => 4,
};
};という定義で$model->set( bookmark => {
user_id => 1,
url_id => 1,
bookmark_id => time(),
}といった形でsetすると、keyの部分で(idの文字数)+2バイト、valueで(Mapの定義が1バイト+カラム名の部分のサイズ合計3バイト+user_idがFixNumなので1バイト+user_idも1バイト+bookmark_atはuint32なので5バイト)バイトの計11バイトで格納出来ます。と、これまでに紹介してない利点としては、KVSに保存するのはシリアライズされたハッシュオブジェクトなので、カラムの追加とかを自由に出来ると言う事ですね。ALTER TABLEなんかやらないでもアプリケーションのコードを変更するだけでカラムが増やせたり減らせるので簡単です!(減らしてもデータは消されないけど。)
特定のカラムの値でしかlookupしないのであれば、KVSをストレージとして選択してしまうというのもありかもしれませんね。
あんまり良くわかってないけどRemedieとかもそういう使い方をSQLiteでやってる?
特定のkey以外でもKVSを使ってデータの取得をするインターフェィスも作りたいとは思ってるので、それなりにRDBMSの置き換えとかできるかもしれないです。
KVSで簡単にORM風なインターフェィスを使うのにはData::Modelが最高というお話でした。
sfujiwaraさんがPostgreSQL用のDBDドライバも作ってくださってるようなので、ますます広がるData::Modelの可能性にご期待下さい!

Test::系のモジュールを書いている人は要注意 - Charsbar::Note
注意に気づいたので Test::PPPort を直してshipitしました。
ちなみに何する物かと言うと、XS用のppport.hはperl ppport.hとするとXSなコードを色々検査してくれるという事で有名ですが、このテストをあなたのテストスイートに組み込んで快適なXSライフが実現出来るというとても素敵なTest moduleなのですよ旦那さん!

全国的にみんな真面目だな〜。勉強会の目的なんてないよ。楽しいからやっている。それで何が悪いのかな?の実況中継、その勉強会への 参加そのものについてちょっと考えなおした方がいいかもしれない。
Imager::ExifOrientationをCPANにうpりました。
Exif の Orientation というパラメータを元にして回転済みのImagerオブジェクトを返します。
一緒に Imager::Filter::ExifOrientation もバンドルしてるので、filterとしても利用出来ます。
Orientationは何かと言うと、カメラに縦方向センサーが入ってる機種で、画像に対してカメラの上方向はどちらかというような情報が入っている所です。
わかり易い説明は500で見れないのでgoogleのキャッシュを見てみてください。
使い方は簡単で、exif入りの画像のパスをrotateメソッドに渡すとexif情報に基づいて回転したimager objectが帰ってきます。
my $image = Imager::ExifOrientation->rotate(
file => 'foo.jpg'
);
もしくは、適当に読み込んだ画像データを渡す事も出来ます。
my $data = do {
open my $fh, '<', 'foo.jpg';
local $/;
<$fh>;
};
my $image = Imager::ExifOrientation->rotate(
data => $data
);
カメラで撮ったオリジナルのjpegファイル自体を回転させるのもいいですが、Imagerのフィルターとしても使えるようにしました。
use Imager;
use Imager::ExifOrientation;
my $img = Imager->new;
$img->filter(
type => 'exif_orientation',
path => 'foo.jpg',
);
こんな感じで、 foo.jpg に入ってるexif情報を元に$imgの画像を回転させます。試しにfilterを使ってacotieを回転させてみましょう。
以下ソース
use strict;
use warnings;
use Imager;
use Imager::Filter::ExifOrientation;
for my $i (1..8) {
my $img = Imager->new;
$img->read( file => 'acotie.png' );
$img->filter( type => 'exif_orientation', orientation => $i );
$img->write( file => "おうっふ_$i.jpg" );
`open おうっふ$i.jpg`;
}
acotie.png は
これです。
Orientation の 3 は、単純に180度回転なのですが、Imagerのrotateを使うと汚くなるのでclip( dir => 'hv' )して、左右上下反転しました。
rotateは計算して頑張って画像を回転させるというのと、flipは単純にピクセルを並び替えるという差が奇麗さの差になってると思います。rotateはデータをコピーして計算するし。
90度やら270度回転は、流石にrotate使うしか無いけど。
追記:
そもそも90度づつの回転の場合は $img->rotate( right => 90 * $x );使うべきなので、書き換えて0.03をshipiしました。
90度やら270度の回転した画像も奇麗になた!

あざーす。循環参照しすぎるとバターになる。。なんでそんなに人の目を気にするのだろうと、マジレス。
早速ですが Data::Model っていう O/Rマッパー 的な物を CPAN にあげました。
Data::Model
http://github.com/yappo/p5-Data-Model/tree/master
元来は MVC モデルで言う所の Model を一括でまかなえるつもりで実装していますが、ロジック処理は普通の Perl のクラスで書いちゃった方が潰しが聞くため、主にストレージを Perl のオブジェクトにマッピングする ORM 的な使い方が主流となっています。
そして、 Data::Model の多くの実装や設計などは Data::ObjectDriver を参考にして開発しました。
他にも後述してる ORM の実装を参考にしています。
あ、あとは tokuhirom 先生による日本語チュートリアルがあります。
現在の所の情報源は CPAN に上がってるドキュメントの他に http://d.hatena.ne.jp/tokuhirom/searchdiary?word=Data%3a%3aModelとかhttp://d.hatena.ne.jp/yappo/searchdiary?word=Data%3a%3aModelぐらいですね。
あと、Hatetterのコードも結構参考になると思います。
Perl の ORM といえば、 Class::DBI をはじめに DBIx::Class, Data::ObjectDriver, Fey::ORM, Rose::DB, Jifty::DBI, DBIx::MoCo など( DBIx::Skinny も github にあるよ )があり、再実装する必要が無いようにも思います。
しかしながら既存の物は、 Inflate/Deflate まわりが貧弱で ForuceUTF8 的な事をやるのもちょっと大変だったり不安定だったり、 cache させるのが面倒だったり、 Moose 使ってたり、 社内の最新リポジトリと CPAN のバージョンが乖離していたりと「こいつと一緒にやりたい!」的な物が見つかりませんでした。確かに DBIC なんかは良いものだとは思いますが、複雑な事が出来てしまうがためにgdgdしてしまう事もあったりしたのです。
Data::ObjectDriver がだいぶ希望に近かったのですが、ドキュメントや利用事例が少なくてユーザになるのに二の足を踏みました。
という現状の ORM に持っていた不満点もあったのですが、それ以外の要因としては RBDMS を kvs 的なインターフェィスで使いたいな。そもそも Web アプリケーションだったら RDBMS の R の要素って使わなくても、やってけてるんじゃないか? だったら kvs 的に使えるように下ほうがさっくり DB の処理書けるんじゃないかな? という観点で作り始めました。
そういったスタンスなので Data::Model::Driver::Memcached という memcached protocol を喋るストレージサーバをバックエンドストレージとして使えるようになってます。
あまり長文はアレなので軽く特徴を
user テーブルの id というカラムと同じ役割のカラムを別のテーブルに持つ。それも沢山のテーブルで user id なんかを持ってたいと言うケースは多々あると思います。
そんな時は column sugar を使うと、カラムの詳細定義は一度だけ書いて、後は column sugar を呼ぶだけですみます。
# 定義する
column_sugar 'user.id'
=> int => {
required => 1,
unsigned => 1,
};
# user テーブルでの定義
column 'user.id' => { # ここではカラム名が id になる
auto_increment => 1, # auto_increment 属性だけ追加する
};
# bookmark テーブルでの定義
column 'user.id'; # ここではカラム名が user_id になる
user id だと当てはまらないですが、 複数のテーブルで定義するカラムで char がた見たいな仕様が代わり安いカラムだと、文字長の仕様変更が入っても一ヶ所だけ size を書き直せば良いので、楽でミスも減ります。
他の ORM でもよくあるですが、 Data::Model 使って定義したスキーマを CREATE TABLE の SQL に出力します。
そして column sugar が強力にいかせるのは、スキーマ定義に変更が入ったら as_sqls してしまって、そのまま RDBMS 側の DDL も一緒に変えると言う事です。
DB 側のスキーマ情報を自動的に読み込んで ORM のスキーマとしてやるのもありますが、それだとスキーマを二ヶ所で変えなきゃいけなくて面倒なので ORM 側のスキーマのみ変更すれば良いように考えています。
rails のようはマイグレーションも自動的にやりたい所だがまだ未実装です。DB と ORM 側の差分を自動的に反映したいな。
Tokyo Tyrant や groonga や kai などの memcached protocol を使える kvs 等を DBI の代わりに利用する事が出来ます。決定的な制限として primary key でしかデータが引けません。がこれは別の driver と組み合わせる事で対応可能にする方向性です。
Data::ObjectDriver インスパイアですが、 cache driver の failback driver を設定した driver object を使う時は、 cache にデータが無ければ、自動的に fallback driver にリクエストする用になります。
cache は Data::Model の Row object その物を渡す感じですが、 DBIC とは違って必要最低限の情報しか入ってないので、あまり問題にならない予定です。
また failback driver には Driver::Memcached を使う事も出来ますが、いわゆる memcached protocol しゃべる kvs は、それ単体での高速性を売りにしているためやる意味が分からんすね。
Data::Model の get method では index を特別に扱います。
例えば index post (user_id, post_at) の用な index を張っていたら
my $iterator = $model->get( tweet => { index => { post => [ 1, 1281729102 ] } } );
といった形でクエリを引けます。
Data::Model では標準で Q4M が扱えます。
以下の例は SELECT queue_wait('smtp', 'pop', 10); を発行して、 queue が帰ってきたらそれぞれのクロージャを呼び出します。
第一引数には dequeue された queue の row object が渡されますので、改めて query を発行せずに、 queue の処理が行えます。
my $retval = $model->queue_running(
smtp => sub {
my $row = shift;
is($row->id, 'foo');
is($row->data, 1);
},
pop => sub {
my $row = shift;
},
timeout => 10,
);
カラムにエイリアスを張ります。
バイナリデータをデータベースに格納するカラムがあるとして、利用する時には文字列形式とバイナリ形式を使いたい場合に、カラムにエイリアスを張ると両方の形式で利用出来ます。
columns qw( name nickname );
alias_column name => 'name_name';
alias_column nickname => 'nickname_name'
=> {
inflate => sub {
my $value = shift;
Name->new( name => $value );
# Name は name っていうメソッドを持ってるよ
},
deflate => sub {
my $obj = shift;
$obj->name;
},
};
こんな風にしておくと
$row->nickname; # 普通に文字列が返る
$row->nickname_name; # Name オブジェクトが返る
$row->nickname('test'); # 文字列をセット
$row->nickname_name->name; # test が返る
$row->nickname_name(Name->new( name => 'おうっふ' )); # オブジェクトをセット
$row->name; # おうっふ が返る
とエイリアス張る前と張った後のメソッドでも保持するデータを相互的に補完し合います。
当然対応しています。 Driver::DBI::MasterSlave です。
今どきのモダンなウェブアプリは slave の mysql は lvs 噛ましてると思うので、 slave は一個しか指定出来ません。このあたり Data::ObjectDriver 弄った事ある人なら、いかようにも read dbh 分散する仕組み作れると思います。
row object に メソッドを生やせる為の add_method って DSL がついてます。
同じ method をいっぱいの table に生やしたい時は mixin 機構があるので、サクサクメソッド生やせます。
DBIx::Class::ResultSet 的な所にメソッド生やしたい場合は、普通に use base 'Data::Model' してるクラスにメソッド生やせばおkです。
最近実装しました、 DBIx::Class::Storage::TxnScopeGuard インスパイアで以下のように書けます。
sub foo {
my $is_die = shift;
my $model = Your::Model->new;
my $txn = $model->txn_scope; # トランザクション開始
# トランザクション中は $txn からしか DB の操作出来なくなりますよっと
my $row = $txn->lookup( user => 1 );
$row->name('transaction name');
$txn->update( $row ); # update
return if $is_die; # スコープ抜けて commit されてないのでロールバックされる
if ($is_die) {
$txn->rollback; # 明示的にロールバック
return;
}
$txn->commit; # commit する
}
foo(1); # rollback されてる
foo(0); # commit できる
eval {}; if ($@) {} みたいなトランザクションの実行だと、例外があってメソッドをそのままreturnして抜ける事が出来ないので、こっちのが簡潔で気持ちいいと思ってます。ORM だと、よく1テーブル/1クラスファイルみたいな感じになっちゃいますが(普通にそうならなく出来るけど)、 Data::Model だと、1クラス=1データベース みたいな感じにする方向性なので、1つのクラスファイルに沢山テーブルの定義をやっちゃいます。
なんとリレーション周りを標準でサポートしてません!
add_method 使えば has_a くらいは楽に書けるよ。
よい実装手法があれば作りたい所。
kazuho ware の新作 Pacificに対応予定。
リゾルバとのやり取りを Data::Model 側でやるかどうするかは考えてないけども、結構簡単にラッピング出来るイメージ。
予定つながりだと FriendFeedのアレとかも入れたいですね。
まだ特徴はあるですが、面倒なのでまとめる。
作り始めてから半年以上経ってようやくリリースできました。
現在自分がバリバリのユーザですが、使ってみた感じだと徐々に良い感じにもなってるし、テストも充実させている、ドキュメントもそこそこ使い方がわかる程度には書いてあるので是非ともお試しください。
あ、あと重要な事ですが、何でも自分で作りたい病だから作った訳ではないです。

「全裸は違法だということを言われた。ええええ、そんな法律があるのか?Debugはできるようになるかもしれない。」と思っておセンチなyappoです。
hashを簡単にmergeするCPAN moduleとしてHash::Mergeがあるのは有名ですが、デフォルトだと色々頑張ってマージしちゃうので、例えばHTTP::Engine::Middlewareの使いたいMiddlewareをARRAY refで書いちゃったりして、base.yamlとproduction.yamlでmergeした時に、以下のような混ざりかたでとんでも無い目にあいます。
use strict;
use warnings;
use YAML;
use Hash::Merge;
my $base = {
Middlewares => [
{ module => 'HTTPSession', config => { name => '開発やらステージング用の設定だよ' } },
{ module => 'MethodOverride' }, # 全部で共通して使いたいよ
],
name => 'base',
base => 1,
};
my $production = {
Middlewares => [
{ module => 'HTTPSession', config => { name => '本番用の設定だよ' } },
],
name => 'production',
production => 1,
};
my $config = Hash::Merge::merge($base, $production);
print Dump($config);
---
Middlewares:
- config:
name: 開発やらステージング用の設定だよ
module: HTTPSession
- module: MethodOverride
- config:
name: 本番用の設定だよ
module: HTTPSession
base: 1
name: base
production: 1
これは、マズいですね、HTTPSessionの設定を開発と本番で別けたいのにARRAYだから全部混ざっちゃいます。
そんな時はspecify_behaviorでmergeのルールを弄れるのです。左のreftype => 右のreftypeみたいな形で、左の要素がSCALARで右の要素がARRAYだったどうこうするみたいな事が出来ます。
ぶっちゃけ左の要素がHASHで右の要素がARRAYとかだいぶあり得ないので、そういった組み合わせになったらdieするとかすると混乱無いと思います。
こんかいは左右でreftypeが違うと混乱するし、ARRAY同士でmergeしないで右要素だけを生かしたいと言う要望でbehaviorを作ったです。あと、behavior作っちゃうとデフォルトの振る舞いが上書きされるのでget_behaviorで今の振る舞いを取っておいて用が済んだらset_behaviorすると良いと思います。
use strict;
use warnings;
use YAML;
use Carp;
use Hash::Merge;
my $base = {
Middlewares => [
{ module => 'HTTPSession', config => { name => '開発やらステージング用の設定だよ' } },
{ module => 'MethodOverride' }, # 全部で共通して使いたいよ
],
name => 'base',
base => 1,
};
my $production = {
Middlewares => [
{ module => 'HTTPSession', config => { name => '本番用の設定だよ' } },
{ module => 'MethodOverride' }, # array は上書きされるので、こっちにもかく
],
name => 'production',
production => 1,
};
my $old_behavior = Hash::Merge::get_behavior;
Hash::Merge::specify_behavior({
SCALAR => {
SCALAR => sub { $_[1] },
ARRAY => sub { Carp::croak 'SCALAR and ARRAY cannot merge in config file.' },
HASH => sub { Carp::croak 'SCALAR and HASH cannot merge in config file.' },
},
ARRAY => {
SCALAR => sub { Carp::croak 'ARRAY and SCALAR cannot merge in config file.' },
ARRAY => sub { $_[1] },
HASH => sub { Carp::croak 'ARRAY and HASH cannot merge in config file.' },
},
HASH => {
SCALAR => sub { Carp::croak 'HASH and SCALAR cannot merge in config file.' },
ARRAY => sub { Carp::croak 'HASH and ARRAY cannot merge in config file.' },
HASH => sub { Hash::Merge::_merge_hashes( $_[0], $_[1] ) },
},
}, 'MY_CONFIG_STRICT_MODE' );
my $config = Hash::Merge::merge($base, $production);
Hash::Merge::set_behavior( $old_behavior );
print Dump($config);
---
Middlewares:
- config:
name: 本番用の設定だよ
module: HTTPSession
- module: MethodOverride
base: 1
name: production
production: 1
素敵にマージされましたね。

こんにちわ!gitがむづかしすぎてgitなんか滅んでしまえば良いのにと思ってる金曜日の天使ことyappoです。
表題の通り HTTP::Engine 関連のプロジェクトを github に引っ越しました。
http://github.com/http-engine
http://twitter.com/httpengine
http-engineアカウントを取ってそっちで管理する感じです。
必要な方にはコラボレータ追加したりとか良い感じで運用しようと思います。
なおHTTP::Engine 0.1.8 をshipitしました。
Any::Moose 0.08 での変更の追随や
http://example.com/?aco=tie でリクエストたときに $req->uri の中身が http://example.com?aco=tie になってしまうバグが解決されています。
次は、$req->uri->baseがInterfaceによって取れる値が違うのでこれを共通化する方向にしたりとか、良い感じでapplicationのroot pathを取れる仕組みを追加したい所ですが何校中です。
ちなみに移行にはperl製のsvn2gitをforkしてhttp://github.com/yappo/svn2git/tree/master使いました。
$ mkdir hoge $ cd hoge $ git init $ svn2git --strip-tag-prefix 'release-' http://svn.example.com/some-project $ # git remote ついか $ git push origin master $ git push --all $ git push --tagな感じで、branches/tagsも含めて全部移行できました。authorsとかのコンバートは面倒いのでやらんす。

Perlをもっとブログの表舞台に - Iron ManコンテストとかPM 05:36 Iron Man Blogging Challengeとか見て僕も応募してみたよ!
エスペラント語だろうが地球語だろうが言語は何でも良いそうなので日本のPerl書きの皆も申し込めば良いよ!
ironman@shadowcat.co.ukにblogのurlとそのblogの詳細を送れば参加出来るみたいだよ!
僕はURLと日本の諺を添えて送っただけだけどちゃんと受理されるかな?
上手くすればmstの髪の毛の色を好きに変える権利も持てるみたいだし損する事は無いので日本のPerlの盛り上がりぶりを世界に知らしめるチャンスだから皆応募しようぜ!

Log::Dispatch::Screen::Color を shipit しました。(りぽじとりはこっち)
昨年末に空前のlog colorブームがあったのですが、最近僕もようやくLog::Dispatchをまともに使うようになったので、Log::Dispatch::Screenに色付けたくなって付けました。
うそです。hirose31さんが呟いてたので作りました。
こんなコードと
use strict;
use warnings;
use Log::Dispatch::Config;
Log::Dispatch::Config->configure('test.cfg');
my $log = Log::Dispatch::Config->instance();
$log->info('いんふぉー');
$log->error('えらーーーーーだよ');
$log->warning('warningwarningwarning');
こんなconfigで
dispatchers = screen screen.class = Log::Dispatch::Screen::Color screen.min_level = debug screen.stderr = 1 screen.format = [%d] [%p] %m at %F line %L%nこうなります
もちろんLog::Dispatch::Colorfulは知っているのですが、これを使うとLog::Dispatchのメソッドを書き換えちゃうので、やや微妙という所もありすっきり仕上げてみたしだいです。
パッチ送れって話もあるですが、$foo->debug({ foo => 'bar' })みたいな事したらDumpしてくれるようにvalidateとか変えてあって、ちょっと僕の欲しい物の方向性じゃ無さそうだという所で新たに作ったのでした。
Log::Dispatch::Colorfulとの互換性はあるので安心です。
とか書いてるうちにcharsbarさんがWin32対応書いてくれたす charsbar++

こんにちは!近頃咳と痰と鼻水と鼻づまりがすごく多い、金曜日の天使ことYappoです。
ちょっとしたツールをPerlで書いて、お友達に使ってもらいたいときってありますよね?普通は常識的にgithubとかのurlを教えれば良いのですが、それも出来ない人とかもいた場合が非常に面倒です。
そんな時の便利ツールとしてPlatypusがあるのは有名ですね。
Platyputsを使えば簡単にXSを含めたアプリが配布出来ますんです。
XSとかはアーキテクチャ等によって違うバイナリが吐かれてる事が知られますが、今回はあなたと同じMacOSのバージョンが入ってる事を前提にしちゃって問題無いです。
Macユーザ同士なんだからCPUのアーキテクチャは、殆どの場合は一緒だろうしOSのバージョンもLeopard使ってる前提にしちゃいましょう。
まずは作業用ディレクトリでも、作りましょう。mkdir ~/yourappname-work/とかで良いでしょう。
cd ~/yourappname-work/ してから mkdir extlib します。
あなたのアプリで使ってるCPANモジュールを突っ込むのです。
mkdir -p lib/local して local::lib の lib.pm を lib/local ディレクトリの中に入れます。
以下のextlib install用のスクリプトを~/yourappname-work/の中において実行します。
use strict; use warnings; use lib 'lib'; use local::lib '--self-contained', 'extlib'; # miyagawaさんのアドバイスで書き換えました use CPAN; CPAN->shell;もしくはlocal::libを普通にインストールして、miyagawaさんが書いたhttp://gist.github.com/104823使うのがいいかなと。
あまり良くわかってないけど、/System/Library/Perl/5.8.8以下にMacOSが添付してるモジュールが入ってるようなので、@INCをいじって標準モジュール以外はキッチリインストール出来るようにしておきますね。
で、このスクリプトはCPAN Shellになってるので、頑張ってあなたのアプリを実行するのに必要なCPANモジュールをインストールしてください。XSでも大丈夫ですが、外部ライブラリに依存するような物(TokyoCabinetなど)はちょっとやり方解らないので誰か教えてください。
今度はPlatypusがkick startするscriptを用意します。#!/usr/bin/env perl とかshebangしとくと良いでしょう。ちなみにこのスクリプトの中では@ISAを弄る必要は特に無いですが
use FindBin;
use lib ("$FindBin::Bin/remedie-git/lib", "$FindBin::Bin/remedie-git/extlib", "$FindBin::Bin/extlib/lib/perl5");
とかしてextlibへのパスを通す必要はあります。
もし、あなたのアプリが$ENV{HOME}を使うようなら
BEGIN {
$ENV{HOME} = "$FindBin::Bin/home";
}
use Remedie::CLI::Server;
Remedie::CLI::Server->new_with_options(
root => "$FindBin::Bin/remedie-git/root",
)->run();
とかして、使用するPATHには気を使う必要があります。
$FindBin::Binは YourApp.app/Contents/Resources が該当するため、あなたのスクリプトの使うディレクトリはアプリの外のディレクトリを使わないように気を使いましょう。
Platypusを起動して必要な項目とか埋めたり選択して下さい。ここでは詳しく書きません。
Script Pathは、上で書いた.app用のscriptでを選択して下さい。
重要なのは左下の「Show Advanced Options」をクリックして出てくる

でして、右側の+をクリックして頑張ってCPANインストールしたextlibのパスを指定して下さい。
配布アプリの中にそのままコピーされて含まれるのです。
extlib以外の物を配布アプリに含めたい時は任意に好きなだけ追加してください。僕はremedieをgit cloneしたディレクトリを丸っと入れたりしました。
あとは「Create」して、アプリが出来るのを待ちます。
僕の場合は YourApp.app/Contents/script に実行bitが立ってなかったので、 chmod ugo+x YourApp.app/Contents/script しました。
それをやればあっという間に普通のMacのアプリで実行出来る筈です。
MacでPARみたいにする手順をずらずら書きました。
Platypus、 local::lib、scriptで使うファイルは$FindBin::Binの中に入れるとアプリケーションの外を汚さなくてすむ。という簡単な要素で作れます。
僕もこれでRemedia.app作ったら他の人のMacでも動きました(最近のmacはlibxml2はいってるっぽ)
さぁ皆さんもPerl使って素敵なMacアプリ開発ライフを過ごしてください。Enjoy!

こんにちわ!金曜日担当・Shibuya内フェアリーことYappoです。
mixi Engineers’ Blog » PerlとRubyで省メモリなハッシュを使おうにて
100万件のレコードを格納した場合のメモリ使用量と処理時間を測ってみましょう。Perl(5.8.8)でテストコードを動かしたところ、以下の改善が確認できました。標準のハッシュに比べて、メモリ使用量がTCのオンメモリハッシュだと約61%、TCのオンメモリツリーだと約37%になることがわかります。処理時間に関しては157%ほどになっていますが、まあ許容範囲ですよね。といった事が書かれており、その文面の上の解説で、tieしたので、tieしてるからおせーんじゃねーの?とテストコードも見ないで呟いてたらmikioさんからtie使わないでやってるよ!とつっこんでいただきました
でもまぁ腑に落ちない所もあり「mikio wareがperlのhashより遅いわけが無い!」と思いながらもshibuya.pmとかあって放置してたのですが、OpenFrepaカンファレンスも終わったのでTokyoCabinet.pmの実装を見てみたら、引数の値チェックをpure perlでやりつつXSのコードを呼んでいる実装でした。
引数の値チェックは置いといて、Perlと言うのは関数呼び出しのコストが馬鹿に出来ないので、試しにXSの関数を直接呼ぶように書き換えてベンチマークを取ってみました。
以下結果で、hashが元のテストコードで言う所のPerlのハッシュの実装で、tc_mikioがmikioさんのTCを使った実装で、tc_yappoが今回XSを直接呼ぶようにしてみた実装です。
$ perl ./benchmark.pl
Rate tc_mikio hash tc_yappo
tc_mikio 333333/s -- -29% -52%
hash 469484/s 41% -- -32%
tc_yappo 694444/s 108% 48% --
=== ちゃんとkey/valueが入ってるか見るよ at ./benchmark.pl line 41.
hash : 00222791 => h00222791 at ./benchmark.pl line 43.
mikio: 00222791 => m00222791 at ./benchmark.pl line 44.
yappo: 00222791 => y00222791 at ./benchmark.pl line 45.
やっぱりTokyoCabinetの方が断然高速ですね!mikio++
以下ベンチマークスクリプトです
#!/usr/bin/perl
use strict;
use warnings;
use blib;
use Benchmark 'cmpthese';
use TokyoCabinet;
my $runnum = 1000000;
my $tc_args = sprintf('*#bnum=%d#mode=wct#xmsiz=0', $runnum);
my %hash;
my $mikio_db = TokyoCabinet::ADB->new;
$mikio_db->open($tc_args) || die 'mikio open failed';
my $yappo_db = TokyoCabinet::adb_new();
TokyoCabinet::adb_open($yappo_db, $tc_args) or die 'yappo open failed';
my($hash_i, $mikio_i, $yappo_i) = (0, 0, 0);
cmpthese(
$runnum, {
hash => sub {
my $buf = sprintf('%08d', $hash_i);
$hash{$buf} = 'h'.$buf;
$hash_i++;
},
tc_mikio => sub {
my $buf = sprintf('%08d', $mikio_i);
$mikio_db->put($buf, 'm'.$buf);
$mikio_i++;
},
tc_yappo => sub {
my $buf = sprintf('%08d', $yappo_i);
TokyoCabinet::adb_put($yappo_db, $buf, 'y'.$buf);
$yappo_i++;
}
}
);
warn "=== ちゃんとkey/valueが入ってるか見るよ";
my $key = sprintf('%08d', int(rand($runnum)));
warn "hash : $key => " . $hash{$key};
warn "mikio: $key => " . $mikio_db->get($key);
warn "yappo: $key => " . TokyoCabinet::adb_get($yappo_db, $key);
$mikio_db->close;
TokyoCabinet::adb_close($yappo_db);
結論としてはTokyoCabinet.xsにid:gfxパワーが加わると(xsの中で引数チェックとかするの意)とんでもない速度になりそうです。

こんにちは、本日のHOTEL担当、素敵なレディーことYappoです。3人の荷物が家族のオモチャにされないか心配だけどもう寝るぞ!話は変わるけど、acotieさんはアクメアクメ言っててどんだけアクメ好きなんだよ!と思ったのは内緒だぞ!
という訳でShibuya.pmで発表してきました。二本立てです。
一本目は、一般的なperl userの作法のBやらDevel::Peekの紹介に加えて、新しく作ったDevel::RunOpsAnalizeを使ってOPCODEの実行単位でPerlの動作を覗き見る方法の紹介をしました。
二本目はLTで、dan the eval botの作り方を説明する為のCentOSのインストールをするというのを口実にHatetterのアーキテクチャや、なぜこれらの要素を採用したかを紹介しました。
もちろんCentOSのインストールもCobblerとKoanのお陰で完了して、local::libでdan the eval botに必要なperlモジュールも楽々installできるとか嘘つきながら、3分クッキングメソッドで無事にirc botもirc serverにjoinする所までLTの限られた時間の中でデモできました。
LTの中で二つの題材を同時進行で発表するメソッドは案外使えるんだなと思いましたね。30秒オーバするポカやらかしたけど。
ちなみにnon-blockingとか言いましたが、実際にはmemcachedやらQ4Mの処理でblockは発生します。が、気にしなくても良い程度のblockです。maybe
資料は、http://svn.coderepos.org/share/docs/yappo/20090422-shibuyapm11から適当に辿って下さい。VMのサンプルスクリプトもありますよ。
Devel::RunOpsAnalizeはhttp://github.com/yappo/p5-devel-runopsanalyze/tree/masterから
LTのサイトのソースコード一式はhttp://github.com/yappo/website-hatetter/tree/masterからどうぞ。
関係無いけど、英語が出来ない,OCamlがわからない,etc etc etcなどと言ったくだらない理由で、そういう自分が苦手だとかいうのから遠ざかるのは馬鹿だなーと思ったなー。僕なんて相変わらず英語でコミュニケーション取るのがXS書くのより大変だけど、なぜか俺の横で海外組の二人が寝てるよ。起こしかたとか朝飯とかどうすりゃいいんだかわからんけど。
あーあとhidekさんのスター画像作んなきゃ

CPUの気持ちになってプログラムを書くということ Kansai.pm#11 参加記その1 - プログラマになりたい
ちなみに、下記のコードはデータハザードを解消する為のコーディング例です。データハザードは、命令が利用するデータ間に依存関係がある場合に発生します。前の命令が終わらないと後ろの命令が実行できないとか。ですので、それを解きほぐしてやれば、並列で処理が出来るようになります。という感じでnaoyaさんもぶこめで
loop unrolling は perl でもちゃんと効果があるって書いてるけど、それforブロック(スコープ)が一段増えてる事で差が出てるんじゃないかと思うわけです。はい。
以下検証コード
use strict;
use warnings;
use Benchmark qw(:all);
cmpthese(5000000, {
'pseudo loop unrolling' => sub {
my $sum = 10;
my $i = 1;
$sum = $sum + ($i + 0);
$sum = $sum + ($i + 1);
$sum = $sum + ($i + 2);
},
'scope 1' => sub {
{
my $sum = 10;
my $i = 1;
$sum = $sum + ($i + 0);
$sum = $sum + ($i + 1);
$sum = $sum + ($i + 2);
};
},
});そして結果$ perl ./loop.pl
Rate scope 1 pseudo loop unrolling
scope 1 1524390/s -- -25%
pseudo loop unrolling 2040816/s 34% --
なぜかブロックを1つ増やしただけなのに、こんなに差がでちゃいましたね!不思議!
ブロックがあるという事は、スコープがあると同義なのは当たり前ですが、スコープが変わるという事はレキシカル変数の処理などをやらなきゃいけないわけで、{}があるだけでもPerlは処理をいっぱいするわけです。
別にブロック増やすなというわけではないですが、ベンチマークを取る時にはこういう所にも気をつけたい所ですね。
!hyoshiokさんが、そもそもloop unrollingがperlで意味あるか?というのを気にしていたようなので、効果あるよって言うベンチマークしたす。
forしたコードと、for文だと3回scopeの出入りがあるので、それにあわせるコードも追記して、さらにmy $jのコストも加算するようにした。
use strict;
use warnings;
use Benchmark qw(:all);
cmpthese(5000000, {
'pseudo loop unrolling' => sub {
my $sum = 10;
my $i = 1;
$sum = $sum + ($i + 0);
$sum = $sum + ($i + 1);
$sum = $sum + ($i + 2);
},
'scope 1' => sub {
{
my $sum = 10;
my $i = 1;
$sum = $sum + ($i + 0);
$sum = $sum + ($i + 1);
$sum = $sum + ($i + 2);
}
},
'scope 3' => sub {
{
my $sum = 10;
my $i = 1;
{
$sum = $sum + ($i + 0);
}
{
$sum = $sum + ($i + 1);
}
{
$sum = $sum + ($i + 2);
}
}
},
'scope 3 and my $j' => sub {
{
my $sum = 10;
my $i = 1;
{
my $j = 0;
$sum = $sum + ($i + $j);
}
{
my $j = 1;
$sum = $sum + ($i + $j);
}
{
my $j = 2;
$sum = $sum + ($i + $j);
}
}
},
'loop' => sub {
my $sum = 10;
my $i = 1;
for my $j (0..2) {
$sum = $sum + ($i + $j);
}
},
});結果$ perl ./loop.pl
Rate loop scope 3 and my $j scope 3 scope 1 pseudo loop unrolling
loop 683995/s -- -11% -17% -48% -63%
scope 3 and my $j 772798/s 13% -- -6% -42% -58%
scope 3 823723/s 20% 7% -- -38% -55%
scope 1 1322751/s 93% 71% 61% -- -28%
pseudo loop unrolling 1824818/s 167% 136% 122% 38% --
dh004:t ko$ perl ~/bin/htmlescape.pl loop.pl
やる意義については置いておいて、意味はあるとは思うですよ。

昨年末にHE con #1 が開催されてから久しいですが、あの前後で話題になっていた
「HTTP::Engineは依存が大杉メモリ食いまくり」な件に関しては、Shikaという回答を出し、その後Mouse版の0.1.1をリリースしました、
そして最近Stevanから「Any::Mooseはどうか? lang:en」と言った話も有り、現在Any::Mooseに依存した0.1.4を出すべく0.1.4_xをCPANにあげています。
クラスビルダーにMooseを使うか捨てるか論争は、0.1.4にて妥協出来る所に落ち着いたんじゃないかなと思います。
Any::MooseやMouseが細かい所で挙動が変わるかどうかは今のところわかりませんが、少なくともHTTP::Engineで採用した事により安定する方向になるんじゃないでしょうか?
もちろんより高い互換性の為の変更は入るでしょうが。
0.1.4によってデフォルトはMouseを使い必要とあればMooseで動くようになるので、CatalystのEngineとして使う時はMooseで、Mooseを使うコストが気になる時はMouseが使えるようになりました。
MooseとMouseは細かい所では互換性ありませんが、HTTP::Engineで使ってる内容ではAny::Mooseを噛ますだけで、この差異はほぼ吸収出来ています。
MooseX, MouseXだと互換性が今イチわからない(というか基本的にMouseXはMooseXのが使えるように進める方向性みたい)、これも互換性の高いMo[ou]seX::Typesしか使っていないため問題無いです。
最新のHTTP::EngineではMooseがインストールされた環境でperl ./Makefile.PLするとデフォルトのテストとは別にMoose用のテストを生成して両方テストするようにしています。
cpantestersなどでテスト結果を見るとt/mooseをテストしてるのやテストしてない人が居るとおもいます。(0.1.4_01ではバグってておかしいけど)
Any::Mooseとは、端的に言ってしまえば「use Any::Mooseほげほげ」した時に、Mooseがloadされていれば「use Any::Mooseほげほげ」が「use Mooseほげほげ」と同等の処理になり、Mooseがloadされていなければ「use Mouseほげほげ」になる感じです。
一度そのクラスでuse Any::Mooseされてれば、次回以降そのクラスの中でuse Any::Moose呼ばれた時には最初に選んだほう(Moose/Mouse)が使われます。
any_mooseに関しても同じ
特に何もしなければ、一番最初にuse Any::Mooseした時に選んだ方が他の時にも使われる。
HTTP::EngineはWSGIやRackインスパイアである事は周知の事実ですが、HTTP::Engineが始まった当初からHTTP::Engine::Middlewareという物を作る予定になっていました。
これは a( b( c( handler() ) ) ) のような形で、実際のハンドラ処理にmiddlewareの処理がラッピングされるイメージに近しいイメージで処理をラッピングします。
現在は、様々な方の成果をまとめてDebugScreen/DebugRequest/Encode/Static/HTTPSession/FillInForm/Profil/ReverseProxyなどなど、このレイヤで利用度の高そうな処理を行ってくれるmiddlewareが標準でついてきます。
認証周りを誰か作ってくれないかなぁという所です。OpenIDはzigorouさんだけど。
middlewareは、あくまでもHTTP::Engineとアプリケーションの中間層なのでHTTP::Engineのプラグインでない事に注意が必要です。
plugin的な物が欲しければ、アプリ側にあるべきです。
アプリのプラグインとして、アプリ固有のmiddlewareなんかでもいいです。
ものすっごくベーシックなアプリならHTTP::Engine + HTTP::Engine::MiddlewareだけでもWAFを使わずにかけるかなと言う感じです。
もちろんWAFとかのレイヤがないとMVCやらMVACやら出来ないので大変だけど。
HTTP::Engineは非同期処理とか出来るInterfaceを付けたいなと思ってます。もちろんドキュメントやチュートリアルも。
0.1.x系統で、APIやら基盤はかなり安定してきているためドキュメントを日本語でも良いから増やしたいですね。
HTTP::Engine::Middlewareはパッケージングをどうするか等を詰める感じでしょうか。
0.1.4が出てからは、Mooseな人もMouseな人も使えるようになりますので、是非使ってみて下さい。
参考書籍は無いですが
また、良質の日本語記事としてcharsbarさんのgihyoの記事もあるよ!

MouseX::Typesを作るにあたり、あまり使った事のないMooseX::Typesを試していてドはまりした。
普段Mooseのsubtypeとか指定するときは
subtype 'Natural' => where {};とかやってtype name と定義の間をfat commaで繋げたりする。subtype Natural => where {};みたいな事を書いていたわけ。
MooseX::Typeで
use MooseX::Types -declare => [qw/ Natural /]のような感じで定義しようとした時には、MooseX::TypesがNaturalという関数をexportするんですね。
use MyTypes 'Natural'で、この定義がisaやdoesなどで使えるようになる。
has foo => ( is => 'rw', isa => Natular );といったhas定義が書ける。(クオートでくくる必要が無い)
で、MooseX::Typesをきちんと使うためには、subtype/coerce/class_type/role_type/hasのisa/doesなどに、このexportされた関数を渡さなくてはならない。
文字列を渡してはならないのだ。
この関数はMooseX::Types::TypeDecoratorのオブジェクトを返す。このオブジェクトはoverloadされており文字列で評価された時には、typeの名前が返ってくる。
標準で、定義したクラス名+定義名になるので、今回の場合は「MyTypes::Natural」という文字列が変える。
ようするに
subtype 'MyTypes::Natural' => where {};has foo => ( is => 'rw', isa => 'MyTypes::Natular' );という定義をしている事と同等なのだ。
さて、冒頭のうかつな
subtype Natural => where {};は、どうなるというとfat commmaなのでNaturalの部分が文字列として評価されてMyTypes::Naturalの定義がされない事になる。まとめとしてはMooseX::Typesを使う時には
subtype Natural, where {};のようにfat commaは絶対使っちゃダメ!

JPerl Advent Calendar 2008が始まりました。Perl に関するちょっとした Tips を、毎日一個とか書いてくのです。
codereposのアカウントがあれば誰でもかけます。
はてなアイデアでadvent calendar ( http://perl-users.jp/articles/advent-calendar/2008/ ) が一ヶ月続いたら、id:precuredaisukiが執筆者全員に雛寿司を奢るというアイデア。codereposのアカウント持ってれば誰でも書けるよ!というアイデアも出されているので、寿司食べたい人は参加するといいよ。

流石に3日連ちゃんで発表するのは、どこのYAPC::Asia状態だよ!?と思っていて当初は控えていたのですが、案外体力的にも行けそうだったので当日になって飛び入りで発表させて頂きました。
Yokohama.pm++
本日の発表は、既にtokuhiromが書いてるけど、Shikaについてです。
http://svn.coderepos.org/share/docs/yappo/20081128-yokohamapm3/shika.pl
軽量化MooseなんだったらなぜMouseじゃないのか?Shikaを使う利点は何か?今のステータスはどういう物か?等を話してきました。
前日の昼にスタートしたプロジェクトの事を勉強会で発表するなんて早漏すぎだと思われるかもしれないけれども、Shikaのようなものの需要はだいぶ前から構想されてたのでちょうどいいのです。
必然的にHTTP::EngineをCGIでそこそこ使える時代になってきそう。
ちゃんとフォーローしときますがMooseが駄目だとかそういう話ではないです。あくまでも用途とMooseで出来る事にちょっとしたギャップがあっただけ。
本当はShikaの話は5分で終わってData::Modelのプレゼンしようと思ってたけどShikaだけで時間つかっちゃいましたw
id:nekokakによるDBIx::SkinnyのプレゼンがそのままData::Modelの資料として転用出来そうなので、それをコピペして改変してどっかで発表出来ればなと思っています。
たぶんORMconあたり。
ちなみにDBIx::SkinnyよりData::Modelの方が速いとかとか。
「僕たちはMOPを使いたいんじゃなくて気持ちよくコードを書きたいだけ」という事を再認識しました。

perl weekという事でHTTP::EngineカンファレンスとShibuya.pmで発表してきました。
http://svn.coderepos.org/share/docs/yappo/20081126-hecon1/hecon1.pl
http://www.nicovideo.jp/mylist/8698529
HEConはhidekさんの絶大な協力によりつつがなく終わる事ができました。Yacafi::Engineに感動しっぱなしでした。
dannさんも切望してるのでHECon#2なんかもあったりするかもしれません。
http://svn.coderepos.org/share/docs/yappo/20081127-shibuyapm10/shibuyapm10.pl
http://www.nicovideo.jp/mylist/9691133
shibuya.pmでは、主に今やってる事の紹介などをしてきました。
なんかしらの勉強会をやると世の中が動くとは孔子もいってましたが、良い感じのプロジェクトも始まりましたが、そのお話は後日ということで。
週末にはSUTEKI hackathonが開催されるので、今回発表したもの周りのコードをぐいっと進めたい所ですね。

HECon前の前菜に最適だったので。
404 Blog Not Found:perl - LWP::UserAgentで進捗表示しつつダウンロード
というかHECon1は参加条件緩めたしまだあと10名程来れるので是非是非きて下さい。発表枠も1-2枠くらい余ってます。Shibuya.pmの前夜祭的な参加もおkす。
で、何をやったかというとファイルアップロードされるとプログレスバーを表示する。
ServerSimpleやPOE向きの実装。
これを使う事によりアップロードされまくってる感が増大します。しかも簡単なhackで済んでるところも素敵ですね。
こんな感じにコンソール出力されます。
$ perl ./http-engine-progressbar.pl
HTTP::Server::Simple: You can connect to your server at http://localhost:1978/
Upload[15774168]: 100% [=========================================================================================================]D 0h00m04s
use strict;
use warnings;
use HTTP::Engine;
use Term::ProgressBar;
my $engine = HTTP::Engine->new(
interface => {
module => 'ServerSimple',
args => { port => 1978 },
request_handler => sub {
my $req = shift;
return HTTP::Engine::Response->new(
body => q|<form method="post" enctype="multipart/form-data">
<input type="file" name="upload_file" />
<input type="submit" />
</form>|
) unless $req->param('file');
},
}
);
{
my $progress;
my $content_length = 0;
my $read_size = 0;
$engine->interface->request_builder->meta->make_mutable;
$engine->interface->request_builder->meta->add_before_method_modifier(
_read_init => sub {
my($self, $args) = @_;
return unless $content_length = $args->{content_length};
$read_size = 0;
$progress = Term::ProgressBar->new({
count => $content_length,
name => "Upload[$content_length]",
ETA => 'linear',
});
},
);
if (1) {
$engine->interface->request_builder->meta->add_around_method_modifier(
_read_chunk => sub {
my $next = shift;
my $size = $next->(@_);
$read_size += $size;
$progress->update($read_size);
return $size;
},
);
}
$engine->interface->request_builder->meta->add_after_method_modifier(
_read_to_end => sub {
return unless $content_length;
$content_length = 0;
$read_size = 0;
},
);
$engine->interface->request_builder->meta->make_immutable;
}
$engine->run;

来る11月27日(水)にShibuya Perl Mongersテクニカルトーク#10が行われます。
具体的に話す内容は決まってませんが大筋のテーマに沿ったものになるます。
Perlを第二言語にしてもらえる予備軍の人向けの話は他の人にゆづるかんじで。

Crypt::RSA を Mac で使いたくて Crypt::RSA を install 仕様としたら Math::Pari でこけた。
なにやっても入らない macports しても無駄。fuckfuckfuckfuckだったのですが、ようやく入れる事が出来た。
GCC の インライン最適化を仕様として全オブジェクトファイルに_overfllowというシンボルを作ってリンクできなかったかんじ?
cd /tmp
wget ftp://megrez.math.u-bordeaux.fr/pub/pari/unix/OLD/pari-2.1.7.tgz
pari-2.1.7が必要
tar zxvf pari-2.1.7.tgz
sudo cpan> look Math::Pari
で 2.010800 を入れようとして shell に。
おもむろに vim Makefile.PL して GCC_IN がついてる行をコメントアウト。
vim libPARI/Makefile.PL もして同上。
perl ./Makefile.PL paridir=/tmp/pari-2.1.7 machine=none
make
make test
make install
Crypt::RSAもちゃんとはいった。。。あーつかれた。もう疲れてRT送る気力無い。いつか送る。

色々とbug fixやらがたまってきたので 0.0.18 として shipit しました。
仕様はほぼほぼ固まっているのでドキュメントを充実させて1.0.0を出すために0.9.1_xx系統をやって行きたいとは思ってます。
川崎さんにmod_fastcgi + apach2な環境のテスト作ってもらえたら嬉しいなぁ。なんて。

Yacafiが色々と拡張されました。
TemplateはMojo::Templateを改造したMENTA::Templateを移植して使っています。MENTA::Template について - TokuLog 改めB日記も参考にしてください。
Template機能を使わない状態で--packした場合には不要なコードが消えるようになってたりします。
アクションは、今まで./yacafi.cgi?action=fooだったらdo_fooを呼ぶようにしてたんですが、./yacafi.cgi/fooという形をとるようにしました。./yacafi.cgi/foo/bar/bazでdo_foo_bar_bazが呼ばれます。./yacafi.cgi/foo_bar_bazも同様です。
その他実際に動いている様子をhttp://tech.yappo.jp/demo/yacafi/yacafi.cgi/やhttp://tech.yappo.jp/demo/yacafi/yacafi-template.cgi/で確認出来ます。
ファイルアップロードCGIつくるための方法は無いですがおいおい考える事にする。

株式会社KDDIウェブコミュニケーションズさんの御好意のお陰でHEconが開催される事となりました。
http://soozy.org/index.cgi?HEcon1
主にHTTP::Engineや、それに類する技術についての勉強会です。(場合によってはHyperEstraierも可)
11月まつのPerlMongers3連日の初日にあたる2008年11月26日(水)20時から麹町で行われます。
定員は30名までなので席のあるうちにお早めにどうぞ。
基本的にHTTP::EngineのAUTHORの方は全員参加という事でひとつ。

MENTA というウェブアプリケーションフレームワークをかいてみた - TokuLog 改めB日記やらNanoA というウェブアプリケーションフレームワークをかいてみた - id:kazuhookuのメモ置き場やらと軽量CGIフレームワーク作りが流行ってるようなので昼飯食った後に20分くらいで書いたよ。
Yacafi(Yet another CGI application framework interface)と言います。
http://svn.coderepos.org/share/lang/perl/Yacafi/trunkからsvn coできるけど、Yacafiはモジュール一個だけあれば動くようにしてあるのでhttp://svn.coderepos.org/share/lang/perl/Yacafi/trunk/lib/Yacafi.pmからwgetとかしてきても使えるよ!
Yacafi は使い捨て等の軽めのCGIを、いわゆる MVC 的なノリで開発する事が出来ます。
Yacafi.pm と index.cgi 以外のファイルを編集する必要もありません。
いわゆる MVC のノリで開発すると、ディレクトリ掘ったりとかファイルが増えてしまい使い捨てCGIなのに、ちょっと面倒くさくなっちゃうというデメリット(?)が回避できます。
配布する時は 、Yacafi.pm と index.cgi をサーバにアップロードする等することも出来ますし、perl index.cgi --pack というコマンドラインを実行する事によって、 Yacafi.pm と index.cgi を合成したMENTAインスパイアの1つのファイルにまとめて配布する事も可能です。
Yacafi.pm を見れば判りますがblessすら使ってません。全部クラスデータ的なとこに突っ込んでます。
MENTA や NanoA は、いわゆる普通の Web Application Framework を使うかの如く CGI の開発をしつつ軽量性に重点を置いているのに対して、 Yacafi は軽量な使い捨て CGI の開発を行い易くなるような所を重点に置いている違いがあります。
使い方はhttp://svn.coderepos.org/share/lang/perl/Yacafi/trunk/example/index.cgiを参考にして下さい。
といってもとても簡単で
use strict;
use warnings;
use Yacafi;
dispatch;
sub do_index {
view 'index';
}
sub view_index {
'hello yacafi!';
}といったコードだけでディスパッチャ機能付きのCGIが作れます。
ディスパッチする方法としては今の所、index.cgi?action=foo といった形でactionの値を使って、その値に対応するコントローラ関数のdo_*関数を呼び出します。
action=fooならdo_fooとといった感じです。
do_*関数の戻り値は view 'view_name'; と行った感じでViewを呼び出す事を推奨します。
別途
sub do_foo {
return {
headers => { 'Content-Type' => 'text/plain' },
body => 'hello raw view',
};
}のようにして生データも返せます。
viewの定義としてはview_を頭に付けた関数名を書いて下さい。
barというviewを作りたければ sub view_bar { 'hoo' } です。
コントローラ関数等からは view 'bar'; として呼び出せます。
view 'bar', %options といったように引数も渡せ、sub view_bar { my %args = @_; 'aaa' } といった感じで受け取れます。
view関数の戻り値は、ブラウザに返したいコンテンツをそのまま返して下さい。
テンプレート周りが欲しければ別途用意してください。
上記 do_foo のような形式の HASH リファレンスを直接返す事もできます。
modelの定義も出来ますが今の所ノープランでviewと同じ挙動です。
query('param_name') といった感じでクエリパラメータの取得ができます。MENTAから主にコードをパクっています。
redirect $uri; といった関数を使ってリダイレクト可能です。status codeを変更したければ redirect $uri => 301; のようにして下さい。
サニタイズ目的で filter 関数が使えます。 filter "<script>alert('hello');</script>", => 'html'; の用にお使い下さい。
複数のフィルタを同時に使う事が出来ますが今の所 html しか用意していません。
必要なら
filter->{uri} = sub {
my $uri = shift;
# 処理
return $uri;
};
といった感じで拡張して filter "http://", => 'uri'; のように呼び出せます。
TODOは、せめてファイルアップロード機能くらいはつけたいです。あと、pre_request, post_request的なフックも。

Update: Mojo作者のSebastianもベンチマークとってくれたよ! (new benchmark by Sebastian)
Mojo vs. HTTP::Engine - Sebastian Riedel - Perl and the Web
sri++
And if there is time, i make benchmark of FCGI.
本気bar効果でMojoが注目されてるのでHTTP::Engineとの速度差を簡単にとった。
そもそもMojo単体のWeb Serverの使い方が良くわからないので Mojolicious の CLI を見てそれっぽい Mojo::Server::Daemon を使った。
on New MacBook 2.4G
use strict; use warnings; use Mojo::Server::Daemon; my $daemon = Mojo::Server::Daemon->new; $daemon->port(8082); $daemon->run;
use strict;
use warnings;
use HTTP::Engine;
use HTTP::Engine::Response;
HTTP::Engine->new(
interface => {
module => 'ServerSimple',
args => { port => 8081 },
request_handler => sub {
my $req = shift;
HTTP::Engine::Response->new(
body => 'Congratulations, your Mojo is working!',
);
},
}
)->run;
bash-3.2$ ab -n 2000 -c 2 http://127.0.0.1:8082/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 127.0.0.1 (be patient)
Completed 200 requests
Completed 400 requests
Completed 600 requests
Completed 800 requests
Completed 1000 requests
Completed 1200 requests
Completed 1400 requests
Completed 1600 requests
Completed 1800 requests
Completed 2000 requests
Finished 2000 requests
Server Software:
Server Hostname: 127.0.0.1
Server Port: 8082
Document Path: /
Document Length: 38 bytes
Concurrency Level: 2
Time taken for tests: 4.229 seconds
Complete requests: 2000
Failed requests: 0
Write errors: 0
Total transferred: 318000 bytes
HTML transferred: 76000 bytes
Requests per second: 472.91 [#/sec] (mean)
Time per request: 4.229 [ms] (mean)
Time per request: 2.115 [ms] (mean, across all concurrent requests)
Transfer rate: 73.43 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.2 0 3
Processing: 2 4 0.7 4 11
Waiting: 1 3 0.6 3 9
Total: 2 4 0.8 4 11
Percentage of the requests served within a certain time (ms)
50% 4
66% 4
75% 4
80% 5
90% 5
95% 5
98% 6
99% 7
100% 11 (longest request)
$ ab -n 2000 -c 2 http://127.0.0.1:8081/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 127.0.0.1 (be patient)
Completed 200 requests
Completed 400 requests
Completed 600 requests
Completed 800 requests
Completed 1000 requests
Completed 1200 requests
Completed 1400 requests
Completed 1600 requests
Completed 1800 requests
Completed 2000 requests
Finished 2000 requests
Server Software:
Server Hostname: 127.0.0.1
Server Port: 8081
Document Path: /
Document Length: 38 bytes
Concurrency Level: 2
Time taken for tests: 1.912 seconds
Complete requests: 2000
Failed requests: 0
Write errors: 0
Total transferred: 230000 bytes
HTML transferred: 76000 bytes
Requests per second: 1045.86 [#/sec] (mean
Time per request: 1.912 [ms] (mean)
Time per request: 0.956 [ms] (mean, across all concurrent requests)
Transfer rate: 117.45 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.2 0 10
Processing: 1 2 0.6 2 12
Waiting: 0 2 0.5 2 7
Total: 1 2 0.7 2 14
Percentage of the requests served within a certain time (ms)
50% 2
66% 2
75% 2
80% 2
90% 2
95% 3
98% 4
99% 4
100% 14 (longest request)
H::Eはlazy_requestがきいているお陰か、速度が倍くらい違う。
YappoはMojoでのベンチマークの仕方も判ってないから不公平感があるかもしれない。
sriが計測したベンチマークのコードとかどこかに無いかしら?

QRCode大好きclouderさんがText::QRcodeを作ったのをみたnipotanさんが早速terminal化した物をgyazoにうpしてたので、gazoのコードを見ながら脳内コピペして10分くらいでTerm::QRCodeを作りました。
http://svn.coderepos.org/share/lang/perl/Term-QRCode/

ターミナルで作業してる時に、不意にQRCodeが必要になっても落ち着いてQRCodeを参照できるようになりましたね!
Text::QRCodeはCPANに上がってないけど、ネタでCPANに上げるかな

lopnorさんからpluginファイル中に複数のpackageがあった時に、複数分取り扱えるmultipleサポートをコミットして頂いたのでModule::Collectをversion++してshipitしました。
List::Rubyishはid:hibomaにdelete_ifの挙動が逆!って突っ込みを貰って、どーしよっかと思ってたらid:naoyaにバグッてるからコード差し替えといて!と正しいコードを教えてもらってるうちにid:secondlifeが直してコミットしてくれた!一緒にrejectメソッドも追加してもらったよ!
あとid:walf443からsort_byメソッドも追加してもらって、切りがいいのでshipit!
僕は殆ど何もしてないよ!CodeReposって素晴らしいね!

ブクマコメントでnaoyaさんからhttp://github.com/naoya/list-rubylike/tree/master/lib/List/RubyLike.pmがバグも無くていい奴だから、そっちとdiffとって適用したほうがいいよ!とアドバイスいただいて、その差分をmergeしつつList::RubyListのテストコードをコピペするだけの簡単なお仕事をしてテストカバレッジ率も100%
になったのでshipitしました。
というかnaoyaさん & secondlife 組の元コードのテストカバレッジ率が90%くらいだったので物凄く楽出来ました^^
http://search.cpan.org/dist/List-Rubyish/にそのうち反映されるはず。
List::RubyLike は use すると list 関数を export してくれるのですが、List:Rubyish では list 関数は export せずに new した時にリストを渡せるようにしました。
my $list = List::Rubyish->new(qw/ foo bar baz /);が出来る。
my $list = List::Rubyish->new(qw/ foo bar baz/);
$list->delete(sub { $_ eq 'bar' }); # bar を削除
List::RubyLike では + と >> を overload してるのですが、これを少し拡張して << を unshift に割り当てました。
他にもちょろちょろ本家から変えたりしてますが、基本的な挙動は互換性保ててるとおもいます。

DBIx::MoCoというhatena謹製のO/Rマッパは有名ですが、DBIx::MoCo::ListというRubyっぽいリスト操作を行ってくれるモジュールがあります。
概要はPerl のリスト操作を Ruby 風に - naoyaのはてなダイアリーが詳しいです。
DBIx::MoCo::ListはautoboxじゃないのにList::UtilやList::MoreUtilsを活用して実装してあります。
ちょっとしたリスト操作には使い勝手が良さそうなのですが、最大の欠点があります。
それはDBIx::MoCoに含まれるモジュールだという事です。DBIx::MoCoごと入れろと言われたらおしまいですが><
実はDBIx::MoCo::ListはDBIx::MoCoの他のモジュールに依存する箇所がどこにも無く簡単に切り離せるという事実があり、とあるIRCチャンネルでも単独で使いたいケースあるよね的な話が出たので、このたびList::Rubyish(命名 by lopnor++)としてforkさせました。
http://svn.coderepos.org/share/lang/perl/List-Rubyish/trunkにあります。
http://svn.coderepos.org/share/lang/perl/List-Rubyish/trunk/lib/List/Rubyish.pm と http://search.cpan.org/src/JKONDO/DBIx-MoCo-0.18/lib/DBIx/MoCo/List.pmを見比べても驚く程同じ。
コピーしてs/DBIx::MoCo::List/List::Rubyish/gするだけの簡単なお仕事でした。
原作と違う所は map_* 系のメソッドを抜いたのとgrepメソッドでHASHリファレンスの時は$hash->{$code}するという挙動を追加したくらいです。
test codeもそのままです。
jkondさんかnaoyaさんに怒られなければこのままshipitする予定でございます。

Method::SignaturesというPerlのメソッド定義や関数定義を直感的でかつ書き易く行う事が出来るcool moduleがあります。
たとえば
sub lopnor { # DBIx::Class test code style
my($self, %args) = @_;
$self->{danjou} = $args{danjou};
}といったコードをmethod lopnor (:$danjou) {
$self->{danjou} = $danjou;
}という風に書けます。いいかんじじゃないっすか?
このほどschwernによるプレゼン資料の中にM::S is 1% slowerとか書いてあったのでベンチ取ってみた。
use strict;
use warnings;
package My::Faster;
sub new {
my($class, %args) = @_;
bless {%args}, $class;
}
sub get { $_[0]->{$_[1]} }
sub set { $_[0]->{$_[1]} = $_[2] }
package My::Normal;
sub new {
my($class, %args) = @_;
bless {%args}, $class;
}
sub get {
my($self, $key) = @_;
$self->{$key};
}
sub set {
my($self, $key, $val) = @_;
return $self->{$key} = $val;
}
package My::MethodSignatures;
use Method::Signatures;
method new (%args) {
return bless {%args}, $self;
}
method get ($key) {
return $self->{$key};
}
method set ($key, $val) {
return $self->{$key} = $val;
}
package main;
use Benchmark ':all';
cmpthese(
timethese(
50000,
{
faster => sub {
my $obj = My::Faster->new( bar => 'baz' );
$obj->get( 'bar' );
$obj->set( foo => 'bar' );
$obj->get( 'foo' );
},
normal => sub {
my $obj = My::Normal->new( bar => 'baz' );
$obj->get( 'bar' );
$obj->set( foo => 'bar' );
$obj->get( 'foo' );
},
MethodSignatures => sub {
my $obj = My::MethodSignatures->new( bar => 'baz' );
$obj->get( 'bar' );
$obj->set( foo => 'bar' );
$obj->get( 'foo' );
},
}
)
);こんな感じで。平均値っぽい値の結果は下記の通り。
$ perl ./benchmark.pl
Benchmark: timing 50000 iterations of MethodSignatures, faster, normal...
MethodSignatures: 0 wallclock secs ( 0.49 usr + 0.00 sys = 0.49 CPU) @ 102040.82/s (n=50000)
faster: 1 wallclock secs ( 0.32 usr + 0.01 sys = 0.33 CPU) @ 151515.15/s (n=50000)
(warning: too few iterations for a reliable count)
normal: 0 wallclock secs ( 0.37 usr + 0.00 sys = 0.37 CPU) @ 135135.14/s (n=50000)
(warning: too few iterations for a reliable count)
Rate MethodSignatures normal faster
MethodSignatures 102041/s -- -24% -33%
normal 135135/s 32% -- -11%
faster 151515/s 48% 12% --激おそでは無いが許容出来そうな感じでもありますな。This is ALPHA SOFTWARE which relies on YET MORE ALPHA SOFTWARE. Use at your own risk. Features may change.とか書いてあるから困りそうな所で使わないけど。

Perlのモジュールをまず最初に作る時はpmsetupやModule::Starterなどを使うのが一般的です。
かく言う余もpmsetupでガリガリ書いてたんですが、はこべさんやらdannさんやらの最近の記事を見て思う所もあってpmsetupをモジュール化してみました。
http://svn.coderepos.org/share/lang/perl/Module-Setup/trunk/
使い方は簡単!cpan Module::Setupでinstallして(まだCPANにあげてないよ!)
$ module-setup Foo:Barを実行するだけ!
これだけじゃまったく意味が無いのでModule::Setupらしい所を。。。
Module::Setup には flavor という概念があり(Module::Startっぽい)module-setupコマンドを叩く時にflavorを切り替える事で、様々なモジュールのひな形を利用出来ます。
現在はDefaultとCodeReposのflavorがあり
$ module-setup --init --flavor-class=CodeRepos coderepos $ module-setup CodeRepos::Module codereposという操作で、codereposのflavorを作って、そのflavorをひな形にしたモジュールを作成出来ます。
flavorは~/.module-setup/flavorの中にflavor別のディレクトリに入っています。
codereposなら ~/.module-setup/flavor/coderepos/template の中身がひな形として使われています。
flavorを使ってひな形を作る時には、このtemplateディレクトリの構成そのまま使われますので、自分の趣味に合うように編集したり必要なファイルとかを追加すると良いでしょう。
このflavor用の設定ファイルは ~/.module-setup/flavor/coderepos/config.yaml にあります。pluginsディレクトリがありますが、この中に適当なファイル名でModule::Setup::Pluginを継承したモジュールを書いてconfig.yamlのpluginsにmodule nameを追加しておくと、このflavorのひな形を作るときにプラグインが読み込まれます。
今の所template処理や新規作成するモジュールの情報を変更するフェーズにフック出来るけど、細かいのはModule::Setup:Plugim::*などのソースを読んで下さい。
subversion用のディレクトリやひな形作成後のperl Makefile.PL make make test などは全部Pluginで行っています。
ちなみに =/.module-setup/plugins には、全flavorでloadされる独自pluginを置いておけます。
flavorを自分好みに編集したらsvnで管理するにしろtar.gzにするにしろ自由ですが--packオプションでflavorの中身全てを一つのpmファイルにしてくれます。
$ module-setup --pack MyCodeRepos coderepos > MyCodeRepos.pmこれで作られたファイルを配布するなり好きにすれば良いでしょう。
$ module-setup --init --flavor-class=+MyCodeRepos myreposとかで出来ます。
いま作った MyCodeRepos.pm を module-setup --init しないでも直接使う事が出来ます。
$ module-setup --direct --flavor-class=+MyCodeRepos myrepos~/.module-setup の変わりに File::Temp で作ったテンポラリディレクトリの中に flavor を展開しているだけです。
--pack やら --direct を上手く活用すると catalyst.pl でやってくれるようなヘルパーアプリを作れます。
Module::Setup->run の $options と $argv に適切な値を渡せば、他のモジュールから叩けるはず。
例えばflavor template の lib/____var-module_path-var____.pm の ____var-module_path-var____ は 実際の module の path に書き換えられるので、フレームワークのモジュール追加のヘルパーアプリとかに応用できる。
既存の物とは違ってひな形の元ファイルを、普通のファイル操作で編集出来るって所が便利なんじゃないのかなぁと思ってる所。(Module::Starter::Plugin::CGIApp も似たアプローチだけどキモイというか、Module::Sterter::PBP的だ)
ひとしきり固まれば pack して、自作アプリに組み込んだりも出来るから便利そうだなぁと。
以前からpmsetupをモジュール化するという話は出ていたのですが、「そこまでやるならModule::Sterter使うだろJK」やら「一枚岩のスクリプトで気が変わったらスクリプトを書き換えればひな形が変えられるのがpmsetupの良い所!」という感じで誰も手を付けませんでした。
もちろん僕もそう思っていたのですが、若干必要に迫られた感もあってModuler::Sterterに手を出してみようと思ったら、すこぶるめんどくさくなったのでModule::Setupを作ったのでした。
たぶん他の人のpmsetupも全部カバーできそうかも?

空前のwassrブームの中皆様いかがおすごしでしょうか。
ついにあのcho45の*ig.rbがまだハイクに対応していなくて面白い感じですが、Mac用のいいツールが無さげです。というかAPIさっき公開したばかりだけど。
来週の、MicroblogConにはてなハイクの中の人に参加してもらいたいのですが、「Wassrを末永くお願いします」と言われたので、僕が勝手にTwitterPodをはてなハイク対応しちゃいました。
かいつまむと「はてなハイクをtwitter APIを使うクライアントからアクセスできるコンバータ付きproxy」です。
Macのターミナルとperlが使える環境の人前程ですが、物凄く簡単にエコー対応が出来ます。
TwitterPodをアプリケーションディレクトリに入れておいて下さい。
そして、ここからターミナル操作です。
まずは
svn co http://svn.coderepos.org/share/lang/perl/misc/HaikuPod ~/HaikuPodとかで、仕組み一式をチェックアウトして
$ cd /Applications $ ~/HaikuPod/install.plとするだけでHaikuPodがアプリケーションディレクトリに出来上がります。
次に肝心のproxyですが、~/HaikuPod/haikupod.plがそうです。
これを使うには各種CPANモジュールが必要なので
$ sudo cpan > install MooseX::Getopt > install HTTP::Server::Simple > install HTTP::Engine > install JSON > install DateTime > install DateTime::Format::W3CDTF; > install XML::Simple > install MooseX::Typesとかして必要なモジュールを全部入れておきます。
$ ~/HaikuPod/mixiechopod.pl --port 8107で起動します。8107はproxyのサーバポートです。
ここまできたらあとはアプリケーションディレクトリのHaikuPodを起動して、設定画面のアカウントは適当なのを入れて、最後が肝心だけど「Enable Proxy」にチェックをいれて「Server」に「127.0.0.1」を入れ「Port」に「8107」を入れればokです。
結構無理栗なhackなのでHaikuPodのアプリケーションが落ちちゃったりする可能性もありますが僕は結構快適に使えてます。
今後の予定ははてなならではの機能をHaikuPodから使えるようにhaikupod.plを拡張してくネタをmixiが実装してくれたらいいですね。
なんでも一から作るのは大変ですが、この程度なら大変じゃなくて良い感じですね。
どうぞご利用下さい。

昨日HTTP::Engine0.0.13をリリースしました。
今回は大きな変更になっています。
0.0.12までだと
use HTTP::Engine;
HTTP::Engine->new(
interface => {
module => 'ServerSimple',
args => { port => 9999 },
request_handler => sub {
my $c = shift;
$c->res->body($c->req->uri);
},
}
)->run;
と、request_handlerにはcontext($c)を引数と渡して、contextの中にreqやres等があり、Catalystのcontextっぽい感じで使えたのですが、0.0.13からは
use HTTP::Engine;
HTTP::Engine->new(
interface => {
module => 'ServerSimple',
args => { port => 9999 },
request_handler => sub {
my $req = shift;
return HTTP::Engine::Response->new( body => $req->uri);
},
}
)->run;
という風にHTTP::Engine::Responseのオブジェクトを明示的に作って返すようになります。当初はcontext objectを使ってmiddleware等からcontext objectにメソッド生やして便利に仕様という意図があったのですが、mstやnothingmuchからは「contextなんてCatalystで大変になってるからやめようぜ」と提案されたり、実装を進めて行く上でcontextの必要性が少なくなってたり、有用な使い方を思いつかなかったのでcontextを削除しました。
ついでに、折角よりシンプルになるので未だに使い道がはっきりしないmiddlewareサポートも削除しました。
とはいえ、APIの互換性が急に無くなって慌てる人が居たら悪いのでanotherさんに足りないとDISられた公共心をフルに発揮してHTTP::Engine::Compatというのも同時にリリースしました。
use HTTP::Engine::Compat;
HTTP::Engine->new(
interface => {
module => 'ServerSimple',
args => { port => 9999 },
request_handler => sub {
my $c = shift;
$c->res->body($c->req->uri);
},
}
)->run;
とHTTP::EngineじゃなくてHTTP::Engine::Compatをuseするだけで0.0.12までとの互換性を保ちます。最後にHTTP::Engineをちっちゃいスクリプトで使いたい時にHTTPEx::Declareもversion upしました(FAIL (4)とか言われてるのであとで直す)。
新たに-Compatモードサポートとresが追加です。
use HTTPEx::Declare;
interface ServerSimple => { port => 9999 };
run {
my $req = shift;
res( body => $req->uri );
};
こんな感じで新しいHTTP::Engineに対応したコードが書けます。use HTTPEx::Declare -Compat;
interface ServerSimple => { port => 9999 };
run {
my $c = shift;
$c->res->body( $req->uri );
};
と書くだけです。
あともう一つHTTP::Engineには新たな要素があります。
0.0.12までは、request_handlerの中で使わないrequest objectの値(cookieとかrequest bodyとかheaderとか)までも全部作っていたのですが、0.0.13からは必要な時にlazyに作成するようになりました。
使うrequest dataを必要な時にENVやらSTDINから作成するのでアプリケーションによっては効率が良くなるはずです。
もうそろそろHTTP::Engineも要件が固まり来てコンセプト段階を終了しようと思う所ですがどうでしょうね?
仕様をフリーズさせてリファクタリングやらドキュメント作成やらCookbookやらを整備して0.1.0もしくは1.0.0のリリースする感じですかね。
ちなみにあたかも自分が全部やったように書いてるけどcontext削除の作業とHTTP::Engine::Compat作りはtokuhiromがやり、lazyなrequestの作業の大部分はnothingmuchがやりました。
僕はHTTPEx::Declareと全部のテストカバレッジ率を100%にしたのとリリース作業くらいしかしていません。

trunkのHTTP::Engineのsubカバレッジが100%になった今日この頃皆様いかがおすごしでしょうか。
今現在はtrunkのテストカバレッジを高めた上で、lazy_requestブランチを本格的に採用すべく動いている所です。
nothingmuchによるブランチで、request関連の情報を必要になった時に作り出すような物になっています。
今までは(Catalystもそうだけど)clientからrequestが有るたびに使いもしないデータを最初に作ってたんだけど、そういった事が解消されます。
ただ、今の状態だとPOSTでfile uploadした時が上手く動かない。
lazy_request自体は外部インターフェィスは変わらない予定なので、別に互換性とかの問題は出ないはずなんですが、このブランチが落ち着き次第 HTTP::Engine::Context を無くすブランチを作る予定す。
今までは request や response の情報は $c に生えているメソッド $c->req や $c->res 経由でアクセスする感じでしたが、mstやnothingmuch曰く「context使うなんてCatalystの二の舞になっちゃうyp!(意訳)」といった提案を受けて、「結局 $c ある利点てそんなにないよね」って考えに至ったのでcontextを無くす方向で動こうと思います。
ぶっちゃけWAF側にcontextあったら、どのコンテキストがWAFのなのかHTTP::Engineのなのかわかんなくなって混乱しそうだしね。
sub handle_request {
my $c = shift;
$c->res->body($c->req->uri);
}このコードが
sub handle_request {
my $req = shift;
return HTTP::Engine::Response->new( body => $req->uri);
}になる感じす。
冗長になっちゃうんじゃ無いか?みたいな意見もありそうですが昔のnothingmuchのプランによると
sub handle_request {
my $req = shift;
return HTTP::Engine::Response::Redirect->new('http://example.com/');
}
(あ、これも冗長か><)
sub handle_request {
my $req = shift;
return HTTP::Engine::Response::JSON->new({ foo => 'bar' });
# 18:39 < t*kihirom> return HTTP::Engine::Response::JSON->new({ foo => 'bar' });
# 18:39 < tokihir*m> HATE HATE HATE
}みたいに、特定用途によってレスポンスのクラスを変えれるようにしたらどうか的な話になった。
HTTPEx::Declareつかえば
use HTTPEx::Declare qw( res redirect );
interface {
module => 'ServerSimple',
args => {
host => 'localhost',
port => 1978,
}
};
run {
my $req = shift;
return redirect('http://example.com/') if $req->uri =~ /redirect/;
return res( body => 'hello' );
};
とかになると思う。
HTTP::Engine::Compat的なモジュールを使って、過去のHTTP::Engineアプリと互換性をなるべく保つようにする事も一応考えています。
HTTP::Engine->newするかわりにHTTP::Engine::Compat->newする感じで。
HTTP::Engineはなるべくシンプルであれというのが我々の共通認識であるのでcontextを無くす変更により、よりスマートになるんではないかと思っている次第です。
今まで時間があいた分を取り戻すかのように怒濤に進める予定。

miyagawaさんに教えてもらったhttp://juerd.nl/files/slides/2006yapceu/undef.htmlこれを見て驚愕したので。
package undef;
use strict;
use warnings;
my $undef = undef;
sub import {
Internals::SvREADONLY(${\undef}, 0);
}
sub reset {
Internals::SvREADONLY(${\undef}, 0);
undef = $undef;
Internals::SvREADONLY(${\undef}, 1);
}
1;こんなのを作った。use strict; use warnings; warn "not" unless undef; use undef; warn "not" unless undef; undef = 1; warn "not" unless undef; warn undef; undef::reset; warn "not" unless undef; warn undef;
内部のPL_sv_undefを書き換えちゃうので、色々な物が動かなくなる事間違い無し。
open() or die;も動かなくなる!

404 Blog Not Found:perl - Const released -- True Readonly
実は、Perl 5.8以降では、Internals::SvREADONLY()という関数がuseなしで使えるようになっていて、Internals::SvREADONLY($scalar, 1)で$scalarをREADONLY flagをonに、Internals::SvREADONLY($scalar, 0)でoffにできます。知らなかった!
これは universal.c にて実装されていて、使い方は lib/Internals.t を見るべし。
Hash::Utilでも使われてるよ。
danさんの
ただし、これではscalarしかflagをいじれません。というわけで、同様のことをXSでやるようにするモジュールを書いたというわけです。これは間違いでARRAYもHASHも弄れます。
use strict; use warnings; my @values; Internals::SvREADONLY(@values, 1); push @values, 1;これは
Modification of a read-only value attempted at ./ro.pl line 5.と怒られる。
Internals::SvREADONLY($values[0], 1);とか局所的にするのも可能。
Internals::SvREADONLY(¥@values, 1);では渡せない。
なにが言いたいかというとConstがUNAUTHORIZEDだという事

Perl本体にパッチをあてる事無く動的に動いてるPerlのコアを書き換えちゃう事が出来るPL_checkやo->op_ppaddrなどについて発表してきました。
資料はそれなりなポインターとして使える風味なので、よろしければご覧下さい。
http://svn.coderepos.org/share/docs/yappo/20080625-shibuyapm9/shibuyapm9-pl_check-hacks.pl

小学校の算数の授業が崩壊しているというニュースがありますが、昨今のナベアツ人気とPerl VM hackのブームが融合して迷惑なCPANモジュールが誕生しました。
Acme::NabeAtzzをインストールして use Acme::NabeAtzz すると、PerlのVMオペコードの数値が3の倍数になるオペコードを実行する時にPerl VMがアホになってしまう迷惑なモジュールなんです。
例外無く全部の3の倍数のオペコードがアホになるので大変です。
もちろんPerl本体へのパッチは不要です。モジュールインストールするだけです。
興味が有る人はソースでも読んでみて下さい。
このネタは特に明日のShibuya.pmでは言及しません。

小学校の算数の授業が崩壊しているというニュースがありますが、昨今のナベアツ人気とPerl VM hackのブームが融合して迷惑なCPANモジュールが誕生しました。
Acme::NabeAtzzをインストールして use Acme::NabeAtzz すると、PerlのVMオペコードの数値が3の倍数になるオペコードを実行する時にPerl VMがアホになってしまう迷惑なモジュールなんです。
例外無く全部の3の倍数のオペコードがアホになるので大変です。
もちろんPerl本体へのパッチは不要です。モジュールインストールするだけです。
興味が有る人はソースでも読んでみて下さい。
このネタは特に明日のShibuya.pmでは言及しません。

perl-users.jp - 日本のPerlユーザのためのハブサイト
YAPC::Asia 2008 で Michael Schwern は「SEOに有効な独自ドメインを取って、もっとPerl初心者が集まりやすいniceなPerlの情報を集めたサイトを作れ!」といったのでperl- users.jpドメインを取って、ここにperl-users.jpを開始します。 以前よりShibuya.pm界隈では、初心者や複雑なPerlの話題をキャッチアップ出来ないPerl利用者をどうすくい上げるか、という議論を盛んに行って降りました。 Schwern の言う通り perl で検索してもなかなかいい情報にたどり着けなかったりと、それは酷い現状をどうにかしたい思いはYAPC::Asia 2008 のスピーカー陣共通の思いだと思っています。といった事を目的としたサイトを立ち上げました。
index.html作ってサーバセットアップしただけで中意味は無いですが、SchwernのPerl IS unDeadみて感銘を受けた人は参加してみませんか?
議論は #shibuya.pm #yapc.asia-ja 辺りでやればいいのかなとも思ってます。
あーあとSEOよろしくお願いしますw

まずは前夜祭のSoozyCon#5の資料
http://svn.coderepos.org/share/docs/yappo/20080514-soozycon5-yapcasia2008/yapcasia2008-http-engine.pl
HTTP::Engineの概要を話してきたよ。
そして昨日はPerlの%^Hの話だよ。
http://svn.coderepos.org/share/docs/yappo/20080515-yapcasia2008/
danさんの素晴らしさ、danさんを大切にしよう!と説いてきました。
ATの部屋が立ち見が出る程の満員でした、マニアっくすぎる話題なのに驚きです!
そしてさっき終わったのですが、デバイス気持ちいい話。
http://svn.coderepos.org/share/docs/yappo/20080516-yapcasia2008/yapcasia2008-device.pl
楽してデバイスで遊ぼうというお話でした。
X Japanのライブのインスパイアです。