Techracho

ZeroClipboardを使っていて、IEでのみ「未知の実行時エラーです」が発生する場合

このエントリーをはてなブックマーク Share
2010.09.11    javascript, 馬場   タグ: , , , , —    baba   

Webを作っていて、「このタグをコピー」ボタンはよく作ります。

HTML/JavaScriptのみでは、IE以外のブラウザでクリップボードにコピーする機能は対応できないため、基本的にFlashを使うことになります。
それを簡単に実現できるライブラリが、ZeroClipboardです。

使い方は簡単。$関数を作っておき、onloadのタイミングでZeroClipboard.Clientオブジェクトを初期化・設定するだけです。

<html>
<head>
<script type="text/javascript">
function $(id) { return document.getElementById(id); }
function init() {
  clip = new ZeroClipboard.Client();
  clip.setHandCursor(true);
  clip.setText('コピーして欲しい文字列');
  clip.blue('button', 'container');
}
</script>
</head>
<body onload="init();">
  <div id="container">
    <img id="button" src="button.png" />
  </div>
</body>

ところが、HTMLを間違えると、IEでのみ「未知の実行時エラーです」となり、動作しないことがあります。
(Firefox/Chrome/Operaなどでは動作します)

未知の実行時エラーです

未知の実行時エラーです

これは、glue()の第2引数として渡すcontainer要素が、pタグなどになっている場合に発生します。
ZeroClipboardは、内部的にembedタグを生成し、Flashを埋め込んでいるのですが、HTMLの仕様上pのなかにembedは入りません(詳細はDTD参照)。

そのため、HTMLとしては一見Validに見える以下のHTMLでも、

  <p id="container">
    <img id="button" src="button.png" />
  </p>

glue(’button’, ‘container’); とやった時点(InnerHTMLが編集される)で、IEのみ厳密なチェックが入るため、エラーになります。

対策として、container要素は必ずdivなどのembedを含める要素にしましょう。

また当然ですが、内部で$()関数を使うため、jQueryやprototypeとの併用には注意が必要です。

CakePHP Containableビヘイビア

このエントリーをはてなブックマーク Share
2010.09.02    CakePHP, PHP, 芝原   タグ: , —    shibachan   

Containableビヘイビアをご存知でしょうか?
もし、使用していならばこれを機にぜひ導入してみてください。

公式ページによると

ContainableBehavior は CakePHP のコアの新機能です。このビヘイビアは find を実行するときに関連したモデルを選別したり限定したりするために使用します。コンテイナブル(Containable)は、データベース中の不要なものを削減し、アプリケーションの速度やパフォーマンスを改善します。このクラスを使うと、ユーザに対するデータの検索とフィルタを、美しく一貫した方法で行うこともできます。

と、魅力的に説明されています。

使用方法や動作は、公式ページをみるのが手っ取り早いので割愛しますm(_ _)m
#ググってください

このビヘイビアのメリットはたくさんあるのですが、
特に便利だと思う点が

  • recursiveやbindModelやunbindModelの記述がなくなって、ソースコードがきれいでわかりやすくなる
  • あとで関連を選別できるからモデルの関連をモリモリの最大で書いておくことができる

の2点で、とにかく便利です。

さらに以下のサンプルのようにモデルのrecursiveのデフォルト値を-1としておけば、
何をcontainすればいいのか、しているのかがソースコードからわかりやすくなってお勧めです。

class UserModel extends AppModel {

    public $recursive = -1;
    public $actsAs = array('Containable');
}

JQuery UI Tabsでタブ表示

このエントリーをはてなブックマーク Share
2010.08.27    HTML, Web, javascript   タグ: , , —    shibachan   

こんにちわ芝原です。

始めてのJavascript関連の投稿です。
お手柔らかにどうぞ。

たくさんのコンテンツをすっきり表示させるための方法として、タブという手法がよくつかわれると思います。
今回は、この便利なタブ表示をJQueryを使って実現する方法を解説します。
動作はこんな感じになります。
http://jqueryui.com/demos/tabs/default.html

必要なファイルのダウンロード

jquery本体とui.core.js、ui.tabs.jsが必要です。

こちらから簡単にダウンロードできますが余計なファイルも多分に入っているので、こちらからファイルを選択してダウンロードしてもいいと思います。

スクリプトの読み込み

必要なファイルを読み込みます。
head内に記述するのが一般的です。

<script type="text/javascript" src="/path/to/jquery.js"></script>
<script type="text/javascript" src="/path/to/ui.core.js"></script>
<script type="text/javascript" src="/path/to/ui.tabs.js"></script>

HTMLの構造

<div id="tabs">
    <ul>
        <li><a href="#tab1">タブに表示する文字</a></li>
        <li><a href="#tab1">タブに表示する文字</a></li>
        <li><a href="#tab3">タブに表示する文字</a></li>
    </ul>
    <div id="tab1">
        タブの中身
    </div>
    <div id="tab2">
        タブの中身
    </div>
    <div id="tab3">
        タブの中身
    </div>
</div>

タブの設定

<script type="text/javascript">
    var $tabs = $('#tabs').tabs();
    $tabs.tabs('select' 1); // 2番目のタブを選択状態にする
                            // デフォルトでは1番目のタブ
</script>

たったこれだけでタブが実装できました。

さらに詳しい情報を知りたい方は、公式ドキュメントをご覧ください。

CakePHP 1.3でのプレフィックスルーティング(Prefix Routing)が簡単になった

このエントリーをはてなブックマーク Share
2010.08.24    CakePHP, PHP, 芝原   タグ: , , , , , , , —    shibachan   

CakePHPのPrefixRoutingは
例えばadmin_editという関数に対して、通常
/:controller/admin_edit
となるURLを
/admin/:controller/edit
とすることができるもの。

管理画面やWebAPIのために特別なURLを用意することができる。

このPrefixRoutingだが、設定の方法がCakePHP1.3より簡単なものに変更された。

そのやり方とは/app/config/core.phpで

Configure::write('Routing.prefixes', array('admin', 'api'));

とするだけ。
# サンプルとしてadminとapiというプレフィックスを設定

ね、かんたんでしょ。

CakePHP1.2の時は複数のプレフィックス設定するのはRoutesをいちいち書いて結構めんどくさかったなー

MusicFly v2.2.3リリース XperiaMini対応

このエントリーをはてなブックマーク Share
2010.07.30    MusicFly, android, java, プレスリリース, 芝原   タグ: , , , , , —    shibachan   

弊社BPSで開発しておりますAndroid端末向け音楽試聴アプリMusicFlyを先ほど1週間ぶりにアップデートしました。

今回のアップデートにより

XperiaMiniに代表される低解像度端末や、反対の高解像度端末などへの対応を果たし

全スクリーンサイズ対応のアプリケーションとなりました。

技術者向けの参考情報

また、以前より原因が解明できずにいたバグのいくつか解決することができました。

そのうちの一つがAndroid1.5でのみタブを利用した画面で強制終了してしまうクリティカルなバグであり、

今回無事解決しました。技術者向けの詳しい話はこちらで。

該当端末を利用している方にはご不便おかけしました。

Android 1.5でTabHostを使った場合、StackOverflowErrorが発生する

このエントリーをはてなブックマーク Share
    android, java, 馬場   タグ: , , , , —    baba   

Androidで便利な、タブ表示。

タブ表示

タブ表示

これは、TabActivity, TabHost, TabSpecを使って簡単に実現できます。

src/MainActivity.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);
  }
}

res/layout/main.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent" android:layout_height="fill_parent">

  <TextView android:layout_width="fill_parent" android:layout_height="fill_parent" android:text="TAB1" android:id="@+id/tab1" />
  <TextView android:layout_width="fill_parent" android:layout_height="fill_parent" android:text="TAB2" android:id="@+id/tab2" />
</FrameLayout>

しかし、サンプルでなく複雑なアプリを作ると、Android 1.5 (SDK Version 3) の時だけ、StackOverflowErrorが発生するという現象に見舞われることがあります。

body : java.lang.StackOverflowError
at android.text.TextUtils#getChars:69
at android.graphics.Canvas#drawText:1278
at android.text.Layout#draw:337
at android.widget.TextView#onDraw:3921
at android.view.View#draw:5838
at android.view.ViewGroup#drawChild:1486
at android.view.ViewGroup#dispatchDraw:1228
at android.view.ViewGroup#drawChild:1484
at android.view.ViewGroup#dispatchDraw:1228
at android.view.ViewGroup#drawChild:1484
at android.view.ViewGroup#dispatchDraw:1228
at android.view.ViewGroup#drawChild:1484
at android.view.ViewGroup#dispatchDraw:1228
at android.widget.AbsListView#dispatchDraw:1319
at android.widget.ListView#dispatchDraw:2820
at android.view.View#draw:5944
….

こちらのGoogleGroupディスカッションでも触れられているようですが、Android 1.5では、タブの中に多重にネストしたコンテンツがあると、StackOverflowErrorが発生します。

手元のエミュレータで試したところ、12回ネストしたところで、エラーになりました。

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent" android:layout_height="fill_parent">

  <TextView android:layout_width="fill_parent" android:layout_height="fill_parent" android:text="TAB1" android:id="@+id/tab1" />

  <FrameLayout android:id="@+id/tab2" android:layout_width="fill_parent" android:layout_height="fill_parent">
    <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent">
      <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent">
        <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent">
          <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent">
            <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent">
              <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent">
                <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent">
                  <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent">
                    <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent">
                      <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent">
                        <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent">
                          <TextView android:text="TAB2" android:layout_width="wrap_content" android:layout_height="wrap_content" />
                        </LinearLayout>
                      </LinearLayout>
                    </LinearLayout>
                  </LinearLayout>
                </LinearLayout>
              </LinearLayout>
            </LinearLayout>
          </LinearLayout>
        </LinearLayout>
      </LinearLayout>
    </LinearLayout>
  </FrameLayout>
</FrameLayout>

XMLをパーツに分けて書いていると、うっかり12回を超えてしまうことがあるので、注意が必要です。
解決策としては、ネスト回数を減らすか、Android 1.5を対象から外すという後ろ向きなものが最適ですね。

RailsサーバUnicornを飼いならす! 運用時の便利技

このエントリーをはてなブックマーク Share
2010.07.28    Ruby, Ruby on Rails, 伊藤   タグ: , , —    tomotaka   

伊藤です。

前回ブログで紹介したRailsサーバUnicornくんを運用し始めて結構時間が経ちました。
サービスを落とさないであるとか、システムの安定性を確保するために、
ちょっとしたユーティリティを作ったり監視ソフトMonitの設定を行ったりしていました。

みなさんのお役に立つかわかりませんが、弊社でUnicornと組み合わせて運用に利用しているツールや設定をブログに掲載してみたいと思います。
もっといいやり方がありましたら、ぜひコメント欄でご紹介頂ければと思います。

ダウンしたら自動的に再起動

これはMonitで行っています。
もちろん同内容の監視ツールGodでも可能だと思いますが、以前設定した経験があって設定が楽そうだったので、Monitでやってみました。(事実楽でした)

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 > 95% for 3 cycles then restart

とりあえず, コピペで使う際に変更しなければいけない箇所は

  • check processのあとの監視タスク名(なんでもよし, unicornを1個しか走らせてないならunicornでいいかも?)
  • start program(後述)
  • stop program(後述)

お分かりかと思いますが、Unicorn起動/停止のためのコマンドは自作しました。
startは簡単なシェルスクリプトです。

#!/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

簡単ですね。コピペで使う際は各変数を書き換えればオッケー。しいて言えばMY_UNICORN_CONFIGはRAILS_ROOTからの相対パスであることに注意でしょうか。(ディレクトリを移動してからコマンドを発行してるため) こういう簡単なツールを組み合わせて便利に使えるのがコンピュータのいいところですね。

unicorn_stopはUnicornのマスタープロセスのPIDをしらべて、それに対してQUITシグナルを送ればよいですね。シェルスクリプトでも出来るシンプルな内容ですが、unicornのプロセス制御のためのライブラリを作ったので、それを使ってやってます。(ライブラリについては後述)

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 [pid=#{pids[:master]}]"
Process.kill :QUIT, pids[:master]
puts "OK"

unicorn_manager.rbというのがライブラリですね。UnicornManager.get_unicorn_pidsというメソッドでUnicornのPID情報をハッシュ形式で返してくれるので、その情報をもとにProcess.killでシグナルを送ってます。unicorn_manager.rbについては、次の自動再起動の項で触れます。unicorn_manager.rbを同じディレクトリにおいて、rails_root変数を書き換えれば動作するはずです。

とりあえず、ライブラリunicorn_manager.rbと、上記のstart/stopコマンド2点があれば

  • unicornが突然死したら自動的に起動
  • unicornがCPU食い過ぎてたら自動的に再起動
  • unicornがメモリ食い過ぎてたら自動的に再起動

などのタスクがMonitだけで完了します。
その他の複雑な条件も設定できる懐の深さがMonitにはありますので、ぜひ一度Monitのドキュメントに目を通してみてください。

これでとってもハッピーになれそうな感じですが、現時点のMonitにはstop programとstart programしかなく、”再起動”も”停止” => “起動”で実現される点が気になりました。というのもUnicornを使用するメリットのひとつはダウンタイムを作らずに子プロセスを新しく生まれ変わらせることができる点です。そのため、メモリを食べ過ぎて太っちゃった子プロセスにQUITシグナルを送るプログラムを先ほどunicorn_manager.rbというプログラムを作成してcronで利用しています。

メモリ使用量の多い子プロセスを定期的にrespawn

というわけで, fat-memory-process-killer.rbです。物騒な名前ですね。

#!/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[:master].keys} c=#{memory[:children].keys.join(",")}"
mpid = memory[:master].keys[0]
mmem = memory[:master][mpid]
logger.debug sprintf("** master-memory: % 7d => %4.2fMB", mpid, mmem.to_f/(1024*1024))

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

logger.info "Finish"

デーモンにすると面倒なことが多いので、5分間隔でcronで実行しています。コピペで利用するには、 end of configより上の部分を書き換えて、unicorn_manager.rbを同じディレクトリに置けば動作するはずです。このプログラムの働きぶりを観察するためにloggerでログに結果を出力していますが、興味がなければlogger関係のコードは削ってしまってもいいかもしれません。

いちおうこんな感じで報告されます。使用メモリが指定した40MBを超えたプロセスが3ついたので、QUITされてるようです。

I, [2010-07-27T11:00:02.734795 #1161]  INFO -- : ----- Start -----
D, [2010-07-27T11:00:02.994152 #1161] DEBUG -- : ** rails_root=/var/www/music-fly.net/webservice2
D, [2010-07-27T11:00:02.994369 #1161] DEBUG -- : ** threshhold=40MB
I, [2010-07-27T11:00:02.994444 #1161]  INFO -- : Got PIDs: m=13550 c=31905,748,30108,980,32380,30389,29861,981,745,31898,30105,746,31679,30106,747,417
D, [2010-07-27T11:00:02.994639 #1161] DEBUG -- : ** master-memory:   13550 => 30.49MB
D, [2010-07-27T11:00:02.994680 #1161] DEBUG -- : ** child-memory:    31905 => 35.09MB
D, [2010-07-27T11:00:02.994720 #1161] DEBUG -- : ** child-memory:      748 => 33.98MB
D, [2010-07-27T11:00:02.994758 #1161] DEBUG -- : ** child-memory:    30108 => 34.14MB
D, [2010-07-27T11:00:02.994795 #1161] DEBUG -- : ** child-memory:      980 => 46.07MB
I, [2010-07-27T11:00:02.994830 #1161]  INFO -- : Sending QUIT signal to child(pid:980) memsize=48304128 > threshhold(41943040)
D, [2010-07-27T11:00:02.994897 #1161] DEBUG -- : ** child-memory:    32380 => 31.07MB
D, [2010-07-27T11:00:02.994936 #1161] DEBUG -- : ** child-memory:    30389 => 36.44MB
D, [2010-07-27T11:00:02.994973 #1161] DEBUG -- : ** child-memory:    29861 => 45.95MB
I, [2010-07-27T11:00:02.995007 #1161]  INFO -- : Sending QUIT signal to child(pid:29861) memsize=48177152 > threshhold(41943040)
D, [2010-07-27T11:00:02.995049 #1161] DEBUG -- : ** child-memory:      981 => 31.05MB
D, [2010-07-27T11:00:02.995086 #1161] DEBUG -- : ** child-memory:      745 => 31.05MB
D, [2010-07-27T11:00:02.995123 #1161] DEBUG -- : ** child-memory:    31898 => 34.82MB
D, [2010-07-27T11:00:02.995160 #1161] DEBUG -- : ** child-memory:    30105 => 34.49MB
D, [2010-07-27T11:00:02.995197 #1161] DEBUG -- : ** child-memory:      746 => 45.10MB
I, [2010-07-27T11:00:02.995231 #1161]  INFO -- : Sending QUIT signal to child(pid:746) memsize=47288320 > threshhold(41943040)
D, [2010-07-27T11:00:02.995272 #1161] DEBUG -- : ** child-memory:    31679 => 31.50MB
D, [2010-07-27T11:00:03.057719 #1161] DEBUG -- : ** child-memory:    30106 => 36.51MB
D, [2010-07-27T11:00:03.057796 #1161] DEBUG -- : ** child-memory:      747 => 31.52MB
D, [2010-07-27T11:00:03.057835 #1161] DEBUG -- : ** child-memory:      417 => 31.05MB
I, [2010-07-27T11:00:03.057998 #1161]  INFO -- : Finish

ダウンタイムなしでコードをリロードするコマンド

Railsのproduction環境では、新しいコードを動作中のサーバに反映するにはいったんサーバを再起動しないといけません。Unicornもダウンタイムこそ無いものの、マスタープロセスのpidを調べて, USR2シグナルを送るという作業が必要になります。UNIX界で長年暮らしてらっしゃる方はそんなもんpsやawk組み合わせたシェルスクリプトで一発だろ、って感じかと思いますが、僕は軟弱者なのでメモリ食い過ぎプロセスを殺すためにつくったライブラリを利用して、Rubyで作りました。unicorn_reloadコマンドです。

#!/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 [pid=#{pids[:master]}]"
Process.kill :USR2, pids[:master]
puts "OK"

unicorn_stopのところで紹介したプログラムとシグナルの名前しか変わってないですね…これはひどい。

unicorn_manager.rb

unicorn_manager.rbのコードも貼付けてやろうかと思いましたが、ちょっと長いのでダウンロードリンクだけにしておきます。

その代わりといっては何ですが、unicorn_manager.rbの機能を紹介しておきます。

  1. Unicornのpidリストを得る: UnicornManager.get_unicorn_pids(”/path/to/rails”) => {:master => 123, :children => [124,125,126,127...] }
  2. Unicornに設定を再読込みさせる(マスターにHUPシグナルを送る): UnicornManager.reload_config(rails_root)
  3. Unicornにプログラムを再読み込みさせる(マスターにUSR2シグナルを送る): UnicornManager.reload_code(rails_root)
  4. Unicornの子プロセスを全て再起動させる(各子プロセスに順番にQUITシグナルを送る): UnicornManager.restart_all_child(rails_root)
  5. Unicornのメモリ使用量をプロセスごとに得る: UnicornManager.get_memories(rails_root) => {:master => {123 => 1000000}, :children => {124 => 1000000, :125 => 1000000, …}}

動作要件:

  • /path/to/railsがRAILS_ROOTとして与えられたとき、/tmp/pids/unicorn.pidにunicornのpidがあること
  • psの出力フォーマットがLinux互換であること

書いてて気づきました。unicorn_stopとunicorn_reloadのコマンドは専用のメソッドがあるじゃないか… もっと短くできますね。

まとめ

Unicornが落ちないような仕組みをMonitで構築した。Unicornの子プロセスがメモリ食い過ぎたらrespawn(日本語でいい表現を思いつかない、再起動とはちょっと違うような…)する仕組みをcronとオリジナルスクリプトで実現した。開発の際に作ったライブラリを使ってコードでプロイ時にも楽できるスクリプトとかも作った。

それではみなさん快適なRailsライフを!

Unicornシリーズ前の記事: 次世代RailsサーバーUnicornを使ってみた

MusicFly 他アプリから起動する

このエントリーをはてなブックマーク Share
2010.07.23    MusicFly, android, java, 芝原      shibachan   

音楽試聴AndroidアプリケーションMusicFlyが先日公開されたバージョン2.2.0より、他のアプリから呼び出すことが可能になりました。

アーティスト名もしくはアルバム名を受け取ってその検索結果一覧画面を表示させることができます。

他アプリケーション

他アプリケーション →

MusicFly

MusicFly

右の画像はサンプルアプリケーションから【hoge】という単語でMusicFlyにアーティスト検索を起動させています。

サンプルアプリケーションのコードを載せておきますので、参考にしていただいて、ぜひとも素晴らしいアプリを開発してください。

        // 入力フィールド
        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&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&name=%s", input));
                Intent intent = new Intent(Intent.ACTION_VIEW, uri);
                startActivity(intent);
            }
        });

IEでJavaScriptからButtonのtypeを変更できない

このエントリーをはてなブックマーク Share
2010.07.20    Windows, javascript, 馬場   タグ: , , , —    baba   

JavaScriptで動的にエレメントを作成するときは、

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

のようにやります。

たとえば、ボタンを作ってそのボタンにクリックイベントを追加、などの良くある処理は、jQueryを使って、

var button = $(document.createElement('button'))
.attr('type', 'button').text('ぼたん');
button.click(function() {
    alert('hello');
});
$('#hoge').next(button);

のようにやると思います。typeを設定しているのは、デフォルトだとsubmit扱いになってしまうからです。

しかしこれ、IEだとエラーになります。

type property can’t be changed

buttonのtypeはなぜか読み取り専用プロパティらしい・・・

ということで、ちょっとダサイですが、以下のようにやって解決。

var button = $('<button type="button">ぼたん</button>');

以上、ちょっとした注意点でした。

PythonでGoogle Language APIを使うときに、&#39;がデコードされなくて困った

このエントリーをはてなブックマーク Share
2010.07.19    Python, 馬場   タグ: , , , , —    baba   

Google Language APIは素晴らしくて、AjaxのAPIがしっかり用意されているほか、RESTfulなAPIとして以下のようなものも使えます。

http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&q={文字列}&langpair={変換前言語}|{変換後言語}

さらに、珍しく日本語ガイドがあるのも良いですね。
http://code.google.com/intl/ja/apis/ajaxlanguage/documentation/

さて、このRESTfulAPIで取得する結果はJSONになっているのですが、シングルコーテーション(アポストロフィ)は&#39; に文字参照されて帰ってきます。

Pythonは特に関係ないんですが、文字参照されたままだと色々困ります。
標準モジュールで簡単にデコードするものが見つからなかったので、http://d.hatena.ne.jp/MOOK/20100407/1270601539を使わせて頂くことにしました。

トータルでは、以下のようなコードになります。

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&q=%s&langpair=ja|en' % text
result = json.loads(urllib.urlopen(url).read())

print entity_reference.encode(result['responseData']['translatedText'])
#I'm peter

Twitter APIなども、実体参照で返ってきたはずなので、注意が必要ですね。

古い投稿 »

COPYRIGHT [C] 2009 BEYOND PERSPECTIVE SOLUTIONS LTD. ALL RIGHTS RESERVED.