<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>ウノウラボ Unoh Labs</title>
    <link rel="alternate" type="text/html" href="http://labs.unoh.net/" />
    <link rel="self" type="application/atom+xml" href="http://labs.unoh.net/atom.xml" />
    <id>tag:labs.unoh.net,2006://2</id>
    <link rel="service.post" type="application/atom+xml" href="http://www.unoh.net/mt32/mt-atom.cgi/weblog/blog_id=2" title="ウノウラボ Unoh Labs" />
    <updated>2010-02-08T15:21:21Z</updated>
    <subtitle>ウノウ株式会社のデモ版サービスやTIPSなどの情報</subtitle>
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type  4.261</generator>
 

<entry>
    <title>cacti の設定をコマンドラインから行う方法</title>
    <link rel="alternate" type="text/html" href="http://labs.unoh.net/2010/02/cacti.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.unoh.net/mt32/mt-atom.cgi/weblog/blog_id=2/entry_id=1755" title="cacti の設定をコマンドラインから行う方法" />
    <id>tag:labs.unoh.net,2010://2.1755</id>
    
    <published>2010-02-08T02:00:32Z</published>
    <updated>2010-02-08T15:21:21Z</updated>
    
    <summary>こんにちは。kyagi です。今回は　cacti の設定をコマンドラインから行う方法をお知らせいたします。 cacti とはサーバの監視/グラフ化ツールです。CPU使用率やロードアベレージ、その他様々な情報をカラフルなグラフで見ることができます。 設定は主にブラウザ上から行うのですが1台のサーバの設定でもSNMPの各項目を選択したり、グラフのデータ元であるデータクエリを設定したりなかなかの作業量になります。設定内容は全て把握していても 1 台につき、マウスでクリックする回数が多いので数十台の追加となると時間もかかりますし、指もかなり疲れます(また、ヒューマンエラーも入り込む余地が生まれます)。 cacti にはこういった設定をコマンドラインから行える php スクリプトが用意されています。標準ではこれらのスクリプトは /var/lib/cacti/cli/ 配下にインストールされています。...</summary>
    <author>
        <name>unoh</name>
        
    </author>
    
    <content type="html" xml:lang="ja" xml:base="http://labs.unoh.net/">
        <![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>]]>
        
    </content>
</entry>

<entry>
    <title>位置情報を取得してみる</title>
    <link rel="alternate" type="text/html" href="http://labs.unoh.net/2010/02/post_139.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.unoh.net/mt32/mt-atom.cgi/weblog/blog_id=2/entry_id=1753" title="位置情報を取得してみる" />
    <id>tag:labs.unoh.net,2010://2.1753</id>
    
    <published>2010-02-03T03:12:55Z</published>
    <updated>2010-02-08T03:44:45Z</updated>
    
    <summary>ウノウでは特に最近、積極的にエンジニアを採用しています。採用ページをご覧になり興味のある方、ぜひご応募ください。Find Job!でも募集してます！ こんにちは。ryosuke です。 先週からモバゲータウン内において、弊社の携帯まち育成ブラウザゲーム「まちつく！モバゲー版」の提供を開始しています。よろしければ遊んでみてください。 まちつく！は、まち育成シミュレーションゲームですが、育成だけではなく携帯電話の位置情報を利用したおみやげやスタンプといった機能があります。最近は海外でもGPS機能を搭載したスマートフォンが普及してきたためか、世界的に位置情報を利用したサービスが活発化し始めているようです。 NHKのTV番組ブラタモリと連携しているiPhoneアプリの「ブラアプリ」や、位置情報でつながる街情報SNS「foursquare」 が話題になったりしていていますね。位置情報自体は今更感があ...</summary>
    <author>
        <name>unoh</name>
        
    </author>
    
    <content type="html" xml:lang="ja" xml:base="http://labs.unoh.net/">
        <![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>を公開しています)試してみてはいかがでしょうか。
]]>
        
    </content>
</entry>

<entry>
    <title>ありえるえりあ勉強会@五反田～テスト編～ 発表資料</title>
    <link rel="alternate" type="text/html" href="http://labs.unoh.net/2010/02/post_138.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.unoh.net/mt32/mt-atom.cgi/weblog/blog_id=2/entry_id=1750" title="ありえるえりあ勉強会@五反田～テスト編～ 発表資料" />
    <id>tag:labs.unoh.net,2010://2.1750</id>
    
    <published>2010-02-01T16:22:46Z</published>
    <updated>2010-02-02T08:49:38Z</updated>
    
    <summary>こんにちは！　山本＠テスト番長です。 1/29にアリエルさんとウノウが合同で実施したピザパーティ　勉強会でお話する機会を頂きました。お集まりいただきました皆様、どうもありがとうございました。 その時の資料を公開したいと思います。 絶版プレミア本に学ぶウェブアプリのテスト方法View more presentations from galtonkatsu. 発表中、最近はなるべくテストをしないように心掛けている、と言ったところ 後で数人の方からその点について質問されました。 また後日考えを纏めて、文章の形で皆さんにご説明してみたいと思っています。 アリエル佐藤寛之さんの発表資料はこちらです。 大変興味深い内容ですので、ぜひご覧ください。 ありえるえりあ勉強会@五反田～テスト編～ 資料 ...</summary>
    <author>
        <name>unoh</name>
        
    </author>
    
        <category term="勉強会" />
    
    <content type="html" xml:lang="ja" xml:base="http://labs.unoh.net/">
        <![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>
]]>
        
    </content>
</entry>

<entry>
    <title>Flash Lite初学者の為のまとめ</title>
    <link rel="alternate" type="text/html" href="http://labs.unoh.net/2010/01/flash_lite_1.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.unoh.net/mt32/mt-atom.cgi/weblog/blog_id=2/entry_id=1746" title="Flash Lite初学者の為のまとめ" />
    <id>tag:labs.unoh.net,2010://2.1746</id>
    
    <published>2010-01-20T04:01:00Z</published>
    <updated>2010-01-20T04:48:42Z</updated>
    
    <summary>おはようございます。内田です。 最近はmixiアプリモバイルやモバゲー上のゲームのようなソーシャルゲームが流行ってるようですね。 私もソーシャルゲーム＆Flash Lite案件を手がけることになったので、その時に参考にしたサイトを紹介します。 開発の前に覚えること 最初にFlash Liteの仕様とケータイ開発の障壁ともいえるキャリア間の差異を知る必要があります。 Flash Lite ことはじめ。 我らがryosuke氏のエントリー 仕様とキャリア毎の情報が分かりやすくまとまってます。 [Flash Lite 1.1]制作前に知っておきたいことをQ＆A形式でまとめてみた 上記エントリーと重複する部分も多いですが、Q＆Aの形で調べやすい。 「一般的なガイドラインが知りたい！」を厳守すれば3キャリアで動作するswfがつくれそうです。 コンテンツの作成 Flash Liteコンテンツのつくりか...</summary>
    <author>
        <name>unoh</name>
        
    </author>
    
    <content type="html" xml:lang="ja" xml:base="http://labs.unoh.net/">
        おはようございます。内田です。
最近は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


おわり

        
    </content>
</entry>

<entry>
    <title>Amazon Web Services入門: PHPとEC2/S3/SQS/SimpleDBで作るビデオ共有サイト</title>
    <link rel="alternate" type="text/html" href="http://labs.unoh.net/2010/01/amazon_web_services_phpec2s3sq.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.unoh.net/mt32/mt-atom.cgi/weblog/blog_id=2/entry_id=1740" title="Amazon Web Services入門: PHPとEC2/S3/SQS/SimpleDBで作るビデオ共有サイト" />
    <id>tag:labs.unoh.net,2010://2.1740</id>
    
    <published>2010-01-03T08:36:48Z</published>
    <updated>2010-01-16T16:55:21Z</updated>
    
    <summary><![CDATA[新年あけましておめでとうございます、五十川です。 PHPデベロッパー向けのAmazon Web Services（AWS）のリソースはhttp://aws.amazon.com/php/にまとめられていますが、そのArticles &amp; Tutorialsカテゴリーにある、Introduction to AWS for PHP Developersという記事は、AWSの主要サービスの概要と、PHPによるその操作を学ぶチュートリアルで、ここで取り上げられているサービスに初めて取り組むPHPデベロッパーには格好の入門となっており、ここではこのチュートリアルを紹介したいと思います。 また、このチュートリアルはAmazon純正のライブラリを利用していますが、AWS用のライブラリには様々なものがあり、この記事の最後ではそのひとつ、CloudFusionを紹介しようと思います。 なお、以下のチュ...]]></summary>
    <author>
        <name>unoh</name>
        
    </author>
    
        <category term="Tips" />
    
    <content type="html" xml:lang="ja" xml:base="http://labs.unoh.net/">
        <![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>]]>
        
    </content>
</entry>

<entry>
    <title>ありえるえりあ勉強会@五反田～テスト編～のご案内</title>
    <link rel="alternate" type="text/html" href="http://labs.unoh.net/2009/12/post_137.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.unoh.net/mt32/mt-atom.cgi/weblog/blog_id=2/entry_id=1737" title="ありえるえりあ勉強会@五反田～テスト編～のご案内" />
    <id>tag:labs.unoh.net,2009://2.1737</id>
    
    <published>2009-12-24T10:12:30Z</published>
    <updated>2009-12-24T10:22:07Z</updated>
    
    <summary>こんにちは。中村です。 アリエル・ネットワークに友人がいるきっかけで、ありえるえりあ勉強会にウノウが参加することになりました。個人的にですが、アリエルさんといえばFirefoxの拡張を作成しているときにFirefox拡張機能(extension)の作り方という記事でとてもお世話になりました。 今回のテーマはテストということで、ウノウからはテスト番長山本がスピーカーとして参加します。 発表予定内容は次のようになっています（告知文より抜粋のため敬称略）。   山本番長【絶版プレミア本に学ぶウェブアプリのテスト方法】            テストの書籍や資料を探すとウェブアプリを対象にしたものは少ないのが現状です。絶版のため高値になっている良書「インターネットアプリケーションのためのソフトウェアテスト」の内容を辿りながら、ウェブアプリのテスト法全般について日本の状況を交えながらお話したいと思いま...</summary>
    <author>
        <name>unoh</name>
        
    </author>
    
    <content type="html" xml:lang="ja" xml:base="http://labs.unoh.net/">
        <![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>]]>
        
    </content>
</entry>

<entry>
    <title>Q4Mを触ってみる</title>
    <link rel="alternate" type="text/html" href="http://labs.unoh.net/2009/12/q4m.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.unoh.net/mt32/mt-atom.cgi/weblog/blog_id=2/entry_id=1735" title="Q4Mを触ってみる" />
    <id>tag:labs.unoh.net,2009://2.1735</id>
    
    <published>2009-12-17T10:19:35Z</published>
    <updated>2009-12-21T09:51:21Z</updated>
    
    <summary>yukiです。そろそろクリスマスですね。みんな浮かれていればいいと思います！最近急に目が悪くなって、ツリーの赤色電球と居酒屋の赤提灯の色が判別出来なくなってきました。嘘です。 今回は、みんな大好きメッセージキュー、Q4Mを触ってみた感想を今更ながらレポートします。 ウノウでは特に最近、積極的にエンジニアを採用しています。採用ページをご覧になり興味のある方、ぜひご応募ください！！Find Job!でも募集開始してます！ Q4M 公式ページはこちらhttp://q4m.31tools.com/ Q4Mはサイボウズラボの奥 一穂氏が開発されており、MySQLの5.1以上でストレージエンジンとして利用できるメッセージキューで、MySQLプラグインとしてGPLライセンスで配布されております。 特長 MySQLのストレージエンジンとして利用できるので、テーブル作成時にストレージエンジンを指定するだけで...</summary>
    <author>
        <name>unoh</name>
        
    </author>
    
    <content type="html" xml:lang="ja" xml:base="http://labs.unoh.net/">
        <![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>]]>
        
    </content>
</entry>

<entry>
    <title>PHPテンプレートエンジンTwigをいじってみました</title>
    <link rel="alternate" type="text/html" href="http://labs.unoh.net/2009/12/phptwig.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.unoh.net/mt32/mt-atom.cgi/weblog/blog_id=2/entry_id=1731" title="PHPテンプレートエンジンTwigをいじってみました" />
    <id>tag:labs.unoh.net,2009://2.1731</id>
    
    <published>2009-12-09T06:50:33Z</published>
    <updated>2009-12-17T08:38:06Z</updated>
    
    <summary><![CDATA[今年のX'masは一人で高いシャンパンを買って飲もうとおもってるKeitaです。 しばらく、情報収集をさぼっている間に、symfonyの開発元であるSensio Labsから、PHPのテンプレートエンジンTwigが出ていたので、1時間ほど試してみました。 つかってみたよーとか、ここきついとかありましたら、コメントなどで教えていただけるとうれしいです。 インストール 本家サイトのINSTALLATIONを参考に僕はtar.gzのファイルを手動どインストールして試してみました。 インストールはpearコマンドなどでもできるようです。 というか、www.twig-project.orgのフッタを見てみるとPEAR Serverも自作してること発見してびっくりました。  テンプレート側 テンプレート側のコードは下記のように記述します。 &lt;html&gt; &lt;title&gt;title...]]></summary>
    <author>
        <name>unoh</name>
        
    </author>
    
    <content type="html" xml:lang="ja" xml:base="http://labs.unoh.net/">
        <![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のベータ版が出ていたりしてそれはそれで興味深いですので正式版がでたら使ってみたいと思います。

何かのご参考になれば幸いです。
]]>
        
    </content>
</entry>

<entry>
    <title>2009年版Python開発環境を整えよう</title>
    <link rel="alternate" type="text/html" href="http://labs.unoh.net/2009/12/2009python.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.unoh.net/mt32/mt-atom.cgi/weblog/blog_id=2/entry_id=1728" title="2009年版Python開発環境を整えよう" />
    <id>tag:labs.unoh.net,2009://2.1728</id>
    
    <published>2009-12-03T07:49:47Z</published>
    <updated>2009-12-04T05:10:57Z</updated>
    
    <summary>Pythonの開発環境・実行環境を整えるのに便利なvirtualenv, pip, virtualenvwrapperの紹介。</summary>
    <author>
        <name>unoh</name>
        
    </author>
    
    <content type="html" xml:lang="ja" xml:base="http://labs.unoh.net/">
        <![CDATA[<p>なでしこの作者じゃない方のsakatokuです。</p>

			<p>以前書いた<a href="http://labs.unoh.net/2007/04/python.html">「Python開発環境を整えよう」</a>という記事からだいぶ時間が経ってしまったので、内容を更新したいなぁと思っていたのですが、ようやくその機会が来ました。</p>
			<h3> virtualenvで開発環境をつくる</h3>
			<p>開発環境をつくるにあたって次のような問題が生じると思います。</p>

			<ul>
				<li> root権限がないためにインストールしたいライブラリが使えない</li>
				<li> 新しいライブラリをインストールしたり、既存のライブラリをアップグレードすることで、既に動いているアプリケーションを壊したくない</li>
				<li> 複数のバージョンのPythonを使って開発、テストを行いたい</li>
				<li> 自作したPythonパッケージのインストールのテストを行いたい</li>

			</ul>
			<p>以前の記事ではvirtual-pythonという解決策を紹介しましたが、現在では<a href="http://pypi.python.org/pypi/virtualenv/">virtualenv</a>というツールが広く使われるようになってきています。</p>
			<p>virtualenvをインストールするには、もしroot権限があるならば、CentOS/Fedoraの場合、</p>
<pre class="code"><code>$ sudo yum install python-setuptools
</code></pre>

			<p>でsetuptoolsというPythonパッケージ配布ライブラリを入れて、setuptoolsに含まれているeasy_installコマンドを使い、</p>

<pre class="code"><code>$ sudo easy_install virtualenv
$ which virtualenv
/usr/bin/virtualenv
</code></pre>

			<p>で入れるのが楽です。</p>
			<p>一般ユーザの権限でvirtualenvを利用するには、適当なディレクトリに最新版のvirtualenv(1.4.3以降)の配布物をダウンロードし、その配布物に含まれるvirtualenv.pyを叩くのが簡単です。最新版の1.4.3以降を薦める理由はpipというツールが同梱されるようになったことにありますが、これに関しては後述します。</p>

<pre class="code"><code>$ wget http://pypi.python.org/packages/source/v/virtualenv/virtualenv-1.4.3.tar.gz
$ tar xzf virtualenv-1.4.3.tar.gz
$ cd virtualenv
$ python virtualenv.py --python=/usr/bin/python2.4 ~/mypython
</code></pre>

			<p>上の例では、最後の行で~/mypythonというディレクトリにPython2.4の仮想開発環境を作成しています。--pythonオプションで利用するPythonのバイナリを指定します。"~/mypython"は、virtualenvで作る仮想的なPython環境のパスですが、これは好みに合わせて何にしても構いません。</p>

			<p>もし、/usr/local/bin/python2.5にPython2.5がインストールされている環境で、そのPython2.5を使った仮想環境を~/mypythonというパスに作りたいならば、以下のようにします。</p>
<pre class="code"><code>$ python virtualenv.py --python=/usr/local/bin/python2.5 ~/mypython
</code></pre>

			<p>実際にこれらの開発環境に切り替えるには、仮想環境ディレクトリにbin/activateというシェルスクリプトがあるのでそれを使います。</p>

<pre class="code"><code>$ source ~/mypython/bin/activate
$ which python
~/mypython/bin/python
$ python
Python 2.5.4 (r254:67916, Nov 28 2009, 20:37:01)
&#91;GCC 4.1.2 20080704 (Red Hat 4.1.2-46)] on linux2
Type &quot;help&quot;, &quot;copyright&quot;, &quot;credits&quot; or &quot;license&quot; for more information.
</code></pre>

			<p>この環境をカスタマイズした場合には、仮想環境ディレクトリにlib/python2.4/site-packages/sitecustomize.pyというファイルを作り、そこで固有の設定を行います。よく行われるのは、デフォルトのエンコーディングの指定です。</p>
<pre class="code"><code>cat &lt;&lt; END &gt; ~/mypython/lib/python2.5/site-packages/sitecustomize.py
heredoc&gt; import sys
heredoc&gt; sys.setdefaultencoding(&quot;utf-8&quot;)
heredoc&gt; END
</code></pre>

			<h3> pipを使ってパッケージを管理する</h3>
			<p>仮想環境を作ると、仮想環境以下のbinディレクトリにpipというコマンドもインストールされます。</p>
<pre class="code"><code>$ source ~/mypython/bin/activate
$ which pip
~/mypython/bin/pip
</code></pre>

			<p>このpipは、Pythonで長らく主流となってきたsetuptools/easy_installに替わって最近使われるようになってきたパッケージ管理ツールで、PHPで言えばpear、Rubyで言えばgem、Perlで言えばcpanコマンドに相当します。</p>
			<p>pipを使ってPythonパッケージをインストールするには、次のように"pip install &lt;パッケージ名&gt;"と入力します。インストールするパッケージが依存している別のパッケージがあれば、それもインストールしてくれます。</p>

<pre class="code"><code>$ pip install Django
</code></pre>

			<p>pipはデフォルトでは、<a href="http://pypi.python.org/pypi">Python Package Index</a>(通称PyPI)に登録されているパッケージをインストールしますが、URLを指定して直接インストールすることもできます。次の例は、Pythonの標準的な画像処理ライブラリであるPILを、tar.gzからインストールする例です。</p>
<pre class="code"><code>$ pip install http://effbot.org/downloads/Imaging-1.1.6.tar.gz
</code></pre>

			<p>インストール済みのパッケージを確認するには、freezeコマンドが利用できます。</p>

<pre class="code"><code>$ pip freeze
IPy==0.70
PIL==1.1.6
uamobile==0.2.8
virtualenv==1.4.3
wsgiref==0.1.2
</code></pre>

			<p>最新版のpipではuninstallコマンドを使ってパッケージのアンインストールもできるようになりました。</p>
<pre class="code"><code>$ pip uninstall IPy
</code></pre>

			<p>pipのコマンドを確認するには、helpコマンドを使います。helpの後にコマンド名を続けると詳細な内容を確認できます。</p>
<pre class="code"><code>$ pip help
$ pip help install
</code></pre>

			<h3> virtualenvwrapperを使って開発環境を切り替える</h3>
			<p>virtualenvとpipを使えば、プロジェクト毎に仮想環境を作っておけば、別のバージョンのライブラリを利用することができます。</p>
<pre class="code"><code># project1という環境を作る
$ python virtualenv.py --python=/usr/bin/python2.5 ~/project1
# 切り替え
$ source ~/project1/bin/activate
# 必要なライブラリをインストール
$ pip install &quot;Django==1.0.4&quot;
</code></pre>

<pre class="code"><code># project2という環境を作る
$ python virtualenv.py --python=/usr/bin/python2.5 ~/project2
# 切り替え
$ source ~/project2/bin/activate
# 別のバージョンのライブラリをインストール
$ pip install &quot;Django==1.1.1&quot;

</code></pre>

			<p>相互の開発環境の切り替えはactivateを使うことになりますが、同時にたくさんの環境を使っていると、いちいち"source ~/project1/bin/activate"を打つのが面倒になってきます。</p>
			<p>そんな状況で便利なのが<a href="http://pypi.python.org/pypi/virtualenvwrapper/">virtualenvwrapper</a>です。</p>
<pre class="code"><code>$ wget http://www.doughellmann.com/downloads/virtualenvwrapper-1.21.tar.gz
$ tar xzf virtualenvwrapper-1.21.tar.gz
$ cd virtualenvwrapper-1.21
</code></pre>

			<p>virtualenvwrapperは普通のPythonパッケージのように配布されていますが、実態はvirtualenvwrapper_bashrcというシェルスクリプトです。このvirtualenvwrapper_bashrcを.bashrcや.zshrcで読み込むことにより、virtualenvを使った開発を便利にするいくつかのコマンドが使えるようになります。virtualenvwrapper_bashrcという名前になっていますが、zshでも使えます。僕の場合は、</p>

<pre class="code"><code>$ cp virtualenvwrapper_bashrc ~/.virtualenvwrapperrc
</code></pre>

			<p>のように、ドットつきでファイル名を改名してホームディレクトリ直下に置き、.zshrcで、</p>
<pre class="code"><code># Import virtualenvwrapper
if &#91; -f ~/.virtualenvwrapperrc ]; then
  source ~/.virtualenvwrapperrc
fi
</code></pre>

			<p>のように読み込むようにしています。さらに、$HOME/.virtualenvsという仮想環境を置くディレクトリが必要なのであらかじめ作成しておきます。</p>

<pre class="code"><code>$ mkdir ~/.virtualenvs
</code></pre>

			<p>もしこのディレクトリを変更したい場合は、WORKON_HOMEという環境変数を定義することで変更できます。</p>
			<p>virtualenvwarrperを読み込むと、ターミナル上で、</p>

<pre class="code"><code>$ mkvirtualenv --python=/usr/bin/python2.5 temp
</code></pre>

			<p>のようにして、仮想環境を作り</p>
<pre class="code"><code>$ workon temp
</code></pre>

			<p>のように"workon (仮想環境名)"と打つと、その開発環境に切り替えてくれるので便利です。その仮想環境を無効にするには、</p>
<pre class="code"><code>$ deactivate
</code></pre>

			<p>のようにdeactivateを使います。</p>
			

			<p>もし、ある仮想環境が必要なくなったならば、deactivateを使って一度その環境を離れた上で、rmvirtualenvコマンドを使って削除することができます。</p>

<pre class="code"><code>$ deactivate
$ rmvirtualenv temp
</code></pre>

<p>普段の開発では、</p>

<pre class="code"><code>$ workon project1
</code></pre>

<p>のようにしてproject1の開発に切り替え、いつも通りコードを書いたり、テストを行って、もし別のproject2のタスクをする必要が出た場合には、</p>

<pre class="code"><code>$ workon project2
</code></pre>

<p>のようにしてproject2の開発に切り替え...のようにして作業を進めています。</p>

<p>virtualenvwrapperは非常に便利なのですが、PATHが通った場所にvirtualenvがないとmkvirtuanenvコマンドはエラーになり実行できません。もし、いつもPATHが通っている場所にvirtualenvコマンドをインストールできるならば、その解決方法がいいような気がしますが、$WORKON_HOMEに手動で「仮想環境を作るための仮想環境」を作れば一応は解決できます。</p>
<pre class="code"><code>$ mkdir ~/.virtualenvs
$ python virtualenv.py --python=/usr/bin/python2.4 ~/.virtualenvs/bootstrap
$ source ~/.virtualenvs/bootstrap/bin/activate
$ pip install virtualenv
$ mkvirtualenv mypython
</code></pre>

			<h3> 書き残していること</h3>
			<p>以上駆け足で、Python開発環境を整えるための三種の神器、virtualenv、pip、virtualenvwrapperを紹介しましたが、ぱっと考え付くだけでも、まだ言及していないことがたくさんあります。</p>

			<ul>
				<li> virtualenvの--no-site-packagesオプション</li>
				<li> virtualenvの--relocatableオプション</li>
				<li> virtualenvの--distributeオプション(Pythonの新しいパッケージ管理ライブラリ<a href="http://pypi.python.org/pypi/distribute/">Distribute</a>について)</li>
				<li> virtualenvと同様によく使われる<a href="http://www.buildout.org/">zc.buildout</a>について</li>

				<li> pipを使って複数のモジュールをまとめる(pip bundle)</li>
				<li> pipを使ってSubversion/git/Mercurialレポジトリから直接モジュールをインストールする</li>
				<li> virtualenvを使った実際のアプリケーションのデプロイ方法</li>
			</ul>
			<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>
]]>
        
    </content>
</entry>

<entry>
    <title>Tokyo Tyrantを使ってみて</title>
    <link rel="alternate" type="text/html" href="http://labs.unoh.net/2009/10/using-tokyo-tyrant.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.unoh.net/mt32/mt-atom.cgi/weblog/blog_id=2/entry_id=1717" title="Tokyo Tyrantを使ってみて" />
    <id>tag:labs.unoh.net,2009://2.1717</id>
    
    <published>2009-10-28T10:08:44Z</published>
    <updated>2009-10-28T10:11:06Z</updated>
    
    <summary> yamaokaです。 通常のデータベースとしてではなく、Key-Valueストアの選択肢として Tokyo Tyrantを少しずつ使ってみています。 実際に運用するにあたって、いくつか行ったことを書いておきます。 ちなみに、現在の構成は1台のみでの運用です。 マルチマスター構成やレプリケーションなどは行っていません。 PHPのクライアント Tokyo Tyrantを利用するのはPHPのアプリケーションからです。 最初はmemcachedプロトコルを利用して PECL::memcacheを使っていましたが、 データの大量更新を連続で行うとデータの取得が正常に行えなくなる現象が発生したため、 Net_TokyoTyrantを一部改変したものをライブラリとして利用しています。 パフォーマンスではPECL::memcacheに負けますが、クリティカルな処理をしていないこともあり、 今のところ問題...</summary>
    <author>
        <name>unoh</name>
        
    </author>
    
        <category term="Tips" />
    
    <content type="html" xml:lang="ja" xml:base="http://labs.unoh.net/">
        <![CDATA[
<p>yamaokaです。</p>

<p>
通常のデータベースとしてではなく、Key-Valueストアの選択肢として
<a href="http://1978th.net/tokyotyrant/">Tokyo Tyrant</a>を少しずつ使ってみています。
実際に運用するにあたって、いくつか行ったことを書いておきます。
ちなみに、現在の構成は1台のみでの運用です。
マルチマスター構成やレプリケーションなどは行っていません。
</p>

<h3>PHPのクライアント</h3>

<p>
Tokyo Tyrantを利用するのはPHPのアプリケーションからです。
最初は<a href="http://1978th.net/tokyotyrant/spex.html#protocol_memcached">memcachedプロトコル</a>を利用して
<a href="http://pecl.php.net/package/memcache">PECL::memcache</a>を使っていましたが、
データの大量更新を連続で行うとデータの取得が正常に行えなくなる現象が発生したため、
<a href="http://openpear.org/package/Net_TokyoTyrant">Net_TokyoTyrant</a>を一部改変したものをライブラリとして利用しています。
パフォーマンスではPECL::memcacheに負けますが、クリティカルな処理をしていないこともあり、
今のところ問題になってはいません。
<a href="http://pecl.php.net/package/tokyo_tyrant">PECL::tokyo_tyrant</a>もそのうち試してみようと思っています。
</p>

<h3>監視</h3>

<p>
<a href="http://www.nagios.org/">Nagios</a>のcheck_tcpプラグインを利用しています。
Tokyo Tyrantが動いているサーバーにmemcachedプロトコルで接続、
statsコマンドを実行してチェックしています。memcachedが動いているサーバーを監視するのと同じ要領ですね。
</p>

<p>
<pre class="code"><code>define command{
        command_name    check_tokyotyrant
        command_line    $USER1$/check_tcp -H $HOSTADDRESS$ -p 1978 -t 5 -E -s 'stats\r\nquit\r\n' -e 'uptime' -M crit
        }
</code></pre>
</p>

<p>
実際には、上のようなコマンドを定義して監視しています。
</p>

<h3>ログローテート</h3>

<p>
Tokyo Tyrantにはログを出力する起動オプションがあり、
クライアントからの接続ログをテキストファイルで残すことができます。
しかし、そのログを保管し続けていると容量を食うので、適宜ローテートさせています。
Tokyo Tyrantを管理するttserverctlはHUPを受け取ることができるので、
次のような設定をlogrotateに対して行うことでローテーションしています。
</p>

<p>
<pre class="code"><code>/var/ttserver/log {
    missingok
    notifempty
    compress
    sharedscripts
    postrotate
        /usr/sbin/ttservctl hup > /dev/null 2>/dev/null || true
    endscript
    rotate 7
    daily
}</code></pre>
</p>

<h3>バックアップ</h3>

<p>
Tokyo Tyrantはホットバックアップを取ることができるので、
1日1回、データ本体をコピーして保存しています。
ホットバックアップはTokyo Tyrant付属のコマンドを実行するだけでOKです。
バックアップとリカバリーの手順については<a href="http://1978th.net/tokyotyrant/spex.html#tutorial_backup">Tokyo Tyrantのドキュメントに詳しく記載されている</a>ので、
そちらを参照しつつ自分の環境に合ったバックアップスクリプトを用意するといいのではないでしょうか。
</p>

<h3>最後に</h3>

<p>
Tokyo Tyrantは非常に扱いやすい環境だと感じています。
実際に運用していて、タイミングによってはかなりたくさんの更新・参照が行われるのですが、
負荷も上がらず非常に安定して稼動しています。また、処理も高速です。
将来的にはセッションストレージとして利用するのもありかな、と思います。
</p>

<p>
Tokyo Tyrantを用いた運用事例の1つとして参考にしていただければ幸いです。
また、皆さんの運用事例やtipsなどありましたら、是非教えてください。
</p>
]]>
        
    </content>
</entry>

<entry>
    <title>ソフトウェアテスト関連のTwitterアカウント</title>
    <link rel="alternate" type="text/html" href="http://labs.unoh.net/2009/10/twitter_1.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.unoh.net/mt32/mt-atom.cgi/weblog/blog_id=2/entry_id=1713" title="ソフトウェアテスト関連のTwitterアカウント" />
    <id>tag:labs.unoh.net,2009://2.1713</id>
    
    <published>2009-10-21T09:32:42Z</published>
    <updated>2009-12-17T09:59:36Z</updated>
    
    <summary>こんにちは！gal_tonkatsu やまもと＠テスト番長です。  今日はソフトウェアテスト関連のTwitterアカウントで知っているものをご紹介します。 ...が、すみません、あまり数はありません。 他にもご存知の方がいらっしゃいましたら是非教えてください。 ウェブサイト/サービス/企業（順不同） RBCS　http://www.rbcs-us.com/ utest  http://www.utest.com/ TestingWebSites　http://www.testing-web-sites.co.uk/ testinggarage　http://testinggarage.blogspot.com/ TestingNews　http://qualitypoint.blogspot.com/ usertesting　http://www.usertesting.com/ Clou...</summary>
    <author>
        <name>unoh</name>
        
    </author>
    
        <category term="Tips" />
    
    <content type="html" xml:lang="ja" xml:base="http://labs.unoh.net/">
        <![CDATA[こんにちは！<a href="http://twitter.com/gal_tonkatsu">gal_tonkatsu</a> やまもと＠テスト番長です。 

今日はソフトウェアテスト関連のTwitterアカウントで知っているものをご紹介します。
...が、すみません、あまり数はありません。
他にもご存知の方がいらっしゃいましたら是非教えてください。

<h3>ウェブサイト/サービス/企業（順不同）</h3>
<a href="http://twitter.com/RBCS">RBCS</a>　<a href="http://www.rbcs-us.com/">http://www.rbcs-us.com/</a><br />
<a href="http://twitter.com/utest">utest</a>  <a href="http://www.utest.com/">http://www.utest.com/</a><br />
<a href="http://twitter.com/TestingWebSites">TestingWebSites</a>　<a href="http://www.testing-web-sites.co.uk/">http://www.testing-web-sites.co.uk/</a><br />
<a href="http://twitter.com/testinggarage">testinggarage</a>　<a href="http://testinggarage.blogspot.com/">http://testinggarage.blogspot.com/</a><br />
<a href="http://twitter.com/TestingNews">TestingNews</a>　<a href="http://qualitypoint.blogspot.com/">http://qualitypoint.blogspot.com/</a><br />
<a href="http://twitter.com/usertesting">usertesting</a>　<a href="http://www.usertesting.com/">http://www.usertesting.com/</a><br />
<a href="http://twitter.com/CloudTesting">CloudTesting</a>　<a href="http://www.cloudtesting.com/">http://www.cloudtesting.com/</a><br />

<h3>達人:海外</h3>
<a href="http://twitter.com/yourdon">yourdon</a>　Ed Yourdon　さん<br />
<a href="http://twitter.com/johannarothman">johannarothman</a>　Johanna Rothman　さん<br />

<h3>達人:国内（50音順）</h3>
<a href="http://twitter.com/akiyama924">akiyama924</a>   秋山 浩一　さん<br />
<a href="http://twitter.com/ikedon">ikedon</a>　池田 暁　さん<br />
<a href="http://twitter.com/mkoszk">mkoszk</a>　鈴木 三紀夫　さん<br />
<a href="http://twitter.com/nagworld">nagworld</a>　永田 敦　さん<br />
<a href="http://twitter.com/YasuharuNishi">YasuharuNishi</a> 西 康晴　さん<br />
<a href="http://twitter.com/honda_">honda_</a>　ほんだ　さん<br />
<a href="http://twitter.com/yumotsuyo">yumotsuyo</a>　湯本 剛　さん<br />
<a href="http://twitter.com/mikantsuki">mikantsuki</a>　みかまま さん<br />


このアカウントを忘れてるよ！という情報がございましたら、
コメントいただけますと有り難いです。
]]>
        
    </content>
</entry>

<entry>
    <title>サーバのネットワーク速度の調査/測定方法</title>
    <link rel="alternate" type="text/html" href="http://labs.unoh.net/2009/10/post_136.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.unoh.net/mt32/mt-atom.cgi/weblog/blog_id=2/entry_id=1707" title="サーバのネットワーク速度の調査/測定方法" />
    <id>tag:labs.unoh.net,2009://2.1707</id>
    
    <published>2009-10-13T02:50:20Z</published>
    <updated>2009-10-13T15:16:27Z</updated>
    
    <summary>こんにちは。kyagi です。先日データセンタ内のサーバ群のうち、なぜか特定の１台だけネットワークの速度が極端に遅いという問題がありました。今回はサーバのネットワーク速度の調査/測定方法と考えられる原因についてお話しします。同様のトラブルが発生している方のお役に立てれば幸いです。問題解決までの手順としては以下になります。 1. 現在の状態を調べる 2. ハード/ソフト含めて考えられる原因をいくつか挙げる 3. 問題が改善されるまでそれぞれの原因への対処策をひとつひとつ実施/検証していく まず現在の NIC の HW 情報を lspci で調査します。ここでは Broadcom の NetXtreme BCM5722 という NIC を使用していることがわかります。 # lspci -vvv | grep Ether 01:00.0 Ethernet controller: Broadcom...</summary>
    <author>
        <name>unoh</name>
        
    </author>
    
    <content type="html" xml:lang="ja" xml:base="http://labs.unoh.net/">
        <![CDATA[こんにちは。kyagi です。先日データセンタ内のサーバ群のうち、なぜか特定の１台だけネットワークの速度が極端に遅いという問題がありました。今回はサーバのネットワーク速度の調査/測定方法と考えられる原因についてお話しします。同様のトラブルが発生している方のお役に立てれば幸いです。問題解決までの手順としては以下になります。

1. 現在の状態を調べる
2. ハード/ソフト含めて考えられる原因をいくつか挙げる
3. 問題が改善されるまでそれぞれの原因への対処策をひとつひとつ実施/検証していく

まず現在の NIC の HW 情報を lspci で調査します。ここでは Broadcom の NetXtreme BCM5722 という NIC を使用していることがわかります。

<pre class="code">
# lspci -vvv | grep Ether
01:00.0 Ethernet controller: Broadcom Corporation NetXtreme BCM5722 Gigabit Ethernet PCI Express
02:00.0 Ethernet controller: Broadcom Corporation NetXtreme BCM5722 Gigabit Ethernet PCI Express
</pre>

次に実際に現在の回線速度を netperf で測定します。ここでは 83M の速度が出ていることがわかります。Broadcom NetXtreme BCM5722 はギガビット対応しているので通常であれば 800M～1000M の速度が出るはずなので、異常に低い数値であることがわかります。(※netperf を使うためにはサーバ netserver を構築する必要があります。詳細は 別途 Web 上の情報をご覧ください。<a href="http://www.netperf.org/netperf/">http://www.netperf.org/netperf/</a>)

<pre class="code">
# netperf -H s1
TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to s1 (10.0.0.81) port 0 AF_INET
Recv   Send    Send
Socket Socket  Message  Elapsed
Size   Size    Size     Time     Throughput
bytes  bytes   bytes    secs.    10^6bits/sec

87380  16384  16384    10.37      83.10
</pre>

次に NIC のドライバ情報とリンクアップ/ダウン情報を dmesg や /var/log/message で調べます。ここでは tg3 ドライバを使用し、初回リンクアップ時(サーバ起動時)に 10M でリンクアップしていることがわかります。その後、1000M に移行し一度ダウンして 100M になっているようです。

<pre class="code">
# dmesg | grep eth0
eth0: Tigon3 [partno(BCM95722) rev a200 PHY(5722/5756)] (PCI Express) 10/100/1000Base-T Ethernet 00:24:e8:7c:ab:7a
eth0: RXcsums[1] LinkChgREG[0] MIirq[0] ASF[1] WireSpeed[1] TSOcap[1]
eth0: dma_rwctrl[76180000] dma_mask[64-bit]
tg3: eth0: Link is up at 10 Mbps, half duplex.
tg3: eth0: Flow control is off for TX and off for RX.
tg3: eth0: Link is up at 1000 Mbps, full duplex.
tg3: eth0: Flow control is off for TX and off for RX.
tg3: eth0: Link is up at 1000 Mbps, full duplex.
tg3: eth0: Flow control is off for TX and off for RX.
tg3: eth0: Link is down.
tg3: eth0: Link is up at 100 Mbps, full duplex.
tg3: eth0: Flow control is off for TX and off for RX.
</pre>

最後に ethtool で NIC の現在の状態を調べます。ここでは NIC 自体がサポートできる速度(Supported link modes)とスイッチから提案された速度(Advertised link modes) リンクは確立しているが(Link detected: yes)、速度は 100Mで(Speed: 100Mb/s) になっていることがわかります。

<pre class="code">
# ethtool eth0
Settings for eth0:
           Supported ports: [ TP ]
           Supported link modes: 10baseT/Half 10baseT/Full
                                              100baseT/Half 100baseT/Full
                                              1000baseT/Half 1000baseT/Full
           Supports auto-negotiation: Yes
           Advertised link modes: 10baseT/Half 10baseT/Full
                                               100baseT/Half 100baseT/Full
                                               1000baseT/Half 1000baseT/Full
           Advertised auto-negotiation: Yes
           Speed: 100Mb/s
           Duplex: Full
           Port: Twisted Pair
           PHYAD: 1
           Transceiver: internal
           Auto-negotiation: on
           Supports Wake-on: g
           Wake-on: d
           Current message level: 0x000000ff (255)
           Link detected: yes 
</pre>

ここまで現在の状態を調査したうえで、考えられる原因は下記になります。
a. スイッチとのオートネゴに失敗した
b. スイッチのポートがおかしい(本来 1000M のはずがこのポートだけ 100M)
c. NIC がおかしい
d. LAN ケーブルがおかしい 

NIC 自体は 1000M に対応しており、実際に 1000M でリンクアップした実績もあるのでここではひとまず(a)のオートネゴを原因として疑い、ひとまずオートネゴをオフにして再設定をしてみます（※注 ethtool による再設定はネットワーク越しではなく、必ず実機で行ってください。(b)スイッチのポート不良の場合、コマンドを打った後にプロンプトが戻ってこず、ネットワークが遮断される可能性があります！）

<pre class="code">
# ethtool -s eth0 speed 1000 duplex full autoneg off
Cannot set new settings: Invalid argument
  not setting speed
  not setting duplex
  not setting autoneg
</pre>

オートネゴをオフにするとコマンドに失敗しました。tg3 ドライバの仕様かスイッチとの相性が考えられます。Advetised auto-negotiation も Yes なので、オートネゴをオンにして実際にスイッチとオートネゴさせてみます。

<pre class="code">
# ethtool -s eth0 speed 1000 duplex full autoneg on
</pre>

うまくいきました。その後速度を再計測すると 83M だった速度が 941M まで復旧できたことがわかります。また ethtool の表示やdmesg にも 1000M になっていることを確認しました。

<pre class="code">
# /usr/local/bin/netperf -H s1
TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to s1 (10.0.0.81) port 0 AF_INET
Recv   Send    Send
Socket Socket  Message  Elapsed
Size   Size    Size     Time     Throughput
bytes  bytes   bytes    secs.    10^6bits/sec

87380  16384  16384    10.04     941.33
</pre>

<pre class="code">
# ethtool eth0
Settings for eth0:
           Supported ports: [ TP ]
           Supported link modes:   10baseT/Half 10baseT/Full
                                                100baseT/Half 100baseT/Full
                                                1000baseT/Half 1000baseT/Full
           Supports auto-negotiation: Yes
           Advertised link modes:  10baseT/Half 10baseT/Full
                                                100baseT/Half 100baseT/Full
                                                1000baseT/Half 1000baseT/Full
           Advertised auto-negotiation: Yes
           Speed: 1000Mb/s
           Duplex: Full
           Port: Twisted Pair
           PHYAD: 1
           Transceiver: internal
           Auto-negotiation: on
           Supports Wake-on: g
           Wake-on: d
           Current message level: 0x000000ff (255)
           Link detected: yes
</pre>

この状態を設定ファイルに記述しておくことで起動時や service network (re)start 時に反映することが可能です。

<pre class="code">
# cat /etc/sysconfig/network-scripts/ifcfg-eth0 
(...snip...)
ETHTOOL_OPTS="speed 1000 duplex full autoneg on"
(...snip...)
</pre>

また、 Nagios などを使用して監視体制を組んでいるのであれば ethtool コマンドを利用したシェルスクリプトをプラグインとして作成することで定期的な監視が可能です。]]>
        
    </content>
</entry>

<entry>
    <title>Flash Lite ことはじめ。</title>
    <link rel="alternate" type="text/html" href="http://labs.unoh.net/2009/10/flash_lite.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.unoh.net/mt32/mt-atom.cgi/weblog/blog_id=2/entry_id=1702" title="Flash Lite ことはじめ。" />
    <id>tag:labs.unoh.net,2009://2.1702</id>
    
    <published>2009-10-05T03:18:18Z</published>
    <updated>2009-10-05T03:23:53Z</updated>
    
    <summary>こんにちは。 コーヒー飲むならマンデリンな ryosuke です。ただ実際の所深いこだわりはありません。 早速ですがFlash Lite は携帯向けという事もあって少なからず制限があります。今回はその辺りを中心に特徴をざくっとまとめてみようと思います。 実装バージョンの普及状況 例によってキャリア毎に制限が異なったりするので Flash Lite の仕様と同時に各キャリアの実装状況を把握する必要があります。 モバイル用のFlashとして登場したFlash Liteですが、現在3キャリアあわせると 1.0/1.1/2.0/3.0/3.1 があります。 1.0はdocomoとSoftbankの端末のいくつかに存在する程度で余り数はありません。auは1.1の実装から提供されています。 普及率やスペック、上位互換性から1.1でパブリッシュされたswfのコンテンツが作りやすく、最も多くのユーザーにリ...</summary>
    <author>
        <name>unoh</name>
        
    </author>
    
    <content type="html" xml:lang="ja" xml:base="http://labs.unoh.net/">
        <![CDATA[p. こんにちは。 コーヒー飲むならマンデリンな ryosuke です。ただ実際の所深いこだわりはありません。

p. 早速ですがFlash Lite は携帯向けという事もあって少なからず制限があります。今回はその辺りを中心に特徴をざくっとまとめてみようと思います。

h2. 実装バージョンの普及状況

* 例によってキャリア毎に制限が異なったりするので Flash Lite の仕様と同時に各キャリアの実装状況を把握する必要があります。
* モバイル用のFlashとして登場したFlash Liteですが、現在3キャリアあわせると 1.0/1.1/2.0/3.0/3.1 があります。
* 1.0はdocomoとSoftbankの端末のいくつかに存在する程度で余り数はありません。auは1.1の実装から提供されています。
* 普及率やスペック、上位互換性から1.1でパブリッシュされたswfのコンテンツが作りやすく、最も多くのユーザーにリーチするバージョンと言えると思います。特別に断りが無ければ以下1.1(Flash 4 Script)の話として進めます。
* docomoはFlash Lite 2.0対応端末(3以降のバージョンは上位互換により対応端末と言えるのかもしれませんが)が存在しておらず、3キャリア対応を考えると(まったく個人的な予想ですが)次の普及層は3.x系になるのではないかと思います。
* Flash Lite 3.0からFLVに対応していますが、対応端末はなく、docomoのi-mode2.0ブラウザに搭載されているFlash Lite3.1に実装された物が初めての様です。


h2. 容量のお話

* 1.0の容量は 20KB。外部データの読み込みは行えません。
* 1.1からは100KBが殆どになり、loadMovie(), loadMovieNum(), loadVariables(), loadVariablesNum() 等の外部からデータを読み込むメソッドが使える様になった事から、容量制限に対する柔軟性が増しました。
* docomoでは外部通信取得分を含めてトータルで100KBまでという制限があり、3キャリア対応となるとココが制限値と言えます。

h2. インラインモードとインタラクティブモード

* Flash Liteの埋め込みには2種類あり、通常のWEBページに埋め込むインラインモードと、Flash主体のページとして読み込むインタラクティブモードがあります。
* ボタン操作はインタラクティブモードでしかできません。
* インタラクティブモードにするには、Flash読み込み用の object タグに declare 属性を付けます。

h2. ボタンの割当

* 0-9までの数字キーと*#キー。カーソルキーの一部と決定ボタンが使えます。
* カーソルキーの左右はSoftBank以外(つまりdocomoとau)は履歴の戻ると進むが割り当てられているため、3キャリア対応する場合は使えないと思った方が良いです。

h2. サーバとの通信

* 容量の所でも触れましたが、1.1からswfからサーバへの通信が可能になりました。
* サーバサイドのプログラムと連携するには loadVariables(), loadVariablesNum() を使ってデータをやり取りする事になります。
* また、loadMovie(), loadMovieNum(), loadVariables(), loadVariablesNum()等は、ユーザーによるボタンアクションによってのみ実行できます。
* さらに、ひとつのボタンアクションに大して1セッションしか通信出来ません。
* 複数指定されている場合は初めに記述されている通信のみ実行され、それ以降は無視されます。

h2. getURLのtelスキーム等

* getURL() で携帯電話特有のスキームにアクセスする事が出来ます。
** http: https: mailto: は従来通り
** tel:電話番号 / 電話をかける事が出来ます
** tel-av:電話番号 / テレビ電話をかける事が出来ます(テレビ電話に対応していれば)
*** 普通です。

h2. FSCommand2

* 携帯特有のコマンドを実行できます。例えば以下の様な物があります。
** GetBatteryLevel (バッテリー残量)
** GetSignalLevelSource (電波状況)
** StartVibrate (バイブレーターを動作させます)
** 詳細はこちら ("http://livedocs.adobe.com/flash/9.0_jp/main/00005843.html":http://livedocs.adobe.com/flash/9.0_jp/main/00005843.html)

h2. オーサリングツール

* Flash4形式で出力すれば対応端末での表示は可能です。
* Flash Lite 特有の機能を使う場合、該当パブリッシュ形式に対応したソフトが必要。
** Flash Lite への対応は Flash MX2004 Professional版以降です。

h3. 参考文献

* "Adobe - Flash Lite: 機能":http://www.adobe.com/jp/products/flashlite/features/
* "作ろうiモードコンテンツ：Flash&reg; | サービス・機能 | NTTドコモ":http://www.nttdocomo.co.jp/service/imode/make/content/spec/flash/
* "iモード向けFlash&reg;の特徴 | サービス・機能 | NTTドコモ":http://www.nttdocomo.co.jp/service/imode/make/content/flash/feature/
* "KDDI au: マルチメディア・コンテンツ &gt; Flashコンテンツ":http://www.au.kddi.com/ezfactory/mm/flash01.html
* "Flash TOP":http://creation.mb.softbank.jp/flash/
* "fscommand2() ":http://livedocs.adobe.com/flash/9.0_jp/main/00005843.html

h2. 最後に

p. どうしても Flash製作となるとデザイン要素が大きいため私にとっては苦手意識が大きいのですが、そのポータビリティーの高さや機能、インパクトの強さからコンテンツ制作に広く使われています。特に携帯ではムービーや音声機能よりも、自由度の高いUIを構築するツールとして使われる事が多いため、携帯サイト利用者にも広く受け入れられている様です。

p. Flash Liteを使う際に私自身何に気をつけるべきか全体像がよくわからなかったので、どんな事が出来てどんなことができないのか？がまずは理解したくて調べました。これは押さえておかないと！ なんてところがあればぜひ教えていただきたいです。]]>
        
    </content>
</entry>

<entry>
    <title>分かったつもりになるAndroid開発方法</title>
    <link rel="alternate" type="text/html" href="http://labs.unoh.net/2009/09/android.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.unoh.net/mt32/mt-atom.cgi/weblog/blog_id=2/entry_id=1700" title="分かったつもりになるAndroid開発方法" />
    <id>tag:labs.unoh.net,2009://2.1700</id>
    
    <published>2009-09-30T09:16:10Z</published>
    <updated>2009-09-30T09:39:16Z</updated>
    
    <summary>こんばんは。うちだです。 皆さんAndroid携帯は購入しましたか？ 社内ではiPhone勢が多く、Android携帯所持は私だけという悲しい現実を目の当たりにしています。 そこで以前、社内勉強会にて、Androidの素晴らしさを皆に知ってもらおうと発表した内容が今回のエントリーです。 今回のエントリーでは開発者視点で分かったつもりになる為に、広く浅く書いてます。 本気で分かるには公式ドキュメントや書籍及び参考リンクをご参照ください。  参考： Android | Official Website 特徴 環境 Linuxカーネル BSD UNIXのlibc アプリケーションはDalvikと呼ばれるVM上で動作 主にJavaで開発 Google提供のSDKあり Eclipseプラグインあり アーキテクチャ 参考： わかった気になる気になるandroid メリット マルチタスク intentの...</summary>
    <author>
        <name>unoh</name>
        
    </author>
    
    <content type="html" xml:lang="ja" xml:base="http://labs.unoh.net/">
        <![CDATA[こんばんは。うちだです。

皆さんAndroid携帯は購入しましたか？
社内ではiPhone勢が多く、Android携帯所持は私だけという悲しい現実を目の当たりにしています。

そこで以前、社内勉強会にて、Androidの素晴らしさを皆に知ってもらおうと発表した内容が今回のエントリーです。

今回のエントリーでは開発者視点で分かったつもりになる為に、広く浅く書いてます。
本気で分かるには公式ドキュメントや書籍及び参考リンクをご参照ください。 

参考： "Android | Official Website":http://www.android.com/



h2. 特徴

h3. 環境

* Linuxカーネル
* BSD UNIXのlibc
* アプリケーションはDalvikと呼ばれるVM上で動作
* 主にJavaで開発
* Google提供のSDKあり
* Eclipseプラグインあり
* "アーキテクチャ":http://upload.wikimedia.org/wikipedia/commons/3/3c/Android%E3%81%AE%E3%82%A2%E3%83%BC%E3%82%AD%E3%83%86%E3%82%AF%E3%83%81%E3%83%A3%28New%29.PNG

参考： "わかった気になる気になるandroid":http://dev.ariel-networks.com/Members/iwanaga/android-intro

h3. メリット

* マルチタスク
* intentの存在
* Androidマーケットの自由度が素敵
* Googleとの連携凄すぎ

h3. デメリット

* UIがまだまだ(レスポンスが悪かったりする）
* 何度か落ちた
* バッテリー使い過ぎ
* マルチタッチ(開発中との噂）


h2. 開発 

h3. 環境構築

参考： "開発環境を構築するには":http://www.adakoda.com/android/000062.html

h3. アクティビティ

いわゆる、コントローラー。１つのウィンドウと考えてもらっても大丈夫だと思います。
Activityクラスを継承したクラスでレイアウトの設定や各種イベントを登録します。
また、インスタンスの生成から破棄までのライフサイクルが非常に重要ですので参考リンク先を参照ください。

Activityクラスの子クラスには専用の仕事をするクラスもあります。

* ListActivity
* ExpandableListActivity
* TabActivity

参考： "勉強会/Android SDK WG 第1回 セッション（2008.10.25）":http://android.siprop.org/index.php?%CA%D9%B6%AF%B2%F1%2FAndroid%20SDK%20WG%20%C2%E81%B2%F3%20%A5%BB%A5%C3%A5%B7%A5%E7%A5%F3%A1%CA2008.10.25%A1%CB

h3. ウィジェット

画面を構成する部品

* TextView
* Button
* Canvas
* 等

参考： "簡単でワクワクするAndroidウィジェット10連発！":http://www.atmarkit.co.jp/fjava/rensai4/android04/android04_1.html

h3. レイアウト

画面のウィジェットの配置は基本的にxmlファイルで定義します。
そしてxmlファイルから自動で生成されるRクラスを使いコントロールします。
ちなみに、手書きだと面倒なのでDroidDrawを使うと楽(Web版は重いです)

参考： "DroidDraw":http://droiddraw.org/

h3. リソース

文字列やアイコン等の定義ファイルです。これもxmlで記述し、Rクラスを使います
文字列はロケールによって切り替え可能。

参考： "Resources and Internationalization | Android Developers":http://developer.android.com/intl/ja/guide/topics/resources/resources-i18n.html

h3. Activity、レイアウト、リソースのサンプル

<pre class="code">
// res/values/string.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="hello">Hello World, ex1Activity!</string>
    <string name="app_name">ex1</string>
</resources>

// res/layout/main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<TextView  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="@string/hello"
    />
</LinearLayout>

// src/net.unoh.ex1/exActivity.java
package net.unoh.ex1;

import android.app.Activity;
import android.os.Bundle;

public class ex1Activity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
}
</pre>

* string.xmlに[hello=Hello World]を設定
* レイアウトファイルにコンテナとTextViewを設置
* TextViewのtextプロパティを設定[android:text="@string/hello"
* Activityにレイアウトをセット
* このコードはeclipseでプロジェクトを作ったときの初期状態です。


h3. インテント

アプリケーションからアクティビティやサービスを起動する仕組み。次の二つのタイプがある

* 明示的インテント
** ActivityやServiceを直接指定して起動
* 暗黙的インテント
** パラメータを設定することでシステムが該当するActivityを起動
** 該当するActivityが複数ある場合は選択ダイアログがでる

参考： "Androidの重要な機能、インテント":http://thinkit.jp/article/921/1/
参考： "勉強会/インテントを発行してみよう - 日本Androidの会（日本アンドロイドの会）":http://www.android-group.jp/index.php?%CA%D9%B6%AF%B2%F1%2F%A5%A4%A5%F3%A5%C6%A5%F3%A5%C8%A4%F2%C8%AF%B9%D4%A4%B7%A4%C6%A4%DF%A4%E8%A4%A6
参考： "OpenIntents":http://www.openintents.org/en/

h3. サービス

バックグラウンド処理を実現します。
例えば、時間のかかるダウンロード処理をバックグラウンドで行う等が可能です。
また、AIDLを使う事でActivity等とのプロセス間通信が可能となります。
電源をonにしたときに起動することでcronやタスクマネージャーのように使う事もできます。

各種センサー機能はシステムサービスとして提供されています


参考： "AIDLによるプロセス間通信":http://xfutures.jp/2009/07/18/60/
参考： "常駐アプリが作成できるAndroidのサービスとは":http://www.atmarkit.co.jp/fjava/rensai4/android07/android07_1.html
参考： "Android のセンサーを活用する":http://www.ibm.com/developerworks/jp/opensource/library/os-android-sensor/

h3. このあたりまでのサンプル

<pre class="code">
// AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="net.unoh.ex1"
    android:versionCode="1"
    android:versionName="1.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".ex1Activity"
            android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <service android:name=".ex2Service" />
    </application>
    <uses-sdk android:minSdkVersion="3" />
</manifest>

// res/values/string.xm
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="hello">Hello World, ex1Activity!</string>
    <string name="app_name">ex1</string>
    <string name="btnEx2">Service</string>
    <string name="btnEx3">Intent</string>
</resources>

// res/layout/main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<TextView  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="@string/hello"
    />
<Button
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:id="@+id/btnEx2"
    android:text="@string/btnEx2"
    />
<Button
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:id="@+id/btnEx3"
    android:text="@string/btnEx3"
    />
</LinearLayout>

// src/net.unoh.ex1.ex1Activity.java
Button btnEx2 = (Button)findViewById(R.id.btnEx2);
    btnEx2.setOnClickListener(new View.OnClickListener(){
        public void onClick(View v) {
        Intent i = new Intent(ex1Activity.this, ex2Service.class);
        Log.v("click", "start");
        startService(i);
    }
});
Button btnEx3 = (Button)findViewById(R.id.btnEx3);
    btnEx3.setOnClickListener(new View.OnClickListener(){
        public void onClick(View v) {
        Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.unoh.net/"));)
        startActivity(i);
    }
});

// src/net.unoh.ex1.ex2Service.java
package net.unoh.ex1;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.widget.Toast;

public class ex2Service extends Service {
    @Override
    public IBinder onBind(Intent arg0) {
        return null;
    }
    @Override
    public void onStart(Intent intent, int startId) {
        Toast.makeText(this, "ex2Service", 500).show();
    }
}
</pre>

* AndroidManifest.xmlのapplication以下にserviceを追加
* res/values/string.xmlにボタンの表示名を設定
* res/layout/main.xmlにボタン追加
* ex1Activity.javaでボタンの設定
* サービスの実装(今回は起動するだけなのでonStartをオーバーライド。プロセス間通信する場合はonBindを実装)
* インテントの発行

h3. コンテンツプロバイダー

アプリケーションが所有するデータを他のアプリケーションに公開する仕組み
例えば電話アプリケーションが所有する通話履歴データを取得できたりします。

また、アプリケーションがデータを永続化する方法として次のものがあります
* プリファレンス
* ファイル
* SQLite

参考： "Content Provider入門":http://d.hatena.ne.jp/isher/20090613/1244932235
参考： "Android SharedPreferences について":http://www.taosoftware.co.jp/blog/2009/03/android_sharedpreferences_gets.html

h3. ネットワーク

もちろん普通にできます。
気をつける点は、デフォルトではセキュリティ上の問題で拒否されている為、許可するためにAndroidManifest.xmlのPermissionsの項目を記述しなければならない。

参考： "HTTP（DefaultHttpClient/HttpHost/HttpGet/HttpResponse/HttpEntity）":http://www.adakoda.com/adakoda/2009/01/android-httpdefaulthttpclienthttphosthttpgethttpresponsehttpentity.html
参考： "HT-03A その９":http://blogmrc.blog84.fc2.com/blog-entry-357.html

h3. tips

参考： "XmlPullParser（XML解析（パース））":http://www.adakoda.com/adakoda/2009/01/android-xmlpullparserxml.html
参考： "JSON形式のデータにアクセス":http://www.adakoda.com/adakoda/2009/01/android-json.html
参考： "AndroidでListView":http://d.hatena.ne.jp/CLSmooth/20090315
参考： "サーフェイスビュー":http://www.saturn.dti.ne.jp/~npaka/android/AnimeEx/index.html
参考： "OpenGL":http://www.saturn.dti.ne.jp/~npaka/android/OpenGL/index.html
参考： "Android 開発情報":http://www.taosoftware.co.jp/android/android.html
参考： "逆引きAndroid入門":http://www.adakoda.com/android/

ただでさえ消費電力が多いので省電力プログラミングがとても重要です

参考： "AndroidのappWidget作成時に行っておくべき消費電力対策についてのまとめ(その1)":http://d.hatena.ne.jp/TAKAOMAYA/20090803/1249303524

h2. アプリケーションの配信

h3. Androidマーケット

* 開発者登録に$25
* 承認プロセスがないので自由に公開できる
* 売り上げの7割が開発者へ、残りが通信会社と課金処理費用。

参考： "開発者登録するには":http://www.adakoda.com/android/000100.html

h3. 野良アプリ

* ブラウザでダウンロード
* SDK付属のadbコマンドを使用

h2. これから必要なこと

* iPhoneを手放す勇気


おしまい
]]>
        
    </content>
</entry>

<entry>
    <title>symfonyでモバイルサイトを作るときにやったこと</title>
    <link rel="alternate" type="text/html" href="http://labs.unoh.net/2009/09/symfony_3.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.unoh.net/mt32/mt-atom.cgi/weblog/blog_id=2/entry_id=1698" title="symfonyでモバイルサイトを作るときにやったこと" />
    <id>tag:labs.unoh.net,2009://2.1698</id>
    
    <published>2009-09-27T16:33:58Z</published>
    <updated>2009-09-27T17:55:35Z</updated>
    
    <summary>こんにちは。中村です。 symfonyを使ってモバイルサイトを作るときにやったことを思い出しながら少し紹介しようと思います。symfonyといってもバージョンは1.0系です。最新のsymfonyでは勝手が違うかもしれませんのでご了承ください。 docomoの場合はURLにセッションIDを埋め込む iモードブラウザ2.0ではないdocomo端末はCookieに対応していないため、セッションを利用する場合にはセッションIDをURLに埋め込む必要があります。これについては解決方法がいろいろありそうですが、私の場合、sfMySQLSessionStorageを利用しようとしたところ親クラスのsfSessionStorageがsession.use_cookiesの値でCookieを使うかどうかを決定していたため、initializeメソッドを継承して分岐を入れることにしました。iniの設定をUse...</summary>
    <author>
        <name>unoh</name>
        
    </author>
    
    <content type="html" xml:lang="ja" xml:base="http://labs.unoh.net/">
        <![CDATA[<p>こんにちは。中村です。</p>

<p>symfonyを使ってモバイルサイトを作るときにやったことを思い出しながら少し紹介しようと思います。symfonyといってもバージョンは1.0系です。最新のsymfonyでは勝手が違うかもしれませんのでご了承ください。</p>

<h3>docomoの場合はURLにセッションIDを埋め込む</h3>

<p>iモードブラウザ2.0ではないdocomo端末はCookieに対応していないため、セッションを利用する場合にはセッションIDをURLに埋め込む必要があります。これについては解決方法がいろいろありそうですが、私の場合、sfMySQLSessionStorageを利用しようとしたところ親クラスのsfSessionStorageがsession.use_cookiesの値でCookieを使うかどうかを決定していたため、initializeメソッドを継承して分岐を入れることにしました。iniの設定をUser-Agentで変更することに気が引けたためですが、iniの設定を切り替えた方が簡潔だったかもしれません。</p>

<p>URLには次のようなrouting.ymlに記載して、常にパスの最初にくるようにしています。</p>

<pre class="code">default_session:
  url: /:session_id/:module/:action/*
  param:
    module: module
    action: action
  requirements:
    session_id: ^[a-zA-Z0-9]{32}$</pre>

<p>あとは、link_toヘルパー内で自動的にセッションIDをURLに入れる（iモードブラウザ2.0ではないdocomo端末のみ）ようにすることで、開発する際に意識せずに済むようにしています。</p>

<h3>絵文字に対応</h3>

<p>変換は<a href="http://labs.unoh.net/2007/02/post_65.html">絵文字の相互変換リスト</a>に基づいてFilterで行っています。絵文字に関しては世の中的に出尽くしている感があるので割愛します。</p>

<h3>携帯特有のタグに対応したヘルパー関数を作る</h3>

<p>携帯特有のタグはまず間違いなくキャリアごとにバラバラです。当たり前なのですが、ヘルパー関数を作っておくと便利です。inputタグのistyle、位置情報取得時のタグ、各キャリアで同じ水平線にするのが大変難しいhrタグなど、ヘルパー関数を作成しています。</p>

<h3>アスキーアートの文字化け対策</h3>

<p>ユーザーが入力したアスキーアートが文字化けする、という現象があったのですが、これはsymfonyがエスケープにhtmlentitiesを利用しているためで、携帯で解釈できない文字参照がそのまま文字として表示されてしまうためでした。<a href="http://blog.symfony.jp/2009/03/05/178">escaping_methodのESC_ENTITIESには注意が必要</a>が参考になります。symfony側のコードを書き換えるのは極力避けたいところですが、この部分に関してはhtmlspecialcharsに変更して対応しています。</p>

<h3>メンテナンス時に確認端末を通す</h3>

<p>メンテナンス時に一般ユーザーにはメンテナンス画面を表示しておいて、登録した携帯のみはアクセスできるようにしておくと、メンテナンス後、公開するまでに動作確認を行えます。次のようなFilterを書いて携帯の端末IDを比較しています。app.ymlに記載がない場合は/top/maintenanceに飛ばしています。</p>

<pre class="code">&lt;?php
class myMaintenanceFilter extends sfFilter
{

    public function execute($filterChain)
    {   
        $maintenance = sfConfig::get('app_maintenance_enabled');
        if ($maintenance !== true) {
            $filterChain-&gt;execute();
        } else {
            $context = $this-&gt;getContext();
            if ($context-&gt;getModuleName() == 'top' &amp;&amp; ($context-&gt;getActionName() == 'maintenance')) {
                $filterChain-&gt;execute();
            } else {
                $mobiles = sfConfig::get('app_maintenance_mobiles', null);
                if (is_array($mobiles) &amp;&amp; in_array($context-&gt;getUser()-&gt;getMobileId(), $mobiles)) {
                    $filterChain-&gt;execute();
                } else {
                    $this-&gt;getContext()-&gt;getController()-&gt;redirect('/top/maintenance');
                }
            }
        }
    }   

}</pre>

<p>app.ymlは次のように記述しています。</p>

<pre class="code">all:
  maintenance:
    enabled: true
    mobiles:
      - xxxxxxxx
      - xxxxxxxx
      - xxxxxxxx</pre>


<h3>文字コードの変換</h3>

<p>表示はShift-JIS、内部は全てUTF-8に統一という構成だと、Shift-JISとUTF-8の変換を行わなければならないのですが、入力は自前でFilterを書いてmb_convert_encodingしています。</p>

<p>出力は</p>

<pre class="code">mb_http_output('SJIS-win');</pre>

<p>と設定してうまくいくかと思ったのですが、Content-Typeがapplication/xhtml+xml（docomoでCSSを使うために必要）にするとmb_http_outputは変換を行いません。仕方がないので、これまた自前で次のようなFilterを書いて対応しています。</p>

<pre class="code">&lt;?php
class myXhtmlFilter extends sfFilter
{

    public function execute($filterChain)
    {   
        $filterChain-&gt;execute();
        if ($this-&gt;getContext()-&gt;getUser()-&gt;isDoCoMo()) {
            $response = $this-&gt;getContext()-&gt;getResponse();
            $response-&gt;setHttpHeader('Content-Type', 'application/xhtml+xml; charset=Shift_JIS');
            $response-&gt;setContent(mb_convert_encoding($response-&gt;getContent(), 'SJIS-win', 'UTF-8'));
        }
    }   

}</pre>

<h3>最後に</h3>

<p>ばらばらとしたTipsになってしまいましたが、それほどトリッキーなことをしなくても、ポイントだけ対処できればモバイルサイト対応ができるので、symfonyによるモバイルサイト構築は1つの選択肢になると思います。</p>]]>
        
    </content>
</entry>

</feed> 

