<?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>BPS株式会社 開発ブログ Beyond Perspective Solutions LTD. &#187; プログラミング言語</title>
	<atom:link href="http://www.bpsinc.jp/blog/archives/category/programming-language/feed" rel="self" type="application/rss+xml" />
	<link>http://www.bpsinc.jp/blog</link>
	<description>BPS株式会社（Beyond Perspective Solutions）のプログラマによる技術・開発などに関してのブログです</description>
	<lastBuildDate>Wed, 20 Jul 2011 08:14:42 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.5</generator>
	<language>ja</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>ZeroClipboardを使っていて、IEでのみ「未知の実行時エラーです」が発生する場合</title>
		<link>http://www.bpsinc.jp/blog/archives/2320</link>
		<comments>http://www.bpsinc.jp/blog/archives/2320#comments</comments>
		<pubDate>Sat, 11 Sep 2010 00:08:40 +0000</pubDate>
		<dc:creator>baba</dc:creator>
				<category><![CDATA[javascript]]></category>
		<category><![CDATA[馬場]]></category>
		<category><![CDATA[Flash]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[エラー]]></category>

		<guid isPermaLink="false">http://www.bpsinc.jp/blog/?p=2320</guid>
		<description><![CDATA[Webを作っていて、「このタグをコピー」ボタンはよく作ります。
HTML/JavaScriptのみでは、IE以外のブラウザでクリップボードにコピーする機能は対応できないため、基本的にFlashを使うことになります。
それ [...]]]></description>
			<content:encoded><![CDATA[<p>Webを作っていて、「このタグをコピー」ボタンはよく作ります。</p>
<p>HTML/JavaScriptのみでは、IE以外のブラウザでクリップボードにコピーする機能は対応できないため、基本的にFlashを使うことになります。<br />
それを簡単に実現できるライブラリが、<a href="http://code.google.com/p/zeroclipboard/">ZeroClipboard</a>です。</p>
<p>使い方は簡単。$関数を作っておき、onloadのタイミングでZeroClipboard.Clientオブジェクトを初期化・設定するだけです。</p>
<pre class="brush:html">
&#60;html&#62;
&#60;head&#62;
&#60;script type="text/javascript"&#62;
function $(id) { return document.getElementById(id); }
function init() {
  clip = new ZeroClipboard.Client();
  clip.setHandCursor(true);
  clip.setText('コピーして欲しい文字列');
  clip.blue('button', 'container');
}
&#60;/script&#62;
&#60;/head&#62;
&#60;body onload="init();"&#62;
  &#60;div id="container"&#62;
    &#60;img id="button" src="button.png" /&#62;
  &#60;/div&#62;
&#60;/body&#62;
</pre>
<p>ところが、HTMLを間違えると、IEでのみ「未知の実行時エラーです」となり、動作しないことがあります。<br />
（Firefox/Chrome/Operaなどでは動作します）<br />
<div id="attachment_2321" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.bpsinc.jp/blog/wp-content/uploads/2010/09/error.png"><img src="http://www.bpsinc.jp/blog/wp-content/uploads/2010/09/error-300x58.png" alt="未知の実行時エラーです" title="error" width="300" height="58" class="size-medium wp-image-2321" /></a><p class="wp-caption-text">未知の実行時エラーです</p></div></p>
<p>これは、glue()の第2引数として渡すcontainer要素が、pタグなどになっている場合に発生します。<br />
ZeroClipboardは、内部的にembedタグを生成し、Flashを埋め込んでいるのですが、HTMLの仕様上pのなかにembedは入りません（詳細はDTD参照）。</p>
<p>そのため、HTMLとしては一見Validに見える以下のHTMLでも、</p>
<pre class="brush:html">
  &#60;p id="container"&#62;
    &#60;img id="button" src="button.png" /&#62;
  &#60;/p&#62;
</pre>
<p>glue(&#8217;button&#8217;, &#8216;container&#8217;); とやった時点（InnerHTMLが編集される）で、IEのみ厳密なチェックが入るため、エラーになります。</p>
<p>対策として、container要素は必ずdivなどのembedを含める要素にしましょう。</p>
<p>また当然ですが、内部で$()関数を使うため、jQueryやprototypeとの併用には注意が必要です。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bpsinc.jp/blog/archives/2320/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CakePHP Containableビヘイビア</title>
		<link>http://www.bpsinc.jp/blog/archives/2299</link>
		<comments>http://www.bpsinc.jp/blog/archives/2299#comments</comments>
		<pubDate>Thu, 02 Sep 2010 08:49:08 +0000</pubDate>
		<dc:creator>shibachan</dc:creator>
				<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[芝原]]></category>
		<category><![CDATA[Behavior]]></category>
		<category><![CDATA[Containable]]></category>

		<guid isPermaLink="false">http://www.bpsinc.jp/blog/?p=2299</guid>
		<description><![CDATA[Containableビヘイビアをご存知でしょうか？
もし、使用していならばこれを機にぜひ導入してみてください。
公式ページによると
ContainableBehavior は CakePHP のコアの新機能です。このビ [...]]]></description>
			<content:encoded><![CDATA[<p>Containableビヘイビアをご存知でしょうか？<br />
もし、使用していならばこれを機にぜひ導入してみてください。</p>
<p><a href="http://book.cakephp.org/ja/view/474/Containable">公式ページ</a>によると</p>
<blockquote><p>ContainableBehavior は CakePHP のコアの新機能です。このビヘイビアは find を実行するときに関連したモデルを選別したり限定したりするために使用します。コンテイナブル(<em>Containable</em>)は、データベース中の不要なものを削減し、アプリケーションの速度やパフォーマンスを改善します。このクラスを使うと、ユーザに対するデータの検索とフィルタを、美しく一貫した方法で行うこともできます。</p></blockquote>
<p>と、魅力的に説明されています。</p>
<p>使用方法や動作は、公式ページをみるのが手っ取り早いので割愛しますm(_ _)m<br />
#ググってください</p>
<p>このビヘイビアのメリットはたくさんあるのですが、<br />
特に便利だと思う点が</p>
<ul>
<li> recursiveやbindModelやunbindModelの記述がなくなって、<strong>ソースコードがきれいでわかりやすくなる</strong></li>
<li> あとで関連を選別できるからモデルの<strong>関連をモリモリの最大</strong>で書いておくことができる</li>
</ul>
<p>の２点で、とにかく便利です。</p>
<p>さらに以下のサンプルのようにモデルのrecursiveのデフォルト値を-1としておけば、<br />
何をcontainすればいいのか、しているのかがソースコードからわかりやすくなってお勧めです。</p>
<pre class="brush:php">class UserModel extends AppModel {

    public $recursive = -1;
    public $actsAs = array('Containable');
}</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.bpsinc.jp/blog/archives/2299/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JQuery UI Tabsでタブ表示</title>
		<link>http://www.bpsinc.jp/blog/archives/2289</link>
		<comments>http://www.bpsinc.jp/blog/archives/2289#comments</comments>
		<pubDate>Fri, 27 Aug 2010 09:34:48 +0000</pubDate>
		<dc:creator>shibachan</dc:creator>
				<category><![CDATA[HTML]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[Tabs]]></category>
		<category><![CDATA[UI]]></category>

		<guid isPermaLink="false">http://www.bpsinc.jp/blog/?p=2289</guid>
		<description><![CDATA[こんにちわ芝原です。
始めてのJavascript関連の投稿です。
お手柔らかにどうぞ。
たくさんのコンテンツをすっきり表示させるための方法として、タブという手法がよくつかわれると思います。
今回は、この便利なタブ表示を [...]]]></description>
			<content:encoded><![CDATA[<p>こんにちわ芝原です。</p>
<p>始めてのJavascript関連の投稿です。<br />
お手柔らかにどうぞ。</p>
<p>たくさんのコンテンツをすっきり表示させるための方法として、タブという手法がよくつかわれると思います。<br />
今回は、この便利なタブ表示をJQueryを使って実現する方法を解説します。<br />
動作はこんな感じになります。<br />
<a href="http://jqueryui.com/demos/tabs/default.html">http://jqueryui.com/demos/tabs/default.html</a></p>
<h3>必要なファイルのダウンロード</h3>
<p>jquery本体とui.core.js、ui.tabs.jsが必要です。</p>
<p><a href="http://jqueryui.com/download/jquery-ui-1.8.4.custom.zip">こちら</a>から簡単にダウンロードできますが余計なファイルも多分に入っているので、<a href="http://jqueryui.com/download">こちら</a>からファイルを選択してダウンロードしてもいいと思います。</p>
<h3>スクリプトの読み込み</h3>
<p>必要なファイルを読み込みます。<br />
head内に記述するのが一般的です。</p>
<pre class="brush:html">&#60;script type="text/javascript" src="/path/to/jquery.js"&#62;&#60;/script&#62;
&#60;script type="text/javascript" src="/path/to/ui.core.js"&#62;&#60;/script&#62;
&#60;script type="text/javascript" src="/path/to/ui.tabs.js"&#62;&#60;/script&#62;</pre>
<h3>HTMLの構造</h3>
<pre class="brush:html">&#60;div id="tabs"&#62;
    &#60;ul&#62;
        &#60;li&#62;&#60;a href="#tab1"&#62;タブに表示する文字&#60;/a&#62;&#60;/li&#62;
        &#60;li&#62;&#60;a href="#tab1"&#62;タブに表示する文字&#60;/a&#62;&#60;/li&#62;
        &#60;li&#62;&#60;a href="#tab3"&#62;タブに表示する文字&#60;/a&#62;&#60;/li&#62;
    &#60;/ul&#62;
    &#60;div id="tab1"&#62;
        タブの中身
    &#60;/div&#62;
    &#60;div id="tab2"&#62;
        タブの中身
    &#60;/div&#62;
    &#60;div id="tab3"&#62;
        タブの中身
    &#60;/div&#62;
&#60;/div&#62;</pre>
<h3>タブの設定</h3>
<pre class="brush:html">&#60;script type="text/javascript"&#62;
    var $tabs = $('#tabs').tabs();
    $tabs.tabs('select' 1); // 2番目のタブを選択状態にする
                            // デフォルトでは1番目のタブ
&#60;/script&#62;</pre>
<p>たったこれだけでタブが実装できました。</p>
<p>さらに詳しい情報を知りたい方は、<a href="http://jqueryui.com/demos/tabs/">公式ドキュメント</a>をご覧ください。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bpsinc.jp/blog/archives/2289/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CakePHP 1.3でのプレフィックスルーティング(Prefix Routing)が簡単になった</title>
		<link>http://www.bpsinc.jp/blog/archives/2276</link>
		<comments>http://www.bpsinc.jp/blog/archives/2276#comments</comments>
		<pubDate>Tue, 24 Aug 2010 11:00:44 +0000</pubDate>
		<dc:creator>shibachan</dc:creator>
				<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[芝原]]></category>
		<category><![CDATA[CakePHP1.3]]></category>
		<category><![CDATA[Prefix]]></category>
		<category><![CDATA[Routing]]></category>
		<category><![CDATA[プレフィックス]]></category>
		<category><![CDATA[ルーティング]]></category>
		<category><![CDATA[変更点]]></category>
		<category><![CDATA[移行]]></category>

		<guid isPermaLink="false">http://www.bpsinc.jp/blog/?p=2276</guid>
		<description><![CDATA[CakePHPのPrefixRoutingは
例えばadmin_editという関数に対して、通常
/:controller/admin_edit
となるURLを
/admin/:controller/edit
とすること [...]]]></description>
			<content:encoded><![CDATA[<p>CakePHPのPrefixRoutingは<br />
例えばadmin_editという関数に対して、通常<br />
/:controller/admin_edit<br />
となるURLを<br />
/admin/:controller/edit<br />
とすることができるもの。</p>
<p>管理画面やWebAPIのために特別なURLを用意することができる。</p>
<p>このPrefixRoutingだが、設定の方法がCakePHP1.3より簡単なものに変更された。</p>
<p>そのやり方とは/app/config/core.phpで</p>
<pre class="brush:php">
Configure::write('Routing.prefixes', array('admin', 'api'));
</pre>
<p>とするだけ。<br />
# サンプルとしてadminとapiというプレフィックスを設定</p>
<p>ね、かんたんでしょ。</p>
<p>CakePHP1.2の時は複数のプレフィックス設定するのはRoutesをいちいち書いて結構めんどくさかったなー</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bpsinc.jp/blog/archives/2276/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MusicFly v2.2.3リリース XperiaMini対応</title>
		<link>http://www.bpsinc.jp/blog/archives/2243</link>
		<comments>http://www.bpsinc.jp/blog/archives/2243#comments</comments>
		<pubDate>Fri, 30 Jul 2010 09:52:45 +0000</pubDate>
		<dc:creator>shibachan</dc:creator>
				<category><![CDATA[MusicFly]]></category>
		<category><![CDATA[android]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[プレスリリース]]></category>
		<category><![CDATA[芝原]]></category>
		<category><![CDATA[XperiaMini]]></category>
		<category><![CDATA[アップデート]]></category>
		<category><![CDATA[バグ]]></category>
		<category><![CDATA[低解像度]]></category>
		<category><![CDATA[高解像度]]></category>

		<guid isPermaLink="false">http://www.bpsinc.jp/blog/?p=2243</guid>
		<description><![CDATA[弊社BPSで開発しておりますAndroid端末向け音楽試聴アプリMusicFlyを先ほど１週間ぶりにアップデートしました。
今回のアップデートにより
XperiaMiniに代表される低解像度端末や、反対の高解像度端末など [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.bpsinc.jp">弊社BPS</a>で開発しておりますAndroid端末向け音楽試聴アプリ<a href="http://musicfly.jp">MusicFly</a>を先ほど１週間ぶりにアップデートしました。</p>
<p>今回のアップデートにより</p>
<p>XperiaMiniに代表される低解像度端末や、反対の高解像度端末などへの対応を果たし</p>
<p>全スクリーンサイズ対応のアプリケーションとなりました。</p>
<p><a href="http://android.asai24.com/archives/51378321.html">技術者向けの参考情報</a></p>
<p>また、以前より原因が解明できずにいたバグのいくつか解決することができました。</p>
<p>そのうちの一つがAndroid1.5でのみタブを利用した画面で強制終了してしまうクリティカルなバグであり、</p>
<p>今回無事解決しました。<a href="http://www.bpsinc.jp/blog/archives/2224">技術者向けの詳しい話はこちらで。</a></p>
<p>該当端末を利用している方にはご不便おかけしました。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bpsinc.jp/blog/archives/2243/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Android 1.5でTabHostを使った場合、StackOverflowErrorが発生する</title>
		<link>http://www.bpsinc.jp/blog/archives/2224</link>
		<comments>http://www.bpsinc.jp/blog/archives/2224#comments</comments>
		<pubDate>Fri, 30 Jul 2010 09:10:17 +0000</pubDate>
		<dc:creator>baba</dc:creator>
				<category><![CDATA[android]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[馬場]]></category>
		<category><![CDATA[XML]]></category>
		<category><![CDATA[エラー]]></category>
		<category><![CDATA[タブ]]></category>
		<category><![CDATA[バグ]]></category>

		<guid isPermaLink="false">http://www.bpsinc.jp/blog/?p=2224</guid>
		<description><![CDATA[Androidで便利な、タブ表示。
これは、TabActivity, TabHost, TabSpecを使って簡単に実現できます。
src/MainActivity.java
package jp.bpsinc.andr [...]]]></description>
			<content:encoded><![CDATA[<p>Androidで便利な、タブ表示。</p>
<div id="attachment_2225" class="wp-caption aligncenter" style="width: 207px"><a href="http://www.bpsinc.jp/blog/wp-content/uploads/2010/07/tab.png"><img class="size-medium wp-image-2225" title="tab" src="http://www.bpsinc.jp/blog/wp-content/uploads/2010/07/tab-197x300.png" alt="タブ表示" width="197" height="300" /></a><p class="wp-caption-text">タブ表示</p></div>
<p>これは、TabActivity, TabHost, TabSpecを使って簡単に実現できます。</p>
<p>src/MainActivity.java</p>
<pre class="brush:java">package jp.bpsinc.android.tabtest;

import android.app.TabActivity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.widget.TabHost;
import android.widget.TabHost.TabSpec;

public class MainActivity extends TabActivity {
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    TabHost tabHost = getTabHost();
    LayoutInflater.from(this).inflate(R.layout.main, tabHost.getTabContentView(), true);

    //タブを作る
    TabSpec tab1 = tabHost.newTabSpec("tab1");
    tab1.setIndicator("tab1");
    tab1.setContent(R.id.tab1);

    TabSpec tab2 = tabHost.newTabSpec("tab2");
    tab2.setIndicator("tab2");
    tab2.setContent(R.id.tab2);

    tabHost.addTab(tab1);
    tabHost.addTab(tab2);
  }
}</pre>
<p>res/layout/main.xml</p>
<pre class="brush:xml">&#60;?xml version="1.0" encoding="utf-8"?&#62;
&#60;FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent" android:layout_height="fill_parent"&#62;

  &#60;TextView android:layout_width="fill_parent" android:layout_height="fill_parent" android:text="TAB1" android:id="@+id/tab1" /&#62;
  &#60;TextView android:layout_width="fill_parent" android:layout_height="fill_parent" android:text="TAB2" android:id="@+id/tab2" /&#62;
&#60;/FrameLayout&#62;</pre>
<p>しかし、サンプルでなく複雑なアプリを作ると、<strong>Android 1.5 (SDK Version 3) の時だけ、StackOverflowErrorが発生する</strong>という現象に見舞われることがあります。</p>
<blockquote><p>body : java.lang.StackOverflowError<br />
at android.text.TextUtils#getChars:69<br />
at android.graphics.Canvas#drawText:1278<br />
at android.text.Layout#draw:337<br />
at android.widget.TextView#onDraw:3921<br />
at android.view.View#draw:5838<br />
at android.view.ViewGroup#drawChild:1486<br />
at android.view.ViewGroup#dispatchDraw:1228<br />
at android.view.ViewGroup#drawChild:1484<br />
at android.view.ViewGroup#dispatchDraw:1228<br />
at android.view.ViewGroup#drawChild:1484<br />
at android.view.ViewGroup#dispatchDraw:1228<br />
at android.view.ViewGroup#drawChild:1484<br />
at android.view.ViewGroup#dispatchDraw:1228<br />
at android.widget.AbsListView#dispatchDraw:1319<br />
at android.widget.ListView#dispatchDraw:2820<br />
at android.view.View#draw:5944<br />
&#8230;.</p></blockquote>
<p><a href="http://groups.google.co.jp/group/android-developers/msg/c7472f71aa9e41c5">こちらのGoogleGroupディスカッション</a>でも触れられているようですが、Android 1.5では、タブの中に多重にネストしたコンテンツがあると、StackOverflowErrorが発生します。</p>
<p>手元のエミュレータで試したところ、12回ネストしたところで、エラーになりました。</p>
<pre class="brush:xml">&#60;?xml version="1.0" encoding="utf-8"?&#62;
&#60;FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent" android:layout_height="fill_parent"&#62;

  &#60;TextView android:layout_width="fill_parent" android:layout_height="fill_parent" android:text="TAB1" android:id="@+id/tab1" /&#62;

  &#60;FrameLayout android:id="@+id/tab2" android:layout_width="fill_parent" android:layout_height="fill_parent"&#62;
    &#60;LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent"&#62;
      &#60;LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent"&#62;
        &#60;LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent"&#62;
          &#60;LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent"&#62;
            &#60;LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent"&#62;
              &#60;LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent"&#62;
                &#60;LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent"&#62;
                  &#60;LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent"&#62;
                    &#60;LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent"&#62;
                      &#60;LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent"&#62;
                        &#60;LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent"&#62;
                          &#60;TextView android:text="TAB2" android:layout_width="wrap_content" android:layout_height="wrap_content" /&#62;
                        &#60;/LinearLayout&#62;
                      &#60;/LinearLayout&#62;
                    &#60;/LinearLayout&#62;
                  &#60;/LinearLayout&#62;
                &#60;/LinearLayout&#62;
              &#60;/LinearLayout&#62;
            &#60;/LinearLayout&#62;
          &#60;/LinearLayout&#62;
        &#60;/LinearLayout&#62;
      &#60;/LinearLayout&#62;
    &#60;/LinearLayout&#62;
  &#60;/FrameLayout&#62;
&#60;/FrameLayout&#62;</pre>
<p>XMLをパーツに分けて書いていると、うっかり12回を超えてしまうことがあるので、注意が必要です。<br />
解決策としては、ネスト回数を減らすか、Android 1.5を対象から外すという後ろ向きなものが最適ですね。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bpsinc.jp/blog/archives/2224/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>RailsサーバUnicornを飼いならす! 運用時の便利技</title>
		<link>http://www.bpsinc.jp/blog/archives/2208</link>
		<comments>http://www.bpsinc.jp/blog/archives/2208#comments</comments>
		<pubDate>Wed, 28 Jul 2010 01:00:43 +0000</pubDate>
		<dc:creator>tomotaka</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[伊藤]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[Unicorn]]></category>

		<guid isPermaLink="false">http://www.bpsinc.jp/blog/?p=2208</guid>
		<description><![CDATA[伊藤です。
前回ブログで紹介したRailsサーバUnicornくんを運用し始めて結構時間が経ちました。
サービスを落とさないであるとか、システムの安定性を確保するために、
ちょっとしたユーティリティを作ったり監視ソフトM [...]]]></description>
			<content:encoded><![CDATA[<p>伊藤です。</p>
<p><a href="http://www.bpsinc.jp/blog/archives/2075">前回ブログで紹介</a>したRailsサーバ<a href="http://unicorn.bogomips.org/">Unicorn</a>くんを運用し始めて結構時間が経ちました。<br />
サービスを落とさないであるとか、システムの安定性を確保するために、<br />
ちょっとしたユーティリティを作ったり監視ソフト<a href="http://mmonit.com/monit/">Monit</a>の設定を行ったりしていました。</p>
<p>みなさんのお役に立つかわかりませんが、弊社でUnicornと組み合わせて運用に利用しているツールや設定をブログに掲載してみたいと思います。<br />
もっといいやり方がありましたら、ぜひコメント欄でご紹介頂ければと思います。</p>
<h2>ダウンしたら自動的に再起動</h2>
<p>これはMonitで行っています。<br />
もちろん同内容の監視ツールGodでも可能だと思いますが、以前設定した経験があって設定が楽そうだったので、Monitでやってみました。(事実楽でした)</p>
<pre class="brush:ruby">
check process unicorn with pidfile "/path/to/rails/tmp/pids/unicorn.pid"
  start program = "/home/tomotaka/monitor/unicorn_start" with timeout 10 seconds
  stop program = "/home/tomotaka/monitor/unicorn_stop"
  if 2 restarts within 3 cycles then timeout
  if cpu usage &#62; 95% for 3 cycles then restart
</pre>
<p>とりあえず, コピペで使う際に変更しなければいけない箇所は</p>
<ul>
<li>check processのあとの監視タスク名(なんでもよし, unicornを1個しか走らせてないならunicornでいいかも?)</li>
<li>start program(後述)</li>
<li>stop program(後述)</li>
</ul>
<p>お分かりかと思いますが、Unicorn起動/停止のためのコマンドは自作しました。<br />
startは簡単なシェルスクリプトです。</p>
<pre class="brush:bash">
#!/bin/bash
UNICORN_RAILS_BIN=/usr/local/bin/unicorn_rails
MY_RAILS_ROOT=/path/to/rails
MY_UNICORN_CONFIG=config/unicorn.rb
MY_RAILS_ENV=production

pushd $MY_RAILS_ROOT
$UNICORN_RAILS_BIN -c $MY_UNICORN_CONFIG -E $MY_RAILS_ENV -D
popd
</pre>
<p>簡単ですね。コピペで使う際は各変数を書き換えればオッケー。しいて言えばMY_UNICORN_CONFIGはRAILS_ROOTからの相対パスであることに注意でしょうか。(ディレクトリを移動してからコマンドを発行してるため) こういう簡単なツールを組み合わせて便利に使えるのがコンピュータのいいところですね。</p>
<p>unicorn_stopはUnicornのマスタープロセスのPIDをしらべて、それに対してQUITシグナルを送ればよいですね。シェルスクリプトでも出来るシンプルな内容ですが、unicornのプロセス制御のためのライブラリを作ったので、それを使ってやってます。(ライブラリについては後述)</p>
<pre class="brush:ruby">
require File.expand_path("./unicorn_manager.rb", File.dirname(__FILE__))

rails_root = "/path/to/rails"
pids = UnicornManager.get_unicorn_pids(rails_root)

puts "Sending signal to unicorn master &#91;pid=#{pids&#91;:master&#93;}&#93;"
Process.kill :QUIT, pids&#91;:master&#93;
puts "OK"
</pre>
<p>unicorn_manager.rbというのがライブラリですね。UnicornManager.get_unicorn_pidsというメソッドでUnicornのPID情報をハッシュ形式で返してくれるので、その情報をもとにProcess.killでシグナルを送ってます。unicorn_manager.rbについては、次の自動再起動の項で触れます。unicorn_manager.rbを同じディレクトリにおいて、rails_root変数を書き換えれば動作するはずです。</p>
<p>とりあえず、ライブラリunicorn_manager.rbと、上記のstart/stopコマンド2点があれば</p>
<ul>
<li>unicornが突然死したら自動的に起動</li>
<li>unicornがCPU食い過ぎてたら自動的に再起動</li>
<li>unicornがメモリ食い過ぎてたら自動的に再起動</li>
</ul>
<p>などのタスクがMonitだけで完了します。<br />
その他の複雑な条件も設定できる懐の深さがMonitにはありますので、ぜひ一度Monitのドキュメントに目を通してみてください。</p>
<p>これでとってもハッピーになれそうな感じですが、現時点のMonitにはstop programとstart programしかなく、&#8221;再起動&#8221;も&#8221;停止&#8221; => &#8220;起動&#8221;で実現される点が気になりました。というのもUnicornを使用するメリットのひとつはダウンタイムを作らずに子プロセスを新しく生まれ変わらせることができる点です。そのため、メモリを食べ過ぎて太っちゃった子プロセスにQUITシグナルを送るプログラムを先ほどunicorn_manager.rbというプログラムを作成してcronで利用しています。</p>
<h2>メモリ使用量の多い子プロセスを定期的にrespawn</h2>
<p>というわけで, fat-memory-process-killer.rbです。物騒な名前ですね。</p>
<pre class="brush:ruby">
#!/usr/local/bin/ruby
require File.expand_path("./unicorn_manager.rb", File.dirname(__FILE__))
require "logger"

logfile = "/path/to/logdir/fat-memory-process-killer.log"
loglevel = Logger::DEBUG # Logger::INFO if this script get enough stable
rails_root = "/path/to/rails"
threshhold = 40 # MB

# ----- end of config -----

puts "fat-memory-process-killer started at #{Time.now.strftime("%Y-%m-%d %H:%M:%S")}"

logger = Logger.new(logfile)
logger.level = loglevel
logger.info "----- Start -----"
memory = UnicornManager::get_memories(rails_root)
logger.debug "** rails_root=#{rails_root}"
logger.debug "** threshhold=#{threshhold}MB"
logger.info "Got PIDs: m=#{memory&#91;:master&#93;.keys} c=#{memory&#91;:children&#93;.keys.join(",")}"
mpid = memory&#91;:master&#93;.keys&#91;0&#93;
mmem = memory&#91;:master&#93;&#91;mpid&#93;
logger.debug sprintf("** master-memory: % 7d =&#62; %4.2fMB", mpid, mmem.to_f/(1024*1024))

# kill fat child
memory&#91;:children&#93;.each do |pid, mem_size|
  logger.debug sprintf("** child-memory:  % 7d =&#62; %4.2fMB", pid, mem_size.to_f/(1024*1024))
  if 1024*1024*threshhold &#60; mem_size then
    logger.info "Sending QUIT signal to child(pid:#{pid}) memsize=#{mem_size} &#62; threshhold(#{1024*1024*threshhold})"
    Process.kill :QUIT, pid
  end
end

logger.info "Finish"
</pre>
<p>デーモンにすると面倒なことが多いので、5分間隔でcronで実行しています。コピペで利用するには、 end of configより上の部分を書き換えて、unicorn_manager.rbを同じディレクトリに置けば動作するはずです。このプログラムの働きぶりを観察するためにloggerでログに結果を出力していますが、興味がなければlogger関係のコードは削ってしまってもいいかもしれません。</p>
<p>いちおうこんな感じで報告されます。使用メモリが指定した40MBを超えたプロセスが3ついたので、QUITされてるようです。</p>
<pre class="brush:ruby">
I, &#91;2010-07-27T11:00:02.734795 #1161&#93;  INFO -- : ----- Start -----
D, &#91;2010-07-27T11:00:02.994152 #1161&#93; DEBUG -- : ** rails_root=/var/www/music-fly.net/webservice2
D, &#91;2010-07-27T11:00:02.994369 #1161&#93; DEBUG -- : ** threshhold=40MB
I, &#91;2010-07-27T11:00:02.994444 #1161&#93;  INFO -- : Got PIDs: m=13550 c=31905,748,30108,980,32380,30389,29861,981,745,31898,30105,746,31679,30106,747,417
D, &#91;2010-07-27T11:00:02.994639 #1161&#93; DEBUG -- : ** master-memory:   13550 =&#62; 30.49MB
D, &#91;2010-07-27T11:00:02.994680 #1161&#93; DEBUG -- : ** child-memory:    31905 =&#62; 35.09MB
D, &#91;2010-07-27T11:00:02.994720 #1161&#93; DEBUG -- : ** child-memory:      748 =&#62; 33.98MB
D, &#91;2010-07-27T11:00:02.994758 #1161&#93; DEBUG -- : ** child-memory:    30108 =&#62; 34.14MB
D, &#91;2010-07-27T11:00:02.994795 #1161&#93; DEBUG -- : ** child-memory:      980 =&#62; 46.07MB
I, &#91;2010-07-27T11:00:02.994830 #1161&#93;  INFO -- : Sending QUIT signal to child(pid:980) memsize=48304128 &#62; threshhold(41943040)
D, &#91;2010-07-27T11:00:02.994897 #1161&#93; DEBUG -- : ** child-memory:    32380 =&#62; 31.07MB
D, &#91;2010-07-27T11:00:02.994936 #1161&#93; DEBUG -- : ** child-memory:    30389 =&#62; 36.44MB
D, &#91;2010-07-27T11:00:02.994973 #1161&#93; DEBUG -- : ** child-memory:    29861 =&#62; 45.95MB
I, &#91;2010-07-27T11:00:02.995007 #1161&#93;  INFO -- : Sending QUIT signal to child(pid:29861) memsize=48177152 &#62; threshhold(41943040)
D, &#91;2010-07-27T11:00:02.995049 #1161&#93; DEBUG -- : ** child-memory:      981 =&#62; 31.05MB
D, &#91;2010-07-27T11:00:02.995086 #1161&#93; DEBUG -- : ** child-memory:      745 =&#62; 31.05MB
D, &#91;2010-07-27T11:00:02.995123 #1161&#93; DEBUG -- : ** child-memory:    31898 =&#62; 34.82MB
D, &#91;2010-07-27T11:00:02.995160 #1161&#93; DEBUG -- : ** child-memory:    30105 =&#62; 34.49MB
D, &#91;2010-07-27T11:00:02.995197 #1161&#93; DEBUG -- : ** child-memory:      746 =&#62; 45.10MB
I, &#91;2010-07-27T11:00:02.995231 #1161&#93;  INFO -- : Sending QUIT signal to child(pid:746) memsize=47288320 &#62; threshhold(41943040)
D, &#91;2010-07-27T11:00:02.995272 #1161&#93; DEBUG -- : ** child-memory:    31679 =&#62; 31.50MB
D, &#91;2010-07-27T11:00:03.057719 #1161&#93; DEBUG -- : ** child-memory:    30106 =&#62; 36.51MB
D, &#91;2010-07-27T11:00:03.057796 #1161&#93; DEBUG -- : ** child-memory:      747 =&#62; 31.52MB
D, &#91;2010-07-27T11:00:03.057835 #1161&#93; DEBUG -- : ** child-memory:      417 =&#62; 31.05MB
I, &#91;2010-07-27T11:00:03.057998 #1161&#93;  INFO -- : Finish
</pre>
<h2>ダウンタイムなしでコードをリロードするコマンド</h2>
<p>Railsのproduction環境では、新しいコードを動作中のサーバに反映するにはいったんサーバを再起動しないといけません。Unicornもダウンタイムこそ無いものの、マスタープロセスのpidを調べて, USR2シグナルを送るという作業が必要になります。UNIX界で長年暮らしてらっしゃる方はそんなもんpsやawk組み合わせたシェルスクリプトで一発だろ、って感じかと思いますが、僕は軟弱者なのでメモリ食い過ぎプロセスを殺すためにつくったライブラリを利用して、Rubyで作りました。unicorn_reloadコマンドです。</p>
<pre class="brush:ruby">
#!/usr/local/bin/ruby

require File.expand_path("./unicorn_manager.rb", File.dirname(__FILE__))

rails_root = "/path/to/rails"
pids = UnicornManager.get_unicorn_pids(rails_root)

puts "Sending signal to unicorn master &#91;pid=#{pids&#91;:master&#93;}&#93;"
Process.kill :USR2, pids&#91;:master&#93;
puts "OK"
</pre>
<p>unicorn_stopのところで紹介したプログラムとシグナルの名前しか変わってないですね&#8230;これはひどい。</p>
<h2>unicorn_manager.rb</h2>
<p>unicorn_manager.rbのコードも貼付けてやろうかと思いましたが、ちょっと長いのでダウンロードリンクだけにしておきます。</p>
<ul>
<li><a href="http://rain.bpsinc.jp/~tomotaka/pub/unicorn_manager.rb">unicorn_manager.rbのダウンロード</a>
</ul>
<p>その代わりといっては何ですが、unicorn_manager.rbの機能を紹介しておきます。</p>
<ol>
<li>Unicornのpidリストを得る: UnicornManager.get_unicorn_pids(&#8221;/path/to/rails&#8221;) => {:master => 123, :children => [124,125,126,127...] }</li>
<li>Unicornに設定を再読込みさせる(マスターにHUPシグナルを送る): UnicornManager.reload_config(rails_root)</li>
<li>Unicornにプログラムを再読み込みさせる(マスターにUSR2シグナルを送る): UnicornManager.reload_code(rails_root)</li>
<li>Unicornの子プロセスを全て再起動させる(各子プロセスに順番にQUITシグナルを送る): UnicornManager.restart_all_child(rails_root)</li>
<li>Unicornのメモリ使用量をプロセスごとに得る: UnicornManager.get_memories(rails_root) => {:master => {123 => 1000000}, :children => {124 => 1000000, :125 => 1000000, &#8230;}}</li>
</ol>
<p>動作要件:</p>
<ul>
<li>/path/to/railsがRAILS_ROOTとして与えられたとき、/tmp/pids/unicorn.pidにunicornのpidがあること</li>
<li>psの出力フォーマットがLinux互換であること</li>
</ul>
<p>書いてて気づきました。unicorn_stopとunicorn_reloadのコマンドは専用のメソッドがあるじゃないか&#8230; もっと短くできますね。</p>
<h2>まとめ</h2>
<p>Unicornが落ちないような仕組みをMonitで構築した。Unicornの子プロセスがメモリ食い過ぎたらrespawn(日本語でいい表現を思いつかない、再起動とはちょっと違うような&#8230;)する仕組みをcronとオリジナルスクリプトで実現した。開発の際に作ったライブラリを使ってコードでプロイ時にも楽できるスクリプトとかも作った。</p>
<p>それではみなさん快適なRailsライフを!</p>
<p>Unicornシリーズ前の記事: <a href="http://www.bpsinc.jp/blog/archives/2075">次世代RailsサーバーUnicornを使ってみた</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.bpsinc.jp/blog/archives/2208/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MusicFly 他アプリから起動する</title>
		<link>http://www.bpsinc.jp/blog/archives/2109</link>
		<comments>http://www.bpsinc.jp/blog/archives/2109#comments</comments>
		<pubDate>Fri, 23 Jul 2010 02:06:46 +0000</pubDate>
		<dc:creator>shibachan</dc:creator>
				<category><![CDATA[MusicFly]]></category>
		<category><![CDATA[android]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[芝原]]></category>

		<guid isPermaLink="false">http://www.bpsinc.jp/blog/?p=2109</guid>
		<description><![CDATA[音楽試聴AndroidアプリケーションMusicFlyが先日公開されたバージョン2.2.0より、他のアプリから呼び出すことが可能になりました。
アーティスト名もしくはアルバム名を受け取ってその検索結果一覧画面を表示させる [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://musicfly.jp">音楽試聴AndroidアプリケーションMusicFly</a>が先日公開されたバージョン2.2.0より、他のアプリから呼び出すことが可能になりました。</p>
<p>アーティスト名もしくはアルバム名を受け取ってその検索結果一覧画面を表示させることができます。</p>
<div id="attachment_2186" class="wp-caption alignleft" style="width: 178px"><img class="size-medium wp-image-2186" title="src" src="http://www.bpsinc.jp/blog/wp-content/uploads/2010/07/src-168x300.png" alt="他アプリケーション" width="168" height="300" /><p class="wp-caption-text">他アプリケーション →</p></div>
<div id="attachment_2187" class="wp-caption alignleft" style="width: 178px"><img class="size-medium wp-image-2187" title="dst" src="http://www.bpsinc.jp/blog/wp-content/uploads/2010/07/dst-168x300.png" alt="MusicFly" width="168" height="300" /><p class="wp-caption-text">MusicFly</p></div>
<div style="clear:both;"></div>
<p>右の画像はサンプルアプリケーションから【hoge】という単語でMusicFlyにアーティスト検索を起動させています。</p>
<p>サンプルアプリケーションのコードを載せておきますので、参考にしていただいて、ぜひとも素晴らしいアプリを開発してください。</p>
<pre class="brush:java">        // 入力フィールド
        final EditText editText = (EditText) findViewById(R.id.text);

        // アーティスト検索ボタン
        final Button artistBtn = (Button) findViewById(R.id.btn_artist);
        artistBtn.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                // 入力フィールドのテキストを取得
                String input = editText.getText().toString();

                // アーティスト検索を実行
                Uri uri = Uri.parse(String.format("musicfly://search?type=artist&amp;name=%s", input));
                Intent intent = new Intent(Intent.ACTION_VIEW, uri);
                startActivity(intent);
            }
        });

        // アルバム検索ボタン
        final Button albumBtn = (Button) findViewById(R.id.btn_album);
        albumBtn.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                String input = editText.getText().toString();
                Uri uri = Uri.parse(String.format("musicfly://search?type=album&amp;name=%s", input));
                Intent intent = new Intent(Intent.ACTION_VIEW, uri);
                startActivity(intent);
            }
        });</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.bpsinc.jp/blog/archives/2109/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>IEでJavaScriptからButtonのtypeを変更できない</title>
		<link>http://www.bpsinc.jp/blog/archives/2147</link>
		<comments>http://www.bpsinc.jp/blog/archives/2147#comments</comments>
		<pubDate>Tue, 20 Jul 2010 10:47:07 +0000</pubDate>
		<dc:creator>baba</dc:creator>
				<category><![CDATA[Windows]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[馬場]]></category>
		<category><![CDATA[IE]]></category>
		<category><![CDATA[jQuery.HTML]]></category>
		<category><![CDATA[バグ]]></category>

		<guid isPermaLink="false">http://www.bpsinc.jp/blog/?p=2147</guid>
		<description><![CDATA[JavaScriptで動的にエレメントを作成するときは、

var div = document.createElement('div');

のようにやります。
たとえば、ボタンを作ってそのボタンにクリックイベントを追 [...]]]></description>
			<content:encoded><![CDATA[<p>JavaScriptで動的にエレメントを作成するときは、</p>
<pre class="brush:javascript">
var div = document.createElement('div');
</pre>
<p>のようにやります。</p>
<p>たとえば、ボタンを作ってそのボタンにクリックイベントを追加、などの良くある処理は、jQueryを使って、</p>
<pre class="brush:javascript">
var button = $(document.createElement('button'))
.attr('type', 'button').text('ぼたん');
button.click(function() {
    alert('hello');
});
$('#hoge').next(button);
</pre>
<p>のようにやると思います。typeを設定しているのは、デフォルトだとsubmit扱いになってしまうからです。</p>
<p>しかしこれ、IEだとエラーになります。</p>
<blockquote><p>
type property can&#8217;t be changed
</p></blockquote>
<p>buttonのtypeはなぜか読み取り専用プロパティらしい・・・</p>
<p>ということで、ちょっとダサイですが、以下のようにやって解決。</p>
<pre class="brush:javascript">
var button = $('&#60;button type="button"&#62;ぼたん&#60;/button&#62;');
</pre>
<p>以上、ちょっとした注意点でした。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bpsinc.jp/blog/archives/2147/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PythonでGoogle Language APIを使うときに、&#39;がデコードされなくて困った</title>
		<link>http://www.bpsinc.jp/blog/archives/2139</link>
		<comments>http://www.bpsinc.jp/blog/archives/2139#comments</comments>
		<pubDate>Mon, 19 Jul 2010 10:10:15 +0000</pubDate>
		<dc:creator>baba</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[馬場]]></category>
		<category><![CDATA[Ajax]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[Twitter]]></category>

		<guid isPermaLink="false">http://www.bpsinc.jp/blog/?p=2139</guid>
		<description><![CDATA[Google Language APIは素晴らしくて、AjaxのAPIがしっかり用意されているほか、RESTfulなAPIとして以下のようなものも使えます。

http://ajax.googleapis.com/aja [...]]]></description>
			<content:encoded><![CDATA[<p>Google Language APIは素晴らしくて、AjaxのAPIがしっかり用意されているほか、RESTfulなAPIとして以下のようなものも使えます。</p>
<blockquote><p>
http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&#038;q={文字列}&#038;langpair={変換前言語}|{変換後言語}
</p></blockquote>
<p>さらに、珍しく日本語ガイドがあるのも良いですね。<br />
<a href="http://code.google.com/intl/ja/apis/ajaxlanguage/documentation/">http://code.google.com/intl/ja/apis/ajaxlanguage/documentation/</a></p>
<p>さて、このRESTfulAPIで取得する結果はJSONになっているのですが、シングルコーテーション（アポストロフィ）は&amp;#39; に文字参照されて帰ってきます。</p>
<p><strong>Pythonは特に関係ない</strong>んですが、文字参照されたままだと色々困ります。<br />
標準モジュールで簡単にデコードするものが見つからなかったので、<a href="http://d.hatena.ne.jp/MOOK/20100407/1270601539">http://d.hatena.ne.jp/MOOK/20100407/1270601539</a>を使わせて頂くことにしました。</p>
<p>トータルでは、以下のようなコードになります。</p>
<pre class="brush:python">
import urllib
import json

#参照URLの実体参照解除コードを、entity_referenceモジュールにした
import entity_reference 

text = urllib.quote("私はピーターです")
url = 'http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&#038;q=%s&#038;langpair=ja|en' % text
result = json.loads(urllib.urlopen(url).read())

print entity_reference.encode(result&#91;'responseData'&#93;&#91;'translatedText'&#93;)
#I'm peter
</pre>
<p>Twitter APIなども、実体参照で返ってきたはずなので、注意が必要ですね。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bpsinc.jp/blog/archives/2139/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

