<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
   <channel>
      <title>ウノウラボ Unoh Labs</title>
      <link>http://labs.unoh.net/</link>
      <description>ウノウ株式会社のデモ版サービスやTIPSなどの情報</description>
      <language>ja</language>
      <copyright>Copyright 2010</copyright>
      <lastBuildDate>Thu, 18 Mar 2010 10:56:28 +0900</lastBuildDate>
      <generator>http://www.sixapart.com/movabletype/?v=4.261</generator>
      <docs>http://blogs.law.harvard.edu/tech/rss</docs> 

      
      <item>
         <title>PHP版 Parallel::Prefork で奥一穂さんと親に感謝しよう</title>
         <description><![CDATA[こんちにわ、去年末に入社した「ちわ」です、こんにちわ。

Perl には <a href="http://search.cpan.org/">CPAN </a> というものがあり、そこには様々なライブラリが登録されています。国内の方々も多くライブラリを登録されていますがその中で<a href="http://mt.endeworks.jp/d-6/">牧大輔さん</a>の <a href="http://search.cpan.org/~dmaki/Queue-Q4M-0.00019/">Queue::Q4M</a>、<a href="http://developer.cybozu.co.jp/kazuho/">奥一穂さん</a>の <a href="http://search.cpan.org/~kazuho/Parallel-Prefork-0.05/">Parallel::Prefork</a> を PHP に移植したので今回は奥一穂さんの Parallel::Prefork のPHP版を紹介したいと思います。(Queue::Q4M はインターフェースを若干変更して移植してしまったので今回は Parallel::Prefork のみ紹介となります)

弊社が提供しているサービスの「まちつく！mixi版」、「まちつく！モバゲー版」の地図を生成、Amazon S3 への転送をキューを使って処理していまして、そのキュー処理に Q4M を導入することになりました。キュー処理の主な流れは下記のようになります。

<strong>主な処理の流れ</strong>
<ul>
<li>Web やバッチで生成キューをエンキュー</li>
<li>生成デーモンがデキューし地図を生成</li>
<li>正常に地図を生成できたら転送キューにエンキュー</li>
<li>転送デーモンがデキューし地図を Amazon S3 に転送</li>
</ul>

地図を生成するデーモンは OpenMP が有効になっている ImageMagick を1プロセスで起動しますが、地図を Amazon S3 へ転送するデーモンはHTTP通信を行うのでマルチプロセスで起動してパフォーマンスを稼ぐ必要があります。
ウノウに入社するまでずっと Perl のエンジニアだったこともあり、この手の処理は <a href="http://search.cpan.org/~dmaki/Queue-Q4M-0.00019/">Queue::Q4M</a> + <a href="http://search.cpan.org/~kazuho/Parallel-Prefork-0.05/">Parallel::Prefork</a> で実装し daemontools で起動したいところですがご存知の通りウノウは Perl な会社ではありません。PHP を使うのもの初めてということもあり、PHP の文法などの勉強がてら Queue::Q4M と Parallel::Prefork (0.05) を PHP に移植することにしました。
実際にサービスで使用しているものとは若干違いはありますがソースは <a href="http://github.com/travail/php-parallel-prefork">github</a> に置いてあります。

Parallel::Prefork の使い方は作者の<a href="http://labs.cybozu.co.jp/blog/kazuho/archives/2008/04/parallel-prefork.php">奥一穂さんのページ</a>か CPAN の <a href="http://search.cpan.org/~kazuho/Parallel-Prefork-0.05/lib/Parallel/Prefork.pm">Parallel::Prefork</a> のドキュメントをご覧ください。
<a href="http://search.cpan.org/~kazuho/Parallel-Prefork-0.05/lib/Parallel/Prefork.pm#SYNOPSIS">Parallel::Prefork の SYNOPSIS のサンプルコード</a>を Parallel_Prefork で書くとするとこうなります。

<script src="http://gist.github.com/335483.js?file=parallel_prefork_synopsis.php"></script>

次に実際に動く単純なサンプルコードを紹介します。

<script src="http://gist.github.com/335530.js"></script>

10行目のコンストラクタで Parallel_Prefork のオブジェクトを生成しています。max_workers は生成したい子プロセスを指定します。このコンストラクタで重要な引数の trap_signals には

<pre class="code">trap_signals => array(
    親プロセスで捕捉したいシグナル => そのシグナルを捕捉した場合に子プロセスに送りたいシグナル
)</pre>

といった配列を指定します。例では、

<pre class="code">trap_signals => array(
    SIGHUP  => SIGTERM,
    SIGTERM => SIGTERM,
)</pre>

と指定いるので SIGHUP, SIGTERM を親プロセスが捕捉したら子プロセスに SIGTERM を送ることになります。Parallel_Prefork では内部でシグナルハンドラを上書きしているので上記の例だと親プロセスが SIGHUP, SIGTERM を捕捉してもそれ自体でプロセスが終了してしまうことはありません。

次に19行目の $pp->signalReceived() ですが、このメソッドは親プロセスが捕捉したシグナルが格納されていますので while は親プロセスが SIGTERM を捕捉するまでループします。

21行目の $pp->start() で子プロセスが max_workers で指定した数まで fork されます。$pp->start() は親プロセスがコールした場合は true を返しますので while の中では親プロセスが23行目以降のコードを実行することはありません。

24行目以降が子プロセスが実行するコードになります。例ではそれぞれの子プロセスがfor文で1〜3秒 sleep して $pp->finish() で exit します。

お子様プロセスがのんきに sleep している間、親プロセスは $pp->start() メソッドの中でお子様プロセスの数が max_workers をキープできるようにお子様プロセスの fork と wait、シグナルが送られていないかなどの監視にせっせと励んでいます。本当、親には感謝しないといけません。今年の母の日は5月9日（日）で父の日は6月20日（日）ですよ。準備はできていますか？

以上が while の中の処理になりますが、この処理の最中に親プロセスが SIGTERM を捕捉していなければ上記の処理を繰り返します。もし、親プロセスが SIGTERM を捕捉していれば while を抜け終了しますが SIGHUP を捕捉した場合は子プロセスを SIGTERM で殺して親プロセス自体は 19行目の while に戻ります。任意のシグナルを捕捉した場合に親プロセスが終了するかどうかは while をどのような条件で回すかによりますが、そもそも trap_signals で指定していないシグナルを捕捉した場合はデフォルトの挙動を取ります。例では SIGINT (Ctrl+C) を親プロセスに送ると直ちにプログラムが終了します。

以上がサンプルコードの説明になります。
このサンプルコードは <a href="http://github.com/travail/php-parallel-prefork">github のリポジトリ</a>にも置いてあるので興味のある方は奥一穂さんのすばらしいライブラリと日頃見守ってくれている親に感謝しつつ実際に動かしてみてください。

<div style="margin:0;padding:.5em;border:2px solid #ccc">ウノウでは特に最近、積極的にエンジニアを採用しています。<br />
<a href="http://www.unoh.net/recruit.html">採用ページ</a>をご覧になり興味のある方、ぜひご応募ください。<br/>
<a href="http://www.find-job.net/fj/showjob.cgi?id=50212">Find Job!</a>でも募集してます！</div>]]></description>
         <link>http://labs.unoh.net/2010/03/php_parallelprefork_de.html</link>
         <guid>http://labs.unoh.net/2010/03/php_parallelprefork_de.html</guid>
         <category></category>
         <pubDate>Thu, 18 Mar 2010 10:56:28 +0900</pubDate>
      </item>
      
      <item>
         <title>快適なsshクライアント生活</title>
         <description><![CDATA[<p>2010/03/13 一部記事修正。</p>
<p>はじめまして、<a href="http://hiroki.jp">HIROKI</a>です。</p>

<p>大規模コンテンツの開発に携わっていると数多くのサーバにsshでログインすることになります。その手間を軽減するために $HOME/.ssh/config を設定してみます。</p>

<h3>sshコマンドを簡略化</h3>
例えば dev01.labs.unoh.netというサーバにsshでログインするのであれば、
<pre class="code"> $ ssh -i ~/.ssh/id_rsa.unoh hiroki@dev01.labs.unoh.net</pre>
<p>という感じのコマンドでログインしているかと思います。</p>
<p>これを</p>
<pre class="code">　$ ssh dev01</pre>
でログインできるように設定してみましょう。
<pre class="code"><code>Host dev01
    User            hiroki
    HostName        dev01.labs.unoh.net
    IdentityFile    ~/.ssh/id_rsa.unoh</code></pre>
<p>秘密鍵を複数使いわけている人はIdentityFileを指定すると便利です。</p>

<h3>さらにホストを追加</h3>
さらにホストを追加してみます。
<pre class="code">Host dev01
    User            hiroki
    HostName        dev01.labs.unoh.net
    IdentityFile    ~/.ssh/id_rsa.unoh

Host home
    User            hirocaster
    HostName 	    home.hiroki.jp
    IdentityFile    ~/.ssh/id_rsa.home</pre>
いままで
<pre class="code"> $ ssh -i ~/.ssh/id_rsa.home hirocaster@home.hiroki.jp</pre>
でログインしていたのが
<pre class="code"> $ ssh home</pre>
でログインできるようになりました。

<h3>各ホストの共通設定</h3>
<p>すべてのホストの共通設定は以下のような感じ</p>

<pre class="code">Host *
     IdentityFile               ~/.ssh/id_rsa
     ForwardAgent               yes
     TCPKeepAlive               yes
     ServerAliveInterval        15
     ServerAliveCountMax        3</pre>

<p>必ず設定ファイルの最後に追加するようにしてください。</p>

<h3>踏み台を経由してログインする場合</h3>
<p>応用編として、踏み台サーバ(op.labs.unoh.net)を経由して
開発サーバ(dev01.labs.unoh.net)にログインする場合</p>

<pre class="code">Host dev*
    User            hiroki
    IdentityFile    ~/.ssh/id_rsa.unoh
    ProxyCommand    ssh op.labs.unoh.net nc -w 6000 %h %p</pre>

<p>踏み台サーバ(op.labs.unoh.net)の/etc/hostsにdev01,dev02などを追加しておくことがポイントです。</p>
<p>このようにしておけば、踏み台サーバを経由して開発サーバに入れます。</p>

<pre class="code"> $ ssh dev01</pre>
にもログインできますが、
<pre class="code"> $ ssh dev02</pre>
にもログインできるようになります。

<p>このようにワイルドカードを利用した設定もできます。</p>

<h3>最終的な$HOME/.ssh/config</h3>
<pre class="code">Host dev*
    User                        hiroki
    HostName                    dev.01.labs.unoh.net
    IdentityFile                ~/.ssh/id_rsa.unoh
    ProxyCommand                ssh op.labs.unoh.net nc -w 6000 %h %p

Host home
    User                        hirocaster
    HostName                    home.hiroki.jp
    IdentityFile                ~/.ssh/id_rsa.home

Host *
     IdentityFile               ~/.ssh/id_rsa
     ForwardAgent               yes
     TCPKeepAlive               yes
     ServerAliveInterval        15
     ServerAliveCountMax        3</pre>

<p>以上でsshコマンドを利用してのログインが簡略化されました。</p>

<h3>最後に</h3>
<p>簡単にログインできるようになったからこそ、本番サーバとテストサーバを間違ってオペレーションしないようにログインした際にはサーバを確認する癖をつけてください。</p>
<p>$HOME/.ssh/configに関するその他の設定は</p>
<pre class="code"> $ man ssh_config</pre>
<p>を参照ください。</p>


<div style="margin:0;padding:.5em;border:2px solid 
#ccc">ウノウでは特に最近、積極的にエンジニアを採用しています。<br /><a
href="http://www.unoh.net/recruit.html"> 採用ページ</a>をご覧になり興味のある方、ぜひご応募ください。<br/><a
href="http://www.find-job.net/fj/showjob.cgi?id=50212">Find Job!</a>でも募集してます！</div>]]></description>
         <link>http://labs.unoh.net/2010/03/ssh_config.html</link>
         <guid>http://labs.unoh.net/2010/03/ssh_config.html</guid>
         <category>Linux</category>
         <pubDate>Fri, 12 Mar 2010 19:00:00 +0900</pubDate>
      </item>
      
      <item>
         <title>TextMateの設定メモ</title>
         <description><![CDATA[<p>はじめまして、 1月から入社した市丸です。</p>
<p>
入退社にあたり開発環境を1から作り直すこととなり、久しぶりにTextMateの設定をやり直しました。<br>
その際、役立ったリンクとPHP開発で使う際のオススメ設定など、私的なメモかもしれませんが、ご紹介いたします。
</p>

<p>
マルチバイト対応のVer.2が出るといってはや2〜3年。このまま消えてしまうのか...<br>
もう一度TextMateの特徴をまとめたいと思います。
</p>
<h3>TextMateの特徴(2010/03現在)</h3>
<ul>
<li>日本語はUTF-8のみ</li>
<li>半角カナが判別しにくい</li>
<li>NFS経由でプロジェクトを作ると重い。(50個ぐらいなら快適)</li>
<li>次期バージョンアップがこない</li>
<li>$55</li></ul>
<p>
基本的にマルチバイト関係があやしいです。<br>
以下にオススメの設定方法を記載します。
</p>
<h3>1. 日本語フォント入れる。</h3>
<p>
<a href="http://d.hatena.ne.jp/hetima/20061102/1162435711">http://d.hatena.ne.jp/hetima/20061102/1162435711<br>
配布サイト
</a>
</p>
<p>
<a href="http://t32k.com/mol/2009/08/textmate-japanese/">http://t32k.com/mol/2009/08/textmate-japanese/<br>
解説わかりやすい
</a>
</p>
<h3>2. 日本語入力のFix</h3>
<p>
<a href="http://hetima.com/textmate/index.html">http://hetima.com/textmate/index.html<br>
配布サイト
</a>
</p>

<h3>3. 日本語入力時に誤動作するSnippetをオフに</h3>
<p>
Bundles -> BundleEditor -> ShowBundleEditorからBundleEditorを開く<br>
<span class="mt-enclosure mt-enclosure-image" style="display: inline;"><img alt="textmate_snap.png" src="http://labs.unoh.net/textmate_snap.png" width="600" class="mt-image-none" style="" /></span>
<pre class="code"><code>HTML -> Spesial: Return Inside Empty Open/Close Tag
Activationの右の入力ボックスを選択し×
</code></pre>
※日本語入力の決定Enterが反応するため
</p>
<h3>4. 全角スペースの色を変える</h3>
<p>
<a href="http://blog.asial.co.jp/506">http://blog.asial.co.jp/506</a><br>
ほんとに助かりました。
</p>
<h3>5.SvnMateまたはProjectPlusを入れる</h3>
<p>
<a href="http://ciaranwal.sh/category/textmate">http://ciaranwal.sh/category/textmate
</a><br>
私はSvnMateを利用しています。
</p>

<p>インストール方法</p>
<pre class="code"><code>cp -r SVNMate.tmplugin ~/Library/Application\ Support/TextMate/PlugIns/
<code></pre>
<br>
<p>
以上です。<br>
Ver2待ちの皆様。なんとか凌ぎましょう。
</p>
<br>
<div style="margin:0;padding:.5em;border:2px solid 
#ccc">ウノウでは特に最近、積極的にエンジニアを採用しています。<br /><a
href="http://www.unoh.net/recruit.html"> 採用ページ</a>をご覧になり興味のある方、ぜひご応募ください。<br/><a
href="http://www.find-job.net/fj/showjob.cgi?id=50212">Find Job!</a>でも募集してます！</div>
]]></description>
         <link>http://labs.unoh.net/2010/03/textmatetips.html</link>
         <guid>http://labs.unoh.net/2010/03/textmatetips.html</guid>
         <category>Mac</category>
         <pubDate>Wed, 10 Mar 2010 22:31:17 +0900</pubDate>
      </item>
      
      <item>
         <title>日本と海外の携帯や携帯コンテンツ市場について色々（個人的）な感想</title>
         <description><![CDATA[はじめまして、1月入社の<a href="http://twitter.com/brandonheato">Brandon</a>と申します。
シンガポール出身で日本ではまだ一年ほどしか働いた経験がないので、
もし日本語で変なところがあったらお許しください。（ご親切にご指摘頂ければさらに幸いです）。

入社したら周りがすごい人達ばかりで、もともと自分がまだまだだなーと思っていたとこをさらにまだまだだなーと思わせる人たちばかりです。
一応エンジニアですが、エンジニア経験はないに等しいもので、このブログを読んでいる人たちに技術系の話をしたら失礼な気がします。
とは言うものの、近いうちに技術系の話はしたいと思っています。
（教えるという立場より、ご指導や意見を頂ければという立場、もしくは教え合おうという立場から）
でも今日は日本と海外の携帯市場についてのちょっとした感想というか、思いついたことの小まとめをみんさんとシェアしたいと考えております。
あくまでも個人的な感想ですので、ただ一人の人間の意見として読んで頂けたらと思います。

長年シンガポールに住んでいたので、海外携帯市場の認識はシンガポールにいる携帯ユーザーの観点的なところもあったりすると思いますが、携帯に関しては日本以外の国はほとんど似ていると思いますので、地域や国によって違いが多少あっても肝心なところに大きな違いはないかと思います。
それと、近年携帯市場の変化はiPhoneが中心になっているようなものなので（特に海外では）、iPhoneがリリースされた前とiPhoneがリリースされた後の段階に分けた形でまとめたいと思います。


<strong><big>iPhoneがリリースされる前</big></strong>

日本と海外の携帯市場は「携帯のみコンテンツ」と「定額プランの違い」のところで決定的な違いがあります。

海外では、携帯のみコンテンツ(コンテンツ)が日本より遥かに少ない。ほとんどないに等しいレベルだったでしょう。
日本と違って、海外ではパケット放題プランがあまりなかった。あるとしてもほとんどが月額のかなり高いプランになってしまいます。
一般の人達が携帯で使うのは、電話とSMS（短信）だけです。
短信はメールと違って、データで料金が計算されるのではなく、メッセージ数で料金が決まるので、データとは何の関わりもない機能です。
情報を調べる時やコンテンツを消費する時はほとんどみんながパソコンや他の媒体などを使用するシチュエーションが多いです。

日本ではほとんど逆な状況になっています。
海外の人からみたら、日本の携帯のみコンテンツは信じられないほどありすぎると感じるでしょう。
一般の人達が情報やコンテンツを消費する時は、携帯を使うシチュエーションが多いです。
逆に一般の人達の中でパソコンが使える人が少ないです。
3年前の事になりますが、私の友達に慶応大学の3年生がいて、その人がMS Wordの基本的な使い方すら完全に知らなかったです（起動の仕方やコピペのやりかたさえわからなかった）。
正直ショックでした。


<strong><big>iPhoneがリリースされた後：海外</big></strong>

ところが、iPhone（特にiPhone 3G）がリリースされてからは海外の携帯市場が急激に変化しました。
iPhoneが出る前からもスマートフォンはありましたが、
iPhoneの使い心地や使いやすさは今までのスマートフォンとレベルが違うものでした。
実際に使ってみたことある人は実感できるでしょう。
（私の場合は、Palm Treo使っていましたが、友達のWindows Mobileスマートフォンとかをいじらせて貰ったこともありまして、iPhoneとは比べ物にならないほど使い心地が悪かった）
今まで殆どはビジネスマンとかしか使わないスマートフォンでしたが、
iPhoneが出てからは一般の人達も使うようになりました。

私からみれば、携帯市場に一番インパクトを与えたのはiPhone 3Gのリリースです。
iPhone 3Gで大きく変わったところ：

・<i>スマートフォン所有コストの低下</i>
今までのスマートフォンは、2年契約を結んだ上で機種代が（日本円で言えば）6万円〜10万円ぐらいはするものでした。ところが、iPhone 3Gが当時市場に出ているスマートフォンの半分以下の値段でした（2年契約付きで機種代が実質2~4万円）。定額データ通信料も今までのプランより安いプランが出ました。今まで非スマートフォンより遥かに高かったスマートフォンは突然同じぐらいの値段で買えるようになりました。

・<i>（ある意味）「携帯向け」ウェブコンテンツの増加</i>
海外では携帯端末に制限された「携帯のみのサイト」があまりなくて、携帯端末がアクセスするコンテンツはPCと同様のウェブコンテンツが多いです。海外での「携帯向け」サイトのほとんどは「携帯に表示を最適しただけ」のサイトです。インターネットのサイトは普通にスマートフォンで見れて、「携帯向け」サイトも普通にスマートフォンや携帯で見れます。

iPhoneが市場に出る前に携帯でウェブコンテンツをアクセスすることがそれほどブームしていなかたのは、定額データ通信料のコストやスマートフォンの使い心地の悪さが主な原因でした。
しかしiPhoneがリリースされたことで、携帯でウェブコンテンツをアクセスする使い心地が一気によくなり、携帯からウェブコンテンツへのアクセスが爆発的に増えました。

その上に、iPhone向けに表示を最適したサイトなどが多くなり、App Storeでウェブサービスとの連携できるアプリも多くリリースされ、使い心地がさらによくなる上に、iPhoneでできること１年や２年で急激に増えました。さらに携帯（iPhone）ゲームが信じられないほどのブームを迎えて（オンラインゲームもオフラインゲームも）、携帯や携帯コンテンツの「楽しさ」が一気にあがりました。
というように、今まで「携帯コンテンツ」がほとんどなかった海外で、コンテンツの量が急激に増加しました。

・<i>グローバル発売</i>
iPhoneはアメリカのみのリリースだったので、アメリカ国以外の国に大きな影響を与えることは難しかった。しかしそれもiPhone 3Gのグローバルリリースで事態が大きく変わりました。iPhoneが世界的に売れたことの直の影響で、世界の各地に開発者からの貢献のお陰で「携帯向け」コンテンツが急増しました。今まで人々が携帯ウェブに対する態度やスタンスが一気に変わり、日本以外の国の「携帯コンテンツ」は著しいブームを迎えることになりました。しかもそれは、規模も自由度も色々制限されている日本の「携帯のみコンテンツ」を遥かに超えた、「グローバルインターネットウェブコンテンツ」でした。


iPhoneブームへの反応として、Web OSやAndroidなど、iPhone OSを意識した「次世代」携帯OSが次々とリリースされました。それらがリリースされた時点ではもうiPhoneのリードが大きすぎた事実もあり、未だにまだiPhoneが大半のマーケットシェアを占めています。この状況の中で、一番苦戦しているのは「今までの携帯」です。例として、海外で絶大のマーケットシェアを占めていたNokiaでさえ<a href="http://www.trefis.com/company?hm=NOK.trefis&hk=299c800b8a78f6c806bdfe98817fe4744e56dc76&from=custom:notd&driver=0053#">苦戦しています。</a>

iPhone 3GSが携帯さらに携帯市場の将来の方向性を示してくれたでしょう。操作が簡単で使い心地がよい上に処理が早い。私iPhone 3GのときからiPhoneを使用していて、3GSがリリースされる前からiPhone 3Gは遅いと感じていました。アプリを起動するやサイトを開くなど処理にかかる時間が長すぎてイライラします。パソコンが隣にあればiPhoneでウェブをしたくありません。あくまでも外にいる時にパソコンがない状況で仕方なく使うものでした。しかしiPhone 3GSでそれが変わりました。パソコンが隣にいても、ベッドで横になったままiPhoneでアクセスすればいいやって思う時もあります。しかも携帯のプロセッサに関してはまだまだ進歩し続ける領域であるので、これから携帯端末がもっと早くなると期待できます。まさに「携帯がパソコン、パソコンが携帯」という未来のビジョンがよりはっきりと目に浮かぶようになりました。


<strong><big>iPhoneが発売された後：日本</big></strong>

ところが、日本では海外に比べてiPhoneの影響が弱いです。もちろんiPhone(とくに3gsになってから)は日本でもかなりブームしています。ソフトバンクの顧客純増数を見れば誰でも分かることでしょう。しかし、日本は他の海外と違っていて、非スマートフォンの携帯端末が非常に進んでいる状態にあります。iPhoneがAndroidやWeb OSリードしているみたいに、日本では「携帯のみコンテンツ」がiPhoneがリリースされる前から遥にリードしていることが事実です。それもコンテンツだけではなく、FelicaやモバイルSuicaなど人々の日常に浸透している端末連携機能も存在しています。こういう状況の中で、iPhoneに興味のある人でも日本携帯端末で捨てがたいところはたくさんあるでしょう。特に携帯のみコンテンツは規模が半端なく巨大であり、それにはまっている人たちは携帯のみコンテンツから完全に離れることにはかなり抵抗を感じるでしょう。

こういう背景もあって、完全にiPhoneだけに切り替えるのではなく、「2台目」としてiPhoneを使う人達が多くいます。しかし、それだと月々の費用や端末代が倍になるので、誰もが選択できる選択肢ではありません。むしろこんな不利な状況の中でiPhoneがここほど売れていることはかなりの成功と言えるでしょう。

しかし、日本の携帯市場はこのままで本当にいいでしょうか？

海外では間違いなくiPhoneをはじめとしたスマートフォン革命が始まっています。非スマートフォン式携帯はどんどん淘汰されつつあり、特に先進国では今までの非スマートフォン式端末がスマートフォン式端末に越される日はもう遠くないでしょう。そして世界は国やキャリアに限られたコンテンツやサービスではなく、世界的なコンテンツやサービスに移行としています。
ところが、日本の場合、大衆が非スマートフォン式携帯から離れる傾向は海外に比べて弱いように見えます。このままだと、日本だけが取り残されるという危険があるのではないでしょうか。


<strong><big>日本携帯市場の鎖国</big></strong>

日本の携帯市場は、今にはじまったことじゃないが、一種の鎖国状態にあると言えるでしょう。他には「ガラパゴス」という言葉もよく聞きます。
海外端末はSMS、日本端末はメール、などの根本的なところで日本の携帯は海外で携帯と違っていて互換性がほとんどありません。

しかし、スマートフォン革命が起きる前は日本にいる誰もがそれを気にしたことなかったでしょう。
スマートフォン革命が起こる前の海外携帯市場は鎖国状態ではないが、コンテンツプラットフォームがなりたっていなかったです。日本携帯市場が鎖国状態にあってもそうでなくても、世界へモバイルコンテンツを発信することは難しいことでした。

しかしスマートフォン革命でその状況が変わりました。世界は世界にコンテンツを発信受信できます。もし日本が今までの携帯のみコンテンツにしがみつき過ぎてスマートフォン革命が使った新しい市場に入り遅れたら、大きなビジネスチャンスを失うことになるのではないでしょうか。

このような事態を回避するには、キャリアやメーカ側の責任が特に重大だと思います。
・<i>キャリア側：海外端末との互換性を改善する</i>
海外スマートフォン端末は日本では携帯として非常に苦労するところがもろもろとあります。
例：Androidから携帯端末にメールを送ったらPCメールフィルターかかってる人にから迷惑メール扱いになるし、その上メール送信失敗通知さえこないからコミュニケーションが成り立たないです。
まさに鎖国とはこういうことでしょう。日本携帯機種じゃないものはシャットアウトされます。
iPhoneはi.softbank.jp独自のソフトバンク提供メールアドレスでこの問題をある程度解消しているが、i.softbank.jpを使えば結局GmailやMobileMeを持っていてもメインとして使えないことになるし、ソフトバンクから離れればメールアドレスもなくなるし、ソフトバンクはメールフォーワード設定出来ないし...などなど基本的なメールをするだけでもたくさん不便が生じます。
そういう根本的な問題が解消されない限り、海外スマートフォンが日本で普遍になる日は来ないでしょう。来るとしても余計に時間がかかってしまいます。
・<i>メーカ側：海外でも日本でも使える互換性ある端末を作り、それらを日本独有のサービスに対応できる携帯にする</i>
モバイルSuicaやFelicaなど日本独特の携帯機能に対応出来るようなスマートフォン端末を日本のメーカが製造すれば、「海外スマートフォンだから〇〇ができない」という問題が解消されます。（さらにそれらの端末は海外でも使える仕様になっていれば、端末やサービスそのものを海外に売り出す可能性もなくはないでしょう）

残りは日本の携帯のみコンテンツの問題ですね。日本の閉鎖的な携帯のみコンテンツは海外の携帯が使える日は永遠に来ないでしょう。海外のスマートフォン革命で発信されるコンテンツだけで、日本の携帯のみコンテンツの代わりになれる豊富なコンテンツができるシチュエーションは難しいと思われます。なぜならの携帯のみコンテンツは日本に最適したローカライズコンテンツであり、海外が配信するコンテンツでそのレベルに達するのは難しいです。その上言語的な問題点も存在しており、そもそも日本語化されないコンテンツも多いでしょう。

となると、日本のコンテンツ提供者側の人達が新しい環境で今までの「携帯のみコンテンツ」に衰えないような質と量のコンテンツを創り出さなければなりません。初めのうちは完全に携帯のみコンテンツの代わりになれるまで行かなくても、せめて携帯のみコンテンツから離れる人たちの拒絶感を減らせるようなレベルに達成する必要があると思います。

日本ではまだ非スマートフォンな携帯端末が一般的で、今も非スマートフォン携帯端末コンテンツがスマートフォンコンテンツより儲かれるポテンシャルが高いかもしれないが、コンテンツ配信者も比較的に少なく、このスマートフォン革命の早い段階から参入した方がブランド力とステータスを高めるポテンシャルがあるはずです。それに、早めに始めた者が後から始める者よりいろいろなノウハウを積むことができ、その積み上げたノウハウをうまく利用することで他人より有利な位置に立つこともあるでしょう。今すぐ目の前にある利益の可能性が少し低くても、将来な利益ポテンシャルは決して少なくないと思います。


スマートフォン革命が作り出してくれた世界的なモバイル事業の波を、日本は乗りこなして世界的なリーダーの位置に昇進するのか、乗り遅れて取り残されるのでしょうか。世界携帯市場が今大きく変化していくように、日本にも大きな変化が必要とされる時期にあるでしょう。
明治維新を行う気持ちで、今の日本の携帯市場鎖国を一緒に解いてみませんか？]]></description>
         <link>http://labs.unoh.net/2010/03/post_142.html</link>
         <guid>http://labs.unoh.net/2010/03/post_142.html</guid>
         <category></category>
         <pubDate>Mon, 08 Mar 2010 11:53:55 +0900</pubDate>
      </item>
      
      <item>
         <title>英語が出来るように思わせてみる</title>
         <description><![CDATA[はじめまして、去年末に入社しましたkayです。
エンジニアとしてまだまだな私ですので、少し英語のお話でもしようと思います。

私自身、アメリカの大学に3年ほど通っており、ついこの間卒業したばかりなのですが、アメリカにいた頃はスラングだということすら知らずに使っていた英語もたくさんありました。
スラングというのはもともAfrican-Americanが使っている言葉として知られていたと思いますが、今は主に若者の言葉や外国の英語の教科書には載っていない用法のことを指しているのではないかと個人的に思っています。
そして、スラングはアメリカ人たちが楽するために使用されるものが多く、仕組みを理解することで外国人でもだいぶ楽して英語を扱える+英語が得意な人だと思わせられるようになります。
ただ、初心者がスラングばかり(特に文法的に間違っている文)を使っているとちゃんとした英語が身に付かない場合もありますので、本当はどうあるべきなのかを頭に入れておくこともとても大切です。

ということで、外国の方々と英語でコミュニケーションをする必要があった場合に少しでも自信を持って英語が扱えるように少しばかりスラングTipsでも紹介致します。

※ なお、ここで紹介のはとてもカジュアルなアメリカ英語であり、地域によっても用法が異なっていたり・私の勝手な解釈だったりするので、ご了承ください。
(私の勝手な解釈が間違っていた場合はお知らせいただければと思います。)


h3. 名詞の動詞化

* 写真を撮る → photograph
* eメールする → email
* SNSで友達申請する → friend (日本でならCan I mymixi you?とか使えそうですね。)
* (女独特の)悪口を言う → bi*th (間違って名詞としてあまり仲の良くない女のひとに使うと大変なことになる可能性がありますが･･･)

のようにスラングでなくても英語では名詞をそのまま動詞にして使用することが多々あります。
どこからどこまでがスラングでないのか微妙なところがあり、私自身もよくわかっていません。
なので、ちゃんと動詞として使っていい単語なのかを考える前にカジュアルな場面なら使ってしまいましょう。実際に辞書に存在しない用法だった場合でもスラングとして大抵の場合は許されます。
take a picture や send an e-mail という風に長ったらしく書くよりも動作の部分の動詞が何になるのかを考える必要がないのでだいぶ楽が出来るかと思います。
※ pictureを動詞で使った場合には写真を撮る意味にはなりません。こういうイレギュラーもありますが、そういう場合だけは覚えるようにしましょう。

h3. 接頭語・接尾語を使う

redo, undo (doの代わり大抵の動詞を入れて使えます。)
が一番使えると思いますが、他にも大量に存在します。
量は多いですが、本気で英語を勉強しようと思った際に覚える単語の数に比べたら可愛いものですし、これらの用法・意味を押さえておくだけでボキャブラリーが倍増しますので、一度頭に入れておくことをおすすめします。
上の名詞の動詞化とミックスしてunfriendなんて使い方も出来ます。

h3. 略語

* OMG → oh my god!
略さずに使う場合、godの代わりにgoshやgoodnessを使うことも多いです。ただキリスト教ではない人にとっては多少違和感のあるフレーズになってしまうかもしれません。
* a.k.a. → also known as
* ASAP → as soon as possible
* BTW → by the way
* FYI → for your information
* LOL → laughing out loud
笑・ｗの代わりになるものですが、もっと分かりやすくhahaやhehe等も使われています。
* TIA → thanks in advance
個人的には略して使用したりしませんが、略す前のフレーズはネット上で非常によく使うので物を尋ねるときは最後に入れましょう。
* pls / plz → please
* thx → thanks
* sup → what's up?
* u / ya → you
* x.o.x.o. → hugs and kisses
動作を表すもので、文章の最後で使用します。

ほんの一例ですが、良く使われているもの達です。
基本的にはネット上で見かけますが、ASAPやFYI等は口頭でも良く使用します。
4, 8, 2といった数字を同じ発音するものの代わりに使うのも有名ですよね。

ただ、みんなに通じるものではないので、意味が分かる程度に抑えてあまり自分からは使用しないようにするのもマナーかもしれません。

h3. アポストロフィーを理解する

* don't → do not
* 'em → them
* 'n' → and
* 'bout → about
* 'cause → because

と、アポストロフィーが挿入されているところには何かが省略されているという意味になります。
これは実際に話す際の発音に近いものになっていることが多いです。
もっとも、アポストロフィーさえ省略されることが多いのであまり参考にはならないかもしれませんが、歌詞などには大抵入っている状態で記されているので、そういう時には何かが省略されているとすぐにわかります。

そういう意味で、don'tやwhat'sなどは日本の教科書にも載っているような用法ですが、略されている=正式ではないということなので、正式な文章には絶対に使わないように心がけましょう。

h3. アメリカ人が使う間違った(良くない)文法

* I want it so bad. / It was real good.
動詞や形容詞を修飾しているので、副詞のbadly / reallyが本当は正しいはずです。
* There was many cars.
carsなので、wereが正しいですが、名詞よりも動詞が最初に来るので複数形にするのを忘れがちなパターンです。
* I'm sorry. I'm late.
I'm sorry for being lateと教科書では教わりますよね。forは実際にカジュアルな場ではそんなに使いません。ついさっきの出来ごとについて謝る場合にはsorry about thatになったりします。
* a tea
a cup of teaが正しいです。
* you ok? / you sleep yesterday? / she go there?
疑問文ではbe動詞やdo系が良く省略されます。
* I haven't a car. / I needn't a car.
動詞のhaveと現在完了で使うhaveを混同させた結果です。
* I never been there.
現在完了のhaveは度々省略されます。
* Do you got a car?
have = have got = got (haveを省略) なので、doを使っているのに過去形の動詞が来ている変な文。

というように、ネイティブスピーカーも間違った文法で英語を使います。一部は流行っているという理由で使用されますが、大半は彼らも面倒くさいと思っていたりするものを使いやすいように変えているので、もちろん外国人である私たちにも使いやすくなっています。

h3. 外国人がよくする間違いに気をつける

* 今から3日後 → × three days later　○ (after) three days from now
スタート地点が過去の場合はlater、今の場合は後者になります。
* 私も好きじゃありません → × I don't like it too.　○ I don't like it either.
も=tooと思っている人が多いのですが、文章がネガティブの場合はeither, neitherが正しいです。
me, too <-> me, neither(or either) / so do I <-> neither do I 
* × Yes, I don't.　○ No, I don't.
これも上と似ていますが、疑問文に賛成していても答えはいいえにならないといけません。
ただ、会話の際に間違えてyeahが出てしまった時には、後にyou're rightをつける(付けなくても意味的にそういう流れなら大丈夫)ことで文法的には正しくなりますので、慣れない内はこれで回避するのも手です。
* × There were an apple and an orange.　○ There was...
合計で2個でもbe動詞の直後の名詞が単数ならwasが正しいです。
* × I and my friends like shopping.　○ My friends and I... / Me and my friends...
自分が後に来る場合はI、最初に来る場合はmeになります。

これらはスラングとまったく無関係ですし、間違えても意味は通じますが、本当に間違えている人が多いので間違えずに使うことで出来る！と思わせることが出来るかもしれません。

<div style="margin:0;padding:.5em;border:2px solid 
#ccc">ウノウでは特に最近、積極的にエンジニアを採用しています。<br /><a
href="http://www.unoh.net/recruit.html"> 採用ページ</a>をご覧になり興味のある方、ぜひご応募ください。<br/><a
href="http://www.find-job.net/fj/showjob.cgi?id=50212">Find Job!</a>でも募集してます！</div>]]></description>
         <link>http://labs.unoh.net/2010/02/post_141.html</link>
         <guid>http://labs.unoh.net/2010/02/post_141.html</guid>
         <category></category>
         <pubDate>Sun, 28 Feb 2010 11:00:00 +0900</pubDate>
      </item>
      
      <item>
         <title>PECL::oauthでxAuth</title>
         <description><![CDATA[<p>yamaokaです。</p>

<p>
<a href="http://twitter.com/">Twitter</a>のBasic認証によるユーザー認証が<a href="http://techcrunch.com/2009/12/09/twitter-le-web-2009/">6月に廃止される</a>ようですね。
認証はOAuthで行ってください、とのことなのですが
OAuthの認証画面を表示するためにブラウザを起動するのがふさわしくないケースや、
そもそも貧弱なブラウザでうまく利用できないケースもあります。
</p>

<p>
そうした場合の解決方法として、xAuthという仕組みがTwitterに実装されています。
詳しくは次に紹介するweb上の記事を参照してください。
</p>

<ul>
<li><a href="http://s-take.blogspot.com/2010/02/twitteroauth-xauth.html">s-take Blog.: Twitterによる簡易版OAuth: "xAuth"</a></li>
<li><a href="http://d.hatena.ne.jp/lyokato/20100212/1265961914">OAuthでデスクトップアプリがブラウザを経由させたくないときのxAuth - Codin' In The Free World</a></li>
<li><a href="http://the.hackerconundrum.com/2010/02/sneak-peek-at-twitters-browserless.html">the.hackerConundrum: Sneak peek at Twitter's browserless OAuth credentials exchange method</a></li>
<li><a href="http://mattn.kaoriya.net/software/lang/python/20100217004716.htm">Big Sky :: デスクトップアプリケーションでも認証可能なOAuth「xAuth」をpythonから試してみた。</a></li>
<li><a href="http://blog.livedoor.jp/maraigue/archives/1109122.html">Maraigue風。:[Ruby][Twitter] OAuthのアクセストークンを、ブラウザなしで、Twitterのユーザ名およびパスワードのみを用いて取得する(通称：xAuth)ためのRubyのコード</a></li>
</ul>

<p>
認証にはユーザーの名前とパスワードを使いますが、
それを元にaccess_tokenとaccess_token_secretを取得できるので以後の認証にはパスワードが不要になるというものです。
これならBasic認証の代わりに使うことができそうですね。
勿論、OAuthを利用できるシーンではOAuthを用いた認証が望ましいのですが、
必ずしも当てはまらないケースもあるということで。
</p>

<p>
PythonやRubyを使った実装サンプルは見つかったので、
PHPのものはないかなと探してみるとありました。
ただし<del datetime="2010-02-25T14:55:00+09:00">ベトナム語</del><ins datetime="2010-02-25T14:55:00+09:00" style="text-decoration:none;">タイ語</ins>なのでPHPのコードしか読めないということと、
実装コードがPHPの関数ベースなので少し使いづらそうです。
</p>

<ul>
<li><a href="http://www.nuuneoi.com/blog/blog.php?read_id=278">NuuNeoI - แจกซอร์ส PHP Twitter xauth</a></li>
</ul>

<p>
そこで普段OAuthを利用する際に使っている<a href="http://jp.php.net/manual/ja/book.oauth.php">PECL::oauth</a>で実装できないか試してみました。
ちなみに通常のOAuth認証を利用する場合のサンプルは<a href="http://cvs.php.net/viewvc.cgi/pecl/oauth/examples/">リポジトリにコミットされているので参照する</a>ことができます。
</p>

<p>
<pre class="code"><code>&lt;?php
$consumerKey         = 'YOUR-CONSUMER-KEY';
$consumerSecret      = 'YOUR-CONSUMER-SECRET';
$userName            = 'YOUR-USER-NAME';
$password            = 'YOUR-PASSWORD';
$xAuthAccessTokenUrl = 'https://api.twitter.com/oauth/access_token';

$response = '';
$parameters = array(
    'x_auth_mode'     =&gt; 'client_auth',
    'x_auth_username' =&gt; $userName,
    'x_auth_password' =&gt; $password,
);

try {
    $oauth = new OAuth($consumerKey, $consumerSecret,
        OAUTH_SIG_METHOD_HMACSHA1, OAUTH_AUTH_TYPE_URI);
    $oauth->fetch($xAuthAccessTokenUrl, $parameters, OAUTH_HTTP_METHOD_POST);
    $response = $oauth->getLastResponse();
} catch (OAuthException $e) {
    echo &quot;Error\n&quot;;
    exit;
}

// oauth_token=xxx&oauth_token_secret=xxx&
// user_id=xxx&screen_name=xxx&x_auth_expires=0
parse_str($response, $accessTokenInfo);

// oauth_token, oauth_token_secret, user_id, screen_name,
// x_auth_expires
var_dump($accessTokenInfo);
</code></pre>
</p>

<p>
$accessTokenInfoの要素として「oauth_token」と「oauth_token_secret」が入っているので、
それをDBなどに保存しておくようにすれば通常のOAuth認証を用いてツイートの投稿などを行うことができるようになります。
そのまま利用して投稿するとすると、次のような感じになります。
</p>

<p>
<pre class="code"><code>$oAuthStatusesUpdateUrl = 'http://twitter.com/statuses/update.xml';

$response = '';
$parameters = array(
    'status' =&gt; 'YOUR-STATUS-MESSAGE',
);

$oauthToken       = $accessTokenInfo['oauth_token'];
$oauthTokenSecret = $accessTokenInfo['oauth_token_secret'];

try {
    $oauth->setToken($oauthToken, $oauthTokenSecret);
    $oauth->fetch($oAuthStatusesUpdateUrl, $parameters, OAUTH_HTTP_METHOD_POST);
    $response = $oauth->getLastResponse();
} catch (OAuthException $e) {
    echo &quot;Error\n&quot;;
    exit;
}

var_dump($response);
</code></pre>
</p>

<p>
仕組みとしては非常に単純なものなので、
現在Twitterの認証にBasic認証を仕方なく使っているケースでも
比較的簡単に置換ができるのではと思います。
当然、OAuthが利用できるのであれば
そちらを使うのが望ましいのは言うまでもありませんが。
</p>

<div style="margin:0;padding:.5em;border:2px solid 
#ccc">ウノウでは特に最近、積極的にエンジニアを採用しています。<br /><a
href="http://www.unoh.net/recruit.html"> 採用ページ</a>をご覧になり興味のある方、ぜひご応募ください。<br/><a
href="http://www.find-job.net/fj/showjob.cgi?id=50212">Find Job!</a>でも募集してます！</div>
]]></description>
         <link>http://labs.unoh.net/2010/02/twitter-xauth-with-pecl-oauth.html</link>
         <guid>http://labs.unoh.net/2010/02/twitter-xauth-with-pecl-oauth.html</guid>
         <category></category>
         <pubDate>Thu, 25 Feb 2010 14:19:47 +0900</pubDate>
      </item>
      
      <item>
         <title>テスト本の読書会を行います。</title>
         <description><![CDATA[こんにちは！やまもと＠テスト番長です。

ただいまテスト本の読書会を企画しています。
昨年秋に出版された「実践アジャイルテスト テスターとアジャイルチームのための実践ガイド」という本をご存知でしょうか？
アジャイルということでWEBアプリ製作の現場により近い内容のため、輪講形式で読み込んでみたいという話になりました。
時期は3月中旬ころ開催の予定です。詳細はこれから詰めますので、
ご興味のある方はお気軽に　yamamoto[at]unoh.net　までご連絡ください。

そういえば買ったけど積んでた！という方、その本まだ見てない！という方、この機会にいかがでしょうか？
テスト好きな方にお集まりいただけますと嬉しいです。ぜひご参加ください。

<div class="amazlet-box" style="margin-bottom:0px;"><div class="amazlet-image" style="float:left;"><a href="http://www.amazon.co.jp/exec/obidos/ASIN/4798119970/unoh-22/ref=nosim/" name="amazletlink" target="_blank"><img src="http://ecx.images-amazon.com/images/I/41q1wwMzUXL._SL75_.jpg" alt="実践アジャイルテスト テスターとアジャイルチームのための実践ガイド (IT Architects'Archive ソフトウェア開発の実践)" style="border: none;" alt="no image" /></a></div><div class="amazlet-info" style="float:left;margin-left:15px;line-height:120%"><div class="amazlet-name" style="margin-bottom:10px;line-height:120%"><a href="http://www.amazon.co.jp/exec/obidos/ASIN/4798119970/unoh-22/ref=nosim/" name="amazletlink" target="_blank">実践アジャイルテスト テスターとアジャイルチームのための実践ガイド (IT Architects'Archive ソフトウェア開発の実践)</a><div class="amazlet-powered-date" style="font-size:7pt;margin-top:5px;font-family:verdana;line-height:120%">posted with <a href="http://www.amazlet.com/browse/ASIN/4798119970//ref=nosim/" title="実践アジャイルテスト テスターとアジャイルチームのための実践ガイド (IT Architects'Archive ソフトウェア開発の実践)" target="_blank">amazlet</a> at 10.02.22</div></div><div class="amazlet-detail">Janet Gregory Lisa Crispin <br />翔泳社 <br />売り上げランキング: 110310<br /></div><div class="amazlet-review" style="margin-top:10px; margin-bottom:10px"><div class="amazlet-review-average" style="margin-bottom:5px">おすすめ度の平均: <img src="http://images-jp.amazon.com/images/G/09/x-locale/common/customer-reviews/stars-5-0.gif" alt="5.0" /></div><img src="http://images-jp.amazon.com/images/G/09/x-locale/common/customer-reviews/stars-5-0.gif" alt="5" /> アジャイル開発のテストの最高のガイドブック<br /></div><div class="amazlet-link" style="margin-top: 5px"><a href="http://www.amazon.co.jp/exec/obidos/ASIN/4798119970/unoh-22/ref=nosim/" name="amazletlink" target="_blank">Amazon.co.jp で詳細を見る</a></div></div><div class="amazlet-footer" style="clear: left"></div></div>
]]></description>
         <link>http://labs.unoh.net/2010/02/post_140.html</link>
         <guid>http://labs.unoh.net/2010/02/post_140.html</guid>
         <category>お知らせ</category>
         <pubDate>Mon, 22 Feb 2010 17:19:27 +0900</pubDate>
      </item>
      
      <item>
         <title>cacti の設定をコマンドラインから行う方法</title>
         <description><![CDATA[こんにちは。kyagi です。今回は　<a href="http://www.cacti.net/">cacti</a> の設定をコマンドラインから行う方法をお知らせいたします。

cacti とはサーバの監視/グラフ化ツールです。CPU使用率やロードアベレージ、その他様々な情報をカラフルなグラフで見ることができます。

設定は主にブラウザ上から行うのですが1台のサーバの設定でもSNMPの各項目を選択したり、グラフのデータ元であるデータクエリを設定したりなかなかの作業量になります。設定内容は全て把握していても 1 台につき、マウスでクリックする回数が多いので数十台の追加となると時間もかかりますし、指もかなり疲れます(また、ヒューマンエラーも入り込む余地が生まれます)。

cacti にはこういった設定をコマンドラインから行える php スクリプトが用意されています。標準ではこれらのスクリプトは /var/lib/cacti/cli/ 配下にインストールされています。これらのスクリプトの使用方法は --help オプションをつけると表示されますが、html 版のドキュメントも用意されています。

■cacti の設定をコマンドラインから行える php スクリプト

<pre class="code">
$ rpm -ql cacti | grep cli | grep php$
/var/lib/cacti/cli/add_data_query.php
/var/lib/cacti/cli/add_device.php
/var/lib/cacti/cli/add_graph_template.php
/var/lib/cacti/cli/add_graphs.php
(...snip...)
</pre>

■上記 php スクリプトのヘルプドキュメント

<pre class="code">
$ rpm -ql cacti | grep cli | grep html$
/usr/share/doc/cacti-0.8.7e/docs/html/cli_add_data_query.html
/usr/share/doc/cacti-0.8.7e/docs/html/cli_add_device.html
/usr/share/doc/cacti-0.8.7e/docs/html/cli_add_graph_template.html
/usr/share/doc/cacti-0.8.7e/docs/html/cli_add_graphs.html
(...snip...)
</pre>

以下にこれらのスクリプトを使用して newserver というサーバを追加していく例を紹介いたします。

1.まず、追加するサーバのタイプ(Web サーバだったり、DB サーバだったりします)を指定するための template の id を調べます。

<pre class="code">
$ sudo -u cacti php /var/lib/cacti/cli/add_device.php --list-host-templates
Valid Host Templates: (id, name)
0	None
1	Generic SNMP-enabled Host
3	ucd/net SNMP Host
4	Karlnet Wireless Bridge
5	Cisco Router
6	Netware 4/5 Server
7	Windows 2000/XP Host
8	Local Linux Machine
9	X DB Server HT
10  	WebServer - Apache
11	Memcached Server
12	X Nginx Server HT
</pre>

2. ここでは template としてシンプルな None を選びます。template が決まったので add_device.php で device を追加します。ここでの cacti の出力の device_id の 90 が以下に使う「--host-id」に渡す値になります。

<pre class="code">
$ sudo -u cacti php add_device.php --description=newserver　--ip=10.0.0.123 --version=2 --avail=pingsnmp --community=public --template=0
　
Adding newserver (10.0.0.123) as "None" using SNMP v2 with community "public"
Success - new device-id: (90)</pre>

3. Data Query を追加します。サンプルとして以下 3 つ(SNMP interface, ucd/net Get Mount, SNMP Get Mount Partitions) を追加します。「--host-id」に先ほどの値 90 を使用します。

<pre class="code">
$ sudo -u cacti php add_data_query.php --host-id=90 --data-query-id=1  --reindex-method=1 #SNMP interface
$ sudo -u cacti php add_data_query.php --host-id=90 --data-query-id=2  --reindex-method=1 #ucd/net Get Mount Partitions
$ sudo -u cacti php add_data_query.php --host-id=90 --data-query-id=8  --reindex-method=1 #SNMP Get Mont Partitions
</pre>

4. Graph Template を追加します。サンプルとして CPU 使用率、ロードアベレージ、メモリ使用量を追加します。グラフテンプレートIDは「--list-graph-templates」オプションで見ることができます。

<pre class="code">
$ sudo -u cacti php add_graph_template.php --host-id=90 --graph-template-id=4  #ucd/net CPU Usage
$ sudo -u cacti php add_graph_template.php --host-id=90 --graph-template-id=11 #ucd/net Load Average
$ sudo -u cacti php add_graph_template.php --host-id=90 --graph-template-id=13 #uce/net Memory Usage
</pre>

5. Graph を追加します。サンプルとして CPU 使用率、ロードアベレージ、メモリ使用量を追加します。

<pre class="code">
$ sudo -u cacti php add_graphs.php --host-id=90 --graph-template-id=4 --graph-type=cg
$ sudo -u cacti php add_graphs.php --host-id=90 --graph-template-id=11 --graph-type=cg
$ sudo -u cacti php add_graphs.php --host-id=90 --graph-template-id=13 --graph-type=cg
</pre>

使い方がわかればこれらをバッチ処理で実行するスクリプトを作成して更に効率化することも可能です。
<a href="http://github.com/kyagi/cacti-add-device-helper.rb/blob/master/cacti-add-device-helper.rb">http://github.com/kyagi/cacti-add-device-helper.rb/blob/master/cacti-add-device-helper.rb</a>

<div style="margin:0;padding:.5em;border:2px solid
#ccc">ウノウでは特に最近、積極的にエンジニアを採用しています。<br /><a href="http://www.unoh.net/recruit.html">採用ページ</a>をご覧になり興味のある方、ぜひご応募ください。<br/><a href="http://www.find-job.net/fj/showjob.cgi?id=50212">Find Job!</a>でも募集してます！</div>]]></description>
         <link>http://labs.unoh.net/2010/02/cacti.html</link>
         <guid>http://labs.unoh.net/2010/02/cacti.html</guid>
         <category></category>
         <pubDate>Mon, 08 Feb 2010 11:00:32 +0900</pubDate>
      </item>
      
      <item>
         <title>位置情報を取得してみる</title>
         <description><![CDATA[<div style="margin:0;padding:.5em;border:2px solid
#ccc">ウノウでは特に最近、積極的にエンジニアを採用しています。<br /><a
href="http://www.unoh.net/recruit.html">採用ページ</a>をご覧になり興味のある方、ぜひご応募ください。<br/><a
href="http://www.find-job.net/fj/showjob.cgi?id=50212">Find
Job!</a>でも募集してます！</div>

こんにちは。ryosuke です。

先週からモバゲータウン内において、弊社の携帯まち育成ブラウザゲーム「まちつく！モバゲー版」の提供を開始しています。よろしければ遊んでみてください。

まちつく！は、まち育成シミュレーションゲームですが、育成だけではなく携帯電話の位置情報を利用したおみやげやスタンプといった機能があります。最近は海外でもGPS機能を搭載したスマートフォンが普及してきたためか、世界的に位置情報を利用したサービスが活発化し始めているようです。

NHKのTV番組ブラタモリと連携しているiPhoneアプリの「ブラアプリ」や、位置情報でつながる街情報SNS「foursquare」 が話題になったりしていていますね。位置情報自体は今更感があるのですが、個人的興味でにわかに位置情報がホットです。

<h3>携帯電話</h3>

位置情報の活用と言えば一番に思い浮かぶのが携帯電話ですね。基地局を利用した位置情報とGPSを利用した位置情報があり、日本の携帯電話ではなじみの深い機能ですがGPSは実装が義務化されているそうです。

<h3>docomo</h3>

<ul>
	<li>オープンiエリア
           <ul><li><a href="http://www.nttdocomo.co.jp/service/imode/make/content/iarea/domestic/">オープンiエリア（国内版）</a></li></ul></li>
        <li>GPS
           <ul><li><a href="http://www.nttdocomo.co.jp/service/imode/make/content/gps/">GPS</a></li></ul></li>
</ul>

オープンiエリアでは5桁のエリアコードが付いており、公開されているエリアテーブルと関連づける事で全国を505に分割した地域名を取得できます。

<pre class="code">&lt;a href="http://w1m.docomo.ne.jp/cp/iarea?ecode=OPENAREACODE&msn=OPENAREAKEY&nl=URL&posinfo=1"&gt;位置情報を送る&lt;/a&gt;</pre>

GPSはaタグやformタグにlcsを付けるだけで、リンク先に位置情報関連の引数を付けて渡してくれます。

<pre class="code">&lt;a href="URL" lcs&gt;位置情報を送る&lt;/a&gt;</pre>

<h3>au</h3>

<ul>
	<li>簡易位置情報 
           <ul><li><a href="http://www.au.kddi.com/ezfactory/tec/spec/eznavi.html">簡易位置情報</a></li></ul></li>
        <li>GPS
           <ul>
               <li><a href="http://symple.jp/16.html">非公開情報だよ！au GPSの使い方</a></li>
               <li><a href="http://www.yaskey.cside.tv/mapserver/gps/#GPSPositionIinfo">GPS位置情報パラメータの取得方法</a></li>
           </ul></li>
</ul>
簡易位置情報はドキュメントどおり以下の様に取得します。

<pre class="code">&lt;a href="device:location?url=URL"&gt;位置情報を送る&lt;/a&gt;</pre>

auはGPSに関する資料は正式に公開されてはいないようです。しかしwebを検索すると有用な情報が揃っています。

簡易位置情報は上記サイトでドキュメント化されていますが、GPSも簡易位置情報の device:location となってる所を device:gpsone に変更すれば、同様に扱えます。

<pre class="code">&lt;a href="device:gpsone?url=URL"&gt;位置情報を送る&lt;/a&gt;</pre>

<h3>SoftBank</h3>
SoftBank も au と同様に以下の様にURLにリンクする事で指定したURLに位置情報を渡してくれます。

<pre class="code">&lt;a href="location:cell?url=URL"&gt;位置情報を送る&lt;/a&gt;</pre>

GPSの場合は cell の部分が gps になります。

<pre class="code">&lt;a href="location:gps?url=URL"&gt;位置情報を送る&lt;/a&gt;</pre>

<h3>WILLCOM </h3>

<ul>
	<li><a href="http://www.willcom-inc.com/ja/service/contents_service/create/location/
">位置情報</a></li>
</ul>

忘れてはいけない WILLCOM です。会社にPHSがあったので、今回はじめて試してみましたが、携帯キャリアと同様に取得できました。(まちつく！mixi版はPHSでも遊べます)

<pre class="code">&lt;a href="http://location.request/dummy.cgi?my=URL&pos=$location"&gt;位置情報を送る&lt;/a&gt;</pre>

<h3>スマートフォン</h3>

<h3>iPhone</h3>
未確認ですが、Core Locationフレームワークを使用するそうです。

<a href="http://developer.apple.com/iphone/library/documentation/CoreLocation/Reference/CoreLocation_Framework/index.html#//apple_ref/doc/uid/TP40007123">Core Location Framework Reference</a>

<h3>Android</h3>
android.location パッケージが提供されています。

<a href="http://developer.android.com/intl/ja/reference/android/location/package-summary.html">android.location</a>

<h4>参考</h4>
<ul>
	<li><a href="http://www.adakoda.com/android/000125.html">位置情報を取得するには/GPSを使用するには</a></li>
	<li><a href="http://blog.justoneplanet.info/2009/07/08/">androidで位置情報を取得する</a></li>
</ul>

<h3>WEBブラウザ</h3>
<h4>Firefox</h4>
Firefox 3.5以降ではプラグイン等を必要とせず、標準でGeolocation APIがサポートされています。

<a href="https://developer.mozilla.org/Ja/Using_geolocation">Geolocation の利用</a>

場所にもよるのかもしれませんが、試してみた所なかなか良い精度で位置情報を取れました。

<h4>Safari</h4>
<ul>
<li>iPhone OS3.1のSafariではGeolocation APIがサポートされているようです(未確認)</li>
<li>ちなみに MacOSX Snow LeopardのSafari4.0.4では動作しませんでした</li>
</ul>

<h3>その他位置情報に関するAPI</h3>
取得した位置情報を簡単に加工する事が出来ます。

<h4>沖電気提供の位置情報API</h4>
<a href="http://okilab.jp/project/location/">http://okilab.jp/project/location/</a>
<ul>
	<li><a href="http://okilab.jp/project/location/2007/11/geocodeapi.html">地名を緯度経度に変換するAPI</a></li>
	<li><a href="http://okilab.jp/project/location/2007/03/api.html">緯度経度から最寄りの駅を見つけ出すAPI</a></li>
	<li><a href="http://okilab.jp/project/location/2007/02/api_3.html">文書中から住所表現を抽出するAPI</a></li>
</ul>

その他、位置情報の加工に便利そうなAPIが提供されています

<h4>シリウステクノロジーズ提供の位置情報API</h4>
<a href="http://lab.cirius.co.jp/GeoPlatformAPI/">http://lab.cirius.co.jp/GeoPlatformAPI/</a>
<ul>
	<li><a href="http://lab.cirius.co.jp/GeoPlatformAPI/GeoFormAPI">携帯電話からキャリアを意識せずに緯度経度、住所を取得できるAPI (GeoFormAPI)</a></li>
	<li><a href="http://lab.cirius.co.jp/GeoPlatformAPI/GeoPointAPI">住所や駅名、緯度経度、郵便番号を相互変換するAPI (GeoPointAPI)</a></li>
</ul>

<h3>まとめ</h3>

実際調べてみると、各社の資料を読むに尽きる感じですが、位置情報を取得すること自体はどの環境でも難しい印象はありませんでした。

実際には取得した情報を加工して使用する事になる為その辺りの処理を行わなければなりませんが、環境ごとに資料やライブラリは揃っているので(ウノウラボでも<a href="http://labs.unoh.net/2008/08/phpgeomobilejp_converter.html">Geomobilejp_Converter</a>を公開しています)試してみてはいかがでしょうか。
]]></description>
         <link>http://labs.unoh.net/2010/02/post_139.html</link>
         <guid>http://labs.unoh.net/2010/02/post_139.html</guid>
         <category></category>
         <pubDate>Wed, 03 Feb 2010 12:12:55 +0900</pubDate>
      </item>
      
      <item>
         <title>ありえるえりあ勉強会@五反田～テスト編～ 発表資料</title>
         <description><![CDATA[こんにちは！　山本＠テスト番長です。

1/29に<a href="http://dev.ariel-networks.com/">アリエル</a>さんとウノウが合同で実施した<strike>ピザパーティ</strike>　<a href="http://atnd.org/events/2658">勉強会</a>でお話する機会を頂きました。お集まりいただきました皆様、どうもありがとうございました。

その時の資料を公開したいと思います。

<div style="width:425px;text-align:left" id="__ss_3047175"><a style="font:14px Helvetica,Arial,Sans-serif;display:block;margin:12px 0 3px 0;text-decoration:underline;" href="http://www.slideshare.net/galtonkatsu/ss-3047175" title="絶版プレミア本に学ぶウェブアプリのテスト方法">絶版プレミア本に学ぶウェブアプリのテスト方法</a><object style="margin:0px" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=2-100201093740-phpapp02&stripped_title=ss-3047175" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=2-100201093740-phpapp02&stripped_title=ss-3047175" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object><div style="font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;">View more <a style="text-decoration:underline;" href="http://www.slideshare.net/">presentations</a> from <a style="text-decoration:underline;" href="http://www.slideshare.net/galtonkatsu">galtonkatsu</a>.</div></div>


発表中、最近はなるべくテストをしないように心掛けている、と言ったところ
後で数人の方からその点について質問されました。
また後日考えを纏めて、文章の形で皆さんにご説明してみたいと思っています。


アリエル佐藤寛之さんの発表資料はこちらです。
大変興味深い内容ですので、ぜひご覧ください。
<a href="http://dev.ariel-networks.com/Members/sato_t/3042308a3048308b3048308a304252c95f374f1a-4e9453cd7530-30c630b930c87de8-8cc76599">ありえるえりあ勉強会@五反田～テスト編～ 資料</a>
]]></description>
         <link>http://labs.unoh.net/2010/02/post_138.html</link>
         <guid>http://labs.unoh.net/2010/02/post_138.html</guid>
         <category>勉強会</category>
         <pubDate>Tue, 02 Feb 2010 01:22:46 +0900</pubDate>
      </item>
      
      <item>
         <title>Flash Lite初学者の為のまとめ</title>
         <description>おはようございます。内田です。
最近はmixiアプリモバイルやモバゲー上のゲームのようなソーシャルゲームが流行ってるようですね。
私もソーシャルゲーム＆Flash Lite案件を手がけることになったので、その時に参考にしたサイトを紹介します。


h2. 開発の前に覚えること

最初にFlash Liteの仕様とケータイ開発の障壁ともいえるキャリア間の差異を知る必要があります。

* &quot;Flash Lite ことはじめ。 &quot;:http://labs.unoh.net/2009/10/flash_lite.html
** 我らがryosuke氏のエントリー
** 仕様とキャリア毎の情報が分かりやすくまとまってます。

* &quot;[Flash Lite 1.1]制作前に知っておきたいことをQ＆A形式でまとめてみた&quot;:http://kanariia.com/blog/archives/650
** 上記エントリーと重複する部分も多いですが、Q＆Aの形で調べやすい。
** 「一般的なガイドラインが知りたい！」を厳守すれば3キャリアで動作するswfがつくれそうです。

h2. コンテンツの作成

Flash Liteコンテンツのつくりかたです。

* &quot;Flash Liteドキュメンテーション&quot;:http://www.adobe.com/support/documentation/jp/flashlite/
** 公式に勝るドキュメントはありませんね。
** 必読

* &quot;携帯フラッシュ作成講座&quot;:http://www.next-system.com/mobileflash_index.html
** 書籍のような感じで非常に分かりやすいです。
** サンプルとリファレンスも嬉しい

h2. 動的生成

ゲームコンテンツの場合、動的にswfを合成することが多くあると思いますが、非常に悩ましい部分です。皆様がどのような方法で開発をおこなっているのか是非教えてください！

* &quot;Ming&quot;:http://sourceforge.net/projects/ming/
** swftophpコマンドによりswfをPHPに変換できる（perl,pythonもある）
** 試してみたがまともに動かない
** 有識者様の意見を是非!

* &quot;swfmill&quot;:http://swfmill.org/
** swf⇔xmlの相互変換ツール
** 使ってみた感じでは非常に安定しています
** しかし外部コマンドを叩いて生成するため、mingと比べると遅いかもしれない


h2. Tips

Flash Lite1.1の鬼門ともいえる100K制限をなんとかするためのTips達です。非常に参考になります。
しかし100Kに収まったとしても、重くてまともに動作しない端末もあるので油断できませんね。

* &quot;携帯Flash　さらなる軽量化&quot;:http://level0.kayac.com/2009/02/flashlite_light.php

* &quot;Flash Lite ファイル容量切り詰めTips&quot;:http://code.nanigac.com/source/view/436


おわり
</description>
         <link>http://labs.unoh.net/2010/01/flash_lite_1.html</link>
         <guid>http://labs.unoh.net/2010/01/flash_lite_1.html</guid>
         <category></category>
         <pubDate>Wed, 20 Jan 2010 13:01:00 +0900</pubDate>
      </item>
      
      <item>
         <title>Amazon Web Services入門: PHPとEC2/S3/SQS/SimpleDBで作るビデオ共有サイト</title>
         <description><![CDATA[<p>新年あけましておめでとうございます、五十川です。</p>
<p>PHPデベロッパー向けのAmazon Web Services（AWS）のリソースは<a href="http://aws.amazon.com/php/">http://aws.amazon.com/php/</a>にまとめられていますが、その<a href="http://developer.amazonwebservices.com/connect/kbcategory.jspa?categoryID=137">Articles &amp; Tutorials</a>カテゴリーにある、<a href="http://developer.amazonwebservices.com/connect/entry.jspa?externalID=2433">Introduction to AWS for PHP Developers</a>という記事は、AWSの主要サービスの概要と、PHPによるその操作を学ぶチュートリアルで、ここで取り上げられているサービスに初めて取り組むPHPデベロッパーには格好の入門となっており、ここではこのチュートリアルを紹介したいと思います。</p>
<p>また、このチュートリアルはAmazon純正のライブラリを利用していますが、AWS用のライブラリには様々なものがあり、この記事の最後ではそのひとつ、<a href="http://getcloudfusion.com/">CloudFusion</a>を紹介しようと思います。</p>
<p>なお、以下のチュートリアルのスクリプトの実行には、もちろん<a href="http://www.amazon.com/gp/aws/registration/registration-form.html">AWSアカウント</a>が必要で、スクリプトの実行に応じてAWSの利用料が課金されます。チュートリアルには、例えば起動したEC2インスタンスを停止（Terminate）するなど、余計な課金がされないようにする手順は説明されていませんので、<a href="http://console.aws.amazon.com/ec2/">AWS Console</a>や<a href="http://developer.amazonwebservices.com/connect/kbcategory.jspa?categoryID=250">各種デベロッパーツール</a>を利用して（あるいはチュートリアルの復習も兼ねて、そうしたプログラムを自作するなどして）、適宜対処してください。</p>

<h3>チュートリアルのシナリオ</h3>
<p>チュートリアルはビデオ共有サイトを題材にしており、AWSのうち、<a href="http://aws.amazon.com/ec2/">EC2</a>、<a href="http://aws.amazon.com/s3/">S3</a>、<a href="http://aws.amazon.com/sqs/">SQS</a>、<a href="http://aws.amazon.com/simpledb/">SimpleDB</a>を利用します。</p>
<ul>
    <li>ウェブサーバはEC2でホストされる</li>
    <li>ユーザは任意の形式のビデオをサイトのファイルアップロードフォームからアップロードできる</li>
    <li>アップロードされたビデオはS3に保存され、SQSで管理されるバッチプロセスでFLVに変換される</li>
    <li>変換されたビデオはS3に保存され配信される</li>
    <li>ビデオのメタデータはSimpleDBに記録される</li>
</ul>
<p>一般的なビデオ共有サイトでは、ユーザから投稿される様々な形式のビデオを、共通の形式（一般的にFLV）に変換して視聴に供します。ビデオの変換は相応のリソースと時間を消費するため、バッチプロセスで処理され、キューシステムで管理されますが、チュートリアルではここにSQSを採用しています。また、バッチプロセスをウェブサーバとは別のコンピュータ（EC2インスタンス）に分離し、さらにそれらが複数に分散されることを想定し、変換前後のビデオはS3に保存します。</p>

<h3>チュートリアルの著者について</h3>
<p>チュートリアルの著者は、Feedsterを経て現在はAPIのマネージメントサービスを提供する<a href="http://www.mashery.com/">Mashery</a>のチーフアーキテクトを務める<a href="http://claylo.com/">Clay Loveless</a>さんです。彼はオライリーのPHP Cookbook Second Editionの4つの章の著者であり、かつて存在していたpearified.comの運営者でもありました。また、このチュートリアルで使われるS3のストリームラッパー実装（Killersoft_Wrapper_S3）とSOAPクライアント（AWSSoapClient）は彼自身の手によるものです。</p>

<h3>チュートリアルファイルのダウンロード</h3>
<p><a href="http://s3.killersoft.com/AWSforPHP/awsfiles.zip">http://s3.killersoft.com/AWSforPHP/awsfiles.zip</a></p>
<p>チュートリアルのPHPスクリプトは、バージョン5.1.2以上のPHPでの実行を前提にしています。チュートリアルファイル中のcompatibility.phpで動作要件を確認できます。</p>
<p>チュートリアルはAmazon純正の以下のライブラリを利用します。</p>
<ul>
    <li><a href="http://developer.amazonwebservices.com/connect/entry.jspa?externalID=1669">PHP Library for Amazon EC2</a></li> 
    <li><a href="http://developer.amazonwebservices.com/connect/entry.jspa?externalID=1135">PHP Library for Amazon SDB</a></li> 
    <li><a href="http://developer.amazonwebservices.com/connect/entry.jspa?externalID=1287">PHP Library for Amazon SQS</a></li> 
</ul> 
<p>チュートリアルファイルにはこれらのライブラリが含まれていますが、それらはチュートリアルが執筆された時点のバージョンのものであり、最新のものではありません。当然、対象となるAPIバージョンもチュートリアルの執筆時点のものとなっている点に注意してください。</p>

<h3>設定ファイルの作成</h3>
<p>チュートリアルは/etc/aws.confファイルに保存された設定情報を利用します。</p>
<p>/etc/aws.confファイルに、<a href="http://aws-portal.amazon.com/gp/aws/developer/account/index.html?action=access-key">Security Credentials</a>で表示されるAccess Key IDとSecret Access Key、及びAccount Numberを、以下の書式で記述します。</p>

<pre class="code">; AWS Security Credentials
; Access Key ID
access_key = &quot;06224BHAZ75910F2&quot;
; Secret Access Key
secret_key = &quot;aIfbA2568+12TEqLDYpiqOyRULvi9&quot;
; Account Number
account_id = &quot;123412341234&quot;</pre>
<p>さらに/etc/aws.confファイルに、チュートリアルのPHPスクリプトが作成するファイルを保存するディレクトリのパスを、以下の書式で追記しておきます。</p>
<pre class="code">; Path to writable directory where we can save files
tutorial_file_path = &quot;/tmp&quot;</pre>

<h3>接続の確認</h3>
<p>チュートリアルの最初に登場するPHPスクリプトは、avail-zones.phpです。このスクリプトは、EC2のゾーンの利用可否を問い合せる<a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-DescribeAvailabilityZones.html">DescribeAvailabilityZones</a>リクエストを発行します。</p>
<pre class="code">$ php avail-zones.php
&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;DescribeAvailabilityZonesResponse xmlns=&quot;http://ec2.amazonaws.com/doc/2008-05-05/&quot;&gt;
...</pre>
<p>このスクリプトは最もプリミティブなRESTリクエストの作成例で、外部ライブラリに依存せずにURLをいちから組み立てています。そのため、スクリプトの実行で、/etc/aws.confファイルに記述したSecurity Credentialsの正当性が確認できるとともに、そのソースを読み解くことで、RESTリクエストのURLの構成、特にその署名（Signature）の作成方法が把握できるようになっています。</p>

<h3>SOAPリクエスト</h3>
<p>すべてのAWSはRESTとSOAPの両インタフェースで利用できます。チュートリアルは基本的にRESTを利用しますが、一部のスクリプトにはそのSOAP版も用意されています。</p>
<p>SOAPリクエストではX.509 Certificateが必要になります。<a href="http://aws-portal.amazon.com/gp/aws/developer/account/index.html?action=access-key">Security Credentials</a>でX.509 Certificateを設定後、/etc/aws.confファイルに、cert-....pemファイルとpk-....pemファイルのパスを以下の書式で追記します。SOAPを利用しない場合は、この手順は不要です。</p>
<pre class="code">; X.509 Certificate Path
cert_file = &quot;/path/to/my/cert-....pem&quot;
; RSA private key 
private_key_file = &quot;/path/to/my/pk-....pem&quot;</pre>
<p>avail-zones-soap.phpは、avail-zones.phpのSOAP版です。</p>
<pre class="code">$ php avail-zones-soap.php 
us-east-1a: available
...</pre>

<p>これ以降に登場するチュートリアルのPHPスクリプトはその冒頭でexample_setup.phpをインクルードしています。このexample_setup.phpは、/etc/aws.confファイルから設定情報を読み込み、あわせて各スクリプトが利用するクラスライブラリ用のオートロードを定義しています。</p>

<h3>EC2インスタンスの起動</h3>
<p>初めてチュートリアルに取り組む際は、実際にEC2インスタンスを起動する前に、まずec2-prelaunch.phpを実行して、キーペアの作成とセキュリティグループの設定を行います。</p>
<h4>ec2-prelaunch.php</h4>
<ol>
  <li><a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-DescribeKeyPairs.html">DescribeKeyPairs</a>リクエストで「awstutorial」キーペアの存在を確認</li>
  <li>キーペアが存在しない場合、<a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-CreateKeyPair.html">CreateKeyPair</a>リクエストでキーペアを作成し、プライベートキーを、/etc/aws.confファイルの「tutorial_file_path」で設定したディレクトリの「id_rsa-awstutorial」ファイルに保存</li>
  <li><a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-DescribeSecurityGroups.html">DescribeSecurityGroups</a>リクエストで「awstutorial」セキュリティグループの存在を確認</li>
  <li>グループが存在しない場合、<a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-CreateSecurityGroup.html">CreateSecurityGroup</a>リクエストでグループを作成</li>
  <li>グループの設定でポート80とポート22が開放されていない場合、<a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-AuthorizeSecurityGroupIngress.html">AuthorizeSecurityGroupIngress</a>リクエストでポートを開放</li>
</ol>
<pre class="code">$ php ec2-prelaunch.php 
Creating awstutorial keypair...
generated fingerprint
f3:e4:e6:c8:92:dd:f1:52:be:ea:a3:9d:75:57:ba:65:61:a7:a3:28
generated material
-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----
Creating awstutorial security group ...done.
Opening awstutorial port 80 ...done.
Opening awstutorial port 22 ...done.</pre>
<p>ec2-launch.phpを実行すると実際にEC2インスタンスが起動します。</p>
<h4>ec2-launch.php</h4>
<ol>
    <li><a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-RunInstances.html">RunInstances</a>リクエストで、ID「ami-2b5fba42」のAMI（Fedora Core 8）のインスタンスを起動し、そのインスタンスIDを、/etc/aws.confファイルの「tutorial_file_path」で設定したディレクトリの「awstutorial-instance.txt」ファイルに保存</li>
    <li>パブリックDNS名（ホスト名）が割り振られるまで、<a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-DescribeInstances.html">DescribeInstances</a>リクエストを定期的に実行し、パブリックDNS名が割り振られたらそれを、/etc/aws.confファイルの「tutorial_file_path」で設定したディレクトリの「awstutorial-hostname.txt」ファイルに保存</li>
</ol>
<pre class="code">$ php ec2-launch.php 
Launching awstutorial instance.
i-b98db8d1 is pending
Waiting for public hostname...........................
i-b98da8d1 is running at ec2-75-101-188-56.compute-1.amazonaws.com
Instance booted in 76.150985002518 seconds.</pre>

<h3>EC2インスタンスの設定</h3>
<p>/etc/aws.confファイルの「tutorial_file_path」で設定したディレクトリに移動し、ec2-prelaunch.phpスクリプトとec2-launch.phpスクリプトの実行によって保存されたファイルを使って、必要な環境変数を設定します。</p>
<pre class="code">$ cd /tmp
$ export AWSTUTORIAL_HOST=`cat \`pwd\`/awstutorial-hostname.txt`
$ export AWSTUTORIAL_KEY=`pwd`/id_rsa-awstutorial</pre>
<p>/etc/aws.confファイルをEC2インスタンスにアップロードし、インスタンス上でチュートリアルのスクリプトを実行する環境を整えます。</p>
<pre class="code">$ scp -i $AWSTUTORIAL_KEY /etc/aws.conf root@$AWSTUTORIAL_HOST:/etc/aws.conf
$ ssh -i $AWSTUTORIAL_KEY root@$AWSTUTORIAL_HOST \
    'curl -O http://s3.killersoft.com/AWSforPHP/awsfiles.zip; \
    unzip awsfiles.zip -d /var/www/'
$ scp -i $AWSTUTORIAL_KEY awstutorial-*.txt root@$AWSTUTORIAL_HOST:/tmp/</pre>
<p>インスタンスにSSHログインします。</p>
<pre class="code">$ ssh -2 -i $AWSTUTORIAL_KEY root@$AWSTUTORIAL_HOST</pre>
<p>インスタンス上で、PHPとApacheのインストールを行います。</p>
<pre class="code"># yum -y install php \
    php-mcrypt.i386 \
    php-soap.i386 \
    php-xml.i386 \
    php-cli.i386 \
    httpd.i386</pre>
<p>インスタンス上で、チュートリアルファイルのindex.phpをドキュメントルートにコピーし、アップロードされたビデオファイルを保存する/var/www/html/uploadsディレクトリを作成して、Apacheを起動します。</p>
<pre class="code"># cp /var/www/awsfiles/index.php /var/www/html/index.php
# mkdir /var/www/html/uploads
# chown apache:apache /var/www/html/uploads
# service httpd start</pre>
<p>インスタンスのApacheの起動後に、ローカルコンピュータのウェブブラウザで、インスタンスのパブリックDNS名にアクセスすると、ファイルアップロードフォームが表示されます。インスタンスのパブリックDNS名は、/etc/aws.confファイルの「tutorial_file_path」で設定したディレクトリの「awstutorial-hostname.txt」ファイルに保存されています（もちろん<a href="http://console.aws.amazon.com/ec2/">AWS Console</a>でも確認できます）。</p>
<p>ファイルアップロードフォームから適当なファイルをアップロードすると、インスタンスの/var/www/html/uploadsディレクトリにファイルが保存されます。現在のindex.phpが行うのはこの単純なファイルアップロード処理だけです。チュートリアルのシナリオでは、アップロードされたファイルはS3に保存され、そのパスがSQSに登録されて変換処理を待ち受けますが、現在のindex.phpは、まだそうした処理は行いません。</p>
<p>そこで次に、SQSにキューを作成し、index.phpを差し替えます。</p>

<h3>SQSキューの作成</h3>
<p>EC2インスタンス上で、sqs-makequeue.phpを実行して「awstutorial」という名前のキューを作成します。</p>
<h4>sqs-makequeue.php</h4>
<ol>
    <li><a href="http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/APIReference/Query_QueryListQueues.html">ListQueues</a>リクエストで、名前が「awstutorial」で始まるキューの存在を確認</li>
    <li>キューが存在しない場合、<a href="http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/APIReference/Query_QueryCreateQueue.html">CreateQueue</a>リクエストでキューを作成</li>
</ol>
<pre class="code"># php /var/www/awsfiles/sqs-makequeue.php 
Creating awstutorial...
Queue awstutorial created at https://queue.amazonaws.com/842929249205/awstutorial</pre>

<h3>アップロードファイルのS3への転送とSQSキューへのメッセージ送信</h3>
<p>EC2インスタンス上で、現在のindex.phpをチュートリアルファイルのindex2.phpと差し替えます。</p>
<pre class="code"># cp /var/www/awsfiles/index2.php /var/www/html/index.php</pre>
<p>新しいindex.phpはファイルアップロード処理の完了後にsqs-queue-conversion.phpをインクルードします。sqs-queue-conversion.phpは、アップロードされたファイルをS3に転送し、そのパスをメッセージとしてキューに送信します。</p>
<h4>sqs-queue-conversion.php</h4>
<ol>
    <li>アップロードされたファイルをS3に転送</li>
    <li><a href="http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/APIReference/Query_QuerySendMessage.html">SendMessage</a>リクエストで、S3に転送したファイルのパスをメッセージとして「awstutorial」キューに送信</li>
</ol>
<p>チュートリアルでは、S3の操作は、チュートリアルの著者であるClay Lovelessさん自身が開発したKillersoft_Wrapper_S3クラスを利用します。Killersoft_Wrapper_S3はS3に対するストリームラッパーの実装で、対応のファイルシステム関数などで、「s3://〜」というURLでS3のオブジェクトを操作できるようにするものです。</p>
<p>以下はsqs-queue-conversion.php中でKillersoft_Wrapper_S3を使用している箇所の抜粋で、Killersoft_Wrapper_S3::selfRegisterメソッドでラッパーを登録することで、is_dir、mkdir、file_put_contentsといったお馴染みの関数で、S3オブジェクトの操作が行われています。</p>
<pre class="code">Killersoft_Wrapper_S3::selfRegister();
...
$bucket = 's3://awstutorial-'
        . md5(
            $creds['access_key'] .
            $creds['secret_key'] .
            $host
        );

if (! is_dir($bucket)) {
    mkdir($bucket);
}
...
file_put_contents(
    "{$bucket}/{$upload_name}",
    file_get_contents($upload_file)
);</pre>
<p>なお、チュートリアルでは、アップロードされたファイルはそのオリジナルのファイル名のままで保存されます。当然、同じ名前のファイルがアップロードされると同名のファイルが上書きされてしまうため、実用に供する場合はユニークなファイル名を割り当てる処理を追加する必要がありますが、チュートリアルではそうした処理は端折られています。</p>

<h3>キューの確認</h3>
<p>キューの状態はjob-check.phpを実行することで確認できます。</p>
<h4>job-check.php</h4>
<ol>
    <li>S3に転送したファイルの存在確認</li>
    <li><a href="http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/APIReference/Query_QueryGetQueueAttributes.html">GetQueueAttributes</a>リクエストでキューにある可視メッセージの大凡の数（ApproximateNumberOfMessages）を取得して表示</li>
    <li><a href="http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/APIReference/Query_QueryReceiveMessage.html">ReceiveMessage</a>リクエストでキューにあるメッセージを受信してそのメッセージボディを表示（メッセージを確認するだけなので、他のプロセスの受信を妨げないようにVisibilityTimeoutは最小限に設定）</li>
</ol>
<pre class="code"># php /var/www/awsfiles/job-check.php 
s3://awstutorial-a136e5e1e1e3ce3c44ffb1affbe79f1d/sample.mov is on S3!
Queue awstutorial has ~1 messages.
Found a message with a body of:
s3://awstutorial-a136e5e1e1e3ce3c44ffb1affbe79f1d/sample.mov</pre>

<h3>キューからのメッセージの受信と削除</h3>
<p>チュートリアルでは、アップロードされたファイルはFLV形式に変換されます。変換処理を担当するプロセスはキューを監視し、新しいメッセージを受信すると変換処理を実施します。job-fetch.phpはこうしたプログラムの例です。</p>
<h4>job-fetch.php</h4>
<ol>
    <li><a href="http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/APIReference/Query_QueryReceiveMessage.html">ReceiveMessage</a>リクエストでキューにあるメッセージを受信（VisibilityTimeoutは20秒に設定）</li>
    <li>メッセージのパスがS3上に実在するか確認</li>
    <li>パスが実在しない場合、<a href="http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/APIReference/Query_QueryDeleteMessage.html">DeleteMessage</a>リクエストでメッセージを削除して終了</li>
    <li>パスが実在する場合、S3からファイルを転送して変換処理を実施</li>
    <li>変換処理が成功したら（変換後のファイルが存在していたら）<a href="http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/APIReference/Query_QueryDeleteMessage.html">DeleteMessage</a>リクエストでメッセージを削除</li>
    <li>変換後のファイルをS3に転送し、変換元のファイルを削除</li>
</ol>
<pre class="code"># php /var/www/awsfiles/job-fetch.php
Conversion complete!
Deleting completed job from queue.
Uploading converted file back to S3
Deleting original since we no longer need it</pre>
<p>メッセージの受信時にVisibilityTimeoutで設定した秒数を経過すると、（メッセージが削除されていない場合）そのメッセージは再び可視状態となり、他のクライアントが受信可能になります。そこで実際のVisibilityTimeoutの設定は、複数のクライアントが重複してメッセージを受信しないように調整する必要があります。</p>
<p>なお、job-fetch.phpはビデオの変換にFFmpegを利用します。従ってjob-fetch.phpを実行するコンピュータにはFFmpegが必要で、チュートリアルの「Step 3: Perform Conversion Job」にはEC2インスタンスへのFFmpegのインストール手順が紹介されています。しかし、FFmpegのインストールや実行はチュートリアルの本旨ではなく、実際のところFFmpegのインストールは結構な手間なので、インストールや変換がうまくいかない場合は、job-fetch.phpのFFmpegの実行コマンドを編成している箇所を、以下のように適当に改変して対処してしまってください。</p>
<pre class="code">// ffmpeg command for transformation
// $cmd = '/usr/bin/ffmpeg -i '
//      . escapeshellcmd($localin)
//      . ' -ar 22050 '
//      . '-acodec mp3 -ab 32k -r 25 -s 320x240 '
//      . '-vcodec flv -qscale 9.5 '
//      . escapeshellcmd($localout);
$cmd = sprintf('cp %s %s',
        escapeshellcmd($localin),
        escapeshellcmd($localout));</pre>

<h3>SimpleDBによるビデオデータベース</h3>
<p>チュートリアルでは、変換処理が完了した各ビデオは、そのデータが以下のような構造のSimpleDBデータベースに登録されます。</p>
<table>
    <thead>
        <th>Item Name</th>
        <th>userid</th>
        <th>category</th>
        <th>file</th>
        <th>description</th>
        <th>size</th>
        <th>tags</th>
    </thead>
    <tbody>
        <td>item1</td>
        <td>clay</td>
        <td>tutorials</td>
        <td>sample.mov</td>
        <td>Just a sample video. Watch!</td>
        <td>71k</td>
        <td>apple</td>
    </tbody>
</table>
<p>本来こうしたデータの登録は、ファイルのアップロードや変換処理の完了にあわせて行われるべきものですが、チュートリアルでは別途に手動で（！）行われます。さらにチュートリアルでは、リストを表示したりビデオを再生するウェブインタフェースは結局用意されません（つまりこのサイトのユーザは、アップロードしたビデオを見ることはできません）。もちろん、そのあたりはチュートリアルの本旨ではないのですが、まあとにかくバッサリ端折られてますんで、あらかじめご了解ください。</p>

<h3>ドメインの作成</h3>
<p>SimpleDBでは、RDBMSのテーブルに相当する概念を「ドメイン」と呼びます。sdb-create-domain.phpを実行すると、「awstutorial」という名前のドメインが作成されます。</p>
<h4>sdb-create-domain.php</h4>
<ol>
    <li><a href="http://docs.amazonwebservices.com/AmazonSimpleDB/latest/DeveloperGuide/SDB_API_CreateDomain.html">CreateDomain</a>リクエストで「awstutorial」という名前のドメインを作成</li>
</ol>
<pre class="code"># php sdb-create-domain.php 
RequestId: 897b7cba-e9c0-1f11-9531-275dcf846e9b
BoxUsage: 0.0055590278</pre>
<p>SimpleDBへのリクエストのレスポンスには、その利用料金の指標となる「Box Usage」の値が含まれます。</p>
<p>EC2では同時に起動可能なインスタンス数はデフォルトで20ヶに制限されていますが、SimpleDBにも同様の制限があり、デフォルトではドメイン数は100ヶまで、1ドメインあたりのデータ量は10GBまでに制限されています。そして、EC2と同様にリクエストベースでこの制限を緩和することが可能です。</p>

<h3>ドメインの一覧</h3>
<p>sdb-list-domains.phpを実行すると、作成したドメインの一覧を確認できます。</p>
<h4>sdb-list-domains.php</h4>
<ol>
    <li><a href="http://docs.amazonwebservices.com/AmazonSimpleDB/latest/DeveloperGuide/SDB_API_ListDomains.html">ListDomains</a>リクエストでドメインの一覧を取得</li>
</ol>
<pre class="code"># php sdb-list-domains.php 
DomainName awstutorial</pre>

<h3>アイテムの追加</h3>
<p>sdb-create-records.phpを実行してアイテム（レコード）を追加します。追加されるアイテムは、上表の「item1」のものです。</p>
<h4>sdb-create-records.php</h4>
<ol>
    <li><a href="http://docs.amazonwebservices.com/AmazonSimpleDB/latest/DeveloperGuide/SDB_API_PutAttributes.html">PutAttributes</a>リクエストで「awstutorial」ドメインに「item1」という名前のアイテム、及びその属性（各カラム値）を保存</li>
</ol>
<pre class="code"># php sdb-create-records.php 
RequestId: ee265eb4-0924-684a-b261-7cec5030ff23
BoxUsage: 0.0000220339</pre>
<p>1アイテムあたりの属性数は256ヶ以下、1ドメインあたりの属性数は10億ヶ以下に制限されています。</p>

<h3>SELECTクエリーの実行</h3>
<p>SimpleDBでは、限定的なSELECT文を用いてアイテムを検索することができます。sdb-sqlselect.phpは、tags属性値が「app」で始まるアイテムを検索する「SELECT * FROM awstutorial WHERE tags LIKE 'app%'」を実行します。</p>
<h4>sdb-sqlselect.php</h4>
<ol>
    <li><a href="http://docs.amazonwebservices.com/AmazonSimpleDB/latest/DeveloperGuide/SDB_API_Select.html">Select</a>リクエストで「SELECT * FROM awstutorial WHERE tags LIKE 'app%'」を実行</li>
</ol>
<pre class="code"># php sdb-sqlselect.php 
Item Name: item1
file: sample.mov
userid: clay
size: 71k
tags: apple
category: tutorials
description: Just a sample video. Watch!</pre>
<p>利用可能なSELECT文の詳細は、<a href="http://docs.amazonwebservices.com/AmazonSimpleDB/latest/DeveloperGuide/UsingSelect.html">Using Select to Create Amazon SimpleDB Queries</a>に記載されています。</p>
<p>1度のリクエストで取得可能なアイテムは2,500件以下、または合計データ量が1MB以下に制限されています。リクエストがこの制限を超えるアイテムにマッチした場合（及びクエリーの実行が5秒以上経過した場合）はレスポンスにNextToken要素が含まれ、その値を用いることで「次ページ」のリクエストが行えます。</p>
<p>チュートリアルのsdb-list-items.phpでは、Selectリクエストではなく、Queryリクエスト、及びQueryWithAttributesリクエストが行われていますが、これらはいずれも最新のAPIバージョン2009-04-15ではDeprecatedとなっています。</p>

<p>チュートリアルの紹介は以上です。チュートリアルではAmazon純正のライブラリを利用していましたが、AWSのライブラリには他にも様々なものがあり、以下ではそのひとつ、<a href="http://getcloudfusion.com/">CloudFusion</a>を紹介します。</p>

<hr />

<h3>CloudFusion（旧称Tarzan AWS）</h3>

<p>CloudFusionはAWS等のクラウドサービス用のPHPライブラリです。CloudFusionは、AWSについては単一のパッケージで複数のサービスをサポートしており、現時点のバージョン2.5では、EC2、S3、SQS、SimpleDB、CloudFront、及びProduct Advertising APIをサポートしています。またAWS以外にも、クラウドサービスの基盤を提供するオープンソースソフトウェアである<a href="http://open.eucalyptus.com/">Eucalyptus</a>をサポートしています。</p>

<div style="padding:.5em;border:1px solid #999;">CloudFusionは以前は「Tarzan AWS」という名称でしたが、2010年1月にリリースされた、Eucalyptusのサポートが追加されたバージョン2.5から、現在の名称に変更されました。このセクションは当初Tarzan AWSについてのものでしたが、CloudFusion 2.5のリリースに伴ない全面的に改訂しました。</div> 

<p>以下はチュートリアルの「sdb-create-records.php」にある、SimpleDBのドメイン「awstutorial」にアイテム「item1」を追加するコードをCloudFusionのもので書き換えた例です。</p>
<pre class="code">require_once 'cloudfusion.class.php';

$sdb = new AmazonSDB(
        'Your AWS Access Key ID',
        'Your AWS Secret Access Key');

$response = $sdb-&gt;put_attributes('awstutorial',
        'item1',
        array(
            'userid'      =&gt;  'clay',
            'category'    =&gt; 'tutorials',
            'file'        =&gt; 'sample.mov',
            'description' =&gt; 'Just a sample video. Watch!',
            'size'        =&gt; '71k',
            'tags'        =&gt; array('apple')),
        true);
print_r($response);</pre>
<p>なお、上の例ではAccess Key IDとSecret Access Keyをコンストラクタのパラメータに指定していますが、これらはCloudFusionでは通常config.inc.phpに記述しておきます。これ以降に登場する例はいずれも、これらがconfig.inc.phpに記述されていることを前提に、コンストラクタのパラメータは省略しています。</p>

<p>CloudFusionには以下のような特徴があります。</p>

<h3>リクエストの並列実行</h3>
<p>CloudFusionではcurl_multi_*によるリクエストの並列実行が可能です。</p>
<p>以下は通常の、逐次リクエストを実行する例です。ここではSQSキューに10ヶのメッセージを送信しています。AmazonSQS-&gt;send_messageメソッドは直ちにリクエストを実行し、レスポンスオブジェクトを返します。</p>
<pre class="code">require_once 'cloudfusion.class.php';

$sqs = new AmazonSQS;
$responses = array();
for ($i = 0; $i &lt; 10; $i++) {
    $responses[] = $sqs-&gt;send_message(
            'https://queue.amazonaws.com/awstutorial',
            &quot;This is message #$i&quot;);
}
print_r($responses);</pre>
<p>以下は上の例を、リクエストを並列実行するように書き換えたものです。CloudFusionのAmazon*クラスの多くのメソッドは、パラメータの最後にTRUEを指定すると、リクエストを実行してレスポンスオブジェクトを返す代わりに、リクエストのcURLハンドルを返します。ハンドルの配列をRequestCore-&gt;send_multi_requestのパラメータに指定するとリクエストが並列実行され、その各レスポンスオブジェクトの配列が返されます。</p>
<pre class="code">require_once 'cloudfusion.class.php';

$sqs = new AmazonSQS;
$handles = array();
for ($i = 0; $i &lt; 10; $i++) {
    $handles[] = $sqs-&gt;send_message(
            'https://queue.amazonaws.com/awstutorial',
            &quot;This is message #$i&quot;,
            true);
}
$request = new RequestCore;
$responses = $request-&gt;send_multi_request($handles);
print_r($responses);</pre>

<h3>組み込みのキャッシュ機構</h3>
<p>CloudFusionにはレスポンスのキャッシュ機構が用意されており、必要に応じて利用することができます。現在対応しているキャッシュストレージは、ファイル、SQLite、MySQL、PostgreSQL、APC、及びMemcacheとなっています。</p>

<h3>容易なクラスのカスタマイズ</h3>
<p>CloudFusionでは、通常内部的に使われるクラスについても容易にそのカスタムクラスが利用出来るようになっています。以下は例として、リクエストURLを返すgetRequestUrlメソッドを実装したResponseCoreの継承クラスを作成しています。カスタムクラスを利用するには、Amazon*クラスのset_*_classメソッドのパラメータにカスタムクラスの名前を指定します。</p>
<pre class="code">require_once 'cloudfusion.class.php';

class CFCustomResponse extends ResponseCore {
    public function getRequestUrl() {
        if (isset($this-&gt;header['x-cloudfusion-requesturl'])) {
            return $this-&gt;header['x-cloudfusion-requesturl'];
        }   
        return null;
    }   
}

$sqs = new AmazonSQS;
$sqs->set_response_class('CFCustomResponse');
$response = $sqs-&gt;send_message(
        'https://queue.amazonaws.com/awstutorial',
        "This is another test message.");
echo $response-&gt;getRequestUrl() . &quot;\n&quot;;</pre>
<p>カスタムクラスはCloudFusionの命名規則に従ったファイル名を与えることで、CloudFusionのオートロードの対象になります。現在のCloudFusionのクラスファイルの命名規則は、クラス名が「Amazon」で始まる場合はそれを除去し、「CF」で始まる場合はそれをアンダースコアに置換し、クラス名をすべて小文字にして「.class.php」を続けるというものです。例えば上の例の「CFCustomResponse」クラスの場合、そのファイル名は「_customresponse.class.php」となります。</p>

<h3>ドキュメント</h3>
<p>CloudFusionの<a href="http://getcloudfusion.com/docs">ドキュメント</a>は比較的よく整備されており、<a href="http://getcloudfusion.com/docs/latest/">APIリファレンス</a>には、多くのメソッドにサンプルコードが用意されています。</p>

<p>以上、AWS用のライブラリの例としてCloudFusionを紹介しました。AWS用のライブラリには、このCloudFusionや、チュートリアルで登場したKillersoft_Wrapper_S3のように、Amazon純正のもの以外にも様々なものがあり、プロジェクトのニーズ次第では検討の余地があるのかもしれません。</p>

<div style="margin:1em 0;padding:.5em;border:2px solid#ccc">ウノウでは特に最近、積極的にエンジニアを採用しています。<br /><a href="http://www.unoh.net/recruit.html" target="_blank">採用ページ</a>をご覧になり興味のある方、ぜひご応募ください！！<br /><a href="http://www.find-job.net/fj/showjob.cgi?id=50212" target="_blank">Find Job!</a>でも募集開始してます！</div>]]></description>
         <link>http://labs.unoh.net/2010/01/amazon_web_services_phpec2s3sq.html</link>
         <guid>http://labs.unoh.net/2010/01/amazon_web_services_phpec2s3sq.html</guid>
         <category>Tips</category>
         <pubDate>Sun, 03 Jan 2010 17:36:48 +0900</pubDate>
      </item>
      
      <item>
         <title>ありえるえりあ勉強会@五反田～テスト編～のご案内</title>
         <description><![CDATA[<p>こんにちは。中村です。</p>
<p><a href="http://www.ariel-networks.com/">アリエル・ネットワーク</a>に友人がいるきっかけで、ありえるえりあ勉強会にウノウが参加することになりました。個人的にですが、アリエルさんといえばFirefoxの拡張を作成しているときに<a href="http://dev.ariel-networks.com/articles/workshop/firefox-extension-development/">Firefox拡張機能(extension)の作り方</a>という記事でとてもお世話になりました。</p>
<p>今回のテーマはテストということで、ウノウからは<a href="http://labs.unoh.net/cgi-bin/mt-search.cgi?tag=yamamoto&blog_id=2">テスト番長山本</a>がスピーカーとして参加します。</p>
<p>発表予定内容は次のようになっています（告知文より抜粋のため敬称略）。</p>
<ul>
  <li>山本番長【絶版プレミア本に学ぶウェブアプリのテスト方法】
    <ul>
      <li>テストの書籍や資料を探すとウェブアプリを対象にしたものは少ないのが現状です。絶版のため高値になっている良書「インターネットアプリケーションのためのソフトウェアテスト」の内容を辿りながら、ウェブアプリのテスト法全般について日本の状況を交えながらお話したいと思います。 </li>
    </ul>
  </li>
  <li>佐藤【rhino on junit】
    <ul>
      <li>JavaによるJavaScript処理系であるMozilla Rhino上で、JUnitを用いてJavaScriptのユニットテストを行う手法や Javaのクラスを対象にしたテストケースをJavaScriptで記述する手法などを紹介します。</li>
    </ul>
  </li>
</ul>
<p>開催は来年になりますが、年始の忙しさから少し落ち着く時期ではないかと思いますので、ご興味のある方は下記ATNDから是非参加登録ください。</p>
<ul>
  <li>日時: 2010年1月29日（金） 19:00～21:30</li>
  <li>定員: 30人</li>
  <li>会場: ウィン五反田ビル6F (株)ワークスソリューションズ （東京都品川区西五反田1-30-3）</li>
  <li>備考: 勉強会のあと、ピザパーティー(無料)があります。</li>
  <li>参加登録: <a href="http://atnd.org/events/2658">ありえるえりあ勉強会@五反田～テスト編～ : ATND</a></li>
</ul>]]></description>
         <link>http://labs.unoh.net/2009/12/post_137.html</link>
         <guid>http://labs.unoh.net/2009/12/post_137.html</guid>
         <category></category>
         <pubDate>Thu, 24 Dec 2009 19:12:30 +0900</pubDate>
      </item>
      
      <item>
         <title>Q4Mを触ってみる</title>
         <description><![CDATA[<p>yukiです。そろそろクリスマスですね。みんな浮かれていればいいと思います！最近急に目が悪くなって、ツリーの赤色電球と居酒屋の赤提灯の色が判別出来なくなってきました。嘘です。</p>

<p>今回は、みんな大好きメッセージキュー、Q4Mを触ってみた感想を今更ながらレポートします。</p>

<div style="margin:0;padding:.5em;border:2px
solid#ccc">ウノウでは特に最近、積極的にエンジニアを採用しています。<br /><a
href="http://www.unoh.net/recruit.html">採用ページ</a>をご覧になり興味のある方、ぜひご応募ください！！<br
/><a href="http://www.find-job.net/fj/showjob.cgi?id=50212">Find
Job!</a>でも募集開始してます！</div>

<h3>Q4M</h3>
<p>公式ページはこちら<a href="http://q4m.31tools.com/">http://q4m.31tools.com/</a></p>
<p><a href="http://q4m.31tools.com/">Q4M</a>はサイボウズラボの<a href="http://developer.cybozu.co.jp/kazuho/">奥 一穂氏</a>が開発されており、MySQLの5.1以上でストレージエンジンとして利用できるメッセージキューで、MySQLプラグインとしてGPLライセンスで配布されております。</p>

<h4>特長</h4>
<p>MySQLのストレージエンジンとして利用できるので、テーブル作成時にストレージエンジンを指定するだけで利用できます。</p>
<pre class="code"><code>CREATE TABLE hoge (
     ...
 ) ENGINE = QUEUE</code></pre>
<p>キューの作成(enqueue)は通常のレコード操作と同様にINSERTで行い、キューの取り出し(dequeue)も同様にSELECTで行えるので、シンプルに扱う事が出来ます。</p>

<h4>導入事例</h4>
<p>公式ページには導入事例として以下の2つが載っています。</p>
<ul>
<li><a href="http://pathtraq.com/">pathtraq</a></li>
<li><a href="http://mixi.jp/recent_echo.pl">mixiボイス</a></li>
</ul>

<h3>インストール</h3>
<p>最新版は0.8.9となっています。<a href="http://q4m.31tools.com/install.php">こちら</a>からバイナリ・ソース版と用意されているので、適切なものを選んでインストールします。</p>
<p>GCCのバージョンによってはコンパイルに失敗するエラーがありましたが、現バージョンでは解消されて手軽にインストールできるようになりました。</p>
<p>インストールが終わると、MySQLにプラグインとして認識されているのがわかります。</p>
<pre class="code"><code>mysql> show plugins;
+------------+----------+----------------+--------------------+---------+
| Name       | Status   | Type           | Library            | License |
+------------+----------+----------------+--------------------+---------+
| binlog     | ACTIVE   | STORAGE ENGINE | NULL               | GPL     |
| partition  | ACTIVE   | STORAGE ENGINE | NULL               | GPL     |
| ARCHIVE    | ACTIVE   | STORAGE ENGINE | NULL               | GPL     |
| BLACKHOLE  | ACTIVE   | STORAGE ENGINE | NULL               | GPL     |
| CSV        | ACTIVE   | STORAGE ENGINE | NULL               | GPL     |
| FEDERATED  | DISABLED | STORAGE ENGINE | NULL               | GPL     |
| MEMORY     | ACTIVE   | STORAGE ENGINE | NULL               | GPL     |
| InnoDB     | ACTIVE   | STORAGE ENGINE | NULL               | GPL     |
| MyISAM     | ACTIVE   | STORAGE ENGINE | NULL               | GPL     |
| MRG_MYISAM | ACTIVE   | STORAGE ENGINE | NULL               | GPL     |
| QUEUE      | ACTIVE   | STORAGE ENGINE | libqueue_engine.so | GPL     |
+------------+----------+----------------+--------------------+---------+</code></pre>

<h3>実際に動かしてみる</h3>
<p>まずはテーブルを作成します。</p>
<pre class="code"><code>mysql> CREATE TABLE queue_table (
  message TEXT NOT NULL,
  priority TINYINT UNSIGNED NOT NULL DEFAULT 10
)
ENGINE = QUEUE</code></pre>
<p>次に、実際に処理するキューを作るため、キューをINSERTします。</p>
<pre class="code"><code>mysql> INSERT INTO queue_table (message) VALUES ('ms1'), ('ms2') ,('ms3');</code></pre>
<p>dequeueしてみます。dequeueにはqueue_waitというfunctionを利用します。</p>
<pre class="code"><code>mysql> SELECT queue_wait('queue_table');
+---------------------------+
| queue_wait('queue_table') |
+---------------------------+
|                         1 |
+---------------------------+
1 row in set (0.00 sec)</code></pre>
<p>成功すると、結果として1が返って来ます。<br />
キューを取り出しているこの状態をオーナーモードと呼び、この状態だと、該当のテーブルからは1レコードだけ引けるようになります。</p>
<pre class="code"><code>mysql> SELECT * FROM queue_table;
+---------+----------+
| message | priority |
+---------+----------+
| ms1     |       10 |
+---------+----------+
1 row in set (0.00 sec)</code></pre>
<p>取り出して処理が完了した場合、queue_endを呼ぶと、取り出したキューが削除されます。同時にオーナーモードが解除され、非オーナーモードに戻ります。</p>
<pre class="code"><code>mysql> SELECT queue_end();
+-------------+
| queue_end() |
+-------------+
|           1 |
+-------------+
1 row in set (0.00 sec)</code></pre>

<p>非オーナーモードに戻ったので、通常のSELECTを行うと、残りの全キューを引くことができます。<br />ただし、別のコネクションでオーナーモードになっている場合、そのコネクションで得たキューは表示されません。(後述。)</p>
<pre class="code"><code>mysql> SELECT * FROM queue_table;
 +---------+----------+
 | message | priority |
 +---------+----------+
 | ms2     |       10 |
 | ms3     |       10 |
 +---------+----------+
 2 rows in set (0.00 sec)</code></pre>

<p>またこのとき、処理中に例外エラーなどでキューを戻したい場合は、queue_abort()を利用すると直前に取り出したキューを戻します。queue_wait()→queue_abort()した際の流れです。</p>
<pre class="code"><code>mysql> SELECT queue_wait('queue_table');
+---------------------------+
| queue_wait('queue_table') |
+---------------------------+
|                         1 |
+---------------------------+
1 row in set (0.00 sec)

mysql> SELECT * FROM queue_table;
+---------+----------+
| message | priority |
+---------+----------+
| ms2     |       10 |
+---------+----------+
1 row in set (0.00 sec)

mysql> SELECT queue_abort();
+---------------+
| queue_abort() |
+---------------+
|             1 |
+---------------+
1 row in set (0.00 sec)

mysql> SELECT * FROM queue_table;
+---------+----------+
| message | priority |
+---------+----------+
| ms2     |       10 |
| ms3     |       10 |
+---------+----------+
2 rows in set (0.00 sec)</code></pre>

<h3>オーナーモードと非オーナーモード</h3>
<p>queue_wait()を呼ぶとオーナーモードに入り、先述したように、そのコネクション内では1行のみ取得できるようになります。<br />また、別のコネクションでは、他コネクションでオーナーモードで取得した行以外を取得できるようになります。</code></pre>
<p>コネクション1</p>
<pre class="code"><code>% mysql -u test test
mysql> SELECT * FROM queue_table;
+---------+----------+
| message | priority |
+---------+----------+
| ms2     |       10 |
| ms3     |       10 |
+---------+----------+
2 rows in set (0.01 sec)</code></pre>

<p>コネクション2</p>
<pre class="code"><code>% mysql -u test test
mysql> SELECT * FROM queue_table;
+---------+----------+
| message | priority |
+---------+----------+
| ms2     |       10 |
| ms3     |       10 |
+---------+----------+
2 rows in set (0.01 sec)</code></pre>

<p>コネクション1でオーナーモードに入る</p>
<pre class="code"><code>mysql> SELECT queue_wait('queue_table');
+---------------------------+
| queue_wait('queue_table') |
+---------------------------+
|                         1 |
+---------------------------+
1 row in set (0.00 sec)

mysql> SELECT * FROM queue_table;
+---------+----------+
| message | priority |
+---------+----------+
| ms2     |       10 |
+---------+----------+
1 row in set (0.00 sec)</code></pre>

コネクション2でキューを全件表示すると、コネクション1で引いたキューは表示されない。
<pre class="code"><code>mysql> SELECT * FROM queue_table;
+---------+----------+
| message | priority |
+---------+----------+
| ms3     |       10 |
+---------+----------+
1 row in set (0.00 sec)</code></pre>

<h3>優先度別キュー取出</h3>
<p>優先度低めのキューテーブルを作り、優先して取得したい順にqueue_waitの引数に加えます。</p>
<pre class="code"><code>mysql> CREATE TABLE low_priority_queue (
   message TEXT NOT NULL,
   priority TINYINT UNSIGNED NOT NULL DEFAULT 10
 )
 ENGINE = QUEUE;

mysql> INSERT INTO low_priority_queue (message) VALUES ('lm1'), ('lm2'), ('lm3');

mysql> SELECT queue_wait('queue_table', 'low_priority_queue');
+-------------------------------------------------+
| queue_wait('queue_table', 'low_priority_queue') |
+-------------------------------------------------+
|                                               1 |
+-------------------------------------------------+
1 row in set, 1 warning (0.00 sec)</code></pre>
<p>成功すると、取得できるテーブルの順の番号が返って来ます。(上記は1なのでqueue_table、2であればlow_priority_queueになります)あとは通常通り取得します。</p>
<pre class="code"><code>mysql> SELECT * FROM queue_table;
+---------+----------+
| message | priority |
+---------+----------+
| ms2     |       10 |
+---------+----------+
1 row in set (0.00 sec)</code></pre>

<p><strike>ここの挙動がよくわかりにくく、どなたか分かる方がいたら教えて頂ければ大変嬉しいのですが、優先度が高いテーブル(queue_table)の中身が空の時、タイムアウトを指定しないでqueue_waitすると「ゼロ」(データ無し)と返って来ます。</strike></p>
<p>2009/12/21追記: 複数指定する場合は、必ずタイムアウト引数を付けなくてはいけないので、この用法は間違いでした。お詫びいたします。</p>
<pre class="code"><code>mysql> TRUNCATE queue_table;
Query OK, 0 rows affected (0.01 sec)

mysql> SELECT queue_wait('queue_table', 'low_priority_queue');
+-------------------------------------------------+
| queue_wait('queue_table', 'low_priority_queue') |
+-------------------------------------------------+
|                                               0 |
+-------------------------------------------------+
1 row in set, 1 warning (0.00 sec)</code></pre>

<p>タイムアウトを与えてやると、正しく取得できます。下記の場合はqueue_tableにレコードがないので、low_priority_queueから取得するため2番が返り、期待通りの動作となります。</p>
<pre class="code"><code>mysql> SELECT queue_wait('queue_table', 'low_priority_queue', 10);
+-----------------------------------------------------+
| queue_wait('queue_table', 'low_priority_queue', 10) |
+-----------------------------------------------------+
|                                                   2 |
+-----------------------------------------------------+
1 row in set (0.00 sec)

mysql> SELECT * FROM low_priority_queue;
+---------+----------+
| message | priority |
+---------+----------+
| lm1     |       10 |
+---------+----------+
1 row in set (0.00 sec)</code></pre>

<h3>条件付き取り出し</h3>
<p>簡易なWHERE句のようにして取得することが可能です。queue_waitのテーブルを指定する引数に、条件を付加して取得します。<br />下記の例は優先度2で新たなキューを発行し、優先度3以下で取得するようにしてみます。</p>
<pre class="code"><code>mysql> INSERT INTO queue_table(message, priority) values ('blocker', 2);
Query OK, 1 row affected (0.00 sec)
mysql> SELECT * FROM queue_table;
+---------+----------+
| message | priority |
+---------+----------+
| ms1     |       10 |
| ms2     |       10 |
| ms3     |       10 |
| blocker |        2 |
+---------+----------+
4 rows in set (0.00 sec)

mysql> SELECT queue_wait('queue_table:priority<3');

mysql> SELECT * FROM queue_table;
+---------+----------+
| message | priority |
+---------+----------+
| blocker |        2 |
+---------+----------+
1 row in set (0.00 sec)</code></pre>

<h3>リレー</h3>
<p>別のサーバにキューをリレーする事が出来ます。同梱されているq4m-forwardというperlスクリプトを起動すると、無限ループでキューを待ち、別のサーバへ転送するような処理になっています。<br />同様の処理であれば、自作のスクリプトで同様の処理が可能です。<br /><a href="2008/07/daemontools.html">daemontools</a>などを使えば、割とお手軽に転送させることが出来るかと思います。</p>

<h3>まとめ</h3>
<p>いかがでしたでしょうか。メッセージキューイングというと<a href="http://activemq.apache.org/">ActiveMQ</a>やTheSchwartzなど、いろいろなソリューションがあると思いますが、キューイング方法などかなり手軽に扱えるので、1度試してみてはいかがでしょうか。</p>
<p>試している最中、queue_wait()してオーナーモード中にtruncateしてしまい、drop databaseすら効かなくなってrm -r /var/lib/mysql/testしたりしましたが、ご愛敬ということで。</p>]]></description>
         <link>http://labs.unoh.net/2009/12/q4m.html</link>
         <guid>http://labs.unoh.net/2009/12/q4m.html</guid>
         <category></category>
         <pubDate>Thu, 17 Dec 2009 19:19:35 +0900</pubDate>
      </item>
      
      <item>
         <title>PHPテンプレートエンジンTwigをいじってみました</title>
         <description><![CDATA[<p>今年のX'masは一人で高いシャンパンを買って飲もうとおもってるKeitaです。</p>

<p>しばらく、情報収集をさぼっている間に、symfonyの開発元であるSensio Labsから、PHPのテンプレートエンジンTwigが出ていたので、1時間ほど試してみました。</p>
<p>つかってみたよーとか、ここきついとかありましたら、コメントなどで教えていただけるとうれしいです。</p>

<h2>インストール</h2>
<p><a href="http://www.twig-project.org/installation">本家サイトのINSTALLATION</a>を参考に僕はtar.gzのファイルを手動どインストールして試してみました。</p>

<p>インストールはpearコマンドなどでもできるようです。</p>
というか、www.twig-project.orgのフッタを見てみるとPEAR Serverも自作してること発見してびっくりました。</p>


<h2> テンプレート側</h2>
<p>テンプレート側のコードは下記のように記述します。</p>

<pre class="code">
&lt;html&gt;
&lt;title&gt;title&lt;/title&gt;
&lt;/html&gt;
&lt;body&gt;
メリー {{ congratulation }}!!
メリー {{ congratulation|safe }}!!
&lt;/body&gt;
</pre>

<h2> 実際のコード</h2>
<p>テンプレートを呼び出す側のコードは<a href="http://www.twig-project.org/book/03-Twig-for-Developers">Twig for Developers</a>にあります。</p>
<p>これをほぼ丸写しして下記のようなコードを書いてみました。</p>

<pre class="code">
&lt?php
require_once '/path/to/twig/lib/Twig/Autoloader.php';
Twig_Autoloader::register();

$loader = new Twig_Loader_Filesystem('/path/to/template/'); //(1)ファイルのほかに文字列直接とか配列を指定できる。
$twig = new Twig_Environment($loader,
array(
  'cache' => '/path/to/var/tmp/cache',
  'auto_reload' => true, //デフォルトがfalseなわきゃないと思うだけど
)
);
$escaper = new Twig_Extension_Escaper(true); //(2) デフォルトHTMLエスケープしてパラメータをつけるとエスケープしないようなコードがかける
$twig->addExtension($escaper);

$template = $twig->loadTemplate('nomal.html');
echo $template->render(array('congratulation' => 'X\'ss'));
</pre>


<p>実行してみると下記のようなHTMLが出力されます。</p>

<pre class="code">
&lt;html&gt;
&lt;title&gt;title&lt;/title&gt;
&lt;/html&gt;
&lt;body&gt;
メリー X&amp;#039;ss!!
メリー X'ss!!
&lt/body&gt;
</pre>


<p>(1) の部分でファイルからの読み込みが指定されてますが配列や文字列そのももの指定できるようような指定ができます。また、Loader自体の拡張も、たとえばMySQLやKVS的なものからデータを読み込むような指定もできます。</p>

<p>(2)の部分は、変数の出力時に何も指定しなければエスケープ処理を行うようにしてあります。
エスケープしない場合は{{hoge|safe}}のような記述します。
また上記設定しない場合は{{hoge|e}}とった感じの書き方でエスケープされます。</p>

<h2>テンプレート継承</h2>
テンプレートを下記のように記述します。<br />
base.html
<pre class="code">
&lt;html&gt;
&lt;title&gt;{% block title %}テスト{% endblock %}&lt;/title&gt;
&lt;/html&gt;
&lt;body&gt;
{% block body %}
本文だよ
{% endblock %}
&lt;/body&gt;
</pre>

title.html
<pre class="code">
{% extends "base.html" %}
{% block title%}継承テスト{% endblock %}
</pre>

<p>title.htmlを実行すると下記のような出力が行われます。</p>
<pre class="code">
&lt;html&gt;
&lt;title&gt;継承テスト&lt;/title&gt;
&lt;/html&gt;
&lt;body&gt;

本文だよ

&lt;/body&gt;
</pre>

<h2>キャッシュされるテンプレート</h2>
<p>どうやって継承とかしているのなーと思いキャッシュされたテンプレートを覗いてみました。</p>
<pre class="code">
&lt;?php

/* base.html */
class __TwigTemplate_0071f6af5144b1d5aaf62ae6db08f444 extends Twig_Template
{
  public function display(array $context)
  {
    // line 1
    echo "&lt;html&gt;
&lt;title&gt;";
    // line 2
    $this-&gt;block_title($context);
    echo "&lt;/title&gt;
&lt;/html&gt;
&lt;body&gt;
";
    // line 5
    $this-&gt;block_body($context);
    // line 7
    echo "
&lt;/body&gt;
";
  }

  // line 2
  public function block_title($context)
  {
    echo "テスト";
  }

  // line 5
  public function block_body($context)
  {
    echo "
本文だよ
";
  }

}
</pre>

title.html
<pre class="code">
&lt;?php

$this->loadTemplate("base.html");

/* title.html */
class __TwigTemplate_f7f5efb7dcc094ca38d2c84bd671d4bc extends __TwigTemplate_0071f6af5144b1d5aaf62ae6db08f444
{
  public function display(array $context)
  {

    parent::display($context);
  }

  // line 2
  public function block_title($context)
  {
    echo "継承テスト";
  }

}
</pre>

なるほど、クラスを生成して普通の継承を行っているんですね。
よく考えれば当たり前な気がしますが正直、Smartyなどのテンプレートエンジンは素のPHPっぽいテンプレートを返すのでクラスを吐き出すというのが自分的にはとても新鮮でした。

<h2>感想</h2>
触ってみた時間は短いですが、「あぁ考えられているな」と感じました。
そのほかにもSandboxやデバッグなどの機能があるみたいですが試せてはいません。
また、マルチバイトがかなり意識されていて、Filterのソースコードを見ると、mb_stringがあった場合には、それを使って処理するようになっています。海外のアプリケーションでmb_stringを使っているものを久しぶりに見ました。

PHPのテンプレートエンジンといえば、PHPそのものはもちろん、Smartyが有名ですが、これはこれで、メジャーバージョン3のベータ版が出ていたりしてそれはそれで興味深いですので正式版がでたら使ってみたいと思います。

何かのご参考になれば幸いです。
]]></description>
         <link>http://labs.unoh.net/2009/12/phptwig.html</link>
         <guid>http://labs.unoh.net/2009/12/phptwig.html</guid>
         <category></category>
         <pubDate>Wed, 09 Dec 2009 15:50:33 +0900</pubDate>
      </item>
      
   </channel>
</rss>
