2012年11月26日月曜日

写真投稿テスト

写真投稿テスト


2012年11月23日金曜日

FB連携テスト

テストPOST

2012年4月14日土曜日

HerokuでRuby1.9.3 + Rails3.2環境構築


HerokuでRuby1.9.3 + Rails3.2環境構築
参考)http://railsapps.github.com/rails-heroku-tutorial.html


■0. はじめに

HerokuはRuntime環境を"stack"という管理概念で保持している。
・Stackの一覧
=> https://devcenter.heroku.com/articles/stack

デフォルトのstackはBamboo。
Ruby1.9系はCedarを使う。
※cedarは2012/04/14現在、public beta。


■1. herokuプロジェクト作成

・プロジェクト作成

# gitが居なければ初期化
# git init
$ heroku create {myapp} --stack cedar

# stackの確認
$ heroku stack
  aspen-mri-1.8.6
  bamboo-mri-1.9.2
  bamboo-ree-1.8.7
* cedar (beta)

$ heroku ps
Process  State           Command
-------  --------------  -------
web.1    created for 4m

・Rubyバージョンの確認

$ heroku run console
Running console attached to terminal... up, run.1
sh: console: not found
# cedarではタスクの実行は"heroku run hoge"
# rakeの実行は"heroku run rake db:reset"など
# まだrailsプロジェクトをデプロイしてないのでconsoleは動かない
# ここでconsoleが起動するようだと、後々ちょっと迷う。(後述)

・環境確認

$ heroku info
=== {myapp}
Git URL:       git@heroku.com:{myapp}.git
Owner:         myapp@example.com
Stack:         cedar
Web URL:       http://{myapp}.herokuapp.com/

$heroku config
# レスポンスなし


■2. ruby1.9.3導入
http://railsapps.github.com/rails-heroku-tutorial.html

$ heroku labs:enable user_env_compile -a {myapp}
----> Enabling user_env_compile for {myapp}... done
WARNING: This feature is experimental and may change or be removed without notice.

$ heroku config:add RUBY_VERSION=ruby-1.9.3-p125
Adding config vars and restarting app... done, v2
  RUBY_VERSION => ruby-1.9.3-p125

$ heroku config:add PATH=bin:vendor/bundle/ruby/1.9.1/bin:/usr/local/bin:/usr/bin:/bin
Adding config vars and restarting app... done, v3
  PATH => bin:vendor/bundl...in:/usr/bin:/bin

$heroku config
PATH         => bin:vendor/bundle/ruby/1.9.1/bin:/usr/local/bin:/usr/bin:/bin
RUBY_VERSION => ruby-1.9.3-p125


■3. railsデプロイ

cedarはデフォルトでwebrickが動く。
thisサーバに変更しておく。

# RAILS_ROOT/Gemfile
+ group :production do
+   gem 'thin'
+ end

・デプロイ実行

# git add .
# git commit -m "foo"
$ git push heroku master

・環境確認

$ heroku ps
Process  State       Command
-------  ----------  ------------------------------------
web.1    up for 20s  bundle exec thin start -R config.r..
# Thisサーバで実行されている。

$ heroku config
DATABASE_URL        => foobar
GEM_PATH            => vendor/bundle/ruby/1.9.1
LANG                => en_US.UTF-8
PATH                => bin:vendor/bundle/ruby/1.9.1/bin:/usr/local/bin:/usr/bin:
/bin
RACK_ENV            => production
RAILS_ENV           => production
RUBY_VERSION        => ruby-1.9.3-p125
SHARED_DATABASE_URL => foobar

$heroku run console
Loading production environment (Rails 3.2.1)
irb> RUBY_VERSION
RUBY_VERSION
=> "1.9.3

ここで「2. ruby1.9.3導入」のステップを踏んでいるにも関わらず1.9.2が返ってくる場合は、恐らく1.9.3を導入してからアプリのデプロイを行っていない。
もう一度git push heroku masterするとrubyが1.9.3になる。
コマンドベースで反映できるのかどうかは分からない。
※heroku restartしてもダメだった。


■4. 困ったら見るサイト

http://d.hatena.ne.jp/language_and_engineering/20110914/p1
http://d.hatena.ne.jp/xyk/20101102
http://railsapps.github.com/rails-heroku-tutorial.html
https://devcenter.heroku.com/articles/rails3
https://devcenter.heroku.com/articles/rails3x-asset-pipeline-cedar

2012年2月26日日曜日

Zend Framework + WURFLでPC、携帯、スマホのUA判定


いつまで経ってもUA判定面倒だぜ。。

って、やっぱりみんな思ってる。
WURFL(Wireless Universal Resource FiLe)というモバイル判定を行うデータベースが整備されています。

ZendのUserAgent判定にWURFLを組み込む方法。

参考)
http://framework.zend.com/manual/ja/zend.http.user-agent.html
http://framework.zend.com/manual/en/zend.http.user-agent-features-wurfl.html


0. 環境

PHP 5.3.10
Zend 1.11.10
wurfl-php-1.3.1


1. WURFLのダウンロードと配置

WURFL PHPをダウンロード。
http://sourceforge.net/projects/wurfl/files/
http://sourceforge.net/projects/wurfl/files/WURFL%20PHP/

任意のディレクトリに展開してOKだけど、Zendのドキュメントに書いてある通り、application/libraryに展開します。

library
 └wurfl-php-1.3.1
  ├docs
  ├examples
  ├tests
  ├tools
  ├WURFL
  ├COPYING
  └README


2. キャッシュディレクトリの設定

WURFLデータベースのストレージとしてFile、Memcache、Memory、Mysqlの4つが使えるっぽいです。

以下、簡単そうなFileストレージを採用します。
WURFLのXMLファイルをリクエスト毎にパースしていたら大変なのでFileストレージは最初のアクセス時にキャッシュを作っておきます。

/wurfl-php-1.3.1/WURFL/Storage/File.php
を見てみると、デフォルトのキャッシュパスが/var/tmpになっています。

これをZendのドキュメントに倣って
APPLICATION_ROOT/data/wurfl/cache
とします。

mkdir -p data/wurfl/cache
chmod -R o+rwX data/wurfl/cache


3. データファイルコピー

wurfl-php-1.3.1/tests/resources/
配下のWURFLデータベースを先ほど作ったdataディレクトリにコピーします。

cp library/wurfl-php-1.3.1/tests/resources/wurfl-2.0.27.zip data/wurfl/
cp library/wurfl-php-1.3.1/tests/resources/web_browsers_patch.xml data/wurfl/


4. 設定

Zend先生は
application/config/wurfl-config.php
を作って、
application.ini
からwurfl-config.phpをロードしなさい、と言われていますが、キャッシュディレクトリの設定が上手くいきません。

参考)
<?php
$resourcesDir            = dirname(__FILE__) . '/../../data/wurfl/';
 
// $wurfl['main-file']      = $resourcesDir  . 'wurfl-latest.zip';
$wurfl['main-file']      = $resourcesDir  . 'wurfl-2.0.27.zip';
$wurfl['patches']        = array($resourcesDir . 'web_browsers_patch.xml');
 
$persistence['provider'] = 'file';
$persistence['dir']      = $resourcesDir . '/cache/';
 
$cache['provider']       = null;
 
$configuration['wurfl']       = $wurfl;
$configuration['persistence'] = $persistence;
$configuration['cache']       = $cache;

この辺りのドキュメントのwurflapi.wurfl_config_array.*パラメタをwurfl-config.phpで設定しておきなさい、ということのようですが、
wurflapi.wurfl_config_array.persistence.dir
が効かないっぽいですし、
wurflapi.wurfl_config_array.cache.*
なんてドキュメントには無い。

よく分かんないですが、wurfl-config.phpを作らずにapplication.iniから設定します。

; application/configs/application.ini
; WURFL API
;
resources.useragent.wurflapi.wurfl_lib_dir = APPLICATION_PATH "/../library/wurfl-php-1.3.1/WURFL/"
resources.useragent.wurflapi.wurfl_api_version = "1.1"
resources.useragent.wurflapi.wurfl_config_array.wurfl.main-file = APPLICATION_PATH "/../data/wurfl/wurfl-2.0.27.zip"
resources.useragent.wurflapi.wurfl_config_array.wurfl.patches = APPLICATION_PATH "/../data/wurfl/web_browsers_patch.xml"
resources.useragent.wurflapi.wurfl_config_array.persistence.provider = "file"
resources.useragent.wurflapi.wurfl_config_array.persistence.dir.dir = APPLICATION_PATH "/../data/wurfl/cache"

; resources.useragent.wurflapi.wurfl_config_array.persistence.dir = FOO
; キャッシュディレクトリは恐らくこう↑設定するのが正しいのだと思いますが、これだと動作しません。
; /wurfl-php-1.3.1/WURFL/Storage/File.phpのコンストラクタにdirパラメタが渡ってきません。
; こう↓すれば渡ってきます。
; resources.useragent.wurflapi.wurfl_config_array.persistence.dir.dir = FOO
; Zendの不具合??仕様??。


5. トラブルシュート1

これで設定はお終いでパスが正しく設定されていれば動作する、とのことですが、上手く行きません。

キャッシュディレクトリとして作成した
data/wurfl/cache
がWritableじゃないよ、と言われます。

chmod -R o+rwX data/wurfl/cache
してるのにな、と/wurfl-php-1.3.1/WURFL/Storage/File.phpを見てみると、

if(!is_writeable(dirname($this->root))){
    throw new WURFL_Storage_Exception("The file cache directory is not writeable: ".$this->root);
}

となっており、一つ上のdata/wurflディレクトリがWritableでないとエラーが出ます。

if(!is_writeable($this-&gt;root)){
に修正しても良さそうに見えますが、data/wurflのパーミッションを777にして対応しました。


6. トラブルシュート2

Fatal error: Class 'XMLReader' not found

となった場合は

$ yum install php-xml
$ service httpd restart
# それでもダメならコンパイルオプションの問題かも。


7. 実行

適当なコントローラで

$bootstrap = $this->getInvokeArg('bootstrap');
$userAgent = $bootstrap->getResource('useragent');
$device = $userAgent->getDevice();
var_dump($device);

してみると色々取れてて面白い。

// モバイル、PC、タブレット判定
$device->getFeature('is_mobile');
$device->getFeature('is_desktop');
$device->getFeature('is_tablet');
// モバイル、スマホ判定
$device->getFeature('device_os')
// SSLサポート
$device->httpsSupport();
// 最大画像サイズ(?)
$device->getMaxImageWidth();
$device->getMaxImageHeight();
// 画面解像度(?)
$device->getPhysicalScreenWidth();
// Flashサポート
$device->hasFlashSupport()
// audioサポート
if ($userAgent->hasFeature('mp3') && $userAgent->getFeature('mp3')) {
    // embed HTML5 audio tag...
}


8. 付録

エミュレータを使ったスマホ判定実験結果一覧。

端末名 OS device_os device_os_token brand_name
DC GALAXY NEXUS(SC-04D) Android 4.0 Android Android 4.0.1 Android
SB iPad iOS5 iPhone OS iPhone OS Apple
SB iPhone4 iOS5 iPhone OS iPhone OS Apple
DC HT1100 Windows Mobile 6 Windows Mobile OS Windows CE Generic
DC BlackBerry Bold 9700 BlackBerry OS5.0 RIM OS NULL RIM
DC NM850iG Symbian OS 8.0 NULL NULL DoCoMo

Symbianだけガラケー判定しそうだけど、基本的にはdevice_osの有り無しで見てしまっていいんではないだろうか。。

2012年2月16日木曜日

CentOS6.2 KVM環境構築

CentOS5.4で運用してきましたがそろそろ6.xにアップデート。
Xenで管理してきた仮想化環境を6系からCentOS標準になったKVMに移行。

以下、その記録。

http://www.oss-d.net/virt/kvm
こちらを参考に。

■環境

$ cat /etc/redhat-release
CentOS release 6.2 (Final)

$ cat /proc/version
Linux version 2.6.32-220.4.2.el6.x86_64 (mockbuild@c6b18n3.bsys.dev.centos.org) (gcc version 4.4.6 20110731 (Red Hat 4.4.6-3) (GCC) ) #1 SMP Tue Feb 14 04:00:16 GMT 2012

■KVMインストール

$ yum groupinfo kvm
Loaded plugins: fastestmirror, refresh-packagekit
Setting up Group Process
Loading mirror speeds from cached hostfile
 * base: rsync.atworks.co.jp
 * extras: rsync.atworks.co.jp
 * updates: rsync.atworks.co.jp
Warning: Group kvm does not exist.

おっと、いきなりダメじゃん。

ここまで辿り着くまでにRAID組んだりX入れたりVNC入れたり色々用意してたんですが、CentOS6.2で管理されてるパッケージがこれまでと地味に色々変わってる。

$ yum groupinstall Virtualization "Virtualization Client" "Virtualization Platform" "Virtualization Tools"

が正解。
参考 http://unix.stackexchange.com/questions/18802/how-to-install-kvm-on-centos-6

後は基本的に書かれてある通り。

■ブリッジ設定

$ cp /etc/sysconfig/network-scripts/ifcfg-eth0 /etc/sysconfig/network-scripts/ifcfg-br0
$ vi /etc/sysconfig/network-scripts/ifcfg-br0

DEVICE="br0"
BOOTPROTO="static"
BROADCAST="192.168.12.255"
DNS1="192.168.12.1"
GATEWAY="192.168.12.1"
#HWADDR="00:22:19:0B:6F:F0"
IPADDR="192.168.12.51"
NETMASK="255.255.255.0"
#NM_CONTROLLED="yes"
ONBOOT="yes"
TYPE="Bridge"

$ vi /etc/sysconfig/network-scripts/ifcfg-eth0

DEVICE="eth0"
#BOOTPROTO="static"
#BROADCAST="192.168.12.255"
#DNS1="192.168.12.1"
#GATEWAY="192.168.12.1"
HWADDR="00:22:19:0B:6F:F0"
#IPADDR="192.168.12.51"
#NETMASK="255.255.255.0"
#NM_CONTROLLED="yes"
ONBOOT="yes"
TYPE="Ethernet"
BRIDGE="br0"

$ service network restart

$ vi /etc/sysctl.conf
# 恐らく変更の必要ない

ここまででブリッジを見るように設定できた。
ただ、rebootしたりするとWANが見えなくなる。
何でかよく分からないけどservice network restartすると見える。

■仮想マシンマネージャー起動

X上で
$ virt-manager

Error polling connection 'qemu:///system': internal error Cannot find suitable
emulator for x86_64

となれば、恐らくBIOSのVirtualizationが無効になっている。
BIOS設定からVirtualizationをenableに変更すればOKだった。

■ゲストOSインストール(失敗)

virt-managerからGUIで仮想マシンをインストールしようとすると、ネットワーク越しのインストールが出来ない。
URIを指定してインストールを試みると
The location must be the root directory of an install tree.
とかって言われる。

検索してみてもバグ?とか何とか、よく分からない。
しょうがないのでローカルメディアからインストーラを起動してネットワークインストール。

■仮想マシンインストール(続き)

CDROMにネットワークインストールのメディアを焼いてそこからインストールを試みた。
途中までは良かったけれど、インストール中にUSB接続キーボードのアンダースコアが表示できない。

keymapとか色々あるんだろう。

ググってみてもVmwareの場合はいくつか出てくるけど、KVMはよく分からない。

仕方がないのでUSのキーボードレイアウトでインストール実行。
「ほ」の辺りのキーをShift押しながらでアンダースコア。

無理やり感漂うけれど、まぁ、インストールはできた。

インストール後日本語レイアウトに変更。

$ vi /etc/sysconfig/keyboard

KEYTABLE="us"
MODEL="pc105+inet"
LAYOUT="us"
KEYBOARDTYPE="pc"

↓

KEYTABLE="jp106"
MODEL="jp106"
LAYOUT="jp"
KEYBOARDTYPE="pc"

アンダースコアも大丈夫。

・ゲストOS環境

$ cat /etc/redhat-release
CentOS release 6.2 (Final)

$ cat /proc/version
Linux version 2.6.32-220.el6.x86_64 (mockbuild@c6b18n3.bsys.dev.centos.org) (gcc version 4.4.6 20110731 (Red Hat 4.4.6-3) (GCC) ) #1 SMP Tue Dec 6 19:48:22 GMT 2011

2012年2月1日水曜日

Android, Viewにstyleを動的に設定する方法

AndroidアプリのButtonやViewに動的にstyleを設定したい。
例えばActivityからnew Button()したようなオブジェクトに共通で使っているstyleを設定したい。

かなり探したけど全然見つからなかった。
唯一ここに発見。
ソースコード内で生成したViewインスタンスにStyleを適用

はじめは書いてある内容が理解できなかったので、備忘録として以下メモ。
#リンク先と同じこと書いてるだけ。

・アウトライン

Viewのコンストラクタを見てると
View(Context context)
View(Context context, AttributeSet attrs)
View(Context context, AttributeSet attrs, int defStyle)
こんな風に定義されている。

Contextはクラスのオブジェクトを指定。この辺りを参照。
AttributeSetはXMLで指定した場合のプロパティが渡ってくる。
style指定は3つ目のdefStyle。

なので、Activityから生成したViewオブジェクトにstyleを指定した場合は、3つ目のパラメタにR.foo.barのリソースIDを渡せばよい。
っていうのは比較的すぐ分かるんですが、具体的にどうやるのかは一苦労。

以下。

・styleの指定

R.styleというのがあるので、こいつを指定すればいいんだろうと格闘してましたが、どうやら違ってR.attrでないとダメな模様。
このstyleリソースIDを直接指定できれば楽なんだけどなー、というのが最初のリンク先で触れられていた内容。

・R.attrについて

R.attrのドキュメント

ドキュメントを見る限り、R.attrはwidthやcheckedのようなAndroidのXMLエレメントのアトリビュートを定義してるものらしい。
R.attrの中にはdialogLayoutやbuttonStyleのようなレイアウト周りのリソースIDを指定していると思われるものも存在しますが、本来styleとは直接は関係ない(はず)。
なのでR.attrの指定からしかstyleを適用できない、というのは勘違いかAndroidのバグだと思う。

でも他にやり方が分からないので以下進めます。
#詳しい方、教えて。。

・R.attrを指定する

XMLはres/values/style.xmlで指定する。
#ここじゃないとダメなのかはよく分からない。

1. 適用させるstyleを作成
<!-- <item name="android:layout_*">の要素はR.attrでスタイル適用出来ないっぽい -->
<style name="MyButtonStyle" parent="android:style/Widget.Button">
    <item name="android:layout_width">match_parent</item>
    <item name="android:layout_height">wrap_content</item>
    <item name="android:layout_marginBottom">2dp</item>
    <item name="android:textColor">@color/foo</item>
    <item name="android:textSize">16dp</item>
    <item name="android:background">@drawable/bar</item>
    <item name="android:textStyle">bold</item>
</style>

作ったstyleをR.attrで参照可能なように設定。

2. テーマの適用

theme属性としてstyleを設定するので、先にテーマをアプリケーションに適用させておく。
AndroidManifest.xml
  <application
      android:icon="@drawable/ic_launcher"
      android:label="@string/app_name"
+     android:theme="@style/MyApplicationStyle" >


3. テーマの設定

<style name="MyApplicationStyle" parent="android:Theme">
</style>


4. styleのテーマへの組み込み

+ <attr name="myButtonStyle" format="integer|reference" />
  <style name="MyApplicationStyle" parent="android:Theme">
+      <item name="myButtonStyle">@style/MyButtonStyle</item>
  </style>

これでR.attr.myButtonStyleが参照可能になった。

5. Activityでの適用

Button btn = new Button(this, null, R.attr.myButtonStyle);

でstyle定義済みのViewオブジェクトが生成可能。
後は如何様にも。

btn.setText("foo");
LinearLayout layout = new LinearLayout(this);
layout.addView(
    btn,
    new LinearLayout.LayoutParams(
        LinearLayout.LayoutParams.WRAP_CONTENT,
        LinearLayout.LayoutParams.WRAP_CONTENT));
setContentView(layout);

とか。

2012年1月26日木曜日

Zend HeadLink ヘルパーでコンディショナルCSS

ZendViewヘルパーを使って<head>タグや<meta>タグを管理すると嬉しいことが一杯。

・layoutファイルがすっきりする(場合によっては全てのmoduleに同じlayoutファイルを適用できるようになる)
・ベタ書きしてれば微妙に大変な<title>の変更なんかも一発
・コントローラで設定すれば、継承してサブクラスでどんどんappendできる

CSSのlink設定でのTipsをメモ。

標準的には以下のような感じで設定。

Controllerで設定
{
public function preDispatch()
{
    parent::preDispatch();
    $this->view->headTitle('MyWEB', 'SET');
    $this->view->headLink()->appendStylesheet($this->view->baseUrl('path_to_css/css1.css'))
                           ->appendStylesheet($this->view->baseUrl('path_to_css/css2.css'));
    $this->view->headMeta()->setCharset('UTF-8'); //こんなのはbootstrapとかどこか固定で設定してもいい
}
Viewで出力
<?php echo $this->doctype(); ?>
<html>
<head>
<?php echo $this->headTitle() ?>
<?php echo $this->headMeta() ?>
<?php echo $this->headLink() ?>
<?php echo $this->headScript() ?>
</head>
<body>

コンディショナルな指定をする場合。
例えばIE7だけで適用するCSSの設定。

こんな感じ。
public function preDispatch()
{
    parent::preDispatch();
    $this->view->headLink()->appendStylesheet($this->view->baseUrl('path_to_css/common.css'))
                           ->appendStylesheet($this->view->baseUrl('path_to_css/ltIE7.css'), 'screen', 'lt IE 7');
    // <!--[if lt IE 7]> <link href="/path_to_css/ltIE7.css" media="screen" rel="stylesheet" type="text/css" ><![endif]-->
}

参考)
Zend Viewヘルパー