<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>qui-no Labs</title>
	<atom:link href="http://labs.qui-no.com/feed" rel="self" type="application/rss+xml" />
	<link>http://labs.qui-no.com</link>
	<description>株式会社キノの技術メモやTIPSなどの情報</description>
	<lastBuildDate>Fri, 18 Jun 2010 10:32:33 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>ja</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>FTPをコマンドラインから便利に使う</title>
		<link>http://labs.qui-no.com/259</link>
		<comments>http://labs.qui-no.com/259#comments</comments>
		<pubDate>Fri, 18 Jun 2010 10:32:33 +0000</pubDate>
		<dc:creator>加藤 雄亮</dc:creator>
				<category><![CDATA[Linux]]></category>

		<guid isPermaLink="false">http://labs.qui-no.com/?p=259</guid>
		<description><![CDATA[
皆さん、プログラムのデプロイはどうしていますか？？

通常scpやrsync、その他のデプロイツールを使用すれば、簡単かつ確実に運用サーバにプログラムを配備することが出来ます。

しかし、利用するサーバによって、FTP [...]]]></description>
			<content:encoded><![CDATA[<p>
皆さん、プログラムのデプロイはどうしていますか？？<br />
<br />
通常scpやrsync、その他のデプロイツールを使用すれば、簡単かつ確実に運用サーバにプログラムを配備することが出来ます。<br />
<br />
しかし、利用するサーバによって、FTP接続しか出来ない場合があります。<br />
LinuxのFTPコマンドは非常に使い勝手が悪く、ディレクトリ配下を全てアップロードする等という事が出来ません。<br />
また、ソースコードをローカルにダウンロードしてFTPソフトウェアでアップロードする方法は効率が悪く、アップロードしたく無いファイル等は事前に削除するなど、非常にミスを誘発しそうな作業です。<br />
<br />
サーバ上のコマンド一発でFTPアップロードが出来たら、確実に便利です。<br />
<br />
今回は、サーバ間でFTPアップロードが出来るシェルスクリプトを作成してみました。<br />
<span id="more-259"></span><br />
<h3 class="title">NcFTP Clientをインストール</h3>
まず、NcFTPという通常のFTPコマンドより使い易いコマンドを利用します。<br />
※NcFTPは <a href="http://www.ncftp.com/download/" target="_blank">Download NcFTP Client</a> からインストールしてください。<br />
<br />
<strong>ソースコードからインストールする場合</strong><br />
<pre class="brush: bash;">
# ソースコードをダウンロードします。
[user@centos ~]$ wget ftp://ftp.ncftp.com/ncftp/ncftp-3.2.4-src.tar.gz

# tarボールを解凍します。
[user@centos ~]$ tar zxvf ncftp-3.2.4-src.tar.gz

# Makeして実行ファイルを生成します。
[user@centos ~]$ cd ncftp-3.2.4
[user@centos ncftp-3.2.4]$ ./configure
[user@centos ncftp-3.2.4]$ make

# インストールします。
# デフォルトで /usr/local/bin に配置されます。
[user@centos ncftp-3.2.4]$ make install
</pre>
<br />
<br />
<h3 class="title">FTPアップロード シェルスクリプト</h3>
このスクリプトは、expectという会話形式通信を自動的に行うことができるコマンドを利用します。<br />
rsyncの&#8211;exclude-fromオプションのように、アップロードしたくないリストを記述したファイルを外部で管理する事も出来ます。<br />
<br />
<strong>deploy.sh</strong><br />
<pre class="brush: bash;">
#!/bin/bash

#
# deploy.sh
#
# 使用方法    : ./deploy.sh
# 設定ファイル: deploy.exclude.txt (非アップロードファイルがある場合のみ)
#

## Config ------------------------------------------------------
FTP_HOST='ftp.xxxxx.co.jp'        # FTPホスト名
FTP_USER='username'               # FTPユーザー名
FTP_PASS='password'               # FTPパスワード

SRC_DIR='/home/user/appname/'     # アップロード元ローカルディレクトリ
DEST_DIR='/'                      # アップロード先FTPサーバのログインディレクトリ
EXCLUDE_FILE='deploy.exclude.txt' # 非アップロード設定ファイル

## Parse Exclude File -------------------------------------------
parse_exclude_file()
{
    if [ ! -f $EXCLUDE_FILE ]; then
        return
    fi

    echo '[ Exclude Pattern ]'

    local base_ifs=&quot;${IFS}&quot;
    IFS='
'
    local file=(`cat $EXCLUDE_FILE`)
    IFS=&quot;${base_ifs}&quot;

    local line
    for line in &quot;${file[@]}&quot;
    do
        if echo $line | grep -q '^#'; then
            continue
        fi
        if [ -z &quot;${line}&quot; ]; then
            continue
        fi

        line=`echo $line | awk '{print $1}'`
        echo $line

        line=`echo $line | \
              sed 's:\.:\\\.:' | \
              sed 's:\*:\.*:' | \
              sed 's:^/:\^/:'`

        if [ -n &quot;${EXCLUDE_PATTERN}&quot; ]; then
            line=&quot; ${line}&quot;
        fi

        EXCLUDE_PATTERN=&quot;${EXCLUDE_PATTERN}${line}&quot;
    done
    echo
}

## Create Deploy List ------------------------------------------
create_deploy_list()
{
    echo '[ Deploy Target File ]'

    local list=`find $SRC_DIR | \
                grep -v CVS | \
                grep -v .svn | \
                grep -v .git`

    local file target
    for file in $list
    do
        if [ -d $file ]; then
            file=&quot;${file}/&quot;
        fi

        target=`echo $file | sed &quot;s:${SRC_DIR}::&quot;`
        if [ -z &quot;${target}&quot; -o &quot;${target}&quot; = '/' ]; then
            continue
        fi

        if is_exclude $target; then
            continue
        fi

        echo $target
        echo $target &gt;&gt;$TEMP_FILE
    done
    echo
}

## Is Exclude ---------------------------------------------------
is_exclude()
{
    local target=$1

    local pattern
    for pattern in $EXCLUDE_PATTERN
    do
        if echo &quot;/${target}&quot; | grep -q $pattern; then
            return 0
        fi
    done

    return 1
}

## FTP Upload --------------------------------------------------
ftp_upload()
{
    local base_ifs=&quot;${IFS}&quot;
    IFS='
'
    local list=`cat $TEMP_FILE`
    IFS=&quot;${base_ifs}&quot;

    cd $SRC_DIR
    expect - &lt;&lt;EOF
        set timeout -1

        spawn ncftp -u $FTP_USER -p $FTP_PASS $FTP_HOST

        expect &quot;ncftp*&gt;&quot;
        send &quot;cd $DEST_DIR\r&quot;

        foreach file {$list} {
            expect &quot;ncftp*&gt;&quot;
            if {[regexp {.*\/\$} \$file]} {
                send &quot;mkdir \$file\r&quot;
            } else {
                send &quot;put -fz \$file \$file\r&quot;
            }
        }

        expect &quot;ncftp*&gt;&quot;
        send &quot;exit\r&quot;
EOF
    echo
}

## Clean -------------------------------------------------------
clean()
{
    if [ -f &quot;${TEMP_FILE}&quot; ]; then
        rm -f $TEMP_FILE
    fi
}

## Main --------------------------------------------------------
EXCLUDE_PATTERN=''
parse_exclude_file
if [ $? -ne 0 ]; then
    echo &quot;[Error] Failed to parse the '${EXCLUDE_FILE}'.&quot; &gt;&amp;2
    exit $?
fi

TEMP_FILE=`mktemp`
create_deploy_list
if [ $? -ne 0 ]; then
    echo '[Error] Failed to create the source list.' &gt;&amp;2
    clean
    exit $?
fi

echo -n &quot;Do you upload it? [y/n]: &quot;
read ANSWER
if [ &quot;${ANSWER}&quot; != 'y' ]; then
    echo 'Canceled the upload.'
    exit
fi

ftp_upload
if [ $? -ne 0 ]; then
    echo '[Error] Upload failed.' &gt;&amp;2
    clean
    exit $?
fi

clean
echo '----'
echo &quot;'${FTP_HOST}' deploy success!&quot;

</pre>
<br />
<br />
<strong>deploy.exclude.txt</strong><br />
<pre class="brush: bash;">
#
# deploy exclude
#
# 除外ファイルの設定（除外したいファイルがある場合のみ）
#   deploy.exclude.txtファイルに除外パターンを記述する
#   例）
#     *.txt       *.txt と一致する全てのファイル名を除外
#     /foo/       ルートにある foo ディレクトリを除外
#     bar/*.log   bar ディレクトリ内の *.log に一致するファイルを除外
#

# ルートにあるappディレクトリを除外
/app/  # コメントも書けます

# ログファイルを除外
*.log

</pre>
<br />
<br />
<h3 class="title">実行例</h3>
以下のようなディレクトリ構成があるとします。<br />
<pre>
app/
app/1.txt
src/
src/2.txt
var/
var/3.log
</pre>
<br />
deploy.sh を実行すると、src/、src/2.txt、var/ のみがアップロード対象となります。<br />
<pre class="brush: bash;">
[user@centos ~]$ ./deploy.sh  ← プログラムを実行

[ Exclude Pattern ]
/app/
*.log

[ Deploy Target File ]
src/
src/2.txt
var/

Do you upload it? [y/n]: y  ← アップロードするか質問されます。「y」と応答

... FTPアップロード
...
...
--
deploy success.

</pre>
<br />
ご利用のサーバ環境に合わせて設定を変更すれば、簡単にサーバ間のFTPアップロードが出来るので、参考にして頂ければと思います。<br />
</p>
]]></content:encoded>
			<wfw:commentRss>http://labs.qui-no.com/259/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>EC-CUBE用FeliCaログイン認証モジュール</title>
		<link>http://labs.qui-no.com/203</link>
		<comments>http://labs.qui-no.com/203#comments</comments>
		<pubDate>Wed, 14 Apr 2010 03:19:50 +0000</pubDate>
		<dc:creator>加藤 雄亮</dc:creator>
				<category><![CDATA[Flash/Flex]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://labs.qui-no.com/?p=203</guid>
		<description><![CDATA[
前回、Flash/AIR で FeliCa へアクセスでご紹介した通り、FlashからFeliCaを扱う事が出来るようになりました。
まだFeliCaの用途を試行錯誤している最中ですが、試しにECシステムのオープンソー [...]]]></description>
			<content:encoded><![CDATA[<p>
前回、<a href="http://labs.qui-no.com/191">Flash/AIR で FeliCa へアクセス</a>でご紹介した通り、FlashからFeliCaを扱う事が出来るようになりました。<br />
まだFeliCaの用途を試行錯誤している最中ですが、試しにECシステムのオープンソースであるEC-CUBEにFeliCaを使ってログインするモジュールを開発してみました。<br />
<br />
通常、MYページ等のログイン認証にはIDとパスワードを入力しますが、FeliCaが保持する固有のIDとパラメータを使用して、ID/PW以外のログイン方法を提供します。<br />
<br />
FeliCaのログイン画面が表示されたら、予め登録済みのFeliCaをタッチすることでログイン出来るという構成です。<br />
<span style="color: #800000;">※FeliCaログインを利用するには、PC内蔵の「FeliCaポート」や専用のリーダーが接続されている事、また<a href="http://www.sony.co.jp/Products/felica/pcrw/fsc_dl.html" target="_blank">FeliCaポートソフトウェア</a>がインストールされている必要があります。</span><br />
<div class="clearfix">
<div style="float: left;">
<h4>FeliCaログイン</h4>
<a href="http://labs.qui-no.com/uploads/felica_login1.jpg" target="_blank"><img class="alignnone size-medium wp-image-223" title="felica_login1" src="http://labs.qui-no.com/uploads/felica_login1-300x175.jpg" alt="FeliCaログイン" width="280" height="170" /></a><br />
<br />
</div>
<div style="float: right;">
<h4>MYページFeliCa登録</h4>
<a href="http://labs.qui-no.com/uploads/felica_login2.jpg" target="_blank"><img class="alignnone size-medium wp-image-224" title="felica_login2" src="http://labs.qui-no.com/uploads/felica_login2-300x175.jpg" alt="MYページFeliCa登録" width="280" height="170" /></a><br />
<br />
</div>
</div>
<span id="more-203"></span><br />
<h3 class="title">ダウンロード</h3>
<table class="table" border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<th>バージョン</th>
<th>日時</th>
<th>ファイル名</th>
<th>備考</th>
</tr>
<tr>
<td>1.0.0</td>
<td>2010/04/14</td>
<td><a onclick="_gaq.push(['_trackEvent', 'SourceCode', 'Download', 'FeliCaLogin-1.0.0.zip']);" href="http://labs.qui-no.com/uploads/FeliCaLogin-1.0.0.zip">zip</a> | <a onclick="_gaq.push(['_trackEvent', 'SourceCode', 'Download', 'FeliCaLogin-1.0.0.tar.gz']);" href="http://labs.qui-no.com/uploads/FeliCaLogin-1.0.0.tar.gz">tar.gz</a></td>
<td>EC-CUBE ver.2.4.3対応</td>
</tr>
</tbody>
</table>
<br />
<h3 class="title">導入方法</h3>
下記の構成ファイル一覧をコピーしてください。<br />
既にカスタマイズをされている場合は手動でのマージをお勧めします。<br />
<br />
<h3 class="title">構成ファイル一覧</h3>
<h4>追加ファイル</h4>
<pre>data/Smarty/templates/default/mypage/felica.tpl
data/Smarty/templates/default/mypage/felica_add.tpl
data/Smarty/templates/default/mypage/felica_login.tpl
data/class/pages/frontparts/LC_Page_FrontParts_FelicaLogin.php
data/class/pages/mypage/LC_Page_Mypage_Felica.php
data/class/pages/mypage/LC_Page_Mypage_FelicaAdd.php
data/class/pages/mypage/LC_Page_Mypage_FelicaLogin.php
html/frontparts/felica_login.php
html/mypage/felica.php
html/mypage/felica_add.php
html/mypage/felica_login.php
html/user_data/packages/default/img/mypage/felicaadd.gif
html/user_data/packages/default/img/mypage/felicaadd_on.gif
html/user_data/packages/default/img/mypage/felicaadd_title.jpg
html/user_data/packages/default/img/mypage/felicalogin_title.jpg
html/user_data/packages/default/img/mypage/navifelica.jpg
html/user_data/packages/default/img/mypage/navifelica_on.jpg
html/user_data/packages/default/img/mypage/subtitlefelica.gif
html/user_data/packages/default/js/swfobject.js
html/user_data/packages/default/swf/expressInstall.swf
html/user_data/packages/default/swf/felicaadd.swf
html/user_data/packages/default/swf/felicabloc.swf
</pre>
<h4>変更ファイル</h4>
<pre>data/Smarty/templates/default/bloc/login.tpl
data/Smarty/templates/default/mypage/login.tpl
data/Smarty/templates/default/mypage/navi.tpl
data/Smarty/templates/default/shopping/index.tpl
data/mtb_constants_init.php
html/install/sql/column_comment.sql
html/install/sql/create_table_mysql.sql
html/install/sql/create_table_pgsql.sql
html/install/sql/drop_table.sql
html/install/sql/insert_data.sql
html/install/sql/table_comment.sql
</pre>
<br />
<h3 class="title">変更箇所</h3>
変更ファイル内の変更箇所は下記のコメントが挿入されています。<br />
<h4>PHPファイル</h4>
<pre class="brush: plain;">
// start FeliCa認証
...
// end FeliCa認証
</pre>
<h4>TPLファイル</h4>
<pre class="brush: plain;">
&lt;!--{** start FeliCa認証 **}--&gt;
...
&lt;!--{** end FeliCa認証 **}--&gt;
</pre>
<h4>SQLファイル</h4>
<pre class="brush: plain;">
-- start FeliCa認証
...
-- enf FeliCa認証
</pre>
<br />
<h3 class="title">ライセンス</h3>
プログラム本体であるEC-CUBEのGPLライセンスに従います。<br />
GPLライセンス下でソースコードの改変、再配布を行えます。</p>
]]></content:encoded>
			<wfw:commentRss>http://labs.qui-no.com/203/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Flash/AIR で FeliCa へアクセス</title>
		<link>http://labs.qui-no.com/191</link>
		<comments>http://labs.qui-no.com/191#comments</comments>
		<pubDate>Mon, 05 Apr 2010 04:04:40 +0000</pubDate>
		<dc:creator>加藤 雄亮</dc:creator>
				<category><![CDATA[Flash/Flex]]></category>

		<guid isPermaLink="false">http://labs.qui-no.com/?p=191</guid>
		<description><![CDATA[
最近、ソニーが開発した非接触ICカード技術“FeliCa”への関心が高まっています。先日、SDK for FeliCa AIR/Flash というFlash/AIRからFeliCaを操作出来るSDKがリリースされました。このSDKには、Basic版（無償）とStandard版（有償）があり、機能が制限されていますが、簡単な動作確認であれば、Basic版で十分です。
SDK for FeliCa &#038; Adobe&#174; AIR&#174; / Adobe&#174; Flash&#174;

今回は新しくFlash Builber 4を使用してFlex4で簡単にサンプルを作成してみました。

FeliCaのIDmとPMmを読み取るサンプル
下記の動作には、FeliCaポート/パソリが接続されている事、またFeliCaポートソフトウェアがインストールされている必要があります。




swfobject.embedSWF('/uploads/FeliCaBasic.swf', 'FeliCaBasic', '300', '200', '10.0.0', null, {}, { menu: 'false', wmode: 'transparent' });

FeliCaサンプル


MXMLソースコード

&#60;?xml version=&#34;1.0&#34; encoding=&#34;utf-8&#34;?&#62;
&#60;s:Application xmlns:fx=&#34;http://ns.adobe.com/mxml/2009&#34; 
               xmlns:s=&#34;library://ns.adobe.com/flex/spark&#34; 
          [...]]]></description>
			<content:encoded><![CDATA[<p>
最近、ソニーが開発した非接触ICカード技術“FeliCa”への関心が高まっています。先日、SDK for FeliCa AIR/Flash というFlash/AIRからFeliCaを操作出来るSDKがリリースされました。このSDKには、Basic版（無償）とStandard版（有償）があり、機能が制限されていますが、簡単な動作確認であれば、Basic版で十分です。<br />
<a href="http://www.sony.co.jp/Products/felica/pdt/adb.html" target="_blank">SDK for FeliCa &#038; Adobe&reg; AIR&reg; / Adobe&reg; Flash&reg;</a><br />
<br />
今回は新しくFlash Builber 4を使用してFlex4で簡単にサンプルを作成してみました。<br />
<span id="more-191"></span><br />
<h3 class="title">FeliCaのIDmとPMmを読み取るサンプル</h3>
<span style="color: #800000;">下記の動作には、FeliCaポート/パソリが接続されている事、また<a href="http://www.sony.co.jp/Products/felica/pcrw/fsc_dl.html" target="_blank">FeliCaポートソフトウェア</a>がインストールされている必要があります。</span><br />
<br />
<div style="width: 300px; border: 1px solid #cccccc;">
<script src="/js/swfobject.js" type="text/javascript"></script>
<script type="text/javascript">
swfobject.embedSWF('/uploads/FeliCaBasic.swf', 'FeliCaBasic', '300', '200', '10.0.0', null, {}, { menu: 'false', wmode: 'transparent' });
</script>
<div id="FeliCaBasic">FeliCaサンプル</div>
</div>
<br />
<h3 class="title">MXMLソースコード</h3>
<pre class="brush: as3;">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;s:Application xmlns:fx=&quot;http://ns.adobe.com/mxml/2009&quot; 
               xmlns:s=&quot;library://ns.adobe.com/flex/spark&quot; 
               xmlns:mx=&quot;library://ns.adobe.com/flex/mx&quot; 
               minWidth=&quot;300&quot; minHeight=&quot;200&quot;&gt;
    &lt;s:TextArea id=&quot;textArea&quot; lineHeight=&quot;150%&quot; visible=&quot;false&quot;/&gt;
    &lt;s:Button id=&quot;button&quot; label=&quot;FeliCa読み込み開始&quot; click=&quot;{this._onButtonClick()}&quot;/&gt;
    &lt;fx:Script&gt;
        &lt;![CDATA[
            import com.sony.jp.felica.FeliCaCloseReaderWriterRequest;
            import com.sony.jp.felica.FeliCaCloseReaderWriterResponse;
            import com.sony.jp.felica.FeliCaControl;
            import com.sony.jp.felica.FeliCaOpenReaderWriterAutoRequest;
            import com.sony.jp.felica.FeliCaOpenReaderWriterAutoResponse;
            import com.sony.jp.felica.FeliCaPollingAndGetCardInformationRequest;
            import com.sony.jp.felica.FeliCaPollingAndGetCardInformationResponse;
            import com.sony.jp.felica.FeliCaSessionRequest;
            import com.sony.jp.felica.FeliCaSessionResponse;
            import com.sony.jp.felica.error.FeliCaAccessError;
            import com.sony.jp.felica.event.FeliCaStatusEvent;
            import com.sony.jp.felica.event.OpenStatusEvent;
            
            import mx.utils.ObjectUtil;
            
            /** FeliCaProxy ポート番号 */
            private static const FELICA_PORT:uint = 10250;
            /** FeliCaProxy 通信タイムアウト秒数 */
            private static const FELICA_TIMEOUT:uint = 10;
            
            /** FeliCaProxy と通信を行うクラス */
            private var _felica:FeliCaControl = new FeliCaControl();
            
            /** ポーリング用 Timer (500ミリ秒毎, 20回 = 5秒間) */
            private var _pollingTimer:Timer = new Timer(500, 10);
            
            private function _onButtonClick():void
            {
                this.textArea.width   = this.width;
                this.textArea.height  = this.height;
                this.textArea.visible = true;
                this.button.visible   = false;
                this._open();
            }
            
            private function _open():void
            {
                this._felica.responseTimeout = FELICA_TIMEOUT * 1000;
                this._felica.addEventListener(OpenStatusEvent.OPEN_COMPLETE, this._onOpenComplete);
                this._felica.addEventListener(OpenStatusEvent.OPEN_FAILURE,  this._onOpenFailure);
                this._felica.open(FELICA_PORT);
            }
            
            private function _close():void
            {
                if (this._pollingTimer.running) {
                    this._pollingTimer.reset();
                }
                if (!this._felica.close()) {
                    this._log('[ NG ] Disconnect FeliCa Proxy Error!');
                    this._close();
                    return;
                }
                this._log('[ OK ] Disconnect FeliCa Proxy.');
            }
            
            private function _onOpenComplete(event:OpenStatusEvent):void
            {
                this._log('[ OK ] Connect FeliCa Proxy.');
                this._felica.addEventListener(FeliCaStatusEvent.FELICA_ACCESS_COMPLETE, this._onFelicaAccessComplete);
                this._felica.addEventListener(FeliCaStatusEvent.FELICA_ACCESS_FAILURE,  this._onFelicaAccessFailure);
                this._lock();
            }
            
            private function _onOpenFailure(event:OpenStatusEvent):void
            {
                this._log('[ NG ] Open FeliCa Proxy Error!');
                this._log(ObjectUtil.toString(event));
            }
            
            private function _lock():void
            {
                var request:FeliCaSessionRequest = new FeliCaSessionRequest();
                request.type          = FeliCaSessionRequest.HOLD;
                request.lockTimeout   = 10;
                request.unlockTimeout = 30;
                this._felica.access(request);
            }
            
            private function _unlock():void
            {
                var request:FeliCaSessionRequest = new FeliCaSessionRequest();
                request.type = FeliCaSessionRequest.RELEASE;
                this._felica.access(request);
            }
            
            private function _polling():void
            {
                if (!this._pollingTimer.hasEventListener(TimerEvent.TIMER)) {
                    this._onPollingTimer();
                }
                this._pollingTimer.addEventListener(TimerEvent.TIMER,          this._onPollingTimer);
                this._pollingTimer.addEventListener(TimerEvent.TIMER_COMPLETE, this._onPollingTimerComplete);
                this._pollingTimer.start();
            }
            
            private function _onPollingTimer(event:TimerEvent = null):void
            {
                this._log('Polling ...');
                var request:FeliCaPollingAndGetCardInformationRequest = new FeliCaPollingAndGetCardInformationRequest();
                request.systemCode = 'FFFF';
                this._felica.access(request);
            }
            
            private function _onPollingTimerComplete(event:TimerEvent):void
            {
                this._log('[ OK ] Stop Polling.');
                this._close();
            }
            
            private function _onFelicaAccessComplete(event:FeliCaStatusEvent):void
            {
                if (event.object is FeliCaSessionResponse) {
                    var session:FeliCaSessionResponse = event.object as FeliCaSessionResponse;
                    if (session.type == FeliCaSessionResponse.HOLD) {
                        this._log('[ OK ] FeliCa Session Hold.');
                        this._felica.access(new FeliCaOpenReaderWriterAutoRequest());
                    } else if (session.type == FeliCaSessionResponse.RELEASE) {
                        this._log('[ OK ] FeliCa Session Release.');
                        this._close();
                    }
                } else if (event.object is FeliCaOpenReaderWriterAutoResponse) {
                    this._log('[ OK ] Start Polling.');
                    this._polling();
                } else if (event.object is FeliCaPollingAndGetCardInformationResponse) {
                    this._log('[ OK ] Open FeliCa Reader/Writer.');
                    if (this._pollingTimer.running) {
                        this._pollingTimer.reset();
                    }
                    var pgcResponse:FeliCaPollingAndGetCardInformationResponse = event.object as FeliCaPollingAndGetCardInformationResponse;
                    this._log('\nIDm: ' + pgcResponse.idm);
                    this._log('PMm: ' + pgcResponse.pmm + &quot;\n&quot;);
                    this._felica.access(new FeliCaCloseReaderWriterRequest());
                } else if (event.object is FeliCaCloseReaderWriterResponse) {
                    this._log('[ OK ] Close FeliCa Reader/Writer.');
                    this._unlock();
                }
            }
            
            private function _onFelicaAccessFailure(event:FeliCaStatusEvent):void
            {
                if (event.object is FeliCaAccessError) {
                    var feliCaAccessError:FeliCaAccessError = event.object as FeliCaAccessError;
                    if (feliCaAccessError.rwError == 157) {  // Error Code: No FeliCa
                        return;
                    }
                }
                if (event.object is Error) {
                    var error:Error = event.object as Error;
                    if (error.errorID == 7011) {
                        this._log('[ NG ] FeliCa Proxy Timeout Error!');
                    }
                }
                this._log('[ NG ] FeliCa Access Error!');
                this._log(ObjectUtil.toString(event));
                this._close();
            }
            
            private function _log(message:String):void
            {
                this.textArea.appendText(message + &quot;\n&quot;);
            }
        ]]&gt;
    &lt;/fx:Script&gt;
&lt;/s:Application&gt;
</pre>
<br />
<h3 class="title">ダウンロード</h3>
Flash Builder 4 プロジェクトダウンロード： <a href='http://labs.qui-no.com/uploads/FeliCaBasic.zip' onclick="_gaq.push(['_trackEvent', 'SourceCode', 'Download', 'FeliCaBasic.zip']);">FeliCaBasic.zip</a><br />
<br />
<br />
<br />
Standard版（有償）を利用すれば、データ領域にアクセス出来るため、様々な事に応用出来そうな気がします。また、読み取り側の普及次第となりますが、ECサイトの決済サービス等も増えてきそうな気がします。</p>
]]></content:encoded>
			<wfw:commentRss>http://labs.qui-no.com/191/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>PHPUnitでPrivateメソッドの単体テスト</title>
		<link>http://labs.qui-no.com/185</link>
		<comments>http://labs.qui-no.com/185#comments</comments>
		<pubDate>Thu, 18 Mar 2010 07:23:57 +0000</pubDate>
		<dc:creator>加藤 雄亮</dc:creator>
				<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://labs.qui-no.com/?p=185</guid>
		<description><![CDATA[
皆さん、単体テストしてますか？？
PHPで単体テストを実施する場合、私はPHPUnitを使用します。コーディングの時間が無く、テストを書けない時もありますが、出来ればTDD（テスト駆動開発）を実践したいですよね。

さ [...]]]></description>
			<content:encoded><![CDATA[<p>
皆さん、単体テストしてますか？？<br />
PHPで単体テストを実施する場合、私はPHPUnitを使用します。コーディングの時間が無く、テストを書けない時もありますが、出来ればTDD（テスト駆動開発）を実践したいですよね。<br />
<br />
さて、今回はPHPUnitでPrivateやProtectedなどのアクセス権を設定したメソッドのテストコードについてです。<br />
<br />
<a href="http://d.hatena.ne.jp/t_komura/20090808/1249748073" target="_blank">プライベートメソッドに対するテスト方法</a>で紹介されているような方法もあると思いますが、ここではもっと簡単なテスト方法をご紹介します。<br />
<span id="more-185"></span><br />
<h3 class="title">テスト対象のクラス</h3>
あまり良い例ではありませんが、ここでは単純にBMIを計算するBmiクラスを作成しました。PublicメソッドとProtectedメソッドの2つのメソッドが存在します。<br />
<pre class="brush: php;">
&lt;?php
class Bmi
{
    public function getBmi($height, $weight)
    {
        $height = $this-&gt;_convertHeight($height);

        return round($weight / ($height * $height), 1);
    }

    protected function _convertHeight($height)
    {
        return $height / 100;
    }
}
?&gt;
</pre>
<br />
<h3 class="title">テストを実施するクラス</h3>
通常のままだとProtectedメソッドのテストが行えないため、Bmiクラスを継承したBmiExtendedクラスを作成し、ProtectedメソッドをラップしたPublicメソッドを作成します。<br />
テストコード内では、Bmiクラスでは無く、BmiExtendedクラスを使用してテストを行います。<br />
<pre class="brush: php;">
&lt;?php
require_once 'PHPUnit/Framework.php';
require_once 'Bmi.php';

class BmiTest extends PHPUnit_Framework_TestCase
{
    protected $_bmi;

    protected function setUp()
    {
        $this-&gt;_bmi = new BmiExtended();
    }

    public function testGetBmi()
    {
        $this-&gt;assertEquals(24.2, $this-&gt;_bmi-&gt;getBmi(170, 70));
    }

    public function testConvertHeight()
    {
        $this-&gt;assertEquals(1.7, $this-&gt;_bmi-&gt;convertHeight(170));
    }
}

class BmiExtended extends Bmi
{
    public function convertHeight($height)
    {
        return parent::_convertHeight($height);
    }
}
?&gt;
</pre>
<br />
<h3 class="title">単体テスト実施</h3>
<pre class="brush: bash;">
[user@www ~]$ phpunit BmiTest.php
PHPUnit 3.4.11 by Sebastian Bergmann.

..

Time: 0 seconds, Memory: 3.50Mb

OK (2 tests, 2 assertions)
</pre>
<br />
このようにテストを実施するクラスのファイル内にテスト対象のサブクラスを作成すれば、簡単にPublicメソッド以外のアクセス権を持ったメソッドのテストが出来ます。<br />
<br />
テスト時にアクセス権を書き換えている場合や、不要なPublicメソッドを作成している場合、Publicメソッド内でPrivateメソッドの命令が網羅されているか不安な場合など、この方法なら簡単にテストを実施する事ができますので、お試しあれ。</p>
]]></content:encoded>
			<wfw:commentRss>http://labs.qui-no.com/185/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Redmine0.9.2の設定と運用</title>
		<link>http://labs.qui-no.com/170</link>
		<comments>http://labs.qui-no.com/170#comments</comments>
		<pubDate>Wed, 17 Feb 2010 06:21:51 +0000</pubDate>
		<dc:creator>加藤 雄亮</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://labs.qui-no.com/?p=170</guid>
		<description><![CDATA[
前回のエントリー「CentOSにRedmine0.9.2をインストール」で、とりあえずRedmineをインストールする事が出来ました。今回は、RedmineとApacheを連携させてバーチャルホストでの運用、またその他 [...]]]></description>
			<content:encoded><![CDATA[<p>
前回のエントリー「<a href="http://labs.qui-no.com/140">CentOSにRedmine0.9.2をインストール</a>」で、とりあえずRedmineをインストールする事が出来ました。今回は、RedmineとApacheを連携させてバーチャルホストでの運用、またその他の設定などをやってみたいと思います。<br />
<br />
<img src="http://labs.qui-no.com/uploads/redmine4.jpg" alt="" title="redmine4" width="420" height="111" class="alignnone size-full wp-image-182" />
<br />
※ここではRedmineと連携するHTTPサーバ（Apache）が構築済みという前提で進めていきます。<br />
<br />
<span id="more-170"></span><br />
<h3 class="title">Apacheとの連携</h3>
Apacheと連携するにはPassengerというRubyライブラリをインストールし、Apacheモジュール（mod_passenger.so）を作成します。<br />
参考：<a href="http://redmine.jp/tech_note/apache-passenger/" target="_blank">Apache上でRuby on Railsアプリケーションを動かす &#8211; Redmine.JP</a><br />
<pre class="brush: bash;">
# Passengerライブラリをインストールします。
[user@centos ~]$ gem install passenger --include-dependencies

# Apacheモジュールのビルドとインストールを行います。
# ビルドにはAPXSおよびAPRを必要とします。
[user@centos ~]$ passenger-install-apache2-module
...
Enterを押して進みます。

# 最後に設定内容が表示されます。
LoadModule passenger_module /usr/lib/ruby/gems/1.8/gems/passenger-2.2.9/ext/apache2/mod_passenger.so
PassengerRoot /usr/lib/ruby/gems/1.8/gems/passenger-2.2.9
PassengerRuby /usr/bin/ruby

&lt;VirtualHost *:80&gt;
  ServerName www.yourhost.com
  DocumentRoot /somewhere/public    # &lt;-- be sure to point to 'public'!
  &lt;Directory /somewhere/public&gt;
     AllowOverride all              # &lt;-- relax Apache security settings
     Options -MultiViews            # &lt;-- MultiViews must be turned off
  &lt;/Directory&gt;
&lt;/VirtualHost&gt;

# 完了
</pre>
<br />
ここではRedmineのインストール先を/usr/local/redmineにしたので、DocumentRootとDirectoryディレクティブのPATHを「/usr/local/redmine/public」に変更します。<br />
httpd.confにPassengerの設定とバーチャルホストの記述を追加してApacheを再起動します。<br />
<pre class="brush: bash;">
# Apacheを再起動します。
[user@centos ~]$ /etc/init.d/httpd restart
httpd を停止中:                                           [  OK  ]
httpd を起動中:                                           [  OK  ]

# 完了
</pre>
<br />
これで任意のバーチャルホストでRedmineを動作させる事が出来ます。<br />
<br />
<h3 class="title">RMagickのインストール</h3>
RedmineはオプションでRMagickを利用してグラフ等の画像を出力出来るので、RMagickをインストールしてみます。<br />
<pre class="brush: bash;">
# ImageMagickをインストールします。
[user@centos ~]$ yum install ImageMagick ImageMagick-devel
...
Installed:
  ImageMagick.i386 0:6.2.8.0-4.el5_1.1
  ImageMagick-devel.i386 0:6.2.8.0-4.el5_1.1

Complete!
# 完了
</pre>
<br />
続いてRMagickをインストールします。<br />
現時点ではyumでインストールできるImageMagickのバージョンが6.2.8なのでRMagick 2系のインストールは出来ません。1系の最終バージョン(v1.15.17)をインストールする事にします。<br />
<pre class="brush: bash;">
[user@centos ~]$ /usr/local/src

# RMagickがTrueTypeフォントを必要とするのでRPM版をインストールします。
[user@centos src]$ wget http://www.zacharywhitley.com/linux/rpms/fedora/core/6/i386/msttcorefonts-2.0-1.noarch.rpm
[user@centos src]$ rpm -ivh msttcorefonts-2.0-1.noarch.rpm

# TrueTypeという名称でシンボリックリンクを作成します。
[user@centos src]$ ln -s /usr/share/fonts/msttcorefonts /usr/share/fonts/default/TrueType

# RMagickをインストールします。
# -vオプションでバージョン（1.15.17）を指定します。
[user@centos ~]$ gem install rmagick -v 1.15.17 --include-dependencies
...
# 完了
</pre>
<br />
<h3 class="title">ログ設定</h3>
RedmineはデフォルトでINFOレベル以上のイベントがログファイルに記録されるようになっています。INFOレベル以上の設定だとアクセスする度に毎回ログが記録され、いつの間にか膨大なログが溜まっているという状況になります。<br />
運用する際はWARNレベル以上のイベントをログファイルに記録するようにします。<br />
<pre class="brush: bash;">
[user@centos ~]$ vi /usr/local/redmine/config/environments/production.rb
# 以下をログ関連の記述箇所に追記します。
config.logger = Logger.new(config.log_path)
config.logger.level = Logger::WARN

# 保存して完了
</pre>
<br />
さらに、ログローテーションの設定を行います。設定内容は任意ですが、「copytruncate」コマンドだけは最低限記述するようにしておきます。<br />
<pre class="brush: bash;">
# redmine用のログローテーション設定ファイルを新規作成します。
[user@centos ~]$ vi /etc/logrotate.d/redmine
/usr/local/redmine/log/*.log {
    missingok
    notifempty
    compress
    copytruncate
}

# 保存して完了
</pre>
<br />
<h3 class="title">その他の設定</h3>
Redmine.JPやRedmine.JP Blogで紹介されている記事の中でRedmineを使い易くするために実施しておくと良いものを挙げてみます。<br />
<ul>
    <li><a href="http://redmine.jp/faq/general/change-help-url-to-gude-ja/" target="_blank">ヘルプの日本語化</a></li>
    <li><a href="http://redmine.jp/faq/wiki/wiki_syntax_ja/" target="_blank">wikiのヘルプを日本語化</a></li>
    <li><a href="http://redmine.jp/faq/issue/send_reminders/" target="_blank">期限日が間近のチケットをメールで通知する</a></li>
    <li><a href="http://blog.redmine.jp/articles/redmine-0_9-url-to-fetch-changesets/" target="_blank">コミットと同時にリポジトリの情報を取得する</a></li>
</ul>
<br />
トラブル等がある場合は「<a href="http://redmine.jp/faq/" target="_blank">FAQ &#8211; Redmine.JP</a>」を見る解決するかもしれませんので参考にしてみてください。</p>
]]></content:encoded>
			<wfw:commentRss>http://labs.qui-no.com/170/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>CentOSにRedmine0.9.2をインストール</title>
		<link>http://labs.qui-no.com/140</link>
		<comments>http://labs.qui-no.com/140#comments</comments>
		<pubDate>Wed, 17 Feb 2010 03:58:53 +0000</pubDate>
		<dc:creator>加藤 雄亮</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://labs.qui-no.com/?p=140</guid>
		<description><![CDATA[
最近のプロジェクト管理ツールの中で人気が高いRedmineの最新版0.9.2をCentOS5.4へインストールしてみたいと思います。
Redmine0.9系ではプロジェクトの階層化やユーザー管理、通知等が改善され、さら [...]]]></description>
			<content:encoded><![CDATA[<p>
最近のプロジェクト管理ツールの中で人気が高いRedmineの最新版0.9.2をCentOS5.4へインストールしてみたいと思います。<br />
Redmine0.9系ではプロジェクトの階層化やユーザー管理、通知等が改善され、さらに使いやすくなっています。<br />
<a href="http://blog.redmine.jp/articles/redmine-0_9-improvements/" target="_blank">Redmine 0.9の変更点 &#8211; Redmine.JP Blog</a><br />
<br />
<img src="http://labs.qui-no.com/uploads/redmine1.jpg" alt="" title="redmine1" width="400" height="78" class="alignnone size-full wp-image-164" />
<br />
※ここではRedmineで利用するデータベースサーバ（MySQL、SQLite等）とメールサーバが構築済みという前提で進めていきます。<br />
<span id="more-140"></span><br />
<h3 class="title">1. 既存Rubyのアンインストール</h3>
Redmineが使用するRubyライブラリはRuby1.8.6以上のバージョンが必要になります。<br />
yumインストールされているRubyのバージョンが古い場合は、一旦アンインストールします。<br />
<pre class="brush: bash;">
# rubyがインストールされているか確認します。
[user@centos ~]$ yum list installed | grep ruby
ruby.i386                1.8.5-5.el5_4.8                installed
ruby-libs.i386           1.8.5-5.el5_4.8                installed

# yum removeコマンドは依存ファイルも全て削除されてしまう為
# rpm -e --nodepsコマンドでRubyのみをアンインストールします。
[user@centos ~]$ rpm -e --nodeps ruby ruby-libs

# rubyがアンインストールされているか確認します。
[user@centos ~]$ yum list installed | grep ruby

# 完了
</pre>
<br />
<h3 class="title">2. Rubyのインストール</h3>
Rubyの最新版1.9系だとRedmineでテンプレートエラーが発生してしまうため、1.8系の最終バージョンをRPMビルドしてインストールします。<br />
現時点ではruby-1.8.7-p249です。<br />
※最新版は<a href="http://www.ruby-lang.org/ja/downloads/" target="_blank">ダウンロードサイト</a>で確認してください。<br />
<pre class="brush: bash;">
[user@centos ~]$ cd /usr/local/src

# ソースコードをダウンロードします。
[user@centos src]$ wget ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.7-p249.tar.gz

# tarボールを解凍します。
[user@centos src]$ tar zxvf ruby-1.8.7-p249.tar.gz

# Makeして実行ファイルを生成します。
[user@centos src]$ cd ruby-1.8.7-p249
[user@centos ruby-1.8.7-p249]$ ./configure --prefix=/usr
[user@centos ruby-1.8.7-p249]$ make

# RPMパッケージングします。
# checkinstallは別途yum install checkinstall でインストールしてください。
[user@centos ruby-1.8.7-p249]$ checkinstall --fstrans=no
...
いくつか質問されますが、全て[Enter]で進めます。

以下のメッセージが表示されたら「R」を回答します。
Slackware [S], RPM [R] or Debian [D]? R　←　RPMを回答
...

**********************************************************************

 Done. The new package has been saved to

 /usr/src/redhat/RPMS/i386/ruby-1.8.7-p249-1.i386.rpm
 You can install it in your system anytime using:

      rpm -i ruby-1.8.7-p249-1.i386.rpm

**********************************************************************

# RPMパッケージをインストールします。
[user@centos ~]$ rpm -ivh /usr/src/redhat/RPMS/i386/ruby-1.8.7-p249-1.i386.rpm

# インストールされたRubyを確認します。
[user@centos ~]$ ruby -v
ruby 1.8.7 (patchlevel 249) [i686-linux]

# 完了
</pre>
<br />
<h3 class="title">3. RubyGemsのインストール</h3>
Rubyのパッケージ管理システムであるRubyGemsをインストールします。<br />
※最新版は<a href="http://rubyforge.org/frs/?group_id=126&amp;release_id=37073" target="_blank">ダウンロードサイト</a>で確認してください。<br />
<pre class="brush: bash;">
[user@centos ~]$ cd /usr/local/src

# ソースコードをダウンロードします。
[user@centos src]$ wget http://rubyforge.org/frs/download.php/60718/rubygems-1.3.5.tgz

# tarボールを解凍します。
[user@centos src]$ tar zxvf rubygems-1.3.5.tgz

# セットアップを実行します。
[user@centos src]$ ruby rubygems-1.3.5/setup.rb

# インストールされたRubyGemsを確認します。
[user@centos ~]$ gem -v
1.3.5

# 念のため最新版にアップデートします。
# 以降はこのコマンドで最新版にアップデートできます。
[user@centos ~]$ gem update --system
Updating RubyGems
Nothing to update

# 完了
</pre>
<br />
<h3 class="title">4. Rubyライブラリのインストール</h3>
Redmineが使用するフレームワークやその他のパッケージをインストールします。<br />
<br />
<strong>Railsフレームワーク</strong><br />
<pre class="brush: bash;">
[user@centos ~]$ gem install rails --include-dependencies
...
# しばらく時間がかかりますが、そのままにしておきます。
# 完了
</pre>
<br />
<strong>MySQL用のライブラリ</strong><br />
RedmineのデータベースにMySQLを使用します。<br />
SQLiteを使用する場合は「sqlite3-ruby」をインストールします。<br />
※テスト用途の場合はSQLite、運用ではMySQLを利用する方が良いです。<br />
<pre class="brush: bash;">
[user@centos ~]$ gem install mysql --include-dependencies
...
# 完了
</pre>
<br />
<h3 class="title">5. データベース作成</h3>
MySQLを利用する場合は、Redmine用のデータベースを作成します。<br />
ここでは、データベース（redmine）を作成し、専用ユーザー（redmine_user）にredmineデータベースの全ての操作権限を付与しておきます。<br />
<pre class="brush: bash;">
[user@centos ~]$ mysql -u root -p
*******　←　パスワード

# redmineデータベースを作成します。
mysql&gt; CREATE DATABASE `redmine` CHARACTER SET utf8;
Query OK, 1 row affected (0.00 sec)

# 作成したデータベースを確認します。
# ※データベース名は任意の値に変更してください。
mysql&gt; SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| redmine            |　←　作成したデータベース
+--------------------+
3 rows in set (0.01 sec)

# redmineデータベースを操作するユーザーを作成します。
# ユーザー名：redmine_user、パスワード：redmine_password
# ※ユーザー名、パスワードは任意の値に変更してください。
mysql&gt; GRANT ALL PRIVILEGES ON `redmine`.`*` TO 'redmine_user'@'localhost' IDENTIFIED BY 'redmine_password';
Query OK, 1 row affected (0.00 sec)

mysql&gt; \q

# 完了
</pre>
<br />
<h3 class="title">6. Redmineのインストール</h3>
Redmineは最新版の0.9.2をインストールします。<br />
※最新版は<a href="http://rubyforge.org/frs/?group_id=1850" target="_blank">ダウンロードサイト</a>で確認してください。<br />
<pre class="brush: bash;">
[user@centos ~]$ cd /usr/local/src

# ソースコードをダウンロードします。
[user@centos src]$ wget http://rubyforge.org/frs/download.php/69052/redmine-0.9.2.tar.gz

# tarボールを解凍します。
[user@centos src]$ tar zxvf redmine-0.9.2.tar.gz

# ソースコードを配置します。※場所は任意
# ここでは、/usr/local/redmine-0.9.2 にソースを配置し、
# /usr/local/redmine でアクセスできるようにシンボリックリンクを作成しておきます。
[user@centos src]$ mv redmine-0.9.2 /usr/local/
[user@centos src]$ ln -s /usr/local/redmine-0.9.2 /usr/local/redmine

# 完了
</pre>
<br />
<h3 class="title">7. Redmineの設定</h3>
<strong>データベースの環境設定</strong><br />
<pre class="brush: bash;">
# 設定ファイルを作成します。
[user@centos ~]$ mv /usr/local/redmine/config/database.yml.example \
/usr/local/redmine/config/database.yml

# データベース設定を編集します。
# 環境に応じて項目を変更します。
[user@centos ~]$ vi /usr/local/redmine/config/database.yml
# MySQLを使用する場合
production:
  adapter: mysql
  database: redmine　←　作成したデータベース名
  host: localhost
  username: redmine_user　←　作成したユーザー名
  password: redmine_password　←　作成したパスワード
  encoding: utf8

# SQLiteを使用する場合
production:
  adapter: sqlite3
  database: db/redmine.db

# 保存して完了
</pre>
<br />
<strong>メールの環境設定</strong><br />
<pre class="brush: bash;">
# 設定ファイルを作成します。
[user@centos ~]$ mv /usr/local/redmine/config/email.yml.example \
/usr/local/redmine/config/email.yml

# メール設定を編集します。
# 環境に応じて項目を変更します。
[user@centos ~]$ vi /usr/local/redmine/config/email.yml
production:
  delivery_method: :smtp
  smtp_settings:
    address: localhost　←　自サーバ内にメールサーバがある場合
    port: 25
    domain: example.net　←　ドメイン名
    #authentication: :login　　　　　　←認証が必要無い場合はコメントアウト
    #user_name: &quot;redmine@example.net&quot;　←認証が必要無い場合はコメントアウト
    #password: &quot;redmine&quot;　　　　　　　 ←認証が必要無い場合はコメントアウト

# 保存して完了
</pre>
<br />
<strong>環境設定</strong><br />
<pre class="brush: bash;">
# 30文字以上のランダム文字列を生成します。
# mkpasswdはexpectパッケージがインストールされている必要があります。
[user@centos ~]$ mkpasswd -l 30 -C 0 -s 0
hokmgzmqglnjes2pvkkxtdmpb2ynwr

# 設定ファイルを作成します。
[user@centos ~]$ mv /usr/local/redmine/config/additional_environment.rb.example \
config/additional_environment.rb

# 環境設定ファイルを編集します。
[user@centos ~]$ vi /usr/local/redmine/config/additional_environment.rb
# 以下を追加します。
# :secret の部分は生成したランダム文字列を記述します。
config.action_controller.session = { :key =&gt; &quot;_myapp_session&quot;, :secret =&gt; &quot;hokmgzmqglnjes2pvkkxtdmpb2ynwr&quot; }

# 保存して完了
</pre>
<br />
<h3 class="title">8. Redmineの初期化</h3>
データベースの初期化を行います。<br />
<pre class="brush: bash;">
[user@centos ~]$ (cd /usr/local/redmine; rake db:migrate RAILS_ENV=production)
(in /usr/local/redmine-0.9.2)
==  Setup: migrating ========================================================
...

# 完了
</pre>
<br />
<h3 class="title">9. Redmineの起動</h3>
<pre class="brush: bash;">
# サーバを起動します。
[user@centos ~]$ /usr/local/redmine/script/server -e production
=&gt; Booting WEBrick
=&gt; Rails 2.3.5 application starting on http://0.0.0.0:3000
=&gt; Call with -d to detach
=&gt; Ctrl-C to shutdown server
...

# サーバを終了する場合は Ctrl-C でシャットダウンします。
</pre>
<br />
デフォルトではポート番号3000番を使用してアクセスする事が出来ます。<br />
例：http://example.net:3000/<br />
<br />
初めてログインする場合は、以下でログインします。<br />
ログイン：admin<br />
パスワード：admin<br />
<a href="http://labs.qui-no.com/uploads/redmine2.jpg"><img class="alignnone size-medium wp-image-151" title="redmine2" src="http://labs.qui-no.com/uploads/redmine2-300x101.jpg" alt="" width="300" height="101" /></a><br />
<br />
ログイン後、右上の「My account」で言語を「Japanese（日本語）」に変更すると日本語のインターフェースになります。<br />
<a href="http://labs.qui-no.com/uploads/redmine3.jpg"><img class="alignnone size-medium wp-image-152" title="redmine3" src="http://labs.qui-no.com/uploads/redmine3-300x245.jpg" alt="" width="300" height="245" /></a><br />
<br />
とりあえずログイン後の設定として「管理」→「設定」で全体的な設定を行います。<br />
<ul>
	<li>「既定の言語」を「日本語」に。</li>
	<li>「送信元メールアドレス」を適宜変更。</li>
	<li>「認証が必要」を有効に。</li>
	<li>「ユーザは自分で登録できる」を無効に。</li>
</ul>
参考：<a href="http://redmine.jp/tech_note/install/" target="_blank">Redmineのインストール &#8211; Redmine.JP</a><br />
<br />
<br />
<br />
以上で、基本的なインストールが完了しました。<br />
次はApacheとの連携、運用などの設定をやりたいと思います。<br />
<a href="http://labs.qui-no.com/170">Redmine0.9.2の設定と運用</a></p>
]]></content:encoded>
			<wfw:commentRss>http://labs.qui-no.com/140/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Adobe Stratusを使用したFlash P2P通信について</title>
		<link>http://labs.qui-no.com/122</link>
		<comments>http://labs.qui-no.com/122#comments</comments>
		<pubDate>Mon, 01 Feb 2010 09:20:26 +0000</pubDate>
		<dc:creator>加藤 雄亮</dc:creator>
				<category><![CDATA[Flash/Flex]]></category>

		<guid isPermaLink="false">http://labs.qui-no.com/?p=122</guid>
		<description><![CDATA[
Adobe LabsにRTMFPプロトコルを扱う「Adobe Stratus」があります。現在はベータ版ですが、そろそろリリースが近いのではないかと思います。

RTMFP（Real-Time Media Flow P [...]]]></description>
			<content:encoded><![CDATA[<p>
Adobe LabsにRTMFPプロトコルを扱う「<a href="http://labs.adobe.com/technologies/stratus/" target="_blank">Adobe Stratus</a>」があります。現在はベータ版ですが、そろそろリリースが近いのではないかと思います。<br />
<br />
RTMFP（Real-Time Media Flow Protocol）は、簡単に言うとRTMPの機能限定版です。リアルタイムの映像と音声配信に特化したプロトコルと言えます。Flash Player 10.1とStratus 2.0を使用するとアプリケーションレベルでマルチキャストを使用出来きるそうです。サーバを介す必要がないため、負荷を軽減出来るメリットがあります。<br />
<br />
<img src="http://labs.qui-no.com/uploads/stratus1.png" alt="" title="stratus1" width="525" height="300" class="alignnone size-full wp-image-133" />
<br />
<span id="more-122"></span><br />
<strong>サンプルアプリケーション：</strong><br />
オンラインで公開されているサンプルアプリケーションもありますが、ローカルで動作させてみたい場合は、ソースコードが公開されているのでダウンロードして自由に試す事が出来ます。<br />
<br />
<a href="http://labs.adobe.com/technologies/stratus/samples/" target="_blank">Stratusオンラインサンプル</a><br />
<a href="http://download.macromedia.com/pub/labs/stratus/stratus_article_assets.zip" target="_blank">ソースコードダウンロード</a><br />
<br />
<img src="http://labs.qui-no.com/uploads/stratus2.png" alt="" title="stratus2" width="473" height="629" class="alignnone size-full wp-image-134" />
<br />
<br />
ソースコードを実行する場合は以下の手順が必要です。<br />
※要Flex Builder 3.0.2, Flash Player 10<br />
<br />
<strong>1. Flex Builderで「新規Flexプロジェクト」で「VideoPhoneLabs」プロジェクトを作成します。</strong><br />
<br />
<strong>2. 以下のソースコードを「VideoPhoneLabs/src/」下にコピーします。</strong><br />
　VideoPhoneLabs.mxml<br />
　AbstractIdManager.as<br />
　HttpIdManager.as<br />
　IdManagerError.as<br />
　IdManagerEvent.as<br />
<br />
<strong>3.「VideoPhoneLabs」プロジェクトのプロパティを変更</strong><br />
　「Flexコンパイラ」の「Flex SDK バージョン」を「Flex 3.2」へ変更<br />
　「Flexコンパイラ」の「必要な Flash Player バージョン」を「10.0.0」へ変更<br />
<br />
<strong>4. Stratusベータ版のDeveloper keyを取得します。</strong><br />
　<a href="https://www.adobe.com/cfusion/entitlement/index.cfm?e=stratus" target="_blank">Stratus developer key</a><br />
<br />
<strong>5. Developer keyを「VideoPhoneLabs.mxml」に記述します。</strong><br />
<pre class="brush: as3; first-line: 28;">
// developer key, please insert your developer key here
private const DeveloperKey:String = &quot;取得したDeveloper key&quot;;
</pre>
<br />
<strong>6. 同梱のPythonスクリプト「reg.cgi」が利用するSQLite3のデータベースを作成し、以下のSQLを実行します。</strong><br />
<pre class="brush: sql;">
CREATE TABLE registrations (
    m_username VARCHAR COLLATE NOCASE,
    m_identity VARCHAR,
    m_updatetime DATETIME,
    PRIMARY KEY (m_username)
);
CREATE INDEX registrations_updatetime ON registrations (m_updatetime ASC);
</pre>
<br />
<pre class="brush: bash;">
[user@www ~]$ sqlite3 registrations.db　# データベース作成
SQLite version 3.3.6
Enter &quot;.help&quot; for instructions

# テーブル作成
sqlite&gt; CREATE TABLE registrations (
   ...&gt;     m_username VARCHAR COLLATE NOCASE,
   ...&gt;     m_identity VARCHAR,
   ...&gt;     m_updatetime DATETIME,
   ...&gt;     PRIMARY KEY (m_username)
   ...&gt; );
sqlite&gt; CREATE INDEX registrations_updatetime ON registrations (m_updatetime ASC);

# 終了
sqlite&gt; .quit
</pre>
<br />
<strong>7.「reg.cgi」のデータベースファイルの場所を任意で変更します。</strong><br />
　※「reg.cgi」と「registrations.db」を同階層に設置する場合は以下<br />
<pre class="brush: python; first-line: 30;">
# CHANGE THIS
dbFile = './registrations.db'
</pre>
<br />
<strong>8.「reg.cgi」を任意の場所にアップロードし、URLを「VideoPhoneLabs.mxml」に記述します。</strong><br />
<pre class="brush: as3; first-line: 31;">
// please insert your webservice URL here for exchanging
private const WebServiceUrl:String = &quot;http://設置URL/reg.cgi&quot;;
</pre>
<br />
<strong>9.「VideoPhoneLabs」プロジェクトをコンパイルします。</strong><br />
<br />
<strong>10.「bin-release」ディレクトリに生成されたHTMLをWebサーバへアップロードして完了です。</strong><br />
</p>
]]></content:encoded>
			<wfw:commentRss>http://labs.qui-no.com/122/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>入力値の多言語翻訳について～最終回：まとめ～</title>
		<link>http://labs.qui-no.com/109</link>
		<comments>http://labs.qui-no.com/109#comments</comments>
		<pubDate>Tue, 26 Jan 2010 10:54:37 +0000</pubDate>
		<dc:creator>加藤 雄亮</dc:creator>
				<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://labs.qui-no.com/?p=109</guid>
		<description><![CDATA[



入力値の多言語翻訳について、現時点では機械翻訳の限界といった所でしょうか。単語レベルであれば、ほぼ問題無く翻訳が可能ですが、文章全体としては、ニュアンスが何とか伝わるといった程度です。また、専門用語など、翻訳しな [...]]]></description>
			<content:encoded><![CDATA[<p>
<img src="http://labs.qui-no.com/uploads/translation_image2.png" alt="" title="translation_image2.png" width="590" height="238" class="alignnone size-full wp-image-111" />
<br />
<br />
入力値の多言語翻訳について、現時点では機械翻訳の限界といった所でしょうか。単語レベルであれば、ほぼ問題無く翻訳が可能ですが、文章全体としては、ニュアンスが何とか伝わるといった程度です。また、専門用語など、翻訳しなくても良い単語まで翻訳されてしまい、その結果意味が不明になってしまう事があります。<br />
<br />
<span id="more-109"></span>さらに英語であれば、何とか翻訳結果が正しいのか判断出来そうですが、スペイン語、フランス語など、通常使用しない言語に対しては、専門家で無い限りデバッグ出来ないのが難点です。<br />
<br />
これから発展していく分野である事は間違い無いと思いますが、やはり現在翻訳サービスを展開している企業のAPIに頼るしかありません。もちろん高品質な翻訳結果を得ようとすれば料金が発生するかもしれません。<br />
<br />
インターネットは世界中に繋がっているとは言え、各国の人々とコミュニケーションが取れるのは極一部の人でしかありません。この言語問題を解決すれば、インターネットがさらに魅力的になりますね。<br />
<br />
関連エントリー：<br />
<a href="http://labs.qui-no.com/76">第2回：Zend FrameworkからGoogle Translation APIを使う</a><br />
<a href="http://labs.qui-no.com/50">第1回：構想</a><br />
</p>
]]></content:encoded>
			<wfw:commentRss>http://labs.qui-no.com/109/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>入力値の多言語翻訳について～第2回：Zend FrameworkからGoogle Translation APIを使う～</title>
		<link>http://labs.qui-no.com/76</link>
		<comments>http://labs.qui-no.com/76#comments</comments>
		<pubDate>Mon, 25 Jan 2010 10:49:51 +0000</pubDate>
		<dc:creator>加藤 雄亮</dc:creator>
				<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://labs.qui-no.com/?p=76</guid>
		<description><![CDATA[
弊社で使用しているPHPのZend FrameworkからGoogle Translation APIを使えるようにアダプタを作成してみました。Zend_Translate_Adapterを継承したサブクラスとして実装し、他のAdapterとの併用も可能です。

キャッシュ機構は実装していませんので、取得後に自由にキャッシュしてください。Google Translation APIのバッチインターフェースには未対応です。まだ改善の余地があるソースコードですが、とりあえず公開します。
※Zend Framework 1.9.7対応

参考：
Google Translate Adapter &#8211; ZF Snippets

使用方法：

&#60;?php

try {
    require_once 'Zend/Translate.php';
    require_once 'Quino/Translate/Adapter/Google.php';
    $translate = new Zend_Translate('Quino_Translate_Adapter_Google',
                          [...]]]></description>
			<content:encoded><![CDATA[<p>
弊社で使用しているPHPのZend FrameworkからGoogle Translation APIを使えるようにアダプタを作成してみました。Zend_Translate_Adapterを継承したサブクラスとして実装し、他のAdapterとの併用も可能です。<br />
<br />
キャッシュ機構は実装していませんので、取得後に自由にキャッシュしてください。Google Translation APIのバッチインターフェースには未対応です。まだ改善の余地があるソースコードですが、とりあえず公開します。<br />
※Zend Framework 1.9.7対応<br />
<br />
<span id="more-76"></span>参考：<br />
<a href="http://www.zfsnippets.com/snippets/view/id/35/google-translate-adapter" target="_blank">Google Translate Adapter &#8211; ZF Snippets</a><br />
<br />
<strong>使用方法：</strong><br />
<pre class="brush: php;">
&lt;?php

try {
    require_once 'Zend/Translate.php';
    require_once 'Quino/Translate/Adapter/Google.php';
    $translate = new Zend_Translate('Quino_Translate_Adapter_Google',
                                     null,
                                     'en',
                                     array('source' =&gt; 'ja'));
} catch (Exception $e) {
    // エラー処理
}

var_dump($translate-&gt;_('こんにちは！'));  // 出力：Hello!

?&gt;
</pre>
<br />
<br />
<strong>Google translate adapterクラス</strong><br />
<pre class="brush: php;">
&lt;?php

/** Zend_Http_Client */
require_once 'Zend/Http/Client.php';

/** Zend_Locale */
require_once 'Zend/Locale.php';

/** Zend_Translate_Adapter */
require_once 'Zend/Translate/Adapter.php';

/**
 * Google translate adapter
 *
 * @package Quino_Translate
 * @subpackage Adapter
 */
class Quino_Translate_Adapter_Google extends Zend_Translate_Adapter
{
    /**
     * Translate language api url
     *
     * @var string
     */
    private $_uri = 'http://ajax.googleapis.com/ajax/services/language/translate';

    /**
     * Api version string
     *
     * @var string
     */
    private $_apiversion = '1.0';

    /**
     * Generates the adapter
     *
     * @param  array               $data     Translation data
     * @param  string|Zend_Locale  $locale   OPTIONAL Locale/Language to set, identical with locale identifier,
     *                                       see Zend_Locale for more information
     * @param  array               $options  OPTIONAL Options to set
     */
    public function __construct($data, $locale = null, array $options = array())
    {
        parent::__construct($data, $locale, $options);
    }

    /**
     * Load translation data
     *
     * @param  string|array  $data
     * @param  string        $locale  Locale/Language to add data for, identical with locale identifier,
     *                                see Zend_Locale for more information
     * @param  array         $options OPTIONAL Options to use
     * @return array
     */
    protected function _loadTranslationData($data, $locale, array $options = array())
    {
		$options = $options + $this-&gt;_options;
		if (($options['clear'] === true) ||  !isset($this-&gt;_translate[$locale])) {
			$this-&gt;_translate[$locale] = array();
		}

		$this-&gt;_translate[$locale] = (array) $data + $this-&gt;_translate[$locale] + array($locale);

		return array();
    }

    /**
     * Translates the given string
     * returns the translation
     *
     * @see Zend_Locale
     * @param  string|array       $messageId Translation string, or Array for plural translations
     * @param  string|Zend_Locale $locale    (optional) Locale/Language to use, identical with
     *                                       locale identifier, @see Zend_Locale for more information
     * @return string
     */
    public function translate($messageId, $locale = null)
    {
        if (is_null($locale)) {
            $locale = $this-&gt;_options['locale'];
        }

        try {
            $locale = Zend_Locale::findLocale($locale);
        } catch (Zend_Locale_Exception $e) {
            // language does not exist, return original string
            return $messageId;
        }
        $locale = new Zend_Locale($locale);
        $locale = $locale-&gt;getLanguage();

        $source = null;
        if (isset($this-&gt;_options['source'])) {
            try {
                $source = Zend_Locale::findLocale($this-&gt;_options['source']);
            } catch (Zend_Locale_Exception $e) {
                $source = null;
            }
            if (!is_null($source)) {
                $source = new Zend_Locale($source);
                $source = $source-&gt;getLanguage();
            }
        }

        if ($source == $locale) {
            // return original string
            return $messageId;
        }

        $client = new Zend_Http_Client();
        $client-&gt;setUri($this-&gt;_uri);
        $client-&gt;setConfig(array(
            'maxredirects' =&gt; 0,
            'timeout'      =&gt; 30,
            'useragent'    =&gt; null,
        ));

        $client-&gt;setParameterGet(array(
            'v'        =&gt; $this-&gt;_apiversion,
            'q'        =&gt; $messageId,
            'langpair' =&gt; $source . '|' . $locale,
        ));

        $response = $client-&gt;request();
        if ($response-&gt;getStatus() !== 200) {
            require_once 'Zend/Translate/Exception.php';
            throw new Zend_Translate_Exception('Translate failed to load, got response code ' . $response-&gt;getStatus());
        }

        $data = json_decode($response-&gt;getBody());
        if ($data-&gt;responseStatus !== 200) {
            require_once 'Zend/Translate/Exception.php';
            throw new Zend_Translate_Exception('Google translate api error message is &quot;' . $data-&gt;responseDetails . '&quot;');
        }

        return $data-&gt;responseData-&gt;translatedText;
    }

    /**
     * returns the adapters name
     *
     * @return string
     */
    public function toString()
    {
        return 'Google';
    }
}

?&gt;
</pre></p>
]]></content:encoded>
			<wfw:commentRss>http://labs.qui-no.com/76/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>入力値の多言語翻訳について～第1回：構想～</title>
		<link>http://labs.qui-no.com/50</link>
		<comments>http://labs.qui-no.com/50#comments</comments>
		<pubDate>Mon, 25 Jan 2010 10:15:05 +0000</pubDate>
		<dc:creator>加藤 雄亮</dc:creator>
				<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://labs.qui-no.com/?p=50</guid>
		<description><![CDATA[
Webサービスを世界的に展開しようとすると、動的な多言語対応が必要となります。現在、UIの多言語表示は、gettext等の形式で予め翻訳データを保持しておき、言語にあわせて表示するという方法がありますが、ユーザーの入力 [...]]]></description>
			<content:encoded><![CDATA[<p>
Webサービスを世界的に展開しようとすると、動的な多言語対応が必要となります。現在、UIの多言語表示は、gettext等の形式で予め翻訳データを保持しておき、言語にあわせて表示するという方法がありますが、ユーザーの入力値に対する翻訳機能は考慮されていません。<br />
<br />
SNSやQ&amp;A、掲示板などユーザーの投稿内容が主なコンテンツとなるサービスの場合は、入力値を翻訳出来たら使い易い事は間違いありません。<br />
<br />
例えば、自分は日本語で入力し、英語圏の人が閲覧する時は「日本語の内容を英語に翻訳して表示する」という事です。<br />
<br />
<span id="more-50"></span>自前で翻訳データを用意する事はほぼ不可能に近いので、より多くの言語に対応した<a href="http://code.google.com/intl/ja/apis/ajaxlanguage/" target="_blank">Google Translation API</a>を利用し、何とか出来ないか、という試みです。<br />
<br />
Google Translation APIは基本的に、AJAX用のAPIとなっていますが、リクエスト毎に毎回APIをコールして翻訳データを取得するのは効率が悪いので、翻訳データをキャッシュ出来るように、AJAX以外からの<a href="http://code.google.com/intl/ja/apis/ajaxlanguage/documentation/#fonje" target="_blank">RESTful形式</a>で取得を行い、翻訳データをキャッシュする事が現実的だと思います。<br />
<br />
<img class="alignnone size-full wp-image-53" title="translation_image.png" src="http://labs.qui-no.com/uploads/translation_image.png" alt="翻訳イメージ" width="590" height="450" />
<br />
現在、Google Translation APIでの翻訳は、まだ発展途上であり正確な翻訳データを得る事は難しいですが、Googleの事ですから近い将来にはさらに精度が上がっている事でしょう。<br />
<br />
まだ構想レベルの話ですが、入力値の翻訳が可能となれば、外国語を知らなくても母国語のみで多くの国の人々とのコミュニケーションが可能となります。Webアプリケーションだけで無く、メール等も母国語で送信し、受信側の言語に翻訳して表示するなど、全てのシステムにおける中心的な技術となるのではないでしょうか。<br />
</p>
]]></content:encoded>
			<wfw:commentRss>http://labs.qui-no.com/50/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>FlashでWebカムからQRコードを読み取る</title>
		<link>http://labs.qui-no.com/18</link>
		<comments>http://labs.qui-no.com/18#comments</comments>
		<pubDate>Fri, 22 Jan 2010 10:31:28 +0000</pubDate>
		<dc:creator>加藤 雄亮</dc:creator>
				<category><![CDATA[Flash/Flex]]></category>

		<guid isPermaLink="false">http://labs.qui-no.com/?p=18</guid>
		<description><![CDATA[
以前、社内でQRコードを使用したサービスを検討していた際、FlashでWebカメラを使用してQRコードを読み取る技術が公開されていたのでご紹介します。

ソースコードはSpark Project内のQRCodeRead [...]]]></description>
			<content:encoded><![CDATA[<p>
以前、社内でQRコードを使用したサービスを検討していた際、FlashでWebカメラを使用してQRコードを読み取る技術が公開されていたのでご紹介します。<br />
<br />
ソースコードはSpark Project内のQRCodeReaderプロジェクトとして公開されていて、誰でもサンプルを使用する事が出来ます。<br />
<br />
<span id="more-18"></span>資料：<br />
<a href="http://labs.logosware.com/archives/65" target="_blank">FlashでQRコード読み取り &#8211; ロゴスウェア株式会社</a><br />
<a href="http://www.adobe.com/jp/devnet/flash/articles/qr_code_reader.html" target="_blank">ActionScriptでQRコードを読み取る &#8211; Flashデベロッパーセンター</a><br />
<br />
ソースコード：<br />
<a href="http://www.libspark.org/wiki/QRCodeReader" target="_blank">QRCodeReader &#8211; Spark Project</a><br />
<br />
以下はサンプルコードをパブリッシュして生成したswfファイルです。<br />
<span style="color: #800000;">※このサンプルはWebカメラを使用します。Webカメラが利用出来ない場合はサンプルは動作しません。</span><br />
<div style="width: 350px; border: 1px solid #cccccc;">
<script src="/js/swfobject.js" type="text/javascript"></script>
<script type="text/javascript">
swfobject.embedSWF('/uploads/ReadQrCodeSample1.swf', 'readQrCodeSample', '350', '350', '9.0.124', null, {}, { menu: 'false', wmode: 'transparent' });
</script>
<div id="readQrCodeSample">QRコードサンプル</div>
</div>
<br />
WebカメラにQRコードを近づけると、文字が読み取れます。作者の方曰く、まだ改良の余地があるそうですが、とりあえずは使用できます。<br />
<br />
Flashで動作するという事は、Adobe AIRでデスクトップアプリケーションとして動作させる事も可能です。なにか新しいサービスが出来そうな予感がします。<br />
<br />
サンプルswfファイルダウンロード： <a href='http://labs.qui-no.com/uploads/ReadQrCodeSample.zip' onclick="_gaq.push(['_trackEvent', 'SourceCode', 'Download', 'ReadQrCodeSample.zip']);">ReadQrCodeSample.zip</a></p>
]]></content:encoded>
			<wfw:commentRss>http://labs.qui-no.com/18/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
