メイン

2010年8月19日

PNG画像書き出しの「あとちょっと軽くできたら...」を可能にするファイル作成TIPS
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

こんにちは。ウノウでデザイナーをしているChristelです。

銀色の全身スーツを着、透明チューブの中を走る車で移動する21世紀で暮らす私たち。
夢のクラウド化が囁かれる昨今ですが、未だ携帯電話関連の画像作成には、スカイツリーよりも高い容量の壁があります。
「Flashの3階層メニューで文字も画像で100kb以内でよろしく」とか
「あれとこれとそのファイル合わせて一回で表示するのは20kb以内でね」など、
関係者の皆さんは、1バイトに泣き、1バイトに笑う日々を送っておられることでしょう。

今日はそんな皆さんに
「ビットマップデータを透過PNGで書き出すとき、クオリティを下げずにサイズをちょっとだけ減らせる画像作成のコツ」
をご紹介します。

ニッチ過ぎて申し訳ないです。


1)まずPhotoshopで画像を作成

miyakami_1.jpg
↑ 一世を風靡した感のあるWEB2.0風。画像の痛さには目を瞑ってください。


2)そのまま背景透過のPNG24で書き出します

miyakami_2.jpg
↑背景透過、マットなし、のPNG24です

15.3kbのPNG画像ができました
miyakami_3.jpg

...と、ここまではフツー。


3)それではここでFireworksを立ち上げましょう

miyakami_4.jpg
私たちの未来を明るく照らしだすFireworks先生。ゴールドカラー(きいろとも言う)がまばゆい。


4)先ほどのPSDファイルを読み込み、そのまま背景透過のPNG32で書き出します

miyakami_5.jpg
背景透過、マットなし、のPNG32です


5)ではいま作成したファイルサイズを見てみましょう

miyakami_6.jpg
14.7kbのPNGファイルができました


...なんということでしょう~!!

Photoshop書き出し15.3kb
Fireworks書き出し14.7kb

Photoshopで作成したファイルより軽い♪

二つのファイルを比べてみてもほとんど遜色ありません。

miyakami_7.jpg

ありがとう、ありがとうFireworks先生!!


...端的に申し上げると「Fireworksを使え」という事ですが、意外と皆さんご存知ないようです。
大量のPNGを使用するFlashや携帯サイト等では差が歴然です。
小さな差異を笑ってはいけません。
また、GIFの場合もFireworksを使うと若干軽くなる場合が多いです。



★☆ ↓↓おまけ↓↓ ☆★

◆◆試してみよう~...その1◆◆

ちなみにFireworksによるJpeg画像の書き出しではどうでしょうか。
同じ写真をPhotoshopとFireworksで同じ設定で書き出してみました。


miyakami_8.jpg
元の写真。みかんゼリーおいしい。


画質80、最適化チェック、マットなしのJpeg書き出しです
miyakami_9.jpg

プロパティを見てみると

左:Photoshop書き出し19.2kb
右:Fireworks書き出し10.6kb


Fireworks書き出しの方が俄然軽いですが、やはり画像が荒くなっています。
しかしながら目を覆うほどの劣化ではないので、臨機応変に使い分けて頂ければ良いでしょう。



◆◆試してみよう~...その2◆◆

では更に同じ写真をPNGで書き出したらどうでしょうか。

Photoshop 背景透過、マットなし、のPNG24
Fireworks 背景透過、マットなし、のPNG32
で書き出し。

miyakami_10.jpg

左:Photoshop書き出しのファイル
右:Fireworks書き出しのファイル


とってもきれいでどちらも遜色ありません。

さてファイルのサイズはというと... 

Photoshop書き出し75.2kb
Fireworks書き出し84.2kb

と非常に残念な結果に...。


書き出しは用途を考えて正しく行いましょう~!


では、素敵な毎日を。。。



2010年8月13日

MySQLのチューニングのためのデータの集め方
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

いつの間にか会社で古株になったyamaokaです。

webアプリケーションのバックエンドにMySQLを使っている場合、 クエリ(SQL)のチューニングをする必要がありますよね。 皆さんはチューニングの計画をどのように立てていますか。

もちろん、既に明らかに重いことが想定されているページがあれば、 その処理で使われているクエリを中心にEXPLAINなどを使って解析していけばいいと思います。

でもそうではなく、全体的にクエリの見直しやチューニングを行いたい場合は 実際に実行されているクエリを確認していくという作業が必要です。 そこで使うことができる3つの方法について書きたいと思います。

遅いクエリを記録する

MySQLにはスロークエリログといって、 実行に時間がかかったクエリを記録する機能が最初から付いています。 /etc/my.cnfに次のように設定を書けば実行時間が1秒を超えたクエリが出力されるようになります。

slow_query_log = 1
slow_query_log_file = /path/to/mysql-slow.log
long_query_time = 1
オンラインでset globalを使って変更する場合は次のようにします。
set global slow_query_log = 1;
set global slow_query_log_file = '/path/to/mysql-slow.log';
set global long_query_time = 1;

出力されたログファイルをMySQLに付属しているmysqldumpslowというツールで解析すると便利です。次のように実行すれば、平均の実行時間が長い順にソートして表示してくれます。

mysqldumpslow -s at /path/to/mysql-slow.log
クエリのパラメータは数値はN、文字列はSに置換して表示してくれるので 同じクエリをまとめてチェックすることができます。

実行回数の多いクエリを記録する

実行時間は短いけれど多くの回数実行されるクエリというのもあります。 これらは通常のスローログには出てこないのですが、 実は負荷の大部分を占めている、ということもありえます。 キャッシュなど別の方法を考えることで アプリケーションの負荷を減らすことができるかもしれません。

従来MySQLではlong_query_timeに1秒以上の値しか設定できませんでしたが、 MySQL 5.1から1秒未満の値も設定できるようになりました。 つまり、次のように/etc/my.cnfで「0」を設定すれば 全てのクエリが記録できることになります。

slow_query_log = 1
slow_query_log_file = /path/to/mysql-slow.log
long_query_time = 0

もちろん、全てのクエリの記録は負荷も大きくかかることを 理解してから設定を行うようにしてください。 また、ログの容量も大きくなるので、ディスクの空き容量にも注意が必要です。 オンラインでset globalを使って一時的に値を0に変更し、すぐに元の値(1など)に戻すのがオススメです。

set global slow_query_log = 1;
set global slow_query_log_file = '/path/to/mysql-slow.log';
set global long_query_time = 0;
# 後で set global long_query_time = 1; で元に戻す

出力されたログファイルをmysqldumpslowで次のように解析することで、 実行回数の多い順に表示することが可能です。

mysqldumpslow -s c /path/to/mysql-slow.log

mysqldumpslowは他にもいろいろ機能を持っているので、「--help」を付けて実行して 一度オプションを確認してみるといいかもしれません。

追記: MySQLでは/etc/my.cnfに次のような設定をすることで全てのクエリを記録することが可能です。 最初から全ての記録を保存したい場合はこちらの方法もいいかもしれません。

log = /path/to/mysql-query.log

インデックスを使っていないクエリを記録する

多くの場合、インデックスを使用しないクエリは遅いです。 インデックスの設計は計画的に行う必要があると思いますが、 今現在インデックスを使用していないクエリはどれなのか知りたい場合があると思います。 次のように/etc/my.cnfに記述することでインデックスを使用していないクエリを スロークエリログに記録することができるようになります。

slow_query_log = 1
slow_query_log_file = /path/to/mysql-slow.log
long_query_time = 5
log_queries_not_using_indexes = 1
オンラインでset globalを使って設定する場合は次のようにします。
set global slow_query_log = 1;
set global slow_query_log_file = '/path/to/mysql-slow.log';
set global long_query_time = 5;
set global log_queries_not_using_indexes = 1;

出力されたログファイルは今までと同じように mysqldumpslowを使って解析していくことになると思います。

終わりに

最近は、開発するときにフレームワークに付属のORマッパーを使ったりして 実際に発行されるクエリを意識しないことが多くなっていると思います。 もちろんそれはメリットだと思うのですが、実際に実行されるのはクエリ(SQL)である以上、 完全に意識しないで済むということはありません。

実際に発行されているクエリを眺めつつ、 少しでもパフォーマンスのよいwebアプリケーションを作っていけたらいいと思います。

追記: オプションの変数名がMySQL 5.1基準のものになっていなかったのでMySQL 5.1をベースに修正しました。

2010年5月28日

zshはじめました。
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

今までずっとbashを使ってきて、やっとこzshに乗り換えることに踏み切ったHIROKIです。

昔に同僚がOSデフォルトでついてくるシェルではもの足らず、zshを導入した後にシステムに大きな変更を加えてzshが正常に動作しなくなりました。ユーザーではもちろんログインできず、rootのシェルもzshにしていたために、rootでもログインできず、どうにもこうにもならない状態となっているのを目撃してからはOSデフォルト以外のシェルを使うのをやめていました。

扱うのはLinuxが中心だったので、いままでbashが中心。
FreeBSDを扱うときは、もちろんcshでした。

そして、ウノウではみんなzshであり、魔法のようなコマンドさばきを見ていて、とうとうzshに踏み切りました。

そんなこんながありまして、zshを改めて設定してみました。
皆さんも、導入を検討してみてはいかがでしょうか。

まず、bashがデフォルトのOSであれば、$HOME/.bashrcに下記を追加しておきます。

# use zsh
if [ -f /bin/zsh ]; then
    exec /bin/zsh
fi

こうすることによって、たとえzshが正常に動作しなくなったとしてもzshさえ消せば、OSデフォルトのbashで動作することができます。

ここからは、$HOME/.zshrcをだらだらと書き連ねていきます。


# PROMPT
PS1="[@${HOST%%.*} %1~]%(!.#.$) " # この辺は好み
RPROMPT="%T" # 右側に時間を表示する
setopt transient_rprompt # 右側まで入力がきたら時間を消す
setopt prompt_subst # 便利なプロント
bindkey -e # emacsライクなキーバインド

export LANG=ja_JP.UTF-8 # 日本語環境
export EDITOR=emacs # エディタはemacs

autoload -U compinit # 強力な補完機能
compinit -u # このあたりを使わないとzsh使ってる意味なし
setopt autopushd # cdの履歴を表示
setopt pushd_ignore_dups # 同ディレクトリを履歴に追加しない
setopt auto_cd # 自動的にディレクトリ移動
setopt list_packed # リストを詰めて表示
setopt list_types # 補完一覧ファイル種別表示

# 履歴
HISTFILE=~/.zsh_history # historyファイル
HISTSIZE=10000 # ファイルサイズ
SAVEHIST=10000 # saveする量
setopt hist_ignore_dups # 重複を記録しない
setopt hist_reduce_blanks # スペース排除
setopt share_history # 履歴ファイルを共有
setopt EXTENDED_HISTORY # zshの開始終了を記録

# history 操作まわり
autoload history-search-end
zle -N history-beginning-search-backward-end history-search-end
zle -N history-beginning-search-forward-end history-search-end
bindkey "^P" history-beginning-search-backward-end
bindkey "^N" history-beginning-search-forward-end

# alias
alias ls="ls -G"
zstyle ':completion:*' list-colors 'di=34' 'ln=35' 'so=32' 'ex=31' 'bd=46;34' 'cd=43;34'

[ -f ~/.zshrc.include ] && source ~/.zshrc.include # 設定ファイルのinclude


以上が僕の.zshrcです。コピペで使えば、それなりに幸せになれます。


ポイントとしては、サーバ固有の設定やaliasに関しては、$HOME/.zshrc.includeというファイルを作って、こちらを個別に設定しています。本番サーバなんかはプロントを赤くしたり、特定のサーバにしかないコマンドはこのファイルに書いたりなど。


これが便利だ!という設定があったらぜひ、教えてください!


ではでは、またいつか。

2010年5月22日

git-svn駆け込み寺
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

こんにちは。murahashiです。
gitやgit-svnを使うにあたり、試したことや引っかかったことについて、yukiのエントリ ウノウラボ Unoh Labs: subversionリポジトリでもgitが使えるgit-svn のつづきを書いてみました。

git_svn_bad_200x280.jpgQ. ブランチ名を長くしてしまったので手打ちするのが大変です

git_svn_good_200x289.jpgA. bashでgitコマンドを補完します

gitのコマンド補完は git-completion.bash が便利です。
fedoraにyumでgitを入れた場合には下記場所にあります。

/usr/share/doc/git-VERSION/cntrib/completion/

自分の見える場所にgit-completion.bashがなければ、インストール済みのgitと同じversionのgitのソースをダウンロードします。

cntrib/completion/

に入っているので.bashrcのなかで読み込みましょう。補完が効くようになります。




git_svn_bad_50x70.jpgQ. 除外設定にしていたファイルがコミットされてしまいます

git_svn_good_50x72.jpgA. .git/info/exclude に書きましょう

$ git svn show-ignore >> .git/info/exclude

svn:ignoreと.gitignoreで混乱しないようにしましょう。



git_svn_bad_50x70.jpgQ. 中身が空のディレクトリが作られません

git_svn_good_50x72.jpgA. 自分で作りましょう

gitだけを使ったプロジェクトで空ディレクトリ作りたいときは空の.gitignore ファイルをいれておくのが定番です。
git-svn利用時に.gitignoreをコミットしていいかについては話し合いましょう。



git_svn_bad_50x70.jpgQ. svn externals を自動で取得してくれません

git_svn_good_50x72.jpgA. git-svn-clone-externals を使いましょう

How do I keep an svn:external up to date using git-svn? - Stack Overflow
andrep's git-svn-clone-externals at master - GitHub
ほかにもいろいろ手段はあって、一長一短の解説が書いてあるページもありました(url失念)。私はシンプルなのがいいと、git-svn-clone-externalsを利用しています。事前に別の場所で試してみるとよいでしょう。



git_svn_bad_50x70.jpgQ. git-svn-clone-externals 動かないのですが

git_svn_good_50x72.jpgA. show-externals、みえていますか

$ git svn show-externals

これが見えていないとfetchできません。
私の場合、見えていたリポジトリと見えてないリポジトリがありました。
リポジトリ間の設定を目diffして見えていない側に追加したところ、見えていなかった側からshow-externalsが見えるようになりました。
ここはちょっとよくわからないです。svn側がtrunk決め打ちの人しか下記追加は当てはまらないと思います。

$ git config --add svn-remote.svn.url svn+ssh://example.com/path/to/repository/trunk
$ git config --add svn-remote.svn.fetch :refs/remotes/git-svn

同じプロジェクトで同じ開発マシンを使っているのにshow-externalsが見えない人もいました。原因を探す余裕がない場合は別の手段をとるしかないでしょう。git submodule使うとか、git cloneして放り込んでignoreとか、動く手段を探してください。



git_svn_bad_50x70.jpgQ. svnリポジトリにコミットしたいです

git_svn_good_50x72.jpgA. mergeしてdcommitするのが堅いです

ローカルのgitリポジトリにコミットしたあと、

$ git branch //今のブランチを確認
 * 000_TOPIC_BRANCH
   master
$ git diff //差分ないことを確認
$ git checkout master
$ git branch //今のブランチを確認
   000_TOPIC_BRANCH
 * master
$ git svn rebase //svn update相当
$ git merge --no-ff --no-commit 000_TOPIC_BRANCH
$ git add .
$ git commit -v
$ git svn dcommit

できました!
no-ffなのはよくわかっていなくておまじない状態です。
no-commitは自分でdiffとつき合わせてコミットログを書きたいからです。
ローカルのgit側では頻繁にcommitかつ適当にコメントを書いているので、リモートのsvn側にpushする際にきちんとコミットコメントをかくように調整しています。
ただこの運用でsvn側のコミット粒度が荒くなってしまったので、注意がいるかもしれません。



git_svn_bad_50x70.jpgQ. svnのあれがgitで

git_svn_good_50x72.jpgA. あるていどは割り切りましょう

結局のところ何でもかんでもすべてをgitやgit-svnでやろうとするのは無理があるので、こみいったところはsvnコマンドたたくほうがよいと思います。ほかにもtortoiseSVNとtortoiseGitの違いとかwindowsでgitとかいろいろあると思います。



濱野さんの入門Gitの「chapter16 間違いからの回復」を繰り返し参照することになるので手元にあると便利ですね。

以上デース

ウノウでは特に最近、積極的にエンジニアを採用しています。
採用ページをご覧になり興味のある方、ぜひご応募ください。
Find Job!でも募集してます!

2010年3月12日

快適なsshクライアント生活
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

2010/03/13 一部記事修正。

はじめまして、HIROKIです。

大規模コンテンツの開発に携わっていると数多くのサーバにsshでログインすることになります。その手間を軽減するために $HOME/.ssh/config を設定してみます。

sshコマンドを簡略化

例えば dev01.labs.unoh.netというサーバにsshでログインするのであれば、
 $ ssh -i ~/.ssh/id_rsa.unoh hiroki@dev01.labs.unoh.net

という感じのコマンドでログインしているかと思います。

これを

 $ ssh dev01
でログインできるように設定してみましょう。
Host dev01
    User            hiroki
    HostName        dev01.labs.unoh.net
    IdentityFile    ~/.ssh/id_rsa.unoh

秘密鍵を複数使いわけている人はIdentityFileを指定すると便利です。

さらにホストを追加

さらにホストを追加してみます。
Host dev01
    User            hiroki
    HostName        dev01.labs.unoh.net
    IdentityFile    ~/.ssh/id_rsa.unoh

Host home
    User            hirocaster
    HostName 	    home.hiroki.jp
    IdentityFile    ~/.ssh/id_rsa.home
いままで
 $ ssh -i ~/.ssh/id_rsa.home hirocaster@home.hiroki.jp
でログインしていたのが
 $ ssh home
でログインできるようになりました。

各ホストの共通設定

すべてのホストの共通設定は以下のような感じ

Host *
     IdentityFile               ~/.ssh/id_rsa
     ForwardAgent               yes
     TCPKeepAlive               yes
     ServerAliveInterval        15
     ServerAliveCountMax        3

必ず設定ファイルの最後に追加するようにしてください。

踏み台を経由してログインする場合

応用編として、踏み台サーバ(op.labs.unoh.net)を経由して 開発サーバ(dev01.labs.unoh.net)にログインする場合

Host dev*
    User            hiroki
    IdentityFile    ~/.ssh/id_rsa.unoh
    ProxyCommand    ssh op.labs.unoh.net nc -w 6000 %h %p

踏み台サーバ(op.labs.unoh.net)の/etc/hostsにdev01,dev02などを追加しておくことがポイントです。

このようにしておけば、踏み台サーバを経由して開発サーバに入れます。

 $ ssh dev01
にもログインできますが、
 $ ssh dev02
にもログインできるようになります。

このようにワイルドカードを利用した設定もできます。

最終的な$HOME/.ssh/config

Host dev*
    User                        hiroki
    HostName                    dev.01.labs.unoh.net
    IdentityFile                ~/.ssh/id_rsa.unoh
    ProxyCommand                ssh op.labs.unoh.net nc -w 6000 %h %p

Host home
    User                        hirocaster
    HostName                    home.hiroki.jp
    IdentityFile                ~/.ssh/id_rsa.home

Host *
     IdentityFile               ~/.ssh/id_rsa
     ForwardAgent               yes
     TCPKeepAlive               yes
     ServerAliveInterval        15
     ServerAliveCountMax        3

以上でsshコマンドを利用してのログインが簡略化されました。

最後に

簡単にログインできるようになったからこそ、本番サーバとテストサーバを間違ってオペレーションしないようにログインした際にはサーバを確認する癖をつけてください。

$HOME/.ssh/configに関するその他の設定は

 $ man ssh_config

を参照ください。

ウノウでは特に最近、積極的にエンジニアを採用しています。
採用ページをご覧になり興味のある方、ぜひご応募ください。
Find Job!でも募集してます!

2010年1月 3日

Amazon Web Services入門: PHPとEC2/S3/SQS/SimpleDBで作るビデオ共有サイト
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

新年あけましておめでとうございます、五十川です。

PHPデベロッパー向けのAmazon Web Services(AWS)のリソースはhttp://aws.amazon.com/php/にまとめられていますが、そのArticles & Tutorialsカテゴリーにある、Introduction to AWS for PHP Developersという記事は、AWSの主要サービスの概要と、PHPによるその操作を学ぶチュートリアルで、ここで取り上げられているサービスに初めて取り組むPHPデベロッパーには格好の入門となっており、ここではこのチュートリアルを紹介したいと思います。

また、このチュートリアルはAmazon純正のライブラリを利用していますが、AWS用のライブラリには様々なものがあり、この記事の最後ではそのひとつ、CloudFusionを紹介しようと思います。

なお、以下のチュートリアルのスクリプトの実行には、もちろんAWSアカウントが必要で、スクリプトの実行に応じてAWSの利用料が課金されます。チュートリアルには、例えば起動したEC2インスタンスを停止(Terminate)するなど、余計な課金がされないようにする手順は説明されていませんので、AWS Console各種デベロッパーツールを利用して(あるいはチュートリアルの復習も兼ねて、そうしたプログラムを自作するなどして)、適宜対処してください。

チュートリアルのシナリオ

チュートリアルはビデオ共有サイトを題材にしており、AWSのうち、EC2S3SQSSimpleDBを利用します。

  • ウェブサーバはEC2でホストされる
  • ユーザは任意の形式のビデオをサイトのファイルアップロードフォームからアップロードできる
  • アップロードされたビデオはS3に保存され、SQSで管理されるバッチプロセスでFLVに変換される
  • 変換されたビデオはS3に保存され配信される
  • ビデオのメタデータはSimpleDBに記録される

一般的なビデオ共有サイトでは、ユーザから投稿される様々な形式のビデオを、共通の形式(一般的にFLV)に変換して視聴に供します。ビデオの変換は相応のリソースと時間を消費するため、バッチプロセスで処理され、キューシステムで管理されますが、チュートリアルではここにSQSを採用しています。また、バッチプロセスをウェブサーバとは別のコンピュータ(EC2インスタンス)に分離し、さらにそれらが複数に分散されることを想定し、変換前後のビデオはS3に保存します。

チュートリアルの著者について

チュートリアルの著者は、Feedsterを経て現在はAPIのマネージメントサービスを提供するMasheryのチーフアーキテクトを務めるClay Lovelessさんです。彼はオライリーのPHP Cookbook Second Editionの4つの章の著者であり、かつて存在していたpearified.comの運営者でもありました。また、このチュートリアルで使われるS3のストリームラッパー実装(Killersoft_Wrapper_S3)とSOAPクライアント(AWSSoapClient)は彼自身の手によるものです。

チュートリアルファイルのダウンロード

http://s3.killersoft.com/AWSforPHP/awsfiles.zip

チュートリアルのPHPスクリプトは、バージョン5.1.2以上のPHPでの実行を前提にしています。チュートリアルファイル中のcompatibility.phpで動作要件を確認できます。

チュートリアルはAmazon純正の以下のライブラリを利用します。

チュートリアルファイルにはこれらのライブラリが含まれていますが、それらはチュートリアルが執筆された時点のバージョンのものであり、最新のものではありません。当然、対象となるAPIバージョンもチュートリアルの執筆時点のものとなっている点に注意してください。

設定ファイルの作成

チュートリアルは/etc/aws.confファイルに保存された設定情報を利用します。

/etc/aws.confファイルに、Security Credentialsで表示されるAccess Key IDとSecret Access Key、及びAccount Numberを、以下の書式で記述します。

; AWS Security Credentials
; Access Key ID
access_key = "06224BHAZ75910F2"
; Secret Access Key
secret_key = "aIfbA2568+12TEqLDYpiqOyRULvi9"
; Account Number
account_id = "123412341234"

さらに/etc/aws.confファイルに、チュートリアルのPHPスクリプトが作成するファイルを保存するディレクトリのパスを、以下の書式で追記しておきます。

; Path to writable directory where we can save files
tutorial_file_path = "/tmp"

接続の確認

チュートリアルの最初に登場するPHPスクリプトは、avail-zones.phpです。このスクリプトは、EC2のゾーンの利用可否を問い合せるDescribeAvailabilityZonesリクエストを発行します。

$ php avail-zones.php
<?xml version="1.0"?>
<DescribeAvailabilityZonesResponse xmlns="http://ec2.amazonaws.com/doc/2008-05-05/">
...

このスクリプトは最もプリミティブなRESTリクエストの作成例で、外部ライブラリに依存せずにURLをいちから組み立てています。そのため、スクリプトの実行で、/etc/aws.confファイルに記述したSecurity Credentialsの正当性が確認できるとともに、そのソースを読み解くことで、RESTリクエストのURLの構成、特にその署名(Signature)の作成方法が把握できるようになっています。

SOAPリクエスト

すべてのAWSはRESTとSOAPの両インタフェースで利用できます。チュートリアルは基本的にRESTを利用しますが、一部のスクリプトにはそのSOAP版も用意されています。

SOAPリクエストではX.509 Certificateが必要になります。Security CredentialsでX.509 Certificateを設定後、/etc/aws.confファイルに、cert-....pemファイルとpk-....pemファイルのパスを以下の書式で追記します。SOAPを利用しない場合は、この手順は不要です。

; X.509 Certificate Path
cert_file = "/path/to/my/cert-....pem"
; RSA private key 
private_key_file = "/path/to/my/pk-....pem"

avail-zones-soap.phpは、avail-zones.phpのSOAP版です。

$ php avail-zones-soap.php 
us-east-1a: available
...

これ以降に登場するチュートリアルのPHPスクリプトはその冒頭でexample_setup.phpをインクルードしています。このexample_setup.phpは、/etc/aws.confファイルから設定情報を読み込み、あわせて各スクリプトが利用するクラスライブラリ用のオートロードを定義しています。

EC2インスタンスの起動

初めてチュートリアルに取り組む際は、実際にEC2インスタンスを起動する前に、まずec2-prelaunch.phpを実行して、キーペアの作成とセキュリティグループの設定を行います。

ec2-prelaunch.php

  1. DescribeKeyPairsリクエストで「awstutorial」キーペアの存在を確認
  2. キーペアが存在しない場合、CreateKeyPairリクエストでキーペアを作成し、プライベートキーを、/etc/aws.confファイルの「tutorial_file_path」で設定したディレクトリの「id_rsa-awstutorial」ファイルに保存
  3. DescribeSecurityGroupsリクエストで「awstutorial」セキュリティグループの存在を確認
  4. グループが存在しない場合、CreateSecurityGroupリクエストでグループを作成
  5. グループの設定でポート80とポート22が開放されていない場合、AuthorizeSecurityGroupIngressリクエストでポートを開放
$ php ec2-prelaunch.php 
Creating awstutorial keypair...
generated fingerprint
f3:e4:e6:c8:92:dd:f1:52:be:ea:a3:9d:75:57:ba:65:61:a7:a3:28
generated material
-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----
Creating awstutorial security group ...done.
Opening awstutorial port 80 ...done.
Opening awstutorial port 22 ...done.

ec2-launch.phpを実行すると実際にEC2インスタンスが起動します。

ec2-launch.php

  1. RunInstancesリクエストで、ID「ami-2b5fba42」のAMI(Fedora Core 8)のインスタンスを起動し、そのインスタンスIDを、/etc/aws.confファイルの「tutorial_file_path」で設定したディレクトリの「awstutorial-instance.txt」ファイルに保存
  2. パブリックDNS名(ホスト名)が割り振られるまで、DescribeInstancesリクエストを定期的に実行し、パブリックDNS名が割り振られたらそれを、/etc/aws.confファイルの「tutorial_file_path」で設定したディレクトリの「awstutorial-hostname.txt」ファイルに保存
$ php ec2-launch.php 
Launching awstutorial instance.
i-b98db8d1 is pending
Waiting for public hostname...........................
i-b98da8d1 is running at ec2-75-101-188-56.compute-1.amazonaws.com
Instance booted in 76.150985002518 seconds.

EC2インスタンスの設定

/etc/aws.confファイルの「tutorial_file_path」で設定したディレクトリに移動し、ec2-prelaunch.phpスクリプトとec2-launch.phpスクリプトの実行によって保存されたファイルを使って、必要な環境変数を設定します。

$ cd /tmp
$ export AWSTUTORIAL_HOST=`cat \`pwd\`/awstutorial-hostname.txt`
$ export AWSTUTORIAL_KEY=`pwd`/id_rsa-awstutorial

/etc/aws.confファイルをEC2インスタンスにアップロードし、インスタンス上でチュートリアルのスクリプトを実行する環境を整えます。

$ scp -i $AWSTUTORIAL_KEY /etc/aws.conf root@$AWSTUTORIAL_HOST:/etc/aws.conf
$ ssh -i $AWSTUTORIAL_KEY root@$AWSTUTORIAL_HOST \
    'curl -O http://s3.killersoft.com/AWSforPHP/awsfiles.zip; \
    unzip awsfiles.zip -d /var/www/'
$ scp -i $AWSTUTORIAL_KEY awstutorial-*.txt root@$AWSTUTORIAL_HOST:/tmp/

インスタンスにSSHログインします。

$ ssh -2 -i $AWSTUTORIAL_KEY root@$AWSTUTORIAL_HOST

インスタンス上で、PHPとApacheのインストールを行います。

# yum -y install php \
    php-mcrypt.i386 \
    php-soap.i386 \
    php-xml.i386 \
    php-cli.i386 \
    httpd.i386

インスタンス上で、チュートリアルファイルのindex.phpをドキュメントルートにコピーし、アップロードされたビデオファイルを保存する/var/www/html/uploadsディレクトリを作成して、Apacheを起動します。

# cp /var/www/awsfiles/index.php /var/www/html/index.php
# mkdir /var/www/html/uploads
# chown apache:apache /var/www/html/uploads
# service httpd start

インスタンスのApacheの起動後に、ローカルコンピュータのウェブブラウザで、インスタンスのパブリックDNS名にアクセスすると、ファイルアップロードフォームが表示されます。インスタンスのパブリックDNS名は、/etc/aws.confファイルの「tutorial_file_path」で設定したディレクトリの「awstutorial-hostname.txt」ファイルに保存されています(もちろんAWS Consoleでも確認できます)。

ファイルアップロードフォームから適当なファイルをアップロードすると、インスタンスの/var/www/html/uploadsディレクトリにファイルが保存されます。現在のindex.phpが行うのはこの単純なファイルアップロード処理だけです。チュートリアルのシナリオでは、アップロードされたファイルはS3に保存され、そのパスがSQSに登録されて変換処理を待ち受けますが、現在のindex.phpは、まだそうした処理は行いません。

そこで次に、SQSにキューを作成し、index.phpを差し替えます。

SQSキューの作成

EC2インスタンス上で、sqs-makequeue.phpを実行して「awstutorial」という名前のキューを作成します。

sqs-makequeue.php

  1. ListQueuesリクエストで、名前が「awstutorial」で始まるキューの存在を確認
  2. キューが存在しない場合、CreateQueueリクエストでキューを作成
# php /var/www/awsfiles/sqs-makequeue.php 
Creating awstutorial...
Queue awstutorial created at https://queue.amazonaws.com/842929249205/awstutorial

アップロードファイルのS3への転送とSQSキューへのメッセージ送信

EC2インスタンス上で、現在のindex.phpをチュートリアルファイルのindex2.phpと差し替えます。

# cp /var/www/awsfiles/index2.php /var/www/html/index.php

新しいindex.phpはファイルアップロード処理の完了後にsqs-queue-conversion.phpをインクルードします。sqs-queue-conversion.phpは、アップロードされたファイルをS3に転送し、そのパスをメッセージとしてキューに送信します。

sqs-queue-conversion.php

  1. アップロードされたファイルをS3に転送
  2. SendMessageリクエストで、S3に転送したファイルのパスをメッセージとして「awstutorial」キューに送信

チュートリアルでは、S3の操作は、チュートリアルの著者であるClay Lovelessさん自身が開発したKillersoft_Wrapper_S3クラスを利用します。Killersoft_Wrapper_S3はS3に対するストリームラッパーの実装で、対応のファイルシステム関数などで、「s3://〜」というURLでS3のオブジェクトを操作できるようにするものです。

以下はsqs-queue-conversion.php中でKillersoft_Wrapper_S3を使用している箇所の抜粋で、Killersoft_Wrapper_S3::selfRegisterメソッドでラッパーを登録することで、is_dir、mkdir、file_put_contentsといったお馴染みの関数で、S3オブジェクトの操作が行われています。

Killersoft_Wrapper_S3::selfRegister();
...
$bucket = 's3://awstutorial-'
        . md5(
            $creds['access_key'] .
            $creds['secret_key'] .
            $host
        );

if (! is_dir($bucket)) {
    mkdir($bucket);
}
...
file_put_contents(
    "{$bucket}/{$upload_name}",
    file_get_contents($upload_file)
);

なお、チュートリアルでは、アップロードされたファイルはそのオリジナルのファイル名のままで保存されます。当然、同じ名前のファイルがアップロードされると同名のファイルが上書きされてしまうため、実用に供する場合はユニークなファイル名を割り当てる処理を追加する必要がありますが、チュートリアルではそうした処理は端折られています。

キューの確認

キューの状態はjob-check.phpを実行することで確認できます。

job-check.php

  1. S3に転送したファイルの存在確認
  2. GetQueueAttributesリクエストでキューにある可視メッセージの大凡の数(ApproximateNumberOfMessages)を取得して表示
  3. ReceiveMessageリクエストでキューにあるメッセージを受信してそのメッセージボディを表示(メッセージを確認するだけなので、他のプロセスの受信を妨げないようにVisibilityTimeoutは最小限に設定)
# php /var/www/awsfiles/job-check.php 
s3://awstutorial-a136e5e1e1e3ce3c44ffb1affbe79f1d/sample.mov is on S3!
Queue awstutorial has ~1 messages.
Found a message with a body of:
s3://awstutorial-a136e5e1e1e3ce3c44ffb1affbe79f1d/sample.mov

キューからのメッセージの受信と削除

チュートリアルでは、アップロードされたファイルはFLV形式に変換されます。変換処理を担当するプロセスはキューを監視し、新しいメッセージを受信すると変換処理を実施します。job-fetch.phpはこうしたプログラムの例です。

job-fetch.php

  1. ReceiveMessageリクエストでキューにあるメッセージを受信(VisibilityTimeoutは20秒に設定)
  2. メッセージのパスがS3上に実在するか確認
  3. パスが実在しない場合、DeleteMessageリクエストでメッセージを削除して終了
  4. パスが実在する場合、S3からファイルを転送して変換処理を実施
  5. 変換処理が成功したら(変換後のファイルが存在していたら)DeleteMessageリクエストでメッセージを削除
  6. 変換後のファイルをS3に転送し、変換元のファイルを削除
# php /var/www/awsfiles/job-fetch.php
Conversion complete!
Deleting completed job from queue.
Uploading converted file back to S3
Deleting original since we no longer need it

メッセージの受信時にVisibilityTimeoutで設定した秒数を経過すると、(メッセージが削除されていない場合)そのメッセージは再び可視状態となり、他のクライアントが受信可能になります。そこで実際のVisibilityTimeoutの設定は、複数のクライアントが重複してメッセージを受信しないように調整する必要があります。

なお、job-fetch.phpはビデオの変換にFFmpegを利用します。従ってjob-fetch.phpを実行するコンピュータにはFFmpegが必要で、チュートリアルの「Step 3: Perform Conversion Job」にはEC2インスタンスへのFFmpegのインストール手順が紹介されています。しかし、FFmpegのインストールや実行はチュートリアルの本旨ではなく、実際のところFFmpegのインストールは結構な手間なので、インストールや変換がうまくいかない場合は、job-fetch.phpのFFmpegの実行コマンドを編成している箇所を、以下のように適当に改変して対処してしまってください。

// ffmpeg command for transformation
// $cmd = '/usr/bin/ffmpeg -i '
//      . escapeshellcmd($localin)
//      . ' -ar 22050 '
//      . '-acodec mp3 -ab 32k -r 25 -s 320x240 '
//      . '-vcodec flv -qscale 9.5 '
//      . escapeshellcmd($localout);
$cmd = sprintf('cp %s %s',
        escapeshellcmd($localin),
        escapeshellcmd($localout));

SimpleDBによるビデオデータベース

チュートリアルでは、変換処理が完了した各ビデオは、そのデータが以下のような構造のSimpleDBデータベースに登録されます。

Item Name userid category file description size tags
item1 clay tutorials sample.mov Just a sample video. Watch! 71k apple

本来こうしたデータの登録は、ファイルのアップロードや変換処理の完了にあわせて行われるべきものですが、チュートリアルでは別途に手動で(!)行われます。さらにチュートリアルでは、リストを表示したりビデオを再生するウェブインタフェースは結局用意されません(つまりこのサイトのユーザは、アップロードしたビデオを見ることはできません)。もちろん、そのあたりはチュートリアルの本旨ではないのですが、まあとにかくバッサリ端折られてますんで、あらかじめご了解ください。

ドメインの作成

SimpleDBでは、RDBMSのテーブルに相当する概念を「ドメイン」と呼びます。sdb-create-domain.phpを実行すると、「awstutorial」という名前のドメインが作成されます。

sdb-create-domain.php

  1. CreateDomainリクエストで「awstutorial」という名前のドメインを作成
# php sdb-create-domain.php 
RequestId: 897b7cba-e9c0-1f11-9531-275dcf846e9b
BoxUsage: 0.0055590278

SimpleDBへのリクエストのレスポンスには、その利用料金の指標となる「Box Usage」の値が含まれます。

EC2では同時に起動可能なインスタンス数はデフォルトで20ヶに制限されていますが、SimpleDBにも同様の制限があり、デフォルトではドメイン数は100ヶまで、1ドメインあたりのデータ量は10GBまでに制限されています。そして、EC2と同様にリクエストベースでこの制限を緩和することが可能です。

ドメインの一覧

sdb-list-domains.phpを実行すると、作成したドメインの一覧を確認できます。

sdb-list-domains.php

  1. ListDomainsリクエストでドメインの一覧を取得
# php sdb-list-domains.php 
DomainName awstutorial

アイテムの追加

sdb-create-records.phpを実行してアイテム(レコード)を追加します。追加されるアイテムは、上表の「item1」のものです。

sdb-create-records.php

  1. PutAttributesリクエストで「awstutorial」ドメインに「item1」という名前のアイテム、及びその属性(各カラム値)を保存
# php sdb-create-records.php 
RequestId: ee265eb4-0924-684a-b261-7cec5030ff23
BoxUsage: 0.0000220339

1アイテムあたりの属性数は256ヶ以下、1ドメインあたりの属性数は10億ヶ以下に制限されています。

SELECTクエリーの実行

SimpleDBでは、限定的なSELECT文を用いてアイテムを検索することができます。sdb-sqlselect.phpは、tags属性値が「app」で始まるアイテムを検索する「SELECT * FROM awstutorial WHERE tags LIKE 'app%'」を実行します。

sdb-sqlselect.php

  1. Selectリクエストで「SELECT * FROM awstutorial WHERE tags LIKE 'app%'」を実行
# php sdb-sqlselect.php 
Item Name: item1
file: sample.mov
userid: clay
size: 71k
tags: apple
category: tutorials
description: Just a sample video. Watch!

利用可能なSELECT文の詳細は、Using Select to Create Amazon SimpleDB Queriesに記載されています。

1度のリクエストで取得可能なアイテムは2,500件以下、または合計データ量が1MB以下に制限されています。リクエストがこの制限を超えるアイテムにマッチした場合(及びクエリーの実行が5秒以上経過した場合)はレスポンスにNextToken要素が含まれ、その値を用いることで「次ページ」のリクエストが行えます。

チュートリアルのsdb-list-items.phpでは、Selectリクエストではなく、Queryリクエスト、及びQueryWithAttributesリクエストが行われていますが、これらはいずれも最新のAPIバージョン2009-04-15ではDeprecatedとなっています。

チュートリアルの紹介は以上です。チュートリアルではAmazon純正のライブラリを利用していましたが、AWSのライブラリには他にも様々なものがあり、以下ではそのひとつ、CloudFusionを紹介します。


CloudFusion(旧称Tarzan AWS)

CloudFusionはAWS等のクラウドサービス用のPHPライブラリです。CloudFusionは、AWSについては単一のパッケージで複数のサービスをサポートしており、現時点のバージョン2.5では、EC2、S3、SQS、SimpleDB、CloudFront、及びProduct Advertising APIをサポートしています。またAWS以外にも、クラウドサービスの基盤を提供するオープンソースソフトウェアであるEucalyptusをサポートしています。

CloudFusionは以前は「Tarzan AWS」という名称でしたが、2010年1月にリリースされた、Eucalyptusのサポートが追加されたバージョン2.5から、現在の名称に変更されました。このセクションは当初Tarzan AWSについてのものでしたが、CloudFusion 2.5のリリースに伴ない全面的に改訂しました。

以下はチュートリアルの「sdb-create-records.php」にある、SimpleDBのドメイン「awstutorial」にアイテム「item1」を追加するコードをCloudFusionのもので書き換えた例です。

require_once 'cloudfusion.class.php';

$sdb = new AmazonSDB(
        'Your AWS Access Key ID',
        'Your AWS Secret Access Key');

$response = $sdb->put_attributes('awstutorial',
        'item1',
        array(
            'userid'      =>  'clay',
            'category'    => 'tutorials',
            'file'        => 'sample.mov',
            'description' => 'Just a sample video. Watch!',
            'size'        => '71k',
            'tags'        => array('apple')),
        true);
print_r($response);

なお、上の例ではAccess Key IDとSecret Access Keyをコンストラクタのパラメータに指定していますが、これらはCloudFusionでは通常config.inc.phpに記述しておきます。これ以降に登場する例はいずれも、これらがconfig.inc.phpに記述されていることを前提に、コンストラクタのパラメータは省略しています。

CloudFusionには以下のような特徴があります。

リクエストの並列実行

CloudFusionではcurl_multi_*によるリクエストの並列実行が可能です。

以下は通常の、逐次リクエストを実行する例です。ここではSQSキューに10ヶのメッセージを送信しています。AmazonSQS->send_messageメソッドは直ちにリクエストを実行し、レスポンスオブジェクトを返します。

require_once 'cloudfusion.class.php';

$sqs = new AmazonSQS;
$responses = array();
for ($i = 0; $i < 10; $i++) {
    $responses[] = $sqs->send_message(
            'https://queue.amazonaws.com/awstutorial',
            "This is message #$i");
}
print_r($responses);

以下は上の例を、リクエストを並列実行するように書き換えたものです。CloudFusionのAmazon*クラスの多くのメソッドは、パラメータの最後にTRUEを指定すると、リクエストを実行してレスポンスオブジェクトを返す代わりに、リクエストのcURLハンドルを返します。ハンドルの配列をRequestCore->send_multi_requestのパラメータに指定するとリクエストが並列実行され、その各レスポンスオブジェクトの配列が返されます。

require_once 'cloudfusion.class.php';

$sqs = new AmazonSQS;
$handles = array();
for ($i = 0; $i < 10; $i++) {
    $handles[] = $sqs->send_message(
            'https://queue.amazonaws.com/awstutorial',
            "This is message #$i",
            true);
}
$request = new RequestCore;
$responses = $request->send_multi_request($handles);
print_r($responses);

組み込みのキャッシュ機構

CloudFusionにはレスポンスのキャッシュ機構が用意されており、必要に応じて利用することができます。現在対応しているキャッシュストレージは、ファイル、SQLite、MySQL、PostgreSQL、APC、及びMemcacheとなっています。

容易なクラスのカスタマイズ

CloudFusionでは、通常内部的に使われるクラスについても容易にそのカスタムクラスが利用出来るようになっています。以下は例として、リクエストURLを返すgetRequestUrlメソッドを実装したResponseCoreの継承クラスを作成しています。カスタムクラスを利用するには、Amazon*クラスのset_*_classメソッドのパラメータにカスタムクラスの名前を指定します。

require_once 'cloudfusion.class.php';

class CFCustomResponse extends ResponseCore {
    public function getRequestUrl() {
        if (isset($this->header['x-cloudfusion-requesturl'])) {
            return $this->header['x-cloudfusion-requesturl'];
        }   
        return null;
    }   
}

$sqs = new AmazonSQS;
$sqs->set_response_class('CFCustomResponse');
$response = $sqs->send_message(
        'https://queue.amazonaws.com/awstutorial',
        "This is another test message.");
echo $response->getRequestUrl() . "\n";

カスタムクラスはCloudFusionの命名規則に従ったファイル名を与えることで、CloudFusionのオートロードの対象になります。現在のCloudFusionのクラスファイルの命名規則は、クラス名が「Amazon」で始まる場合はそれを除去し、「CF」で始まる場合はそれをアンダースコアに置換し、クラス名をすべて小文字にして「.class.php」を続けるというものです。例えば上の例の「CFCustomResponse」クラスの場合、そのファイル名は「_customresponse.class.php」となります。

ドキュメント

CloudFusionのドキュメントは比較的よく整備されており、APIリファレンスには、多くのメソッドにサンプルコードが用意されています。

以上、AWS用のライブラリの例としてCloudFusionを紹介しました。AWS用のライブラリには、このCloudFusionや、チュートリアルで登場したKillersoft_Wrapper_S3のように、Amazon純正のもの以外にも様々なものがあり、プロジェクトのニーズ次第では検討の余地があるのかもしれません。

サラリーマン田中K一がゆく!
田中 圭一
角川グループパブリッシング
ウノウでは特に最近、積極的にエンジニアを採用しています。
採用ページをご覧になり興味のある方、ぜひご応募ください!!
Find Job!でも募集開始してます!

2009年10月28日

Tokyo Tyrantを使ってみて
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

yamaokaです。

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

PHPのクライアント

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

監視

Nagiosのcheck_tcpプラグインを利用しています。 Tokyo Tyrantが動いているサーバーにmemcachedプロトコルで接続、 statsコマンドを実行してチェックしています。memcachedが動いているサーバーを監視するのと同じ要領ですね。

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

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

ログローテート

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

/var/ttserver/log {
    missingok
    notifempty
    compress
    sharedscripts
    postrotate
        /usr/sbin/ttservctl hup > /dev/null 2>/dev/null || true
    endscript
    rotate 7
    daily
}

バックアップ

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

最後に

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

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

2009年10月21日

ソフトウェアテスト関連のTwitterアカウント
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

こんにちは!gal_tonkatsu やまもと@テスト番長です。

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

ウェブサイト/サービス/企業(順不同)

RBCS http://www.rbcs-us.com/
utest http://www.utest.com/
TestingWebSites http://www.testing-web-sites.co.uk/
testinggarage http://testinggarage.blogspot.com/
TestingNews http://qualitypoint.blogspot.com/
usertesting http://www.usertesting.com/
CloudTesting http://www.cloudtesting.com/

達人:海外

yourdon Ed Yourdon さん
johannarothman Johanna Rothman さん

達人:国内(50音順)

akiyama924 秋山 浩一 さん
ikedon 池田 暁 さん
mkoszk 鈴木 三紀夫 さん
nagworld 永田 敦 さん
YasuharuNishi 西 康晴 さん
honda_ ほんだ さん
yumotsuyo 湯本 剛 さん
mikantsuki みかまま さん


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

2009年8月18日

Tips for nginx
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

何を今更と思うかもしれませんが、最近、英語圏に住んでいようがいまいが
ソフトウェア開発で英語は必須だと改めて実感したbokkoです。

  • 英語の技術書を読んでいる
  • 日本人の開発者が作ったソフトウェアに付属している仕様書を読んだら英語で書かれていた
  • 日本人の開発者宛に英語でバグレポートを書いていることに気付く(フォーラム全体が英語だった!)

私も自分の書いたライブラリのドキュメントを書き始めましたが、
全部英語だったりします。(少し前に海外の方からライセンスに関する質問を「英語」で受けました)
そして、今日紹介するnginxも開発元はロシアですが、英語のドキュメントが充実しています。

nginxとは

nginxは高速軽量なWebサーバです。(えんじんえっくすと読みます)
基本的なHTTPとしての機能に加えてSSLやFastCGIのサポート、
リバースプロキシ、バーチャルホスト、メールプロキシといった
便利な機能も兼ね備えています。開発元はロシアですが、
ロシア語だけでなく、英語や日本語を含む複数の言語に翻訳されているWikiがあります。

インストール

ソースコードからビルドします。(ここで使用しているバージョンは0.7.61です)

$ ./configure
$ make
$ sudo make install

nginxが使用する外部モジュール

nginxでURI書き換えやgzip圧縮、SSLといった機能を使用するには
外部のモジュールが必要になります。例えばCentOSではそれぞれ
以下のモジュールをyum等でインストールする必要があります。

URI書き換え pcre-devel
gzip圧縮 zlib-devel
SSL open-ssl-devel

cofigure時に指定するオプション

nginxはconfigure時にpcreはデフォルトで使用するようになっていますが、
URI書き換え機能を使わない場合は--without-pcreを指定することで、無効にできます。
また、SSLを使用する際は--with-http_ssl_moduleを指定するのがよいでしょう。
その他のconfigure時のオプションはWikiの以下のページが参考になります。

Compile-time options

nginxの設定

ここではnginxで設定する主要なパラメータについて解説します。

worker_processesとworker_connections

worker_processesとworker_connectionsはApacheのMaxClientsに相当するパラメータです。
まず、worker_processesですが、これはnginxを起動した後に常駐し、
クライアントのアクセスを受け付けるワーカーの数です。
worker_connectionsは1つのワーカーが扱えるクライアントの最大数になります。
つまりものすごく単純化すると、nginxのmax_clientsは、

max_clients = worker_processes * worker_connections

ということになります。worker_connectionsはeventsディレクティブ内に以下のように記述します。

events {
   worker_connections  1024;
   use epoll;
}

useの部分にはnginxが使用するイベントモデルを指定します。
上記のepollのほかにおなじみのselectやkqueue等があります。
また、このあたりのより詳しい設定についてはWikiにあるNginxHttpEventsModulesのページが参考になります。

リバースプロキシとして使う

nginxをリバースプロキシとして動作させる場合の設定例は以下のようになります。
プロキシの後ろにWebサーバ2台(10.0.0.11と10.0.0.12)がぶら下がってるとすると、($nameと$domain_nameは任意)

http {
   upstream $name {
       server 10.0.0.11:80 weight=3;
       server 10.0.0.12:80 weight=3;
   }
   server {
       listen 80;
       server_name $domain_name;
       location / {
           proxy_pass http://$name;
       }
   }
}

という風になります。

プロキシにアクセスしてきたクライアントのIPアドレスをWebサーバに引き継ぐ

通常、クライアントがプロキシサーバにアクセスし、
プロキシサーバがそのリクエストをWebサーバに渡す場合、
Webサーバに記録されるIPアドレスはプロキシサーバのものとなります。
携帯向けサービスでは特にキャリアの種類やPCか携帯からのアクセスか?等によって
処理を振り分ける必要があるので、Webサーバには元のIPアドレスを渡したい
ケースがあります。これを実現するには以下の設定を記述します。

proxy_set_header        Host            $host;
proxy_set_header        X-Real-IP       $remote_addr;
proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;

また、プロキシにぶら下がっているWebサーバがApacheの場合、
mod_extract_forwardedやmod_rpaf等を使うことによって
リバースプロキシ越しのIPアドレスを取得できます。
mod_extract_forwardedを使う場合、
Apacheの設定ファイルには以下のように記述します。

MEForder refuse,accept
MEFrefuse all
MEFaccept x.x.x.x # プロキシのIPアドレス

nginxでSSL

nginxでSSLを使うにはhttpディレクティブ内に以下のような記述をします($nameと$domain_nameは任意)。

server {
   listen       443;
   server_name  $domain_name;
   ssl                  on;
   ssl_certificate      (サーバ証明書へのパス)
   ssl_certificate_key  (秘密鍵へのパス)
   ssl_session_timeout  5m;
   ssl_protocols  SSLv2 SSLv3 TLSv1;
   ssl_ciphers  ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
   ssl_prefer_server_ciphers   on;
   location / {
       root    /usr/share/nginx/html;
       index  index.html index.htm;
   }
}

nginxで中間CA証明書を使用する

nginxには中間CA証明書を直接指定するための方法がありません。
そのため、ちょっと面倒ですが、サーバ証明書に追記する必要があります。
サーバ証明書と中間証明書が以下のような形式だとすると、

サーバ証明書

-----BEGIN CERTIFICATE-----
(サーバ証明書の内容)
-----END CERTIFICATE-----

中間CA証明書

-----BEGIN CERTIFICATE-----
(中間CA証明書の内容)
-----END CERTIFICATE-----

サーバ証明書に中間証明書を追記する形で、サーバ証明書を以下のように編集します。

-----BEGIN CERTIFICATE-----
(サーバ証明書の内容)
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
(中間CA証明書の内容)
-----END CERTIFICATE-----

参考

2009年8月12日

WEBアプリのテストに便利なFirefoxのアドオン
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

こんにちは! のりPと同い年ですが、クラブ通いは●年前に卒業しました やまもと@テスト番長です。

早いもので、もうお盆の帰省シーズンですね。
今年の夏は世間の騒がしい日々が続いておりますが、みなさんお変わりございませんでしょうか。

さて、Firefoxといえば豊富なアドオンですが、今回はテスター目線で
WEBアプリケーションのテストに便利なFirefoxアドオンを並べてみたいと思います。


Firesizer
ブラウザの画面サイズを整えることが出来ます。

InFormEnter
準備しておいた値を入力フォームにセットしてくれます。

MeasureIt
画面上のピクセルサイズを測ることが出来ます。

Regular Expressions Tester
正規表現での検索がその場で出来ます。

FireShot
キャプチャにメモを書き込んだり出来ます。

Web Developer
Firebug

開発者必携のアドオンですが、レポートを書くときなど便利です。
このへんは入れておかないと開発者から信頼されないような気がします。

SQL Injection
HackBar

脆弱性を探すときはあると便利です。

YSlow
サイトのパフォーマンスを計測し、改善に役立てることが出来ます。

User Agent Switcher
ユーザーエージェントを偽装してくれます。

Tamper Data
HTTPリクエスト/レスポンスをモニタリングします。
POSTデータを書き換えて再送することも出来ます。

Live HTTP Headers
HTTPリクエスト/レスポンスをモニタリングします。
流れを見るだけでよければこちらがシンプルです。

HttpFox
HTTPリクエスト/レスポンスをモニタリングします。
表示がしっかりしています。

Selenium IDE
Seleniumを使う方なら必須ですね。

FireMobileSimulator
携帯端末をエミュレートしてくれます。


ツールの有無が生産性に大きく影響することは多々ありますので、
普段から楽をするよう準備に気をつけたいところですね。
他にもいいアドオンがありましたらコメントいただけますと幸いです。

2009年6月 1日

テスターの人権
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

こんにちは!やまもと@テスト番長です。

最近、15年住み続けた築40年以上になる木造アパートから、築2年の駅近マンションに引越しました。
あまりの住環境の落差に、今までは何だったんだろうと呟いていたりします。
変化することを面倒臭がらずに、日々快適な暮らしを目指すべきだったんでしょうね。

さて、テスターが快適に仕事をするに当たって、保障されるべきこととは何でしょうか?
「テスターの権利章典」というものを考えた方がいるのをご存知ですか?
昨年秋に訳されたもので旬は逃しておりますが、最近ふと思い出したのでご紹介してみます。


テスターの権利章典
Tom Gilb & Kai Gilb : Testers Bill of Rights

こちらのページの下のほうに、大西建児さん訳の日本語版があります。


これはテスターの方のみならず、むしろプログラマの方に見ていただきたいなと思います。
お互いを尊重し協業していく上で、相手にとって何が大事なのかを知っておくのは、とても重要なことだからです。

人権というとちょっと大袈裟かもしれませんが、大事にしたいことばかりですね。

2009年3月27日

デキるテスターの七つの習慣
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

こんにちは!やまもと@テスト番長です。

今回はなんだか怪しいタイトルになってしまいましたが、
テスターの心構えについての良い記事がありましたのでご紹介します。

The Seven Habits of Highly Effective Testers - By Steve Miller

以下、まとめ(超意訳)です。
ぜひ原文もお読みになってください。


1. 前向きであれ
プロジェクトが失敗した時、それが他の人や事情のせいだったと考えても得るものはありません。
失敗から得た教訓を次に繋げるべきです。

  • 要件定義に参加するようにしましょう。
  • 漏れがないかトレーサビリティを分析しましょう。
  • テストの効果をメンバーに伝えましょう。
  • 不具合を分かりやすく報告しましょう。

2. ゴールを念頭に置く
周囲と相談の上、前もってゴールとなる品質基準を決めておくべきです。
評価基準を満たしたかどうかを客観的に評価できます。

3. 大事なことから先にやる
重要な機能が正常に動作することをまず確認しましょう。
オーバーフローやインジェクションなどのテストも重要ですが、後で行えばいいことです。

4. 開発チームと良い関係を作る
開発とテストチームがお互いに非難しあうようになってはいけません。
良い協力関係を作りましょう。

  • ナレッジを共有しましょう。
  • 異なった役割の人と一緒にランチを取って交流しましょう。
  • 良い仕事をした人はちゃんと褒めましょう。
  • 困っているメンバーがいたら助けましょう。

5. 他人の話を良く聞く
問題を性急に判断してしまわずに、まず良く理解することを心がけましょう。
異なる考え方を攻撃せず、経験を元により良いアプローチについて説明しましょう。

6. 仲間と協力し合う
共同作業は協調性が重要です。
メンバーは異なる能力を持っているので、互いに長所を生かしましょう。
コミュニケーションを取り合いましょう。


7. 刃を研ぎ澄ます
新しい技術を習得しスキルを磨くことを心がけましょう。テスト本を漁りましょう。
趣味や余暇も充実させましょう。


色々思い当たるところがありますね。
自分ももっと精進しようと思いました。

2009年1月20日

テスト計画書のテンプレート
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

こんにちは!やまもと@テスト番長です。
巷ではインフルエンザが流行っているようですが、皆さんお元気にお過ごしでしょうか。

さて、プロジェクトが立ち上がったとき、(特に受託案件の場合)
テストのドキュメントはどうしようか?という話が出ると思います。
適当にやる訳にも行かないけれどIEEE829をベースにしたものだと重かったり、割と迷う部分です。

英語ですがテスト計画のテンプレートを配布しているサイトがあったので、ご紹介してみます。

Pragmatic Software http://www.pragmaticsw.com/
Software Development Templates http://www.PragmaticSW.com/Templates.asp

テスト計画書
Test Design - http://www.pragmaticsw.com/Template_TestDesign.doc

構成としては全部で6章とIEEE829の半分になっていて手頃な感じです。
特に2.1 Level of Testing の項目は、どのテストを重点的に実施するかを決めておくリストになっていて参考になりそうです。

docをすぐ開けない方向けに項目を抜き出してみます。

  • Performance Testing
  • Windows / Internet GUI Standards
  • Platform Testing
  • Localization
  • Stress Testing
  • Conversion
  • Parallel Testing
  • Regression of unchanged functionality
  • Automated Testing
  • Installation Testing
  • End to End / Interface Testing
  • Usability
  • User's Guide / Training Guides
  • Guerilla Testing
  • Security Testing
  • Network Testing
  • Hardware Testing
  • Duplicate instances of application
  • Temporal Testing
  • Disaster Recovery (Backup / Restore)
  • Input and Boundary Tests
  • Out of Memory Tests

日本語でテストのテンプレートを検索してもあまりヒットしないので、こういったものがあると有難いですね。

このサイトにはテスト計画書の他にも、下記のテンプレートなどがあり役に立ちそうです。
自分もよく読んでみたいと思います。

リスク査定書
Risk Assessment - http://www.pragmaticsw.com/Template_RiskAssessment.doc

ユーザー受け入れテスト報告書
User Acceptance Testing Report - http://www.pragmaticsw.com/Template_UATRelease.doc


2008年12月11日

ImageMagickでGIFアニメをリサイズ
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

ウノウでは特に最近、積極的にエンジニアを採用しています。
採用ページをご覧になり興味のある方、ぜひご応募ください!!

こんにちは、いそがわです。

PHPでアニメーションGIFを操作しようとすると、GDはアニメーションGIFをサポートしていないのでImageMagickを利用することになるかと思いますが、いかんせんImageMagickはメソッドの数がベラボーで分かりづらく、Imagickに至ってはまだまだドキュメントがスッカスカで、間違ってたりもするためなのか、意外とアニメーションGIFのリサイズ処理に混乱が見受けられるようなので、ご存知のかたには今更な話題ですが、あらためて。

ImageMagickでアニメーションGIFを“お手軽に”リサイズする基本的な手順は以下のような感じです。

  1. シーケンスのイメージの“結合”(coalesce)
  2. 各イメージを順次リサイズ
  3. 最適化(必要なら)

このうち重要かつ忘れられがちだと思われるのがcoalesce処理です。アニメーションシーケンスの各イメージはすべてが同じサイズとは限りません。各イメージはそれぞれサイズや表示オフセットが異なっているかもしれませんし、また次のイメージを表示する際に現在のイメージをどう処理するかというdisposal methodとかあったりします。高度に最適化されたアニメーションシーケンスほどその構成は複雑で、こうした点を考慮しないと、期待した結果が得られないかもしれません。coalesceはこうしたアニメーションシーケンスを、手軽に扱えるようにする処理です。

MagickWand C APIのMagickCoalesceImagesの説明が簡潔なので引用します。

MagickCoalesceImages() composites a set of images while respecting any page offsets and disposal methods. GIF, MIFF, and MNG animation sequences typically start with an image background and each subsequent image varies in size and offset. MagickCoalesceImages() returns a new sequence where each image in the sequence is the same size as the first and composited with the next image in the sequence.

訳すとこんな感じでしょうか。

MagickCoalesceImages()はページオフセットやdisposal methodを考慮しながらイメージセットを合成します。GIF、MIFF、及びMNGアニメーションシーケンスは、一般的に背景画像で始まり、以降の各イメージのサイズやオフセットはさまざまに異なります。MagickCoalesceImages()はシーケンスの各イメージが、最初のイメージと同じサイズで、かつシーケンスの次のイメージと合成された新しいシーケンスを返します。

下図は、Gakkunさん作のnatmというアニメーションGIF作成ツールで、http://www.creepygif.com/image.php?i=578に掲載されているアニメーションGIFファイルを開いた画面です。ここではこのアニメーションシーケンスの2フレーム目を選択していますが、左側のウィンドウに表示されているこのフレームのイメージは、前後のフレームのイメージと比較して変化のある箇所だけのものになっています。アニメーション全体の縦横サイズは225×344ピクセルですが、この2フレーム目のイメージの縦横サイズは69×211ピクセルで、その表示オフセットは横55ピクセル、縦8ピクセルとなっています。

オリジナル

下図は同じファイルをcoalecse処理したものです。同じ2フレーム目を選択していますが、オリジナルでは変化のある箇所だけが描画されていたイメージは完全なものに合成され、縦横サイズもアニメーション全体と同じになっています。

coalesce処理

coalesce処理されたアニメーションシーケンスは手軽に扱える一方で、その処理内容を鑑みれば必然ですが、元のアニメーションシーケンスが高度に最適化されていればいるほど、相対的なデータサイズが大きくなってしまいます。

アニメーションシーケンスは最適化処理を施すことでデータサイズを縮小できる場合があります。coalesce処理されたアニメーションシーケンスに対する最もお手軽な最適化処理として伝統的に用いられてきたのがdeconstructです。deconstructは、coalesceによって同じサイズになっているシーケンスの各イメージを、その次のイメージと比較して変化のある領域の四辺より広い範囲を切り捨てます(結果のシーケンスは、各イメージのサイズとオフセットがバラバラになります)。

下図は上述のファイルをcoalecse→deconstruct処理したものです。deconstruct処理によって、イメージは前後のフレームのイメージとの差分だけになっているため、coalecse処理だけを施したものではすべて同じになっていた各フレームの縦横サイズとオフセットは、ここではバラバラになっています。一方イメージの差分は、オリジナルではピクセル単位であったものが、変化のある領域の最大四辺となっており、まだ最適化の余地があるということがわかります。

coalesce→deconstruct処理

なおdeconstructは、coalesce処理されていないアニメーションシーケンスに対しては期待通りの結果が得られない場合があり、またそもそもこれの利用は、今では非推奨とされているようです。Imagickではアニメーションシーケンスの最適化処理にoptimizeImageLayersを利用することができます。

コード例

以下はアニメーションGIFファイル「source.gif」を縦横50%縮小したファイル「dest.gif」を書き出す例です。ここではすべて共通で、最適化処理としてdeconstructを行っています。

Imagickでのコード(エラー処理とか省略)

$source = 'source.gif';
$dest   = 'dest.gif';
$scale  = 0.5;

$images = new Imagick($source);
$images = $images->coalesceImages();
$width  = round($images->getImageWidth()  * $scale);
$height = round($images->getImageHeight() * $scale);
do {
    $images->scaleImage($width, $height);
} while ($images->nextImage());
$images = $images->deconstructImages();
$images->writeImages($dest, true);

MagickWand For PHPで上のコードを写経

$source = 'source.gif';
$dest   = 'dest.gif';
$scale  = 0.5;

$images = NewMagickWand();
MagickReadImage($images, $source);
$images = MagickCoalesceImages($images);
$width  = round(MagickGetImageWidth($images)  * $scale);
$height = round(MagickGetImageHeight($images) * $scale);
do {
    MagickScaleImage($images, $width, $height);
} while (MagickNextImage($images));
$images  = MagickDeconstructImages($images);
MagickWriteImages($images, $dest, true);

ちなみにconvertコマンド

$ convert source.gif -coalesce -scale 50% -deconstruct dest.gif

上のコードを見れば一目瞭然かと思いますが、アニメーションGIFのリサイズは、シーケンスの各イメージを個別に順次リサイズすることになり、必然的にイメージ数が多ければそれだけ処理に時間がかかります。JPEGなどのリサイズと比べて時間がかかることがあるのはそのためです。例えば、数十~数百ものイメージからなるアニメーションGIFのリサイズには数分~数十分もかかるかもしれませんから、ユーザからのアップロードを、キューなどを用いずにリクエスト内で処理しようとするとタイムアウトになる可能性があり、注意が必要です。

おかしいなと思ったときは

GIFを扱うツールはさまざまありますが、中にはシーケンスのさまざまな情報を細かく確認できるものもあります。処理結果が期待通りではない場合は、こうしたツールを利用すると状況が確認できるかもしれません。

上にも登場いただいたnatmもそうしたツールのひとつですが、ちなみにこれに付属のドキュメントは、アニメーションGIFについての非常にわかりやすい説明にもなっていて、例えばdisposal methodって具体的にはなんなの?といった疑問が一読で氷解されると思われ、アニメーションGIFの仕組みをちょっと詳しく知りたいというかたにはお勧めです。

ではでは


2008-12-12改定: 文章だけだとわかりづらい気がしたので図版を追加しました。

2008年11月26日

NetBeansでConsolasフォントを使う
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

yamaokaです。

NetBeansの6.5がリリースされましたね。もともとNetBeansはJava用のIDEですが、今ではPHPやRuby、C/C++の開発にも使えるようになっています。PHPをバンドルしたものを試しているのですが、入力補完など基本的な動作はもちろん、Subversionなどバージョン管理ツールとの連携も便利で個人的な開発にはすっかり手放せないものとなってしまいました。

さて、新しいIDEやエディタを導入したとき、皆さんは初めに何をするでしょうか。私の場合はフォントの設定を行う場合が多いです。Consolasフォントがお気に入りなのですが、Windows環境に導入したNetBeansでエディタのフォントにConsolasを指定すると 日本語が正しく表示されません(豆腐文字になってしまいます)。Windowsのフォントリンクの機能なども試してみましたが、うまく表示されないようです。

NetBeans
NetBeans posted by (C)フォト蔵

NetBeansはSwingで動作しているので、Java側で設定されている論理フォント「Monospaced」の設定を書き換え、「Monospaced」を使うようにすれば表示することができるようになります。ということで、Java側の設定を変更してしまいます。ちなみに、今回NetBeansはJava SDK 1.6.0_10に付属のJREで動作しています。

Javaの設定はプロパティファイルで変更することができます。JDKをインストールしたフォルダに「jre」というフォルダがあるので、その中にある「fontconfig.properties.src」をコピーして同じ場所に「fontconfig.properties」というファイルを作り、エディタで編集します。

まず、Consolasフォントが使えるように末尾に次の内容を追記します。

filename.Consolas=CONSOLA.TTF
filename.Consolas_Bold=CONSOLAB.TTF
filename.Consolas_Italic=CONSOLAI.TTF
filename.Consolas_Bold_Italic=CONSOLAZ.TTF
また、なぜかWindows環境で「Monospaced」が指定された場合に英字フォントより日本語のフォントを優先して使うようになっているので、「sequence.monospaced.windows-31j」の値を「alphabetic」と「japanese」を逆にして次のように変更します。
sequence.monospaced.windows-31j=alphabetic,japanese,dingbats,symbol
最後に、「Monospaced」の英字フォント設定を変更します。デフォルトでは「Courier New」になっているので、「Consolas」に変更していきます。変更箇所は4ヶ所です。
monospaced.plain.alphabetic=Consolas
monospaced.bold.alphabetic=Consolas Bold
monospaced.italic.alphabetic=Consolas Italic
monospaced.bolditalic.alphabetic=Consolas Bold Italic
変更が終わったら「fontconfig.properties」を保存してNetBeansを起動しましょう。エディタのフォントはMonospacedに設定します。

NetBeansでConsolasフォント
NetBeansでConsolasフォント posted by (C)フォト蔵

英字部分はConsolasで、日本語部分はMSゴシックで表示されるようになるかと思います。日本語の表示を他のフォントに変更する場合は、同じように「fontconfig.properties」の値を書き換えることで変更できます。

フォントの変更方法について書いてきましたが、NetBeansはかなり便利です。何より、体感的にEclipseより動作が軽い気がします。XDebugを使ったリモートデバッグもできるようなので、そのうち試してみたいところです。

2008年11月11日

BTSに関する四方山話
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

こんにちは! やまもと@テスト番長です。

最近gihyo.jpで連載させていただいている関係で、BTSについて考える機会が多くなっています。

思えば今までのエンジニア人生で色々なBTSを使ってきました。
今まで経験したことから、幾つか記事には出ないような四方山話をしてみたいと思います。

Bugzillaの蟻?画像が辛い

Bugzillaを使ってシステムテストをしていたとき、ふとTOPページの蟻?画像の話になりました。 使ったことのある方はご存知かと思いますが、昆虫の頭部の顕微鏡写真のようなあいつです。 忙しいだけでも辛いのに、アレを見るとゲンナリする!ということになり 急遽ほのぼの画像に差し替えたところ、相当印象が変わって見えました。 プロジェクトの雰囲気も若干良くなったように思います。

チケットがよく壊れるBTSもある

rubyで出来た某軽量BTS的なものを使っていたとき、チケットが1000件を越える頃から 段々ページが重くなり、頻繁にチケットが壊れるようになりました。 バグを取り扱うシステムに不都合が出るのはなんとも切ないものです。BTSの耐久性や安定性は大事ですね。 オープンソースで歴史のあるBTSはその点信頼性が高いものが多いようです。

ローカルルール色々

バグの取り扱いについての情報はあまり表に出ないように思います。 上手く行ってないけれど台所事情は人に相談しづらいというのが本音でしょう。 正式なお作法はどうなのかという話もそれほどなく、皆さんケースバイケースということのようです。

個人的な経験の中でも特に処理フローはまちまちでした。開発チームの体制に影響されるのが大きいです。


  • スキルの低いテスターが参加する場合は、チケットが有効か判定するフローを作る

  • リリース段階(ステージ→本番、など)に合わせて、確認段階を細かく作る

  • 場合によりクローズの確認を管理者のみ出来るようにする

などはすぐ思いつくところですね。

インストールが嫌

BTSのインストールは面倒なので出来ればやりたくありません。 全般に日本語の情報が少なく、バージョンが変わると以前の情報が役に立たなかったりして、なんだかんだで一日潰れたりします。 ここは皆さん苦労しているはずなので、もっと情報共有すべきなのかもしれません。

私製BTSでの運営は結構多い

既製品のカスタマイズの不便さや不具合を恐れて内製のBTSを使ってらっしゃるところも結構多く、2割くらいあるようです。 色々なものがあるようなので、表に出てきて比較できたら面白いのに。。とつい思ってしまいます。

BTSはコミュニケーションツールかもしれない

バグを管理してくれるBTSですが、結局人間が関わるものですので 「バグを抱えた人々のためのコミュニケーションツール」なのかもしれないと思うことが多々あります。 受託開発で顧客とBTS越しにやりとりする時などは特にそうですね。 バグを記録することだけに注目していると上手く回らないように思います。


xxx

取り留めのない話になりましたが、皆さんのご苦労話もあればお聞かせください。
連載記事のほうもお時間のあるときにでもお読みいただき、ご意見をいただけますと幸いです。

ソフトウェア開発の必須アイテム,BTSを使ってみよう

 

2008年10月10日

Tips for HyperEstraier
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

先月、VX Revolution VX-Rを購入して、その使い心地の良さに素直に感動しているbokkoです。

HyperEstraier

HyperEstraierは平林幹雄さんが開発されている全文検索エンジンです。全文検索エンジンとして使えるのはもちろん、全文検索のためのライブラリとして使うこともできます。ウノウではHyperEstraier(以下HE)をフォト蔵の写真検索に利用しています。

今回はHEの活用や運用に関するTipsについて紹介します。

インデックスの作成

HEのインデックスを作成する方法はいくつかありますが、単にデータが空のインデックスを作るのであれば以下で十分です。

$ estcmd create idx

実際には想定されるインデックスのサイズなどに応じてオプションを追加するといったことが必要になるでしょう。ファイルやディレクトリ(内のファイル)をインデックスに追加するにはgatherコマンドを使います。

$ estcmd gather idx data # dataはファイルもしくはディレクトリ

gatherはデフォルトではサポート外の拡張子のファイルは無視するので、サポートされていない拡張子のファイルをインデックスに追加する場合は、-feオプションを付けましょう。

インデックスの最適化

HEのインデックスに追加されたデータは削除することが可能ですが、データがインデックスから削除されても削除された領域分、データが小さくなるわけではありません。つまり、インデックスからデータが削除されても、削除された領域はゴミとして残ります。これはインデックス内のデータへのアクセス速度に後々影響を与えるので、optimizeコマンドを使って、削除された領域を整理し、インデックスのサイズを縮小するとよいでしょう。

$ estcmd optimize idx

なお、インデックスの最適化はインデックスのサイズが大きいと時間がかかる上にCPUリソースをかなり消費するので、注意しましょう。また、インデックスの無駄な整理するのはpurgeコマンドに-clオプションを付けて実行することでも可能です。

$ estcmd purge -cl idx

インデックスの分割とマージ

HEのインデックスは件数が増えてくると段々(特に更新の)パフォーマンスが劣化し始めます。そのため、導入時などに件数の多いデータのインデックスを作成する際は、まず小さいインデックスをたくさん作り、後で各インデックスをマージしてまとめる方が効率がよいです。

$ estcmd merge idx1 idx2 # idx2をidx1にマージ

属性検索と属性インデックス

属性検索は非常に遅いので、使う場合はできるだけ属性インデックスを作成しましょう。ただ、それでも通常の検索に比べると遅い上にCPUリソースを結構喰うので、どうしても使いたい時だけ使いましょう。特にesmasterに対して検索リクエストを送って属性検索を行うとインデックスのサイズが大きい場合、時間がかかるだけでなく、最悪の場合、estmasterが落ちてしまう可能性があります(estmasterについては後述)。また、属性にインデックスを貼るとインデックスの更新が遅くなります。

$ estcmd create -attr @str_data str idx # 属性str_dataに文字列インデックスを貼る

estmasterの運用

HEのP2P機能やノードAPIを使ってアプリケーションを作成する場合、サーバプログラムであるestmasterを使用する必要があります。estmasterは検索やインデックスの更新、削除などのリクエストをHTTP経由で受け取り、実行します。estmasterを使うにはまず、専用のサーバルートディレクトリを以下のコマンドで作成します。

 $ estmaster init casket

間違っても既にあるサーバルートディレクトリを再度初期化しないようにしましょう。_node以下のインデックスが丸ごと消えます。(導入作業が佳境に差し掛かった頃に一度消して泣きそうになりました)estmasterを起動するには以下のコマンドを実行します。デフォルトではポート番号1978が使用されますが、この設定はサーバルート以下の_confファイルを編集することで変更できます。

 $ estmaster start casket

バックグラウンドで走らせるには-bgオプションを指定します。ただ、estmasterから検索を行う場合、estmasterが落ちてしまうと何もできなくなってしまうので、対策が必要になります。前回のdaemontoolsの解説でも述べましたが、フォト蔵ではestmasterの管理にdaemontoolsを活用しています。起動スクリプトは単純ですが、estmasterを扱う場合、例えば↓のような記述が必要になります。

SERVER_ROOT=/var/casket
PID_FILE=${SERVER_ROOT}/_pid
if [ -e $PID_FILE ]
then
    rm $PID_FILE
else
    :
fi

estmasterは起動すると、サーバールート以下に_pidというプロセスIDが書かれたファイルが作成され、終了するとこのファイルは削除されます。しかし、異常終了した場合はこのファイルが残ってしまい、estmasterを再起動しようとすると、estmaster自身は既に起動していると思い込んでしまい、起動することができなくなります。このため、runスクリプトで_pidの存在の有無を確認し、存在する場合は削除するようにします。

リクエストが受信できているか確認する

estmasterが正常に検索やそのほかのリクエストを受信できているか確認するには、サーバールート以下にある_logファイルの内容を確認します。実際には以下のようにtailコマンドを使うのがよいでしょう。

 $ tail -f _log

管理画面からの操作

HEにはestmasterやestmasterが使用しているインデックスを管理するためのWebインタフェースが用意されています。このestmasterの管理画面ではインデックスの作成やリンクの設定などいろんな操作ができますが、オプションを指定することができないので、実際のインデックスはestcmdコマンドで作成した方がいいでしょう。また、ノード間リンクの設定など、管理画面上から設定してもestmasterが終了すると設定が失われるものがあります。実際の設定変更を行う際は管理画面からではなく、estcallコマンドやAPI経由で行うのがよいでしょう。ただし、コマンドラインからestcallを使ってestmasterに命令を発行する際、ユーザ名とパスワードを直打ちしなければならないので、履歴にパスワードが残ってしまう可能性があります。なので、究極的にはAPIを使う方が良いでしょう。

検索用と更新用にインデックスを分ける

HEではインデックスを更新している間、そのインデックスに対して検索をかけることができません。このため、フォト蔵では検索用のインデックスと更新用のインデックスを明確に分けています。estmasterにHTTP経由で検索クエリを投げる処理はフォト蔵自体がPHPで書かれていることもあって、PHPで書いていますが、インデックスの更新スクリプトはPerlでHTTPを介さず、コアAPIを経由する形で書いています。

1文字検索

HEはN.M-gram方式(N=2、M=2)と転置インデックスにより、データが保存されているので、1文字で検索した場合、検索漏れが生じる可能性があります。1文字の場合はワイルドカード検索になり、一定回数だけ、データをインデックスから検索します。

アルファベットや数字から成る文字列の検索

HEはN.M-gram方式ではありますが、アルファベットや数字から成る文字列に対しては、N文字単位(N=2、後に続くM文字(M=2) )で転置インデックスを作成するようなことはせず、まとめて転置インデックスを作成します。このため、アルファベットや数字から成る文字列に対しては、検索キーワードが完全に一致しなければ検索に引っかからないという現象が発生します。例えば、インデックス内に「photozou」という文字列が格納されている文書がある場合、「photozou」で検索すれば、引っかかりますが、「photo」では引っかかりません。これはSennaやMySQLの全文検索インデックスでも似たような動作をします。理由としては全文検索において、上記のような文字列を含む文書に対して完全なN-gram(N=2)で転置インデックスを作成しても、インデックスが肥大化する割にはさほど効果がないことが挙げられます。HEでこの問題に対処するには、検索条件式を「通常書式」か「簡便書式」にして、キーワードの前方一致や後方一致を有効にします。検索条件式はoptionパラメータによって制御されているので、このパラメータに適切な値をセットすることによって、検索条件式を変更することができます。各検索条件式の値はestraier.hを見ると以下のように定義されています。

enum {                                   /* enumeration for options */
  ESTCONDSURE = 1 << 0,                  /* check every N-gram key */
  ESTCONDUSUAL = 1 << 1,                 /* check N-gram keys skipping by one */
  ESTCONDFAST = 1 << 2,                  /* check N-gram keys skipping by two */
  ESTCONDAGITO = 1 << 3,                 /* check N-gram keys skipping by three */
  ESTCONDNOIDF = 1 << 4,                 /* without TF-IDF tuning */
  ESTCONDSIMPLE = 1 << 10,               /* with the simplified phrase */
  ESTCONDROUGH = 1 << 11,                /* with the rough phrase */
  ESTCONDUNION = 1 << 15,                /* with the union phrase */
  ESTCONDISECT = 1 << 16,                /* with the intersection phrase */
  ESTCONDSCFB = 1 << 30                  /* feed back scores (for debug) */
};

通常書式の場合、前方一致を有効にするには検索キーワードを「[BW] photo」、後方一致を有効にするには検索キーワードを「[EW] photo」という具合に指定します。簡便書式の場合、前方一致を有効にするには検索キーワードを「photo*」、後方一致を有効にするには検索キーワードを「*photo」という具合に指定します。

ただし、1文字検索と同様、これはワイルドカード検索となり、一定回数だけしかデータをインデックスから検索しないので、検索漏れが生じる可能性があり、CPUの負荷も増大します。

estmasterが管理しているインデックスのバックアップ

estmasterは/master?action=backupがリクエストされると、サーバルート以下の_confファイル内のbackupcmdで指定されたバックアップコマンドを実行します。このリクエストを受け取るとestmasterはインデックスをディスクと同期させるので、比較的安全にバックアップを行うことができます。estmasterの起動中に、estmasterが管理しているインデックスをディスクと同期させずにコピーしたり移動したりすると、インデックスが壊れることがあるので、estmasterを起動させたまま、バックアップを取るときは必ずbackupcmdで指定したスクリプトで行いましょう。

パラメータの調整

サーバディレクトリ以下にある_confファイルを編集することによって、estmasterの動作を調整することができます。要はApacheのhttpd.confのようなものです。以下にいくつかのパラメータについて解説します。ほかのパラメータについては公式サイトを参照してください。

maxconn

ApacheでいうMaxClientsです。

searchtimeout

検索のtimeout値です。通常の検索に比べて遅い属性検索を使用する場合は少し高めに設定するのがよいでしょう。

backupcmd

/master?action=backupがリクエストされた際に起動するバックアップコマンドを指定します。

whildmax

先述の通り、HyperEstraierはN.M-gram方式(N=2,M=2)なため、1文字では検索漏れが生じる可能性があります。1文字の場合はワイルドカード検索になり、一定回数しかデータを検索しません。この回数を指定するのがwhildmaxパラメータであり、デフォルト値は256となっています。

参考文献・URL

全文検索システム Hyper Estraier
N.M-gram: ハッシュ値付きN-gram 法による転置インデックスの実現


また、余談ですが、検索に関する基礎的な知識やアルゴリズムについて理解したいのであれば、以下の書籍が参考になると思います。

情報検索アルゴリズム
北 研二 津田 和彦 獅々堀 正幹
共立出版
売り上げランキング: 145553
おすすめ度の平均: 3.5
3 基本知識の足しになれば
4 わかりやすくてよい

2008年10月 1日

四角いリンク
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

yamaokaです。

最近タブをメタファーにしたナビゲーションをよく見るようになりました。タブには大抵、内容を示すキャプションが付けられています。さて、どこからどこまでがリンクでしょうか。どの部分をクリックすればそのタブを選択できるでしょうか。

タブ型ナビゲーション

例えば、キャプションの文字だけにリンクが貼られている場合。利用者はタブの中のさらに狭い範囲、文字の部分を狙ってクリックしなくてはなりません。

タブ型ナビゲーション(文字だけリンク)

実はマウスの操作というのは難しいのです。狭い範囲を狙って指定することにはあまり向いていません。目的到達のために狭い範囲のクリックを強制するのはどう考えてもよいインターフェースではありません。

そこで大抵のタブ型インターフェースではタブの枠の中全体をリンクとして扱えるようになっています。

タブ型ナビゲーション(ブロックリンク)

アンカー要素のdisplay属性をblockにして、必要な高さと幅を与えることでリンクの範囲を四角形に広げることができますね。大きさを固定値で指定してもかまいませんが、そうするとキャプションの文字の大きさによってははみ出てしまうかもしれません。padding属性を使えば大丈夫です。

.nav a {
  display: block;
  padding: 5px 10px;
}

マウスのポインタがタブの上に乗ったときにタブの色に変化をつけてあげると、よりリンクであることを強調することができるかもしれません。

.nav a:hover {
  background-color: #DEE;
}

ほとんどのサイトで同様のテクニックが使われていて、利用する側としては当たり前のように使っているインターフェースはいろいろとあります。

しかしそういうインターフォースでも、「なぜそうなっているのか?」と考えてみると面白いと思います。

2008年9月26日

IDEでマルチプラットフォームなGUIアプリを開発する環境構築のメモ (C++ & wxWidgets)
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

gotandajinです。

なにかGUIアプリケーションを作ろうとした時、一番手軽に手を出せる開発環境はVisual Studioあたりかなぁと思われますが、Visual Studio は基本的にWindows専用です。Javaを使えばプラットフォーム間の差異を吸収して、同一ソースでWindows、Mac、Linux などの複数のOSで動くGUIアプリを作れますが、他の選択肢としては、開発言語をCやC++で、マルチプラットフォームなGUIフレームワークを利用しての開発、なんかが挙げられます。マルチプラットフォームなGUIフレームワークを使えば、Javaと同様に同一ソースで複数のプラットフォーム用のGUIプログラムが作成できます。こちらはJavaとは違い、オブジェクトコードとして生成できるのが特徴です。

代表的なマルチプラットフォームGUIフレームワークにはQT(キュート)やwxWidgetsが挙げられますが、昨今一番隆盛なのはたぶんQTの方です。こちらはSkype、Google Earth、Operaなど、稼動実績に有名どころが集まっているのですが、一番手軽に使えるオープンソース版でもGPLの制限がかかります。GPLより緩く使いたい場合は、ライセンス料を支払う必要があります。

一方、wxWidgetsは成果物のバイナリをほぼ自由に配布できるフレームワーク (http://www.wxwidgets.org/about/licence3.txt 参照) なので、手の出し易さではこちらの方が上と思われます。現在の最新版が2.8.9で更新日時が2008/09/22 、一つ前のバージョンの更新日時が 2008/6/28 なので、割と継続して更新もされています。 http://wxwidgets.info/

今回はwxWidgetsとEclipseなどのIDEを連携させたマルチプラットフォームなGUIアプリ開発環境の構築について書いてみようと思います。また、ここではプログラムをビルドする環境はWindows XP、開発言語はC++ です。

とりあえずまずはC++のコンパイラをインストールする

WindowsでC++のソースをコンパイルしようとした時、手段はVisual C++、Cygwin、Boraland C++ Builder など色々ありますが、ここではMinGWとMSYSを使うことにします。MinGWは、Windows用に移植されたGCCを使うための環境です。また、MSYSはUNIX風なCUI環境としてMinGWを補うツールです。

MinGWとMSYSのインストールについてはここでは割愛します。 http://www.knatech.info/Dev-mingw-install.html
ここの説明が分かりやすいのでご参照ください。


wxWidgets(wxMSW)をインストールする

http://www.wxwidgets.org/downloads/#latest_stable
このwxWidgetsのページからwxMSWのパッケージをダウンロードします。wxMSWはインストーラの形式で配布されています。wxMSWというのは、wxWidgetsのWindows環境用のパッケージです。LinuxのGTK環境用であればwxGTK、Mac環境用であればwxMacを使用します。

wxMSWのインストーラをダウンロードしたら実行し、上でインストールしたMSYSの、homeディレクトリの下層にファイルを展開します。(現在の最新版は2.8.9)

wxMSWinstall
wxMSWinstall posted by (C)フォト蔵
(筆者の場合)

ファイルの展開が終わったら、MSYSから、たった今展開したwxWidgets-2.8.9のディレクトリにcdで移動し、./configureで makefileを設定した後、makeでコンパイル、make install でwxWidgetsをインストールします。

$ pwd
/home/gotanda  (筆者の場合)
$ ls
wxWidgets-2.8.9
$ cd wxWidgets-2.8.9/
$ ./configure --disable-shared --disable-threads --enable-monolithic --enable-unicode
$ make
$ make install

これでインストールできるはずです。

./configure 以下はけっこう時間がかかります。特にmakeではスタティックリンクライブラリを大量に生成するのでなかなか終わらないです。スペックの低いPCだと数十分かかるかもしれません。

./configure 時のオプションの詳細についてはここでは割愛します。
以下参考にさせて頂いたサイトです。
http://0xcc.net/pub/uu-2004-08/
http://www.nslabs.jp/wxwidgets-install.rhtml


サンプルプログラムをコンパイルしてみる。

インストールが終わったらちゃんとGUIアプリを作成できるか試してみます。

test.zipにサンプルプログラムを用意しました(簡単なテキストエディタプログラムです)。解凍したら表示されるtestディレクトリをmsysのhomeの下層ディレクトリに置いてください。

MSYSから

$ pwd
/home/gotanda (筆者の場合)
$ ls
test
$ cd test

で、testディレクトリに移動し、

g++ -c TestApp.cpp TestFrame.cpp `wx-config --cppflags`
g++ -o test.exe TestApp.o TestFrame.o `wx-config --libs`

でコンパイル&リンクします。これでtest.exeが生成され、正常に実行できればwxWidgetsのインストールに成功しています。

test.exeの起動
test_editor
test_editor posted by (C)フォト蔵

wx-config --cppflags というのはコンパイル時のオプションを吐くコマンドで、wx-config --libsはリンク時のオプションを吐くコマンドです。バッククオートで囲ってg++のオプションとして渡しています。

なお、GUIをデザインするためのRADツールにはwxGladewxFormBuilder などがあります。 ここではwxFormBuilderを使ってみました。


IDEからwxWidgetsを使う

やっとwxWidgetsを利用できるようになりましたが、毎回MSYSからコンパイルするのは面倒なのでwxWidgetsのプロジェクトをIDEからビルドできるように設定してみます。wxWidgetsのインストールについての資料はウェブ上でたくさん見つかるのですが、IDEから使う場合についての記述は意外となかったので、これからやろうとしている方々のお役に立てれば幸いです。

IDE(統合開発環境)はプログラミングに必要なツール(ソースエディタやコンパイラなど)を一つのインターフェースからまとめて使えるようにしたり、makefileを自動生成してくれたりと色々便利ですが、種類も色々あります。ここではEclipse CDT、NetBeans の場合について載せておきます。

Eclipse CDT の場合

EclipseはJava用の統合開発環境ですが、プラグインを入れることでC++やPHPの開発にも使えます。 ここではC++の開発ができればよいので、 http://www.eclipse.org/downloads/ から、Eclipse IDE for C/C++ Developers をダウンロードして使ってみました。versionは3.4.0でした。

まずはプロジェクトを作ります。 プロジェクトというのは、1つのプログラムを生成するために使うソースや設定などをひとまとめにしたものです。メニューのFileからNew→C++ Project と進み Project Name に適当な名前を入力したらFinishを押します。

次にwxWidgetsを利用できるようにプロジェクトを設定します。 MSYSからコンパイルする時は、`wx-config --cppflags`のようなコマンド置換によるオプションの生成ができたのですが、どうもEclipse CDT からビルドする際バッククオート(`)がちゃんと評価されないようでうまくいかなかったので、wx-config --xxxで吐かれるオプションをプロジェクトの設定に直書きしてしまい、なんとかビルドできるようにしました。

最初に、コンパイル時の設定をします。 wx-config --cppflags で吐かれるオプション

-I/usr/local/lib/wx/include/msw-unicode-release-static-2.8
-I/usr/local/include/wx-2.8 -D__WXMSW__

を、C:ドライブからのフルパス表記に変えて、それぞれ設定します。

メニューのProjectからProperties→C/C++ Build→Settings→Tool Settings → GCC C++ Compiler と進み、 PreprocessorのDefined Symbolに

__WXMSW__
を、

DirectoriesのInclude Paths(-I)に



C:/msys/1.0/local/lib/wx/include/msw-unicode-release-static-2.8



C:/msys/1.0/local/include/wx-2.8


を追加します。


cdt_setting1
cdt_setting1 posted by (C)フォト蔵



そして、リンク時の設定です。wx-config --libs で吐かれるオプション


-L/usr/local/lib -Wl,--subsystem,windows -mwindows /usr/local/lib/libwx_mswu-2.8.a -lwxregexu-2.8 -lwxexpat-2.8 -lwxtiff-2.8 -lwxjpeg-2.8 -lwxpng-2.8 -lwxzlib-2.8 -lrpcrt4 -loleaut32 -lole32 -luuid -lwinspool -lwinmm -lshell32 -lcomctl32 -lcomdlg32 -lctl3d32 -ladvapi32 -lwsock32 -lgdi32

を、コンパイル時の設定と同様、C:ドライブからのフルパス表記に変えてそれぞれ設定します。

メニューのProjectからProperties→C/C++ Build→Settings→Tool Settings → MinGW Linker と進み、 Libraries の Libraries (-l) に

wx_mswu-2.8 wxregexu-2.8 wxexpat-2.8 wxtiff-2.8 wxjpeg-2.8 wxpng-2.8 wxzlib-2.8 rpcrt4 oleaut32 ole32 uuid winspool winmm shell32 comctl32 comdlg32 ctl3d32 advapi32 wsock32 gdi32
を1つずつ追加、

cdt_setting2
cdt_setting2 posted by (C)フォト蔵


Librariy search path (-L) に


C:/msys/1.0/local/lib

を追加、

Miscellaneous の Linker Flags に


-Wl,--subsystem,windows -mwindows

を追加します。

これで設定は完了です。

最後にビルド、GUIアプリの生成です。 メニューのFiles→New→Source Folder で左側の Project Explorer にソースフォルダが新しく生成されるので、そこに先ほどのtestプログラム(簡易テキストエディタ)のソースファイル4つをpasteします。

eclipse build
eclipse build posted by (C)フォト蔵

そして、メニューのProject→Build Project でビルドに成功するはずです。


NetBeans の場合

NetBeansもEclipse と同じような統合開発環境です。NetBeansでもwxWidgetsを利用できるようにしてみましたが、Eclipse CDT の場合とほとんど同じなので画像だけ載せておくことにします。

netbeans_setting1
netbeans_setting1 posted by (C)フォト蔵

netbeans_setting2
netbeans_setting2 posted by (C)フォト蔵

・・と、こんな感じで、IDEとwxWidgetsを組み合わせて、C++でマルチプラットフォームなGUIアプリを開発できるようになりました。

2008年9月25日

Macでのスクリーンショットの撮り方まとめ
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

yamaokaです。

Mac(Mac OS X)でスクリーンショットを撮る方法についてまとめてみます。いつも忘れてしまうので個人的な備忘録だったりしますが、同じことで悩んでしまう方にとって少しでも参考になれば幸いです。

「Command + Shift + 3」を押下

単純に画面全体のキャプチャ画像が必要な場合に使います。ショートカットキーを押した瞬間、デスクトップに画面全体のキャプチャ画像が保存されます(PNG形式)。

「Command + Shift + 4」を押下

マウスカーソルが十字(ヘアライン)に変わり、画面上の範囲を選択できるようになります。ドラッグして範囲選択した上でマウスのボタンを離すと、選択範囲のキャプチャ画像がデスクトップに保存されます(PNG形式)。

「Command + Shift + 4」を押下、さらに「Space」を押下

マウスカーソルがカメラの形に変わり、その時点で開いているウィンドウが選択できるようになります。いずれかのウィンドウを選択してマウスをクリックすると、そのウィンドウのキャプチャ画像がデスクトップに保存されます(PNG形式)。

クリップボードに保存したい場合

画像をファイルとして保存するのではなくクリップボードに保存したい場合は、今までのショートカットキーに「Control」を加えて押下するようにします。例えば、画面全体のキャプチャは「Command + Shift + Conrol + 3」です。

「グラブ」を使う

「アプリケーション」→「ユーティリティ」とフォルダをたどっていくと、「グラブ」というアプリケーションが目に入ります。実はこのアプリケーション、スクリーンショットを撮るためのものです。ダブルクリックして起動してみましょう。

「グラブ」の特徴は2つあって、「マウスポインタを含めたキャプチャ画像が作れること」、「タイマー撮影が行えること」です。

グラブの環境設定画面

環境設定を見るとデフォルトではマウスポインタを含めない設定になっていますが、含めるように設定すればマウスポインタを含めたスクリーンショットを撮ることができます。また、「取り込み」メニューからタイマー撮影をすることができるのもわかります(10秒後のスクリーンショットを撮ることができます)。

スクリーンショットの撮影後は保存するためのウィンドウが表示されるので、必要な場所にファイルとして保存しましょう(TIFF形式)。

(番外編)screencaptureコマンドを使う

ターミナルを立ち上げて、おもむろに「screencapture test.png」と入力してreturnキーを押下すると画面全体のキャプチャ画像が「test.png」として保存されることになります(PNG形式)。専用のコマンドが用意されているのですね。

man screencapture

screencaptureコマンドにはきちんとmanも用意されているので、見てオプションを確認しておくといいかもしれません。sleepコマンドと組み合わせればタイマー撮影ができるようになりますね。

まとめ

上で挙げた方法はいずれもMacの初期状態で行うことのできるものばかりです。スクリーンショットを撮るには標準の機能だけで十分備わっていると言えます。ただ、頻繁にスクリーンショットを撮るという目的には適わない場合があるかもしれません。そういう場合は、InstantShot!などのソフトウェアを使うとより便利になると思います。

2008年8月 1日

PHPで携帯位置情報を扱うライブラリ「Geomobilejp_Converter」を作りました
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

中村です。

PHPで携帯の位置情報を簡単に取り扱うことができるライブラリ「Geomobilejp_Converter」を作りました。もう半年近く前に作ったものですが、コードを少し整えたので公開することにしました。

GPSに対応した携帯では、各キャリアで指定されている特定のHTMLを記述することで、携帯サイトに位置情報(緯度経度や測地系)を送信することができます。この位置情報を利用すると、「位置情報付きで掲示板に書き込む」などの機能を実装することができます。

キャリアによっては位置情報のなかに土地名を含むものもありますが、通常は緯度経度だけでは土地名がわかりません。そこでGeomobilejp_Converterでは、docomoの提供するオープンiエリアのiエリアデータファイルを利用して土地名を関連付ける機能を実装しています。iエリアデータを利用することで、各キャリアで共通したiエリアコードや土地名を取得することができます。

使い方を少しご紹介

フォーマットや測地系の変換は次のような感じです。

require_once '/path/to/Geomobilejp/Converter.php';

$converter = new Geomobilejp_Converter('34.700695', '135.495243', 'wgs84');
$converter = $converter->convert('tokyo')->format('dms');

echo $converter->getLatitude() . "\n";    // 34.41.50.830
echo $converter->getLongitude() . "\n";   // 135.29.53.007

また、各キャリアの携帯から送られてきた位置情報をiエリアデータの土地名に変換することができます。ここでは、http://example.com/?lat=%2B34.42.02.502&lon=%2B135.29.42.875&geo=wgs84というリクエストがきた場合を仮定しています。

require_once '/path/to/Geomobilejp/Converter.php';
require_once '/path/to/Geomobilejp/IArea.php';
require_once '/path/to/Geomobilejp/Mobile.php';

$mobile = new Geomobilejp_Mobile();

if ($mobile->hasParameter()) {

    $converter = new Geomobilejp_Converter(
        $mobile->getLatitude(),
        $mobile->getLongitude(),
        $mobile->getDatum()
    );

    $area = Geomobilejp_IArea::seekArea($converter);

    echo $area->getIAreaCode() . "\n";    // 17202
    echo $area->getName() . "\n";         // 大阪駅/阪急梅田駅周辺

}

ご興味のある方は

Google Codeでソースコードを公開しました。この中に含まれる「docs/Manual.html」により詳しい説明を書いていますので参考にしてください。

phpgeomobilejp - Google Code

参考ソース

このライブラリを作るにあたって、Perlで書かれたGeo::Coordinates::ConverterGeo::Coordinates::Converter::iArea、またperezvonさんのコードを大変参考にしました。ありがとうございます。

また、私の個人ブログに簡単なGPSのまとめを書いていますので、ご興味があればどうぞ。

2008年7月24日

daemontoolsでデーモン管理
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

Emacsでbackward-charをC-lに割り当てているbokkoです。「指相撲で相手の指に届かないくらい指が短いので一回も勝ったことがないんです。だからそんな短い指でC-bなんて押してたら指が痛いんです」と言ってもなかなか信じてもらえないのですが、そんな私でも(global-set-key "\C-l" 'backward-char)というelispを評価するだけで快適にプログラミングさせてくれるEmacsが大好きです。


と、タイトルと関係ない話はこれくいらいにしておいて、今日はdaemontoolsのお話です。


daemontools

daemontoolsは異常終了してしまったデーモンプロセスを再起動してくれたり、ログローテートを肩代わりしてくれたりするなど、デーモンの制御や管理、監視を行うプログラムの集まりです。例えば、以下のようなプログラムが含まれています。

  • supervise
    • デーモンの起動、監視
  • svc
    • superviseによって監視されているデーモンの制御
  • svstat
    • 指定したデーモンの状態を出力
  • setuidgid
    • ユーザIDとグループIDを変更
  • multilog
    • デーモンプログラムの出力をロギング

ほかにもいろいろありますが、詳しくは本家のマニュアル(日本語版)を見るとよいでしょう。

インストール

ソースコードがこちらで、SRPMがこちらで配布されています。Linuxディストリビューションによってはapt-getでインストールすることもできますが、その場合は名前がdaemontoolsではなく、svtoolsになっているものがあります(Ubuntuは後者でした)。インストールすると、/commandに各プログラムが配置され、/にserviceというディレクトリが作成されます。daemontoolsでデーモンを管理する場合、この/serviceディレクトリにデーモンの起動スクリプトやログ収集のためのスクリプトを配置します。

デーモンの登録

デーモンを登録するには/service以下に登録したいデーモンの起動スクリプトとログ収集のためのスクリプトを配置します。

$ mkdir /var/daemon
$ mkdir /var/daemon/log
$ mkdir /var/daemon/log/main
$ chmod 1755 /var/daemon
$ chmod +x /var/daemon/run
$ chmod +x /var/daemon/log/run
$ chown hoge:fuga /var/daemon/log/main
$ ln -s /var/daemon /service

/var/daemon/run

#!/bin/sh
exec 2>&1 # エラー出力を標準出力へ
exec setuidgid hoge /usr/bin/daemon

/var/daemon/log/run

#!/bin/sh
exec 2>&1 # エラー出力を標準出力へ
exec setuidgid hoge multilog t ./main

runを実行したプロセス自身をデーモン化しなければいかないので、必ずexecを付けます。また、runで実行するプロセスはフォアグラウンドで起動させなければいけません。

追記:(2008/07/24)

/var/daemon/runの内容が/var/daemon/log/runのものになっており、/var/daemon/runの内容が抜けていたのを修正しました。また、現行のdaemontools-0.76ではstickyビットを立てる必要はありません。ご指摘ありがとうございます。>fumiyasさん

デーモンの起動制御

/service以下のデーモンを起動するにはsvscanを使うとよいでしょう。

$ sh -c 'svscan /service &'

↑を実行すると/serviceディレクトリ以下にあるすべてのデーモンに対してsuperviseによるデーモンの監視が行えます。なんらかの原因でデーモンが終了してしまってもsuperviseが自動的にデーモンを再起動してくれます。ただ、デーモンプログラム自体に問題があって起動できない場合、何度も再起動を試み、ずっとログに起動失敗のメッセージを書き込み続けてしまうので注意しましょう。

OS起動時からdaemontoolsに関連するプログラムを起動しておく場合は、/etc/inittabに以下の記述をしておくとよいでしょう。

SV:123456:respawn:/command/svscanboot      

svcでデーモンに命令を発行する

svcコマンドを使うと指定したデーモンに対して以下のような命令を発行することができます。

$ svc -u /service/daemon # 起動
$ svc -d /service/daemon # 一時停止
$ svc -t /service/daemon # 再起動
               ・
               ・
               ・

svstatで状態確認

svstatを使うと指定したデーモンの状態を確認することができます。

$ svstat /service/daemon # 起動中
/service/daemon: up (pid 8131) 3 seconds
$ svstat /service/daemon # 停止中
/service/daemon: down (pid 8131) 57 seconds, normally up

ただ、たまにdaemontools側から起動しているように見えているだけの時があるので注意しましょう。詳しくは後述します。

ロギング

デーモンプログラムの出力は/var/daemon/log/runで実行しているmultilogによって/var/daemon/log/main以下に保存されます。multilogもdaemontoolsに含まれるツールの一つです。保存されるログはそのままでは見づらいので、同じくdaemontoolsに含まれるtai64nlocalで見やすい形式に変換するのがよいでしょう。

$ tai64nlocal < /service/daemon/log/main/current

デーモンが正常に動作しない場合の対処法

最後にdaemontoolsを使用していて実際に遭遇した問題を紹介します。

デーモンがゾンビプロセス化

なんらかの原因でデーモンが異常終了したり、正常に起動しなかった場合、デーモンプロセスがゾンビ化することがあります。daemontools側から見ると正常に動作しているように見えてしまうので、デーモンが正常に動作しているかpsコマンドなどを使って調べてみましょう。特に、異常終了した後に、そのままでは正常に再起動できないようなプログラムをデーモン化している場合は注意が必要です。

superviseがエラーを吐く

supervise: fatal: unable to acquire daemon/supervise/lock: temporary failure

既に指定したデーモンに対してsupervise(もしくはsvscan)が起動していたり、操作ミスなどによりsupervise(もしくはsvscan)自体が異常終了した場合に上記のエラーメッセージが出ることがあります。
この場合、該当するデーモンに対して起動しているsuperviseを終了し(svscanが起動している場合は先にそっちを終了します)、以下のファイルを削除します。

rm /var/daemon/supervise/lock
rm /var/daemon/log/supervise/lock
rm /var/daemon/log/main/lock

追記:(2008/07/24)

一部誤解を与える表現がありましたので、修正しました。

修正箇所

supervise(もしくはsvscan)自体が異常終了した場合に
↓
操作ミスなどによりsupervise(もしくはsvscan)自体が異常終了した場合に

また、lockファイルを削除するよりもいい方法があるようです(コメント
欄参照)。

ご指摘ありがとうございます>fumiyasさん

フォト蔵におけるdaemontoolsの活用例

フォト蔵では今年の7月頃からHyperEstraierによる全文検索を導入したのですが、このHyperEstraierに含まれるestmasterというサーバプログラムの管理にdaemontoolsを活用しています。使い方の一つとしては、estmasterの死活監視があります。estmasterが停止してしまうと検索自体ができなくなってしまいますが、停止してしまってもdaemontools側で自動的に再起動してくれるわけです。


フォト蔵でのHyperEstraierの活用例に関しては、また後日紹介する予定です。


参考ページ

2008年7月17日

シェルスクリプトでプログラミング
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加


パワプロよりパワポケが好きなbokkoです。でも最近はPSPで遊んでいます。


今回はシェルスクリプトやコマンドラインでよく使うプログラムとその使用例の紹介です。

シェルスクリプトでプログラミング

シェルスクリプトでは既にあるコマンドを組み合わせてプログラムを書きます。しかし、シェルスクリプトは分岐や繰り返しといった制御構造を持ち、関数や変数を扱ったり、四則演算を行うこともできます。

演算

シェルスクリプトで演算を行うにはexprを使います。

add.sh

#!/bin/sh
A=1
B=2
C=`expr ${A} + ${B}`
echo ${C}

↑のadd.shを実行すると、

$ sh test.sh
3
$

と表示されます。↓のようにexprの引数をスペースで区切らず渡してしまうと、単に1+2と表示されてしまいますので、注意しましょう。

#!/bin/sh
A=1
B=2
C=`expr ${A}+${B}`
echo ${C}

浮動小数演算

exprでは整数演算しかできません。シェルスクリプトで浮動小数を扱うにはbcコマンドを使います。

compressibility.sh

#!/bin/sh
SRC_SIZE=100
COMPRESSED_SIZE=15
COMPRESSIBILITY=`echo "${SRC_SIZE} / ${COMPRESSED_SIZE}" | bc -l`
echo ${COMPRESSIBILITY}"%"
$ sh compressibility.sh
6.66666666666666666666%
$

有効桁数を指定するにはscale変数を使います。

#!/bin/sh
SRC_SIZE=100
COMPRESSED_SIZE=15
COMPRESSIBILITY=`echo "scale=2;${SRC_SIZE} / ${COMPRESSED_SIZE}" | bc -l `
echo ${COMPRESSIBILITY}"%"
$ sh compressibility.sh
6.66%
$

分岐

if文の使い方は以下のような感じです。/home/bokko以下にtest.txtが存在していれば、そのファイルが削除されます。

#!/bin/sh
TEST_FILE=/home/bokko/test.txt
if [ -e ${TEST_FILE} ]
then
    rm ${TEST_FILE}
    echo "removed "${TEST_FILE}
else
    echo ${TEST_FILE}" is not existed."
fi

繰り返し

繰り返しにはほかの言語でもよく見られるfor文が使用できますが、書き方はif文と同様、少し独特な感じです。

#!bin/sh
for srcname in `find /home/bokko/programming/c | egrep '.+\.c$'`;do
    case `basename $srcname` in
        a.c | b.c | c.c) ;; # exclude
	*)
	    # C言語のソースファイルに何かする
    esac
done

↑のシェルスクリプトを実行すると、/home/bokko/programinng/c以下にあるC言語のソースファイルに対して「# C言語のソースファイルに何かする」の部分に書かれた処理を実行することができます。「#exlude」のコメントアウトがある行はその名の通り、指定したa.c、b.c、c.cを処理の対象から外しています。

パイプ

シェルスクリプトでプログラムを書いたり、普通にコマンドラインで作業していると、あるプログラムの出力を別のプログラムへの入力として扱いたいことがあります。このような複数のプログラム間でのデータの橋渡しをするのがパイプです。一見複雑そうな問題でも個々の小さいプログラムをパイプで繋ぐことによって簡単に解くことができる場合があります。


例えば、以下のようなファイルから重複した行を取り除きたいとします(いい加減な例ですみません)。

bokko.txt

bokko
bokkko
bokkkko
bokko
bokkko
bokko
bokko
bokko
bokkko
bokkko
bokkko
bokkko
bokkko
bokko
bokkko
bokko
bokko
bokkkko
bokkko
bokkko
bokko
bokko
bokkkko
bokko

これは↓のようにsortとuniqをパイプで繋げるだけでできます。

$ sort bokko.txt | uniq
bokkkko
bokkko
bokko
$

各行がいくつ重複しているか調べるにはuniqの-cオプションを使います。

$ sort bokko.txt | uniq -c
      3 bokkkko
     10 bokkko
     11 bokko
$

非常に簡単な例ではありますが、sortとuniqはテキストデータの集計や解析をする際に非常に役に立ちます。

sed

sedはテキストデータを置換するのによく使われるプログラムです。例えば、先程のbokko.txtの全ての行をbokkoに置換してみましょう。

$ cat bokko.txt | sed -e 's/bok\+o/bokko/g' | uniq
bokko
$

という具合に文字列を正規表現を使って簡単に置換することができます。

awk

awkはsedと同じようにテキストを置換したり、整形するためのプログラムです。sedに比べると正規表現の機能が少し弱いですが、テキストの整形機能のほかに四則演算、連想配列、などの機能が備わっています。

sortとuniqの例に比べるとやや冗長ですが、以下のようなawkスクリプトを用意して重複行を数えることができます。

sort_uniq.awk

BEGIN {
    cnt["bokko"] = 0;
    cnt["bokkko"] = 0;
    cnt["bokkkko"] = 0;
}
/^bokko$/ {
    cnt["bokko"]++;
}
/^bokkko$/ {
    cnt["bokkko"]++;
}
/^bokkkko$/ {
    cnt["bokkkko"]++;
}
END {
    print "bokko:" cnt["bokko"];
    print "bokkko:" cnt["bokkko"];
    print "bokkkko:" cnt["bokkkko"];
}
$ cat bokko.txt | awk -f sort_uniq.awk
bokko:11
bokkko:10
bokkkko:3
$

ほかにも、テキストから必要な部分だけを取り出すといったことも簡単に行える機能があります。

$ du -b test.txt
101     test.txt
$

この出力結果の数字の部分だけ取り出したいなら以下のようにします。

$ du -b test.txt | awk '{ print $1 }'  
101
$

という具合に出力結果の数字部分だけを取り出すのがいとも簡単に行えます。あまり意味はありませんが、以下のようなことも可能です。

$ du -b test.txt | awk '{ print $2 }'  
test.txt
$

つまり、$1、$2という具合に区切り区切りで文字列を取得できるのです。awkではこの区切りをセパレータと呼び、必要に応じて変更することができます。


JavaScriptやCSSの縮小結果を表示する

次はちょっとした応用例を紹介します。

映画生活やフォト蔵ではJavaScriptファイルをjs_min.pyで、また、CSSを自作のPHPスクリプトで縮小化しています。CSSの方は縮小化だけでなく、縮小前のソースファイルの収集処理なども全部PHPで書いているのですが、JavaScriptの方はjs_min.pyをシェルスクリプトから呼び出す形にしています。単に縮小化するのもなんなので、どれくらい縮小化できたのか調べてみようと思い、
縮小率の計算や出力結果のフォーマットもやりました。以下はscriptaculous.jsのslider.jsとcheck.js、prototype.jsに対して縮小化スクリプトで実行した時の出力です。

$ js_minify.sh slider.js
minified:                               slider.js  10354bytes ->   7631bytes reduction percentage:26.30%
$ js_minify.sh slider.js check.js  prototype.js
minified:                               slider.js  10354bytes ->   7631bytes reduction percentage:26.30%
minified:                                check.js   3364bytes ->   2448bytes reduction percentage:27.23%
minified:                            prototype.js  96653bytes ->  72255bytes reduction percentage:25.24%
$ 

↑のスクリプトではJavaScriptの縮小前と縮小後のソースファイルから縮小率を計算してその結果を表示しています。ファイルを縮小化させるのにjs_min.pyを使っていますが、残りはシェルスクリプト、sedやawk、bcなどの既存のプログラムだけで実現しています。

以下がそのシェルスクリプトです。引数を指定しない場合はJS_SRC_DIR以下の全てのJavaScriptファイルを縮小化します。

実際に使う場合はJS_SRC_DIRとJS_MINIFIED_DIRのディレクトリ構成が同じである必要があります。また、ファイルパスの長さやファイルサイズに合わせてprintfのフォーマットを調整するのがよいでしょう。

#!/bin/sh
HOME_DIR=/home/${USER}/jsdir # 任意のパラメータ
JS_SRC_DIR=${HOME_DIR}/jssrc # 任意のパラメータ
JS_MINIFIED_DIR=${HOME_DIR}/minifiedjs # 任意のパラメータ
JSMIN_DIR=/home/${USER}/bin # 任意のパラメータ
TOTAL_SRC_SIZE=0
TOTAL_MINIFIED_SIZE=0
js_minimize () {
    SRC_PATH=`echo ${JS_SRC_DIR}/$1 | sed -e 's/\.\///g'`
    MINIFIED_PATH=`echo ${JS_MINIFIED_DIR}/$1 | sed -e 's/\.\///g'`
    SRC_SIZE=`du -b ${JS_SRC_DIR}/$1 | awk '{ print $1;}'`
    python ${JSMIN_DIR}/jsmin.py < ${SRC_PATH} > ${MINIFIED_PATH}
    MINIFIED_SIZE=`du -b ${JS_MINIFIED_DIR}/$1 | awk '{ print $1;}'`
    REDUCTION_PERCENTAGE=`echo "(1.0 - ${MINIFIED_SIZE} / ${SRC_SIZE}) * 100" | bc -l`
    REDUCTION_PERCENTAGE=`echo ${REDUCTION_PERCENTAGE} | sed -e 's/^\(-\?\)\./\10./g'`
    echo $1 ${SRC_SIZE} ${MINIFIED_SIZE} ${REDUCTION_PERCENTAGE} | sed -e 's/\.\///g' | awk '{
         printf("minified:%s %dbytes -> %dbytes reduction percentage:%5.2f%%\n", $1, $2, $3, $4);
	 }'
    TOTAL_SRC_SIZE=`expr ${TOTAL_SRC_SIZE} + ${SRC_SIZE}`
    TOTAL_MINIFIED_SIZE=`expr ${TOTAL_MINIFIED_SIZE} + ${MINIFIED_SIZE}`
}
cd ${JS_SRC_DIR}
if [ "$1" != "" ]
then
    while [ "$1" != "" ];do
	if [ -e ${JS_SRC_DIR}/$1 ]
	then
	    js_minimize $1
	else
	    echo ${JS_SRC_DIR}/$1" does not exist."
	fi
	shift 1
    done
else
    for srcname in `find . | egrep '.+\.js$'`;do
	case `basename $srcname` in
            exclude1.js | exclude2.js) ;; # exclude
	    *)
		js_minimize $srcname
	esac
    done
    TOTAL_REDUCTION_PERCENTAGE=`echo "(1.0 - ${TOTAL_MINIFIED_SIZE} / ${TOTAL_SRC_SIZE}) * 100" | bc -l`
    echo ${TOTAL_SRC_SIZE} ${TOTAL_MINIFIED_SIZE} ${TOTAL_REDUCTION_PERCENTAGE} \
	| awk '{ printf("\ntotal     : %dbytes -> %dbytes reduction percentage:%5.2f%%\n", $1, $2, $3); }'
    echo | awk '{ printf("\nAll JavaScript files minified.\n\n"); }'
fi

参考までに

縮小化スクリプトによってフォト蔵ではCSSを約15%、JavaScriptを約30%縮小化することができました。中にはファイルサイズが半分以下になったものもいくつかあります。

縮小化自体は既存のスクリプトを使えば簡単にできるので、少しでもサイトのパフォーマンスを上げたいと思っているならば、js_min.pyやYUI Compressorの導入を検討してみるといいかもしれません。

参考文献

シェルスクリプト基本リファレンス
山森 丈範
技術評論社
売り上げランキング: 29058
おすすめ度の平均: 5.0
5 シェルスクリプト本が数ある中で、
5 Linux、Unixユーザならば、一度、読んでおきたい本


sed&awkプログラミング
sed&awkプログラミング
posted with amazlet at 08.07.17
デール ドゥラティ アーノルド ロビンス
オライリー・ジャパン
売り上げランキング: 86344
おすすめ度の平均: 4.5
5 0から書いたことがありません。
5 正規表現をマスターしましょう
4 Sed&awkプログラミング

2008年7月 9日

脆弱性検知ツールratproxyをCygwin上で動かしてみました
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

こんにちは!やまもと@テスト番長です。

先日Googleからプロキシ型の脆弱性発見ツール「ratproxy」が公開されました。
これは触らないと!ということでCygwin上で動かしてみました。

ratproxy
http://code.google.com/p/ratproxy/


続きを読む "脆弱性検知ツールratproxyをCygwin上で動かしてみました" »

2008年6月12日

Google Analyticsで特定のリンクのクリック数を調べる
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

yamaokaです。

Webサイトを運営していると、同じページに複数の箇所からリンクが貼られている場合に、特定のリンクからのアクセスがどれぐらいあるかを調べたいことがあります。

もちろん、異なるURLで訪問者にアクセスしてもらえばトラッキングできるので、適当なクエリーストリングをリンクのURLに付加すれば調べることができるようになります。

<a href="/foo?bar">baz</a>
ただし、その場合permalink(固定されたURL)ではなくなってしまいますね。

写真でつながる共有サイト「フォト蔵」では、アクセス解析にGoogle Analyticsを利用しています。Google Analyticsを利用している場合、次のようにして特定のリンクからのアクセスを違う名前で扱うことができるようになります。

<a href="/foo" onclick="pageTracker._trackPageview('/foo?bar')">baz</a>
詳細な情報については、Googleによる「_trackPageviewとは何ですか。どのような場合に使用しますか。」を参照してください。この方法なら、URLは元の状態のままpermalinkを保つことができます。

このリンクからのアクセス数をGoogle Analyticsで調べるには、「/foo?bar」というURLにどれだけアクセスされているかを検索すればOKです。簡単ですね。単純なページ遷移なら「ナビゲーションサマリー」で確認することができますが、特定のリンクをターゲットに調査したい場合にはこの方法が便利です。

Google Analyticsは本格的に使おうとするとかなり高機能なので、ヘルプを見たりあちこちのページを開いたりして、いろいろ試してみるといいと思います。「セッション」「コンバージョン」など、Google Analyticsで用いられている用語の定義も一度確認しておくことをオススメします。

2008年6月 3日

テスト担当者のモチベーション #2
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

こんにちは! やまもと@テスト番長です。
今年も梅雨の季節になりました。これから毎日じめじめするのかと思うと、どうしてもテンションが下がりがちになりますね。前回モチベーションのお話をしたのですが、その後で良い記事を見つけたのでご紹介したいと思います。

Out of the Rut
By Michael Bolton

テストに飽きてしまったらどうしたらよいか?という問題について筆者の経験から色々とアドバイスをしてくれています。詳細は記事を読んでいただくとして、見出しだけちょっとまとめてみましょう。

担当箇所を取り替えてみる


担当箇所を他のメンバーと交換すると、より上手くいくようになるかもしれません。

変化をつける

いったん手を止めて、今と違うアプローチの仕方を考えてみましょう。

他の人々とコミュニケーションする

プログラマとチャットしたり、ハマる箇所についてユーザーと話したり、他のテスターとペアでテストしてみましょう。リフレッシュできます。

他の何かに注目する

一つのことに注目しすぎて煮詰まるのは良くありません。

自動化する

単調な繰り返しのタスクはなるべく自動化してしまいましょう。

費用対効果を考える

やらなくていい作業だからやる気が出ないのかもしれません。重要でないものにコストをかけるのは、クライアントも望まないでしょう。

作業を確認する

自分の作業が有益なものかクライアントやマネージャーと話し合いましょう。

ちゃんと休憩する

散歩に出たり、雑誌を読んだり、自転車に乗ったり、コーヒーを飲んだり、お菓子を食べたり、お使いをしたり、シャワーを浴びたりして、気分を変えましょう。


記事の最後に、「テストがつまらないのはそれが上手くいっていないときだけで
重要な情報を探したり、何かを学べているときは面白いものだ」と述べられています。

常に前向きでいられる工夫を忘れないようにしたいものですね。

2008年5月12日

Mercurialでバージョン管理
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

stoplightで最大化したターミナル上でzshとscreenとEmacsを立ち上げ、 明朝体フォントでプログラミングするbokkoです。

今回はバージョン管理システムの1つであるMercurialについて紹介します。

ウノウではSubversionとTracを組み合わせて開発を行っていますが、 僕個人では今年の春ぐらいからEmacsやzsh、screenなどの各種設定ファイルをMercurialでバージョン管理しています。

Mercurialとは?

Mercurialは分散型のバージョン管理システムです。 これに対して、CVSやSubversion(以下SVN)は集中型のバージョン管理システムにあたります。 分散型と聞くと難しそうなイメージがわくかもしれませんが、 CVSやSVNに比べてると、より手軽にバージョン管理を行うことができるというのが、 Mercurialに対する僕の印象です。というのもCVSやSVNでは、まず単一のリポジトリを作成した後、 バージョン管理したいファイルをリポジトリにimportして、コピーをチェックアウトし、 コピーを編集してからその差分をリポジトリにコミットします。 これに対して、Mercurialではバージョン管理の対象そのものがリポジトリになります。 このため、単に1つのマシン上で編集の履歴を保持したりするだけの場合、 集中型よりも手軽に扱うことができます。もちろん、複数のマシンでファイルの同期を取るといったことも可能です。

続きを読む "Mercurialでバージョン管理" »

2008年4月30日

Javaコードのバグを発見するFindBugs
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

こんにちは。中村です。

Javaコードをコンパイルしたクラスファイルからバグを見つけ出すFindBugsというツールを使ってみました。

FindBugsは単体で動作しますが、IDEのプラグインとしても提供されています。今回はEclipseのプラグインを試してみました。

プラグインの導入

SourceForgeのダウンロードページからedu.umd.cs.findbugs.plugin.eclipse_1.3.3.20080401.zipを取得して 解凍、Eclipseディレクトリのpluginsに置くだけといういつも通りな感じです。

使い方

プロジェクトのプロパティから通知する問題を選択したりと色々設定が出来ますが、単純に使うにはJavaプロジェクトのところで右クリック -> Find Bugs -> Find Bugsをクリックすると プロジェクトを調べて問題箇所にマーカーを付けてくれます。

使ってみる

早速無茶なコードを書いてみました。

FindBugs
FindBugs posted by (C)フォト蔵

すると、このようにバッチリと問題点が指摘されました。実行してNullPointerExceptionの発生箇所の行数を見るよりはこちらの方が一目瞭然で判りやすいと思います。

次に書いてはいけないコードの類をやってみました。

package net.unoh.findbugstest;

public class FindBugsTest {

    public static void main(String[] args) {
        Thread thread = new Thread();
        thread.run();
    }

}

すると次のように問題点が指摘されました。

[Ru] スレッドの中で run を実行しています。(本当は startを代わりに呼び出すべきではないのですか?)。 [RU_INVOKE_RUN]

このメソッドは、オブジェクトのrun()メソッドを明示的に呼び出しています。一般にRunnableを実装したクラスは、新しいスレッドがrun()メソッドを呼び出す事を期待しており、この場合、Thread.start()を呼び出すのが正しいやり方です。

こうした説明文がしっかりと表示される(しかも日本語で)点からすると、教育目的で使うのも良いかもしれません。

他に同じようなことをするものにLint4jなどがあるようなので、今度比較をしてみたいなと思います。

2008年4月22日

CSSによるデザインワークと相性のよいHTMLって?
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

yamazakiです。最近だいぶあたたかくなってきましたね。おかげで日中眠くて仕方ないわけですがいかがお過ごしでしょうか。

ウノウに入る以前も含めてそれなりに長いことHTMLとCSSを書いてきたわけですが、今回は試みに、「だいたいこういうところに気を使われたHTMLだと、CSSでのデザイン適用やレイアウトがやりやすいな」というこれまでの経験則を簡単ですがまとめてみたいと思います。

まあ、このあたりはCSS書く人とHTML書く人の間でちゃんとルールを決めておけばいいだけの話なので、そもそも何の役に立つのか疑問といえば疑問ですが(笑
たとえばユーザがCSSを書いてスキンを作れるようなサービスを作る際、どういったHTMLにするかを決める、みたいな時には少し参考になる、かもしれません。

ID、クラスを適切に割り振って、要素がCSS側から一意に特定できるように

たとえばグローバルナビゲーションとカテゴリー別のナビゲーションが同じulで書かれているとして、どちらがどちらかCSSで特定できないと、別の見た目にしようとしても難しいです。

<ul>
<li>グローバル</li>
<li>グローバル</li>
</ul>

<ul>
<li>カテゴリ内</li>
<li>カテゴリ内</li>
</ul>

なので可能な限り「表示される内容に共通項のない部分」にはそれぞれID割り振るなどして特定できるようにします。

<ul id="gNavi">
<li>グローバル</li>
<li>グローバル</li>
</ul>

<ul id="catNavi">
<li>カテゴリ内</li>
<li>カテゴリ内</li>
</ul>

さらに、「同じ『ナビゲーション』なので」ということで、同じクラスを振っておくと、似たような見た目にしたい場合に便利。

<div id="gNavi" class="navigation">
<ul>
<li>グローバル</li>
<li>グローバル</li>
</ul>
</div>
<div id="catNavi" class="navigation">
<ul>
<li>カテゴリ内</li>
<li>カテゴリ内</li>
</ul>
</div>

もちろん、たとえば「ページ内にH1タグは一つしかない」というポリシーが全ページできちんと貫かれていれば、H1タグに余計なIDをつけたりしなくても問題ないと思います。
大事なのは「ちゃんと別々のものだと区別できること」です。

同じようなものには同じクラスを割り振る

IDはその名の通り、ページ内に唯一のものに割り振っておくべきものです。一方で「クラス」は、同じようなものを「これとこれは同じようなものですよ」ということを表す場合に使います。
似たものはやはり似たような見た目にしたい場合が多いので、似たような要素にはできるだけ同じクラスが割り振られているほうが好ましいと思います。
逆に、たとえば同じような内容なんだけどちょっとだけ違うものに、全く別のクラスが指定されていると色々と面倒です。
たとえば、ブログの新着記事のリストと人気記事のリストがあったとして、

<ul class="recentPostList">
<li>記事1</li>
<li>記事2</li>
</ul>

<ul class="popularPostList">
<li>記事i</li>
<li>記事ii</li>
</ul>

としてしまうと、二つのリストに同じ見た目を指定したいときに、

ul.recentPostList,
ul.popularPostList{}

といちいち書かなくてはいけなくなります。※まあ2つくらいだったらいいのですが、これが多くなってくるとだいぶ残念な感じになっていきます。
こういう場合は、クラスはスペースで区切って複数指定できますので、たとえば

<ul class="postList recent">
<li>記事1</li>
<li>記事2</li>
</ul>

<ul class="postList popular">
<li>記事i</li>
<li>記事ii</li>
</ul>

とすると、CSSでは、共通のスタイルを「ul.postList」で指定し、それぞれちょっと別の見た目にしたければ「ul.recent/ul.popular」に指定、という形でスマートに書きやすくなりますし、メンテナンス性もよくなると思います。

tableのtrごとに「odd」「even」

テーブルは特に大きくなると見にくくなりがちです。
1行おきに色などを変えられるようにする意味で、テーブルの行ごとにクラスをなにかしら交互に指定してあると、スタイル割り当てがしやすくなります。
同じようにリスト系要素(li)など繰り返される要素にも割り当ててあると便利かも。

リスト系要素(ul,ol,dl)の最初と最後が特定できるようにしておく

:first-childなどの擬似要素がすべてのブラウザでちゃんと使えればこんなものはあまり必要ないのですが、IE6などの対応状況を考えると現実問題としてまだまだ使えません。
ので、リストなどの同じ要素の連続するものの場合は、できるだけ最初と最後に「これが最初の要素」「これが最後の要素」だということがわかるようにしておきます。

<ul>
<li class="first">xxxx</li>
<li>xxxx</li>
<li>xxxxx</li>
<li class="last">xxxx</li>
</ul>

なんでこういうことが必要になるかというと、

  • 最初の要素だけマージンを狭く/広くしたい
  • 最後の要素だけマージンを狭く/広くしたい
  • 最初の要素のところにだけ背景画像指定したい
  • インライン化して横並びのメニューにして、間に線を入れたいんだけど全部のli要素に線を割り当てると一本余計になるので消したい

などなど、最初/最後の要素はちょっとだけ違うスタイルにしたいことが結構よくあるからです。

h1~h6タグ直下には<span>か<a>タグが必ず入るようにしておく

「見出し」はやはり「画像に差し替えたい」とか、「特別な装飾を施したい」とかいったことがよくあります。
また、文字の書かれてる部分だけに装飾したい場合や、margin/paddingのコントロールの都合で子インライン要素があるほうが調整しやすくなります。
といったわけで、直下に<span>もしくは<a>タグなどのインライン要素が入るようにしてあると、CSSでのデザインの幅がだいぶ広がると思います。

<h1>hogehoge</h1>

ではなく

<h1><span>hogehoge</span></h1>

その他にもCSSの猛者の皆様的に「こうなっていると嬉しい」という例あると思いますので、もし何かあればぜひ教えてください!

2008年4月 9日

テスト担当者のモチベーション
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

こんにちは!やまもと@テスト番長です。

一般人に向かって自己紹介するとき、
「一応サラリーマンです。WEBサイト作ったりとかしてます。」「専門はテストです。」というと
「出来栄えをチェックする人だから、エライ人なんですねー」
と若干良い方に誤解されがちですが、
同業者に「専門はテストです。」というと「あー、大変っすよねー」と必ず同情されます。

テストというのはどうもモチベーションが上がりにくいお仕事のようです。
今回は来るべき五月病シーズンに向けて、特に新人に近い立場の方がモチベーションを失わずに居られる方法を幾つか考えてみましょう。

テスト担当を押し付けられたとき

新人を安易にテスト業務に割り当てるケースがあります。 新人はまだ経験と信頼性が足りない故に他の作業で使いづらく、そうなりがちです。

もしプログラミングの方に興味があるなら、そういう意向をアピールしておくべきです。
いつ頃プログラミングをさせてもらえるか、見通しを上司と話し合っておきましょう。

その上で今は経験を積むためだと割り切ってしまうのがいいでしょう。
テストのやり方を覚えるのも相当大事なことですし、テストしていても仕様書もコードも見られるし、決して退屈はしないハズ。
#いきなりプロジェクトが炎上してて退屈どころじゃないかもしれませんが。

要領良くこなすとスッキリ。

テストケースの出来具合によっては、まとめてチェック出来る項目が大量にあったりします。 要領良くテストを実施する方法を常に考えましょう。単純作業はなるべく排除しましょう。 やりがいのあるテスト項目に己の時間と精神力を集中させましょう。

攻めの姿勢に出る

用意されたテストケースをただ大量にこなしているだけだと飽きることもあるでしょうが、ここは一つ攻めの姿勢でいきましょう。 テストケースは抜けがあったりするものです。普通あります。 実施しながら穴を探しましょう。穴を見つけたらフィードバックしましょう。 レアなバグを見つけたら、周りの人に見せて褒めてもらうのがいいですね。 チームから頼りにされるようになりましょう。

スキルアップを考える

同じようなテスト作業ばっかり日々繰り返していると、成長できていないことに気づき、人生このままでいいのか悩みだします。スキルアップを心掛けましょう。 テスト関連の良い書籍や資格制度も出てきていますので、手を伸ばしてみましょう。 仲間がいれば一緒にやるといいですね。

休める時に積極的に休暇を取る

テストに関わる(廻される)人は真面目な人が多いので、休むことを積極的に考えましょう。 神経を使う仕事なのでリフレッシュは重要です。 体を動かしたり、趣味の時間を確保するのもいいですね。

たまにはコーディングする

たまにコーディングすると気分転換になります。 プログラムを(ある程度は)組めないとテストも出来ないので、離れてしまわないようにしましょう。 テスト用のツールなどを作れば仕事も楽になりますよ。

会社でのテスト業務の地位が低くて萎えるなら

テストの重要性を理解してもらえない環境だと、テンションのあがりようがありません。 テストを軽視するような人は所詮素人なので、そんな人達が何を言おうと気にすることはありませんが、心が乾いてしまう前に次の展開を考えましょう。


とにかく、状況に流されて何もしないのは一番よくありませんね。
なんだかテストに限らない気もしてきましたが、よかったら試してみてください。

他にも良い方法があればぜひ教えてください!

2008年4月 4日

gdbの使い方
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

今年の2月にマカーになったbokkoです。どうも僕の使っているフォントがほかの人には見づらいらしく、「そのフォントはねぇよw」と言われたり、外付けのキーボードを使っているせいか、「MacBookの意味なし!」と社内で言われてたりしています。

今日はgdbのお話です。gdbは非常に広く使われているデバッガで、特にC、C++のプログラムをデバッグするのによく使われています。

デバッガの使い方

プログラムをデバッグする際、例えば以下の方法が挙げられます。

1. ソースコードを読む
2. ソースコードに出力関数を仕込む(例えばprintf)
3. ソースコードを書き換えて実行してみる

これで十分な場合もありますが、そうでない場合もあります。これらの方法ではプログラムを実行している最中にこちらからソースコードレベルでのアクションを起こすことが難しいので、例えば、プログラムをある時点で止めて変数の内容を確認するといったことが困難です。2と3でもできないことはないですが、CやC++だと何か別のことをやろうとする度にコンパイルし直す必要があります。そこでデバッガの出番です。デバッガを使えばプログラムを1行ずつ実行しながら変数の内容を確認したり、あるループ内の処理がどう実行されてどのようにそのループを抜けたのか確認するのがやりやすくなります。

続きを読む "gdbの使い方" »

2008年3月25日

Amazonの商品個別ページのURLからASINを取得する
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

isogawaです。

題名のままのコードを書く用事があったので、できたものを晒します。とはいえ、ググれば多くの先達が既にさまざまなコードを書いておられ、目新しいものではないんですが。ついでなんで、大昔の「ISBN=~」を含めて、自分の知ってるURLのパターンを洗いなおしてみました(それでも、まだ他のパターンがありそうな気がしますが…)。

例えば、「The Elements of Style」という書籍の個別商品URLとして思いつくものには、以下のようなパターンがあります(細かいバリエーションは適宜省略)。

スキームがhttpの場合とhttpsの場合、ホストの「www.」の有無、及び日本のサイトについては「.co.jp」と「.jp」の両ドメイン名で、表示内容に違いは見られないようです。

なお、ASIN以降スラッシュに続けて、アソシエイトIDを初めとした各種パラメータが付与されますが、必ずASIN以降であるようなので、ここでは無視します。

というわけでコードですが。以下はJavaScriptですが、やってることはパスをバラして正規表現で評価してるだけなので、他の言語にもサクっと置き換えられるかなと。

続きを読む "Amazonの商品個別ページのURLからASINを取得する" »

2008年3月21日

Apache MPM の基礎をしっかりと理解しよう!
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

naoya です。最近、とうとう花粉症の季節に入ったので、生まれて初めて空気清浄機を購入しました。

さて、今日は Apache HTTP サーバの MPM (Multi Processing Module) について解説したいと思います。普段、ウェブサーバを構築するとき、Apache HTTP サーバを使うことが多いと思いますが、Apache HTTP サーバを使う上で MPM について理解しておくことは大事です。

この MPM ですが、Apache HTTP サーバではリクエストを処理する部分のことをさします。MPM は、Apache HTTP サーバ 2.0 系から採用されています。Apache HTTP サーバの MPM には、次の種類があります。

  • prefork
  • worker
  • perchild
  • winnt

それぞれの MPM について解説します。まずは、一番代表的な prefork MPM について解説します。prefork MPM の特徴は、次のとおりです。

  • Apache HTTP サーバ 1.3 系以前のモデル
  • 1 つのリクエストに対して、1 プロセスを割り当てる
  • 負荷に応じて、子プロセスを増減させる

prefork MPM は、次に解説する worker MPM と同じくらいよく使われる MPM です。PHP で使うときは、PHPで書かれたwebサービスを高速化する にもあるとおり、prefork MPM を使う必要があります。PHP を使うとき、worker MPM を使うことは推奨されていないので注意してください。

prefork MPM のデフォルト設定は、次のようになっています。prefork MPM では、ServerLimit と MaxClients は同じ値を設定します。



StartServers 8
MinSpareServers 5
MaxSpareServers 20
ServerLimit 256
MaxClients 256
MaxRequestsPerChild 4000

関連するディレクティブの説明は、次のとおりです。

  • StartServers: 最初に起動する子プロセスの数
  • MinSpareServers: 待機する子プロセスの最小数
  • MaxSpareServers: 待機する子プロセスの最大数
  • MaxClients: 生成する子プロセスの最大数
  • MaxRequestsPerChild: それぞれの子プロセスが扱うリクエスト数の制限数

フォト蔵 のウェブサーバも prefork MPM を使っています。フォト蔵のウェブサーバの設定は、次のとおりです。



StartServers 8
MinSpareServers 5
MaxSpareServers 30
ServerLimit 300
MaxClients 300
MaxRequestsPerChild 50

MaxRequestsPerChild の値が小さいのが特徴だと思います。MaxRequestsPerChild を小さくしている理由は、PHP を使っているとかなりメモリを消費するため、頻繁に子プロセスを生成しなおしたいためです。

prefork MPM を使う場合、大量のアクセスを捌きたい場合には MaxClients の値を増やせばいいのですが、あまり増やしすぎてしまうとメモリ不足などになることが多いので、MaxClients を増やすときは ab(Apache Bench) コマンドなどを使って負荷テストを粉って、どのくらいまで設定できるのか見極める必要があります。


次に workder MPM について解説します。worker MPM の特徴は、次のとおりです。

  • スレッド対応型
  • リクエスト処理は、スレッドが対応する
  • 負荷に応じて、子プロセス数を増減させる
  • 1 子プロセスあたりのスレッド数は固定になっている

worker MPM は、子プロセス数を増減させるというところは prefork MPM と似ていますが、リクエスト処理をスレッドが対応するというところが大きく違っています。worker MPM は子プロセスを生成したとき、リクエスト処理をするスレッドを最初にすべて生成するので、新しいリクエストがきたとき、prefork MPM のように子プロセスの生成を待つ必要がないので prefork MPM よりパフォーマンスがいいです。(*1)

worker MPM のデフォルト設定は、次のようになっています。



StartServers 2
MaxClients 150
MinSpareThreads 25
MaxSpareThreads 75
ThreadsPerChild 25
MaxRequestsPerChild 0

関連するディレクティブの説明は、次のとおりです。

  • StartServers: 最初に起動する子プロセスの数
  • MinSpareThreads: アイドル状態のスレッド最小数
  • MaxSpareThreads: アイドル状態のスレッド最大数
  • MaxClients: 生成する子プロセスの最大数
  • ThreadsPerChild: 子プロセスそれぞれに生成されるスレッド数
  • MaxRequestsPerChild: それぞれの子プロセスが扱うリクエスト数の制限数


次に perchild MPM について解説します。perchild MPM の特徴は、次のとおりです。



  • スレッド対応型

  • リクエスト処理は、スレッドが対応する

  • 負荷に応じて、スレッド数を増減させる

  • 子プロセスの数は固定になっている

perchild MPM は、worker MPM の反対のような特徴をもっており、スレッド数だけが増減する仕組みとなっています。そのため、子プロセスの生成を待つ必要がなく、スレッドも必要なだけになるため、もっともリソースを有効に使うことができる MPM といえます。ただし、prechild MPM は不安定な面もあるという情報があるので、本番環境で使う前には入念なテストが必要です。


最後に winnt MPM について解説します。winnt MPM の特徴は、次のとおりです。



  • スレッド対応型

  • リクエスト処理は、スレッドが対応する

  • Windows NT に特化したスレッドモデル

winnt MPM は、その名の通り Windows NT 向けに特化した MPM です。Windows 上の Apache HTTP サーバでは、winnt MPM がデフォルトで使われます。


というわけで、今回は Apache HTTP サーバの MPM について解説しました。普段から使っているオープンソースでも内部の仕組みを理解しておくと、何かのトラブルに遭遇したときに助けのヒントになることがあるので、仕組みを理解するということを大事にしてきたいと思います。

(*1) 追記:prefork MPM より worker MPM の方がパフォーマンスが高い理由は、リクエスト処理をするために子プロセスを生成するではなくスレッドを使うところにありますが、プロセスとスレッドの生成コストの違いについては別の機会にエントリしたいと思います。

2008年2月12日

モバイルサイトをテストする時の基本的なコツ
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

こんにちは!山本@テスト番長です。

今回は下記のエントリも参考にしながら、モバイルサイトのテストをする際の基本的なコツを書いてみたいと思います。

A Primer in Testing Mobile Phone Applications


URLは直接入力せずにメールで送る


長いURLをへこへこ入力しているとタイプミスしがちです。
PCからメールでささっと送っておきましょう。

テスト端末にメールアドレスを貼っておく

テスト端末が沢山あると、個々のメールアドレスが何だったかすぐ忘れます。 もちろん操作して表示できますが機種によって迷うことがあるので、テプラで裏に貼っておけばすぐ確認できますね。

パスワードは短めに設定する

必ず入力しなくてはいけないのがパスワードです。携帯でのキー入力は難儀なので、短めにすると楽ができます。機密の程度にもよりますが、必要以上に複雑にしないほうがベターです。特に違う文字種が混ざると途端に入力し辛くなります。 機種によってパスワードフォームのデフォルト入力文字種が違うのでそれも考慮して決定しましょう。

開発場所での電波の強さを確認する

都会ではまず問題ないですが、開発合宿などで山奥に行った場合など電波が入らないときがあります。実機での確認ができなくなってしまいますので気をつけましょう。

使い放題プランに加入しておく

これも基本ですが、忘れた時のダメージが大きいので頭の片隅に置いておきましょう。 機種依存の不具合を検証するために他人の携帯を借りたときなど要注意です。

エミュレータを信用しない

PCで開発する際エミュレータは便利なのですが、実機とは挙動が違うことも多いので かならず実機で最終確認するようにしてください。 エミュレータ上でバグを確認した場合はそのように報告書に記載するのを忘れずに。 あえて使わないという選択肢もあるかと思います。

モバイルで使えるツールを探しておく

エミュレータに背を向けるとなると、それに換わるものを自前で用意しなくてはいけません。 プロキシとして動作する携帯変換エンジンやFirefoxのUser Agent Switcherなど、 モバイル開発向けの無料で便利なツールが結構ありますのでチェックしておきましょう。

検証対象の端末について話し合っておく

端末はキャリアや世代によって挙動が相当異なります。 どの端末を検証の対象にするのか、判断・周知するようにしましょう。

こまめにお気に入りを設定する

開発環境をブックマークしておくと何かと便利ですが、意外とその一手間を忘れることが多いです。 あとでまた面倒な手順を踏むことになります。お気に入りはこまめに設定しておきましょう。 開発環境のURLをまとめたページを作って、そこをお気に入り登録しておくのも場合によっては手ですね。

とりあえずリロードすることを忘れない

携帯はPCよりもキャッシュが効きやすいので、とりあえずリロードしてみる癖を付けましょう。

充電器は多めに確保する

テスト端末を複数買うとき、充電器は一個あればいいと考えがちです。 でも開発に熱中しているといつの間にか電池切れになるもの。充電器は多めに確保しましょう。 USB充電器が100ショップで手に入りますので、試してみるといいでしょう。



以上、慣れてらっしゃる方にとっては当たり前のものかもしれませんが、
特に新人さんをテストチームに迎えるときはこのへんを周知しておくとスムーズかと思います。
他にも良い心がけがありましたら是非コメントください!

2008年2月 6日

Ruby on Rails: mongrel_clusterのフロントエンドに nginxを使用する
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

こんにちは satoです。

nginx(えんじんえっくす)はロシアで開発されているwebサーバで、軽量、高速が売りのようです。もちろんvirtualhostやrewrite機能にも対応しています。今回はmongrel_clusterのフロントエンドに使ってみました。

mongrel_railsのインストールと環境構築


mongrel_railsをインストールします
gem istall mongrel_cluster --include-dependencies

設定ファイルを作ります。RAIL_ROOTで
mongrel_rails cluster::configure -e development -p 4000

とすると RAILS_ROOT/conf/mongrel_cluster.yml ができます。
--- 
log_file: log/mongrel.log
port: "4000"
environment: development
pid_file: tmp/pids/mongrel.pid
servers: 2

mongrel_clusterを起動します。
mongrel_rails cluster::start


nginxのインストールと環境構築


nginxは URIのrewrite機能 等に pcre を使うので、 pcre-develをインストールしておきます。
yum install pcre-devel

nginxをソースから入れます
wget http://sysoev.ru/nginx/nginx-0.5.35.tar.gz
./tar zxvf nginx-0.5.35.tar.gz
./configure --with-md5=/usr/lib --with-sha1=/usr/lib
make
sudo make install

設定ファイルを編集します。
vi /usr/local/nginx/conf/nginx.conf
http {
upstream mongrel_cluster {
server localhost:4000;
server localhost:4001;
}
server {
root html;
location / {
proxy_pass http://mongrel_cluster;
}
}
}

設定ファイルのフォーマット等テストをします。
sudo /usr/local/nginx/sbin/nginx -t
2008/02/06 20:47:55 [info] 4249#0: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
2008/02/06 20:47:55 [info] 4249#0: the configuration file /usr/local/nginx/conf/nginx.conf was tested successfully

起動します
sudo /usr/local/nginx/sbin/nginx

設定ファイルを以下のようにすれば静的ファイルは nginxが出力したりと、LVSと比べて Layer7の部分でいろいろできるかもしれないです。
  server {
root html;
if (-f $request_filename) {
rewrite (.*)$1 break;
}
if (!-f $request_filename) {
proxy_pass http://mongrel_cluster;
break;
}
}

続きを読む "Ruby on Rails: mongrel_clusterのフロントエンドに nginxを使用する" »

2008年2月 2日

システム自動管理ツールPuppetを使ってみた
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

miyakeです。今日は、近頃話題のオープンソースなシステム自動管理ツール「Puppet」の小ネタをご紹介します。

今回使用した環境ですが、とりあえず試してみようという感じで、CentOS5.0(x86_64)にDAGリポジトリから0.22.4をインストールしています。現時点でのstable版は0.23.2なのでやや古く、設定や機能も変わっているため、本エントリの内容が合致しない場合もあるかと思いますがご容赦ください。

インストールや基本的な設定は、gihyo.jpにてペパボCTOのmizzyさんが執筆されている連載が大変詳しいので、そちらをご覧ください。

本エントリでは、そうして試したみたところ僕自身が引っ掛かった部分などをご紹介します。

単にpuppetmasterdとpuppetdを起動した状態だと、クライアントが定期的にマスターからマニフェストを取得しますが、通常の運用ではやはりマスターから能動的にマニフェストを配布したい場面が多いのではないでしょうか。そこで用意されているのがpuppetrunですが、個人的に欲しい挙動と少し違ったので、別のアプローチを取っています。

まず、puppetrunを本格的に使うには、LDAPによるノード管理が実質ほぼ必須になってきますが、ちょっと試してみようという向きにはハードルが高いように思います。

また、puppetrunをkillした時にTCP:8139を解放してくれないことがありました。「基本はpuppetrunで走らせるけど、ちょっとverboseで動かしたい」という時にこれで困りました。もっともこれは現行のバージョンでは直っている可能性も高いのですが。

ちなみに、puppetdはTCP:8140、puppetrunはTCP:8139で通信を行いますが、puppetrunを使用する場合はPuppetクライアントとなるサーバがpingに応答する必要があります。どうやら、puppetrunはPuppet通信を行う前に、対象のサーバにpingを投げて疎通確認をしているようです。

そんな経緯で、ssh経由で各クライアントのpuppetdを実行するシェルスクリプトを書きました。ssh経由で「sudo /usr/sbin/puppetd」を実行しているので、それを許可しているネットワークでしか実行出来ません。

#!/bin/sh

PUPPET_SERVER="puppetserver"  # puppetmasterdを動かすサーバ
PUPPET_OPTIONS="--onetime -v --logdest /var/log/puppet/puppet.log"  # puppetdの実行オプション

HOGE_SERVERS=(
HOGE01
HOGE02
...
)

FOO_SERVERS=(
FOO01
FOO02
...
)

dopuppet() {
    for i in $@; do echo "[$i]"; ssh $i sudo /usr/sbin/puppetd --server $PUPPET_SERVER $PUPPET_OPTIONS; echo; done
}

if [ $1 ]
then
    case "$1" in
        all)
        dopuppet ${HOGE[@]}
        dopuppet ${FOO[@]}
        ;;
        hoge)
        dopuppet ${HOGE[@]}
        ;;
        foo)
        dopuppet ${FOO[@]}
        ;;
        *)
        dopuppet $@
    esac
    exit 0
else
    echo "Usage: dopuppet {all|hoge|foo|[servers]}"
    echo ""
    echo "  dopuppet all"
    echo "      run puppetd in all servers"
    echo ""
    echo "  dopuppet hoge"
    echo "      run puppetd in hoge group"
    echo ""
    echo "  dopuppet foo"
    echo "      run puppetd in foo group"
    echo ""
    echo "  dopuppet [servers]"
    echo "      run puppetd in any servers like 'dopuppet server01 server02 ...'"
    echo ""
    echo "This script wrote by Ryo Miyake<miyake@unoh.net>"
    exit 1
fi

HOGE_SERVERSやFOO_SERVERSにサーバの一覧を記述して、それをグループとして扱います。マニフェストのクラス設定に合わせておく想定です。マニフェストと自動で同期出来ないためDRYではありませんが、「使ってみたいけどLDAPで管理するとこまではちょっとしんどい」という場合(すごくニッチかも知れませんが)にはこういうアプローチもあるよということで。マニフェストから自動的にクラス毎のサーバ定義を取得してくれるスクリプトとかあると便利かも知れません。

スクリプト内で指定しているpuppetdの起動オプションの解説もしておきます。

--onetime
マニフェストを一度適用したらpuppetを終了します。コマンドラインから実行する時に。
-v(--verbose)
詳細を標準出力に出す。
--logdest
ログを任意のファイルに出力。confの設定より優先されます。

上記スクリプトでは、マニフェストの適用が1サーバずつになるため、動作の詳細を把握しやすい代わりに、一定の台数を超えると実行に時間がかかりすぎるという問題もあります。

100大規模以上のネットワークではやはりpuppetrunを使用するのが王道かと思いますが、ちょっと試してみたい場合の参考になれば幸いです。

2008年1月 7日

PHPとMecabでキーワード自動リンクを実装する
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

こんにちは、山下です。
今年もどうぞよろしくお願い致します。

Webサービスを開発していると、特定のキーワードを自動でURLリンクにする処理が必要になることがあると思います。今回は、このキーワード自動リンク機能を形態素解析ツールMecabを使ってPHPで実装する方法を紹介したいと思います。

説明に入る前に少し補足しておくと、Trieの実装であるDouble-Array処理だけ利用したいのであれば、MecabからDouble-Array処理の部分を切り出したDartsというライブラリがあります。しかし、なぜMecabを使うかというと、PerlだとDartsのバインディングが公開されているのですが、現時点でPHP版はありません。また、最近のLinuxディストリビューションでは、Mecabのパッケージが最初から用意されているため、より簡単に利用できると思ったからです。

それでは、順を追って説明していきます。

1. mecabインストール

Fedora 8の場合だと、次のようにしてインストールできます。

# yum install mecab mecab-ipadic mecab-devel

2. 自動リンク用辞書の作成

辞書用のディレクトリを作って、単語辞書(url.csv), 連接表(matrix.def), 未知語の文字定義(char.def), 未知語用品詞定義(unk.def), 設定ファイル(dicrc)の5つのファイルを用意します。

# mkdir /usr/lib/mecab/dic/autolink
# cd /usr/lib/mecab/dic/autolink

まずキーワードとURLの対応を記述したファイル url.csv を作成します。文字コードに注意してください。ここでは、UTF-8で記述しました。

url.csv

Google,0,0,-5878,http://www.google.com/
Yahoo,0,0,-4472,http://www.yahoo.com/
ChaSen,0,0,-5878,http://chasen.org/
京都,0,0,-3200,http://www.city.kyoto.jp/


その他のファイルの中身は次のようにします。これらのファイルは末尾に改行があるとエラーになるので、入れないようにします。

matrix.def

1 1
0 0 0

char.def

DEFAULT 1 0 0
SPACE 0 1 0
0x0020 SPACE

unk.def

DEFAULT,0,0,0,*
SPACE,0,0,0,*

dicrc

cost-factor = 800
bos-feature = BOS/EOS
output-format-type=autolink

node-format-autolink = <a href="%H">%M</a>
unk-format-autolink = %M
eos-format-autolink = \n

辞書のコンパイルを行います。

# /usr/libexec/mecab/mecab-dict-index -f utf-8 -c utf-8
./pos-id.def is not found. minimum setting is used
reading ./unk.def ... 2
emitting double-array: 100% |#################################| 
./pos-id.def is not found. minimum setting is used
reading ./url.csv ... 4
emitting double-array: 100% |#################################| 
./matrix.def is not found. minimum setting is used.
reading ./matrix.def ... 1x1

done!

ここで、問題なく作成されているか確認します。次のようにリンクが張られば成功です。

$ mecab -d /usr/lib/mecab/dic/autolink
そうだ京都、行こう。
そうだ<a href="http://www.city.kyoto.jp/">京都</a>行こう。


次にこれをPHPから使ってみましょう。

3. php_mecabインストール

PHPからMecabを利用するための拡張モジュールは、rskyさんが作られているので、有り難く使わせて頂きます。

$ wget http://www.opendogs.org/pub/php_mecab-0.3.0.tgz
$ tar xzvf php_mecab-0.3.0.tgz
$ cd php_mecab-0.3.0
$ /usr/bin/phpize
$ ./configure --with-php-config=/usr/bin/php-config ¥
--with-mecab=/usr/bin/mecab-config
$ make
$ sudo make install

4. 動作確認

サンプルとして次のようなプログラムを書いて実行してみます。

<?php
dl('mecab.so');
$options = array('-d', '/usr/lib/mecab/dic/autolink');

$t = new MeCab_Tagger($options);
$str = '京都についてGoogleとYahooで検索した。';

print $t->parse($str);

実行結果

<a href="http://www.city.kyoto.jp/">京都</a>について
<a href="http://www.google.com/">Google</a>と
<a href="http://www.yahoo.com/">Yahoo</a>で検索した。


以上、高速なキーワード自動リンクを簡単に実装できることが分かっていただけたかと思います。エントリ執筆にあたり、下記のページを参考にさせて頂きました。この場を借りてお礼を申し上げます。


関連リンク:


2007年12月29日

無料の暗号化ディスクなどで実現するノートPCのセキュリティ設定Tips
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

こんにちは、naoyaです。2007 年も残りわずかとなりました。年末は何かとあわただしくなるものですが、普段業務などで使用しているノートPCのセキュリティ設定には気をつけたいものです。

そこで、今日は「無料の暗号化ディスクなどで実現するノートPCのセキュリティ設定Tips」と題して、ノートPCにフォーカスしたセキュリティ設定をいくつか紹介します。

1) 暗号化ディスクを導入する

暗号化ディスクを使うことで、機密性の高いデータを暗号化することができます。暗号化ディスクは、起動するときにパスワードを入力することで、はじめて使うことができるので、機密性の高いデータを守るために暗号化ディスクを導入しておくと便利です。

無料で使える暗号化ディスクで有名なものには、PGPdiskがあります。ウノウではしばらくの間PGPdiskを使っていたのですが、Windows Vistaには対応していません。

そこで、最近はTrueCryptというソフトウェアを使っています。 True Cryptは、WindowsとLinuxで動作可能でウィザード画面に沿って操作をすすめるだけで暗号化ディスクを作成することができます。

True Cryptで暗号化ディスクを作った後は、True Cryptのメイン画面でディスクをマウントしたあと、マウントしているドライブをFavorite Volumesとして保存しておきます。True Cryptの設定画面から、Actions to perform upon log on to Windowsの項目のMount favorite volumesにチェックを入れておくとWindowsが起動したときに自動的にマウントすることができるので便利です。もちろん、このときはパスワードの入力が必要です。

True Cryptはここからダウンロードできます、画面は英語なので注意してください。

余談ですが、ThinkPadにはClient Security Solutionというセキュリティ設定を簡単に行うことができるソフトウェアがあります。現在の最新版は、8.0なのですが、7.0のときにはPrivacy Diskという暗号化ディスクを作成する機能があってとても便利でした。8.0になって、削除されてしまったのがとても残念です。


また、マカーの人はOSXに標準で付属しているFileVaultを使うのが便利なようです。ただし、大きなデータを暗号化すると時間がかかることがあるようなので、必要なデータのみにした方がいいそうです。


暗号化ディスクには、業務で使うデータはもちろんのこと、メールのデータやSSHの秘密鍵などを入れるように徹底します。


2) アンチウィルスソフトウェアを導入する

コンピュータウィルスの被害を防ぐためにアンチウィルスソフトウェアを導入します。最近は無料のアンチウィルスソフトウェアなどもあって、導入するための敷居は下がっています。ウノウでは、AVGというアンチソフトウェアを購入して使っています。マカーの人には、ClamXavを使うといいようです。

アンチウィルスソフトウェアを導入したあとは、必ずソフトウェア本体と定義ファイルのアップデートを手動で行いすぐに最新版にします。また、一定期間おきにウィルススキャンを実行するように設定します。


3) ブラウザに入力する情報を保護する

ブラウザにはたくさんのパスワードを入力して使っていますので、万が一を考えてブラウザに入力する情報を保護するように設定します。

Firefoxには、master passwordという機能があって、これを使うとmaster passwordを入力しない限り、他に入力したパスワードなどの情報を自動的に補完しません。Firefoxの場合は、master passwordを設定すると便利です。IEには同様の機能がないのですが、ThinkPadのユーザはClient Security SolutionにPassword Managerという機能があって、同様の機能が提供されているので便利です。


4) スクリーンセイバーを設定する

席を離れるときのことを考えて、一定時間後にスクリーンセイバーが起動するように設定します。あわせてスクリーンセイバーが起動したとき、コンピュータをロックする設定にするか、スクリーンにパスワードを設定します。


というわけで、今日はノートPCのセキュリティ設定Tipsをいくつか紹介しました。新しい年を迎える前に、もう一度普段使っている自分のノートPCのセキュリティ設定を見直してみてはどうでしょうか?

それでは、よいお年をお迎えください。

2007年12月24日

意外と身近なphar - PHp ARchive
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

こんにちは。shimookaです。

今回は意外と古くて身近、でも意外と知られていないphar(PHp ARchive)を取り上げてみました。

pharとは?

pharとはPHp ARchiveの略で、その名の通りPHPスクリプトのアーカイブです。含まれる内容はPHPスクリプトである必要はなく、複数のファイルを含めることができます。Javaの世界で言うjarに近いもので、拡張子は「.phar」となることが一般的です。

pharの特徴としては、以下のものが上げられます。

  • アーカイブするファイルの圧縮をサポート(gzip・bz2)
  • 署名のサポート(md5・sha1)
  • phar拡張モジュールを使用することで、アーカイブを展開することなく透過的に利用可能

pharの中身と使い道

pharファイルは大まかには、データとスタブ、マニフェスト(アーカイブの情報を格納したバイナリデータ)で構成されます。前述のアーカイブに含まれるファイルはデータとして保存されています。スタブは、含まれているデータを処理するためのスクリプトのかたまりです。これをうまく使うことで、インストーラを作ることができます。つまり、

  • データ:インストールしたいファイル
  • スタブ:ファイルをインストールするPHPスクリプト

という構成ということです。Windows版のPHPに付属している「go-pear.phar」という3MBほどのファイルがあります。これをテキストエディタなどで開くと文字化けしているように見えますが、別に文字化けしている訳ではなく、マニフェストの部分が「文字化けしたように見え」ているだけです。

逆に、「何もしない」スタブを用意することで、純粋なアーカイブになります。

pharファイルを作ってみる

では、phar拡張モジュール使ってpharアーカイブを作ってみます。phar拡張モジュールはPHP5.2.0以降が必要で、2007/12/23時点の最新版はphar1.2.3です。

UNIX系OSの場合、インストールはpeclコマンドでOKです。インストール後、php.iniにextensionディレクティブを追加しておきます。

$ sudo pecl install phar
$ sudo echo "extension=phar.so" >> /path/to/php.ini

今回はクラスを定義した3つのPHPスクリプトを1つのpharにまとめてみます。インストーラではない純粋なアーカイブです。まずは、クラスを定義したファイルは以下の通りです。

Foo.class.php

<?php
class Foo
{
    public function getName() {
        return __CLASS__;
    }
    public function execute() {
        return 'This is ' . $this->getName();
    }
}

Bar.class.php

<?php
class Bar
{
    public function getName() {
        return __CLASS__;
    }
    public function execute() {
        return 'This is ' . $this->getName();
    }
}

Hello.class.php

<?php
class Hello
{
    public function getName() {
        return __CLASS__;
    }
    public function greet() {
        return 'Hello, world!';
    }
}

次に、上記3ファイルを1つのphar(test.phar)にまとめるPHPスクリプトですが、簡単な以下のようになります。

create_phar.php

<?php
$files = array('Foo.class.php', 'Bar.class.php', 'Hello.class.php');

// pharインスタンスを生成
$phar = new Phar(dirname(__FILE__) . '/test.phar', 0, 'test.phar');

// ファイルをアーカイブに追加
foreach ($files as $filename) {
    $phar[$filename] = file_get_contents($filename);
}

echo "created\n";

実行結果は次の通りで、pharを作成する際にphp.iniの設定「phar.readonly」が0である必要があります。

$ php -d phar.readonly=0 create_phar.php
created
$ ls test.phar
test.phar
$

また、phar拡張モジュールはストリームラッパーも提供しています。pharストリームラッパーを使う場合は以下の通りです。

create_phar_wrapper.php

<?php
$files = array('Foo.class.php', 'Bar.class.php', 'Hello.class.php');

// ファイルをアーカイブに追加
foreach ($files as $filename) {
    file_put_contents(
        'phar://test2.phar/' . $filename,
        file_get_contents($filename));

}

echo "created\n";

作成されたtest.pharを利用する側のコードですが、以下のような感じです。require/includeする際にpharストリームラッパーを使って、アーカイブされたファイルを指定します。

test_phar_client.php

<?php
// pharに含まれるファイルを取り出す
require_once 'phar://test.phar/Foo.class.php';
require_once 'phar://test.phar/Hello.class.php';

$foo = new Foo();
echo $foo->execute() . "\n";

$greet = new Hello();
echo $greet->greet() . "\n";

実行すると、以下のようになります。

$ php test_phar_client.php
This is Foo
Hello, world!
$ 

まとめ

ざっとですがpharについて紹介してみました。

PHPには発音の仕方が分からない名前のものが多いですが、「phar」はどう発音するんでしょうか。。。これが一番の問題点かも知れません。

phar拡張モジュールは、「PHP5.3でcoreに入れたいよ」とか「次期PEARであるPEAR2で使われるかも」とか、不確定ですがいろいろと情報がありますので、今後pharを見る機会が増えるのではないかと思います。

個人的にはもうちょっと深堀りしてみたいと思っていますので、この続きはDo You PHP?で;-)

2007年12月17日

Emacsでソースコード解析
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

週末に眼鏡と財布が壊れて踏んだり蹴ったりなbokkoです。


最近、週末に他の人が書いたソースコードを解析したりして遊んでいるのですが、
今回はその際によく使っているツールについて紹介したいと思います。


moccur-edit.el

これはソースコードを全体を検索する際によく使っています。
findとgrepをパイプでつなぐだけでも十分な気がしますが、
moccur-grep-findとmoccur-grep-gotoを組み合わせて使うと、
すぐさま該当箇所にジャンプできたりするので、楽々検索できます。
また、moccur-edit.elにはほかにも複数のファイルに散らばっているキーワードを
1つのバッファ上で編集できるなど非常に強力な機能が備わっているので、
Emacsを使うなら必ず入れておくのがオススメです。(tramp経由でmoccur-grep-findを実行するとすごく遅くなるそうですが)


gdb on Emacs

gdbはCやC++だとprintfデバッグだけではどうにもならないことが多々あるので、よく使っています。
基本的なコマンドは一通り使えるようになっといて損はないでしょう。
また、moccur-edit.elはEmacsの拡張なので当然ですが、gdbはEmacs上でも実行することができます。
Emacsのキーバインドがそのまま使えるのはもちろん、いちいちlistコマンドを使わずに、
別のバッファでプログラムの現在位置を確認しながらステップ実行したり、
ブレークポイントを可視化することができるので、Emacsに慣れている人ならgdbはコンソールで実行するよりも
そのままEmacs上で実行してしまう方がオススメです。

2007年12月11日

Ext JS 2.0正式版リリース - 1.xから2.0への移行のメモ
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

isogawaです。

以前紹介したJavaScriptフレームワークExt JSのメジャーバージョンアップである2.0の正式版が、先週末にリリースされました。

Ext 2.0が提供する機能については、以下のサンプルページをご覧いただくのが手っ取り早いでしょう。

さて、Ext 2.0は従来の1.xから大幅に刷新されており、残念ながら1.xとの互換性は高くありません。おそらく1.x用に書かれたコードの殆どは、そのままでは2.0で動作しないでしょう。以下にマイグレーション用のドキュメントが用意されていますが、かなりの量で、ひと通り目を通すだけでも大変です。

以下では、自分がこれまでに作成した1.x用のコードに対して2.0へのマイグレーションを行ってみた際に気付いた点をまとめてみました。ただし、以下の内容がマイグレーションのすべてを網羅しているわけではなく、また実際のところ、細々とした変更が結構あって、すべて覚えてなかったりするので万全ではない点、ご留意ください(例によって、間違ってるところがあるようでしたら、コメントなどで遠慮なくご指摘ください)。

続きを読む "Ext JS 2.0正式版リリース - 1.xから2.0への移行のメモ" »

2007年12月10日

デザイナの立場からの「デザイン依頼のコツ」
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

こんにちは。yamazakiです。
このブログをご覧になっているのはエンジニアの方が多いと思いますので、デザイナの方とのやりとりをされている方も結構いらっしゃるはず。
社内で「どういうふうに依頼されるのがデザイナとしてはいいもの出てきやすい?」というお話を振られたので今回はそれについて書いてみようと思います。

※もちろんあくまでこれは私個人が思うところであり、全てのデザイナにあてはまるわけではないと思います。
ので、できればこれをご覧になったデザイナーの皆様も、「こういうふうに依頼してくれると力が発揮できる」というポイントなど書いていただけたら非常に嬉しいです。
また逆に、デザイナにはこういう点気をつけて欲しい、といった、エンジニア視点でのデザイナへのリクエストなどもいただけると嬉しいです。

----

ビジョン、ゴールを共有する

これは複数の人間が関わるプロジェクトなら当たり前といえば当たり前かもしれませんが…。

たとえば、サイトのリニューアルをするのであれば、
  • サイトをリニューアルするにいたった理由
  • これまでのサイトが抱えていた問題点についてどう考えているのか
  • リニューアル後に期待している効果は何なのか
など、色々な「事情」、「何をしたいのか」「何を求めているのか」があるはずですし、
新規に作るサイトであれば
  • どういう人向けに作ろうとしているサイトなのか
  • どういうサービスなのか
  • どういうビジネスモデルなのか
  • どうなったら成功なのか
など、色々な野望やコンセプト、ターゲットなどお考えのはずです。

通常、どんなサイトを作るにしても、デザイナよりも依頼者のほうが持っている情報量は多いはずですし、考えていること、こだわり、マインド、色々な部分において依頼者のほうが強いものを持っているはずです。それをできるだけ多く共有し、うまく巻き込んでいただけると、デザイナとしてもアイデア出しや絞り込みがしやすいですし、結果としてアウトプットもよいものが出やすいのではないかと思います。

できるだけ企画の早い段階から関われるように

企画のできるだけ早い段階から関わって口を挟んでいるほうが、デザイナの本来の能力を発揮しやすいです。
たとえば以前、エンジニアのかたがサイト構成や画面構成、UIをほとんど組み上げた段階で、「これをデザインしてください」と言われたことがありました。
正直、そこまで出来上がってしまっていると、変更のコストその他色々な要因で、デザイナとしてできることは、見た目を整える、くらいのことになってしまう場合があります。
もちろん、見た目を整える、というのもデザイナの大事な仕事なのですが、それよりももう少し前の段階から関わることができれば、サービス内容やターゲットに合った画面構成やサイト構成、インタラクションを提案して仕込むことができますので、結果としていいものがアウトプットされやすいと思います。

細かく指定しすぎない

例えば依頼者から「ここはこういうふうに」とこと細かな指示をいただいたり、「●●のサイトと同じような見た目にして」というような形で依頼をいただいた場合、デザイナ側では大抵その指定どおりに作ることになります。それが一番トラブルが少なく、余計な時間(つまりコスト)もかからず、お互いにとって「無難」だからです。
ですが、もしかしたらデザイナは発注者の考えるものよりももっといいアイデアを持っているかもしれません。(というか、持っているべき、ですね…)
指定はある程度細かくいただきたいですが、「ターゲットはこうで、コンセプトとしてはこうで、考えてるイメージとしてあるのは●●のサイトみたいなものなんだけど、もっといいアイデアがあればぜひ提案してほしい」といった、デザイナのアイデアが入り込む余地のある形で依頼をしていただけると、発注される方がどのような事を考えているのか理解しやすく、また色々な提案もしやすいので、最終的なアウトプットとしていいものになる可能性が高まるのではないかと思います。

「どこからどこまでやってほしいのか」をはっきりさせる

プロジェクトによっては、サイトの構成や文章などはすべて別のかたが考えて、デザイナはビジュアルを美しく仕上げること、に注力することもあるでしょう。
逆に文章、構成などひっくるめてサイトのオモテの部分はすべてデザイナがやる、ということもあります。
デザインの依頼をされる場合は、できるだけ「どこからどこまでを任せたいのか」という点をある程度はっきりさせておいていただけるとやりやすいです。

素材のご用意はお早めに

以前あったお話なのですが、依頼をいただいた段階ではロゴが決まっておらず、なかなかロゴなどの素材がいただけないということがありました。
ロゴやサイト内で使いたい素材などは、できるだけお早めにいただけないと、なかなか作業が進められないことがあります。
素材はできるだけ早めに決定稿をご用意いただけると、それだけ実際のデザインに時間の余裕もできますので、結果もよくなると思います。

できる限りのデータを共有する

例えば、サイトリニューアルの案件だった場合、
  • これまでのサイトのアクセスログ
  • ユーザ層、ターゲット層などについての様々なデータ
  • これまでにあった問い合わせ内容
といった何かしらのデータの蓄積がある場合もあると思います。そういったデータは可能な限りデザイナと共有するようにしてほしいと思います。
そうすると、デザイナ側でもデータを見て、依頼いただいた内容をさらに改善する提案もできますし、デザイナ的な視点に基づく疑問点や戦略的な問題など、色々と気づくことがあります。
せっかくデザイナに依頼するのですから、それは「デザイナ視点」での意見を得られるチャンスです。積極的に活用していただきたいと思います。

修正指示はできるだけ具体的に。そしてちゃんと理由を添えて。

例えば、「このページをもっと楽しい雰囲気に」といった類の修正依頼は、デザイナとしてはかなり困ります。
「楽しい雰囲気」というのは、人によって様々です。依頼者の考える「楽しい」とデザイナの「楽しい」がズレていると永遠に平行線になってしまいます。
もう少し具体的に、例えば「このページは子供も見るページなので、子供が喜ぶような、ポケモンとかそういうキャラクターが入ってるような感じで楽しさを出したい」など、例を交えながら伝えていただけると、イメージがつかみやすいです。
また、そこを直したいと思う理由は何なのか、も添えていただければ、「そういうことであれば、こういう形はどうでしょう?」と、修正以上の対応・提案ができる場合があります。「どうしてそのように変更したいのか」の部分も伝えていただけると、いい結果になると思います。

----

以上、ほとんどの部分は、デザイナがヒアリング・打ち合わせの際にできるだけ聞き出すべきところ、も多いのですが、こういったことをデザイナ側で知りたいと思っていることを考慮に入れていただいて、事前に資料などご用意いただくなどしていただけると、プロジェクトがスムーズに進み、よりよいアウトプットも出てくるのではないかと思います。

他にも書き忘れた点や、人によってこうしてほしい、といった部分があると思いますので、そのあたりはきっと他のデザイナの方が何か書いてくれるに違いない…と無駄に煽りつつ、今回は締めさせていただきます。

2007年12月 7日

Linuxをネットワーク経由で自動インストールする方法(後編)
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

こんにちは、miyakeです。早く書くつもりだったのに前回からずいぶんと時間が空いてしまいました。今日は前回構築したPXEブート環境を用いて、いよいよOSの自動インストールに取りかかります。

■前回のフォロー

まず初めに、前回の内容について追加です。前回の手順でうまくインストールできなかったという情報がありましたので、ご紹介させて頂きます。

next-serverの指定をしないとインストール出来なかったという事例が紹介されています。前回の内容でうまく動かなかった方は、/etc/dhcpd.confへの追加設定を、

filename "pxelinux.0";
next-server 192.168.10.10;

のようにしてみてください。next-serverに指定するIPアドレスは、tftpサーバとして使用するマシンのIPを指定してください。前回の記事に沿って設定した場合は、dhcpdを動かしているマシンと同一になるはずです。

通常、next-serverの指定がない場合は、dhcpサーバのIPが適用されるはずなのですが、こういうケースもあるということで、指定しておいた方が無難かも知れません。

自分でいくつかの環境で試した限りではnext-serverの指定はあっても無くても問題なく動作したのですが、もしかするとルータのdhcp設定を有効にしている場合に失敗することがあるのかも知れません。正確な原因は分かっていないので、何かご存じの方はコメント等で教えて頂けるとありがたいです。

では、本題を進めましょう。

続きを読む "Linuxをネットワーク経由で自動インストールする方法(後編)" »

2007年11月28日

PHPでJSONを扱う
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

yamaokaです。

Ajaxの普及に伴い、JavaScriptで扱いやすいJSON形式で サーバーからのレスポンスを返すことが増えてきているように思います。 PHPでJSONを扱う方法についていくつか紹介します。

JSON関数

もともとPECLの拡張モジュールとして提供されていましたが、 PHP 5.2.0以降、デフォルトでPHPに組み込まれるようになっています。 そのため、最も利用しやすい形式なのではないかと思います。

利用方法は以下のとおりです。json_decodeの戻り値はオブジェクトになります(第2引数にtrueを指定すると連想配列になります)。

$values = array('company' => 'ウノウ', 'name' => 'yamaoka');

$json = json_encode($values);
// string '{"company":"\u30a6\u30ce\u30a6","name":"yamaoka"}' (length=49)

$values = json_decode($json);
// object(stdClass)[1]
//   public 'company' => string 'ウノウ' (length=9)
//   public 'name' => string 'yamaoka' (length=7)

Jsphon

JsphonHawkさんの開発によるJSONライブラリです。 PHPで記述されており、PEARコマンドを利用して簡単にインストール、利用することができます。 Unicode Escape Sequenceをきちんと扱うことができるのが特徴です。日本語を扱う場合、心強いですね。

利用方法は以下のとおりです。Jsphon::decodeの戻り値は連想配列になっています。

require_once 'Jsphon.php';
$values = array('company' => 'ウノウ', 'name' => 'yamaoka');

$json = Jsphon::encode($values);
// string '{"company":"\u30a6\u30ce\u30a6","name":"yamaoka"}' (length=49)

$valeus = Jsphon::decode($json);
// array
//   'company' => string 'ウノウ' (length=9)
//   'name' => string 'yamaoka' (length=7)

PHP4とPHP5、また、PEAR環境の有無によってもエラーハンドリングが異なるので注意が必要です。 詳しくはJsphonのページのエラー処理に関する記述を参照してください。

Zend_Json

Zend_JsonはZend Frameworkに含まれるJSONを扱うためのコンポーネントです。 詳細はZend Frameworkのドキュメントを参照してください。

利用方法は以下のとおりです。Zend_Json::decodeの戻り値は連想配列になっています。

require_once 'path/to/Zend/Json.php';
$values = array('company' => 'ウノウ', 'name' => 'yamaoka');

$json = Zend_Json::encode($values);
// string '{"company":"\u30a6\u30ce\u30a6","name":"yamaoka"}' (length=49)

$valeus = Zend_Json::decode($json);
// array
//   'company' => string 'ウノウ' (length=9)
//   'name' => string 'yamaoka' (length=7)

ちなみに、Zend_Json::useBuiltinEncoderDecoderの値をtrueにすると、 JSON関数が利用できる場合はそちらを使うように挙動が変更されます。

まとめ

Zend_Jsonのように、フレームワークに JSONを扱う機能が備わっている場合はそれを使うのが一番手軽だと思います。 そうでない場合、JSON関数かJsphonを利用することになるでしょう。 ただ、日本語を扱う場合はUnicode Escape Sequenceをきちんと扱うことができる Jsphonの方が安心かもしれませんね。

2007年11月16日

Apache で特定のコンテンツへのアクセスに対して帯域制限しよう
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

こんばんは、最近自転車のライトを交換した naoya です。

今日は、Apache で特定のコンテンツへのアクセスに対して帯域制限する方法を紹介したいと思います。まず、特定のコンテンツの帯域を制限しようと思った背景から説明したいと思います。フォト蔵では、写真と動画をサポートしています。そのため、動画へのアクセスが増えると他の写真などへのコンテンツに対するレスポンスが悪くなってしまうことがあります。動画は、FLV 形式ですが比較的ファイルサイズが大きいものが多いため、FLV のみ帯域制限を行ってみることにしました。

まず、Apache で帯域制限できるモジュールについて調査しました。調査には、Software Design 2007年9月号をおもに参考にさせていただきました。

 

Software Design (ソフトウエア デザイン) 2007年 09月号 [雑誌]

 

Software Design (ソフトウエア デザイン) 2007年 09月号 [雑誌]

posted with amazlet on 07.11.15

技術評論社 (2007/08/18)

Software Design 2007年9月号では、いくつかの Apache の帯域制限できるモジュールが紹介されていたのですが、今回選択したモジュールは mod_bw です。

mod_bw を選択した理由は、次のとおりです。

  • バーチャルホストに対応している
  • 特定のコンテンツ (MIME) 別に設定できる
  • 帯域設定が柔軟にできる
  • Apache 2 系で動作する

それでは、mod_bw のインストール方法について説明します。

続きを読む "Apache で特定のコンテンツへのアクセスに対して帯域制限しよう" »

2007年11月14日

jQueryのパフォーマンス最適化に関するTips
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

こんにちは、山下です。
今回は、jQueryのパフォーマンス最適化について説明したいと思います。

軽量と言われているjQueryですが、いろいろな機能を実現しようとして複数のプラグインを導入すると、だんだんと動作が重くなってきます。サーバ側をいくらチューニングしたところで、ブラウザ側での処理に時間がかかっていたら、せっかく訪問してくれたユーザに重いサイトとして認識されてしまいます。以下に、ウノウで運営している「映画生活」で実際に行っている方法を紹介します。

1. Packed版ではなくMinified版を使う

jQuery1.1まではPacked版のみだったのですが、jQuery1.2からMinified版もダウンロードできるようになりました。Packed版よりもMinified版を使うことをお勧めします。どう違うのかというと、Packed版はファイルサイズを極限まで削減するために静的辞書+可読文字符号化という方法を使っているのですが、ページが読み込まれる度に展開処理が必要になり、無駄な処理が発生します。

これに対してMinified版は、コメントや無駄な空白などを取り除くだけですので圧縮率は低いのですが、無駄な展開処理が必要ありません。最新のPCを使っている場合は気にならないかもしれませんが、古いPCを使っている場合にこの差は顕著になります。静的辞書法については、JavaScriptの圧縮 - daily dayflowerに詳しく書かれていますので参考にしてください。

以上のような理由からjQuery1.2からMinified版が提供されるようになったのですが、まだ1.1.4を使っている場合には、自分でMinified版を作成しましょう。私はJSMinのPython版を使っています。jsmin.pyをダウンロードして次のように実行します。

$ python jsmin.py <some.src.js >some.js

2. 代わりにmod_deflateなどを使う

上で説明したように、Minified版はPacked版より圧縮率の点で劣るのですが、Webサーバの機能を使って通信時にgzip圧縮することで圧縮率を高めることができます。WebサーバにApache2を使っている場合は、mod_deflateが利用可能です。

設定例:

LoadModule deflate_module modules/mod_deflate.so
<FilesMatch "\.(html|css|js)$">
SetOutputFilter DEFLATE
</FilesMatch>

3. プラグインを一つのファイルにまとめる

すべてのページで読み込まれるプラグインなどは、jquery.jsと一緒にまとめてしまいましょう。ブラウザがWebサーバと同時に接続できるコネクション数は限られています。また、通信のオーバーヘッドをできるだけ減らすことで、レスポンスの向上が期待できます。
プラグインのjsファイルは圧縮されていないことが多いので、前述のJSMinなどを使って忘れずにMinified処理をしておきます。

4. 自動で実行される処理を止める

ThickBoxはよく使われるjQueryプラグインで、aタグにclass="thickbox"を追加するだけで画像のエフェクト表示を行うことができます。これは、JavaScriptが分からない人でも手軽に使えて便利なのですが、jQuery(document).ready()関数で毎回イベントの割り当が行われるので非常に効率が悪いです。

$(document).ready(function(){   
  tb_init('a.thickbox, area.thickbox, input.thickbox'); ← 削除
  imgLoader = new Image();// preload image
  imgLoader.src = tb_pathToImage;
});

<a class="thickbox">の代わりに、次のようにHTML内の記述を変更します。

<a href="javascript:tb_show('タイトル',
                             '/hoge/?height=300&width=300')">

ThickBoxに限らず、利用するプラグインのソースには目を通して、無駄な処理が実行されていないか確認しましょう。

5. Expiresをできるだけ長く設定する

ブラウザにキャッシュを使ってもらうようにExprireの期限をできるだけ未来に設定します。Apacheの場合は次のように設定します。

Expires On
ExpiresByType text/javascript "access plus 30 day"
ExpiresByType application/x-javascript "access plus 30 day"

6. class指定ではなくid指定にする

以前のエントリで紹介したように、jQueryでは $('div.hoge') などとclass指定でノードを選択することが簡単にできるのですが、class指定での選択はid指定よりも遅いので可能な限り、$('#hoge')のようにidを指定するようにします。HTMLの構造上できない場合もあるかもしれませんが、速度が変わってくることは覚えておいたほうが良いと思います。

 

2007/11/14 17:20追記

コメント欄で質問されたので、下記のようなコードで軽くベンチマークを取ってみました(MacBook+Firefox)。#hogeだと速いのですが、div#hogeだと逆に遅くなってしまうようです。ですので、初掲時のdiv#hogeを#hogeに修正させていただきました。

var txt = '';

var date = new Dae;
for (var i = 0; i < 10000; i++) txt = $('#hoge').html();
alert(new Date - date); // 582

date = new Date;
for (var i = 0; i < 10000; i++) txt = $('div#hoge').html();
alert(new Date - date); // 4771

date = new Date;
for (var i = 0; i < 10000; i++) txt = $('div.hoge').html();
alert(new Date - date);  // 4595

 

以上、jQueryのパフォーマンス最適化について説明してきましたが、これによって向上できる時間は数十〜数百ミリ秒かもしれません。しかし、新しい機能を追加するよりもパフォーマンス・チューニングを行ったほうがアクセス向上に役立ったというデータもあり、サイトを訪れてくれたユーザに少しでも快適に使ってもらうために有効だと思います。

2007年11月 6日

JavaでMP3を再生する
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

こんにちは。NAKAMURAです。最近ではFlashでMMLやDTMの話題など、音楽好きには嬉しい情報が飛び交っています。 ここは音楽ネタで便乗してみたいところですので、JavaでMP3を再生する方法を紹介してみたいと思います。

Java Media Framework APIを利用する方法もありますが、今回はLGPLライセンスで公開されている JLayerを利用してMP3を再生してみます。

再生してみる

早速、JLayerを使ってMP3を再生するサンプルクラスを作ってみました。ダウンロードページよりjarを取得してクラスパスに追加しています。

package net.unoh.mp3;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

import javazoom.jl.decoder.JavaLayerException;
import javazoom.jl.player.Player;

public class MyPlayer {

    private Player player;

    private BufferedInputStream stream;

    public void play(String file)
    throws JavaLayerException, FileNotFoundException {
        stream = new BufferedInputStream((new FileInputStream(file)));
        player = new Player(stream);
        player.play();
    }

    public void close() throws IOException {
        if (player != null) {
            player.close();
        }
        if (stream != null) {
            stream.close();
        }
    }

    public static void main(String[] args) {
        MyPlayer player = new MyPlayer();
        try {
            player.play("Pull Me Under.mp3");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (JavaLayerException e) {
            e.printStackTrace();
        } finally {
            if (player != null) {
                try {
                    player.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}

実行すると、お気に入りのPull Me Underを再生することが出来ました。

少しだけ深追いしてみる

これだけでは面白くありませんので、JLayerのソースコードを少し追ってみることにします。

javazoom.jl.player.Playerクラスのplayメソッドをみてみると、

while (frames-- > 0 && ret)
{
    ret = decodeFrame();
}

というwhileループがあります。ここが再生のループのようです。

次にdecodeFrameメソッドを見てみると、audioという変数がwriteしているのがわかります。

out = audio;
if (out!=null)
{
    out.write(output.getBuffer(), 0, output.getBufferLength());
}

続いて、audio変数の実体のJavaSoundAudioDeviceFactoryを見てみるとwriteImplメソッドでSourceDataLineのwriteをしていることがわかります。

protected void writeImpl(short[] samples, int offs, int len)
    throws JavaLayerException
{
    if (source==null)
        createSource();

    byte[] b = toByteArray(samples, offs, len);
    source.write(b, 0, len*2);
}

これで音を出力することができるのがわかりますが、MP3のフォーマットの制御はどうなっているのでしょうか。

もう一度PlayerクラスのdecodeFrameメソッドを見てみると、decoder変数がアウトプットに必要な情報を取得しているようです。

SampleBuffer output = (SampleBuffer)decoder.decodeFrame(h, bitstream);

javazoom.jl.decoder.DecoderクラスのdecodeFrameメソッドから呼ばれているretrieveDecoderメソッドでMP3のメタ情報の読み込みが行われているのが解ります。

まとめ

JavaでMP3を再生してみました。javax.sound.sampled.AudioFormatクラスやjavax.sound.sampled.SourceDataLineクラスを使ったことのある人であれば、大体想像通りのことをやっているなと思われたのではないでしょうか。

Javaで音を再生してみよう思われた方の参考になれば幸いです。

2007年11月 5日

Linuxをネットワーク経由で自動インストールする方法(前編)
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

miyakeです。今回は近頃流行りの、サーバの自動インストール方法をご紹介します。

1エントリにまとめるには内容が多かったので、2回に渡って書きたいと思います。ひとまず今日のところは「ネットワークブートから手動インストール」までです。

自動化の部分を期待された方は申し訳ありませんが、次回のエントリをお待ちください(普段より早めに書きたいとは思います)。

ウノウラボでは「 ベンチャー流サーバ構築のススメ(ソフトウェア編)」と題して、OSをインストールではなくコピーする方法をご紹介しています。両者を簡単に比較してみると、それぞれ以下のような特徴があります。

■OSコピーのメリット

新サーバの環境構築の手間がほとんどない
最低限、IPアドレスの設定だけ変更すればすぐに実践投入できます。
完全に同じ構成のサーバを用意出来る
当然ながら、インストールされたパッケージだけでなく、サーバ内のファイルも同じになります。

既存のサービスで負荷が大きくなった時に即増設、といった用途には非常に便利です。

■自動インストールのメリット

物理的にディスクを移動する必要がない
コピーする場合はHDDを物理的につなぎ換えますが、その必要がありません。
サーバの構成を完全に把握できる
インストールするパッケージを設定ファイルで指定するため、何が入っているかが把握しやすくなります。
違う構成のサーバを立てやすい
設定ファイルを変更すれば、用途に応じたサーバが用意出来ます。

最初の項は、ネットワーク越しにディスクコピーする環境を作ればまた話は違ってきますが、今のところウノウではそうなっていません。

こちらは初期導入で大量のサーバをセットアップする場合や、用途毎にハード構成が異なる場合に有効です。

また、VMwareでテスト環境を作ったり、別のプロジェクトで新しいサーバを立ち上げるのにも便利です。

それぞれに異なる利点がありますので、用途に応じて使い分けが出来ればいいと思います。

■概要

サーバの自動インストールを行うには、以下のような行程をとります。

  1. PXEブート環境の構築
  2. kickstartファイルの作成
  3. サーバをPXEブートする

2番のkickstartファイル(自動インストール用の設定ファイル)は次回に触れるとして、今日は1番のPXEブート環境の構築方法をご紹介します。

なお、OSはCentOS5(x86_64)を使用した場合を例としますが、他のディストリビューションでも基本は同じのはずです。

続きを読む "Linuxをネットワーク経由で自動インストールする方法(前編)" »

PHPで暗号化・復号あれこれ
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

shimookaです。 皆さんはPHPでデータの暗号化・復号をする必要に迫られた場合、どのようにしているでしょうか?今回は、PHPで利用可能なモジュールやパッケージとそれらのサンプルを3つほど挙げてみました。

mcrypt拡張モジュールを使った暗号化

libmcryptを利用したPHP拡張モジュールです。DES、3DES、Blowfish、RIJNDAEL(ラインダール:AES暗号とも呼ばれる)、Blowfishなどのブロック暗号をサポートしています。利用可能な暗号モードはCBC、OFB、CFB、ECBです。 PHPで利用するには、libmcryptをインストールし、configureオプションに「--with-mcrypt」を付ける必要があります。また、PHP5以降、libmcrypt 2.5.6以降が必要です。 以下は、SSHやファイル暗号化ソフトウェアなどに広く利用されているBlowfishを使った暗号化・復号のサンプルコードです。「encrypted data」の値は、毎回変わります。

※以下のサンプルは、推奨されていない関数mcrypt_cbcを使っています。代替関数のmcrypt_generic() および mdecrypt_generic()を使ったサンプルは、追記2を参照してください。

<?php
// 暗号化するデータ
$data = '小池さんはラーメン大好き';
$base64_data = base64_encode($data);
echo "data : " . $data . "\n";

// 暗号化キー
$key = 'the key value for crypting';

/**
 * 初期化ベクトルを用意する
 * Windowsの場合、MCRYPT_DEV_URANDOMの代わりにMCRYPT_RANDを使用する
 */
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_CBC), MCRYPT_DEV_URANDOM);

// 暗号化処理
$encrypted_data = mcrypt_cbc(MCRYPT_BLOWFISH, $key, $base64_data, MCRYPT_ENCRYPT, $iv);
echo "encrypted data : " . base64_encode($encrypted_data)."\n";

// 復号処理
$base64_decrypted_data = mcrypt_cbc(MCRYPT_BLOWFISH, $key, $encrypted_data, MCRYPT_DECRYPT, $iv);
$decrypted_data = base64_decode($base64_decrypted_data);
echo "decrypted data : " . $decrypted_data . "\n";

echo 'validate : ' . ($data == $decrypted_data ? 'true' : 'false') . "\n";
ここでは、CBCモードを使用するため、mcrypt_cbc関数を使用していますが、その他としてmcrypt_encrypt関数/mcrypt_decrypt関数、mcrypt_generic関数が利用可能です。これらの詳細はPHPマニュアルを参照してください。 サンプルの実行結果は以下の通りです。
$ php ./mcrypt_cbc.php
data : 小池さんはラーメン大好き
encrypted data : bOiwSixcIcwn58/rP5u1RPzmy0wH3T+C7cm4HDtmNDXYiG+NYEuWokFcJg1SLmcq
decrypted data : 小池さんはラーメン大好き
validate : true
$

PEAR::Crypt_Blowfishを使った暗号化

PEARパッケージにも暗号化のパッケージが複数用意されています。先のサンプルで使用した暗号化方式BlowfishのパッケージPEAR::Crypt_Blowfishも用意されています。2007/11/05時点の最新版は1.1.0RC1です。インストールはpearコマンドを使ったいつもの手順でOKです。今回は、Crypt_Blowfish-1.1.0RC1をインストールしました。
$ sudo pear install -a Crypt_Blowfish
PEAR::Crypt_Blowfishはパッケージ内部で、後述するmcrypt拡張モジュールが利用できる場合、そちらを利用するようになっています。この場合、mcrypt_generic関数を使用することになります。 暗号化・復号のサンプルコードは以下の通りです。なお、以下のサンプルではCBCモードを指定しています(Crypt_Blowfishクラスのfactoryメソッドの第1引数)が、デフォルトのECBモードは現在では推奨されていないモードです。
<?php
require_once 'Crypt/Blowfish.php';

echo "mcrypt module is " . (extension_loaded("mcrypt") ? "" : "not ") . "loaded\n";

// 暗号化するデータ
$data = '小池さんはラーメン大好き';
echo "data : " . $data . "\n";

// 暗号化キー
$key = 'the key value for crypting';

// CBCモードで暗号化するため、初期化ベクトルを用意する
$iv = substr(md5(uniqid(rand(), 1)), 0, 8);

// 暗号化処理
$blowfish = Crypt_Blowfish::factory('cbc', $key, $iv);
$encrypted_data = $blowfish->encrypt(base64_encode($data));
echo "encrypted data : " . base64_encode($encrypted_data) . "\n";


/**
 * [BK]mcrypt拡張モジュールがロードされている場合、1つのインスタンスを
 * 使い回すことができない(mcrypt_generic_deinitしていないため)ので、
 * 再度インスタンスを取得する必要がある。イケてない。。。
 */
if (extension_loaded("mcrypt")) {
	$blowfish = Crypt_Blowfish::factory('cbc', $key, $iv);
}


// 復号処理
$decrypted = $blowfish->decrypt($encrypted_data);
if (PEAR::isError($decrypted)) {
	die($decrypted->getMessage() . "\n");
}
echo $decrypted . "\n";
$decrypted_data = base64_decode($decrypted);

echo "decrypted data : " . $decrypted_data . "\n";
echo 'validate : ' . ($data == $decrypted_data ? 'true' : 'false') . "\n";
実行結果は以下のような感じになります。「encrypted data」の値は、毎回変わります。
$ php ./crypt_blowfish.php
mcrypt module is not loaded
data : 小池さんはラーメン大好き
encrypted data : AM7KWxcRFalD8+GNy996PEXlkcGbpo2naceGi9FlIzWpKEy3DBf7ozh1TcAgVTsH
5bCP5rGg44GV44KT44Gv44Op44O844Oh44Oz5aSn5aW944GN
decrypted data : 小池さんはラーメン大好き
validate : true
$ 
また、mcrypt拡張モジュールがロードされている場合は、以下のようになります。
$ php ./crypt_blowfish.php
mcrypt module is loaded
data : 小池さんはラーメン大好き
encrypted data : 4S39zUGp3B7GVSCkyaqQP5m9oTAzLbkMIY2yHp7cUdsrNcAhZ9Gv6XIu7XFaep7R
5bCP5rGg44GV44KT44Gv44Op44O844Oh44Oz5aSn5aW944GN
decrypted data : 小池さんはラーメン大好き
validate : true
$

openssl拡張モジュールを使った暗号化

openssl拡張モジュールを使って、RSA鍵(公開鍵/秘密鍵)を使った暗号化も可能です。先のBlowfishは共通鍵(暗号化・復号に同じ鍵)を使っています。 PHPで利用するには、OpenSSLパッケージをインストールし、configureオプションに「--with-openssl」を付ける必要があります。なお、OpenSSLパッケージは最新のものを使用するようにしましょう。 さて、暗号化・復号を行う前に、以下のような手順で秘密鍵と公開鍵を作成しておきます。
$ mkdir certificates
$ cd certificates/
$ openssl genrsa -out privkey_rsa.pem
$ openssl rsa -pubout -in privkey_rsa.pem -out pubkey_rsa.pem
$ chmod 400 privkey_rsa.pem
$ 
暗号化・復号のサンプルは、local.ch official blogに掲載されているものを参考にさせていただきました。
<?php
/**
 * $ openssl genrsa -out privkey_rsa.pem
 * $ openssl rsa -pubout -in privkey_rsa.pem -out pubkey_rsa.pem
 *
 * @see http://blog.local.ch/archive/2007/10/29/openssl-php-to-java.html
 */
// 公開鍵・秘密鍵を保存したディレクトリ
define('CERT_DIR', './certificates');

// 暗号化するデータ
$data = "小池さんはラーメン大好き";
echo "data : " . $data . "\n";

// 公開鍵を読み込む
$public_key = openssl_pkey_get_public(file_get_contents(CERT_DIR . "/pubkey_rsa.pem"));

// 暗号化処理
openssl_seal($data, $encrypted_data, $env_key, array($public_key));
echo "encrypted data : " . base64_encode($encrypted_data) ."\n";
echo "env_key : " . base64_encode($env_key[0]) ."\n";

// 鍵リソースの解放
openssl_free_key($public_key);


// 秘密鍵を読み込む
$private_key = openssl_pkey_get_private(file_get_contents(CERT_DIR . "/privkey_rsa.pem"));

// 復号処理
if (!openssl_open($encrypted_data, $decrypted_data, $env_key[0], $private_key)) {
	die(openssl_error_string() . "\n");
}
// 鍵リソースの解放
openssl_free_key($private_key);

echo "decrypted data : " . $decrypted_data . "\n";

echo 'validate : ' . ($data == $decrypted_data ? 'true' : 'false') . "\n";
このサンプルの実行結果は以下の通りです。
$ php ./openssl.php
data : 小池さんはラーメン大好き
encrypted data : zvGd1yvHmkptNOlnwg66NSHjwgjSTfNkuH8q3cesaLku115J
env_key : hXVAaC6TmyGld+nAp4F2PJgTmItLZZ1geymEbcBboSyP3PGC/29HDsFCKU833LMNpdPggA3iziR7pp3Voaz9Hg==
decrypted data : 小池さんはラーメン大好き
validate : true
$

まとめ

BlowfishとRSA鍵を使った暗号化・復号のサンプルをそれぞれ挙げてみましたが、いかがでしたでしょうか?本エントリが少しでもお役に立てると幸いです。

参考URL・書籍

本エントリは以下のサイト・書籍を参考に書かせていただきました。情報を公開していただいたことに改めて感謝いたします。

続きを読む "PHPで暗号化・復号あれこれ" »

2007年11月 2日

PEAR::Pagerで生成されるリンクを並び替える
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

bokkoです。

Webアプリケーションではページングの処理を行うことがよくありますが、実際にこの仕組みを作るには少々手間がかかるので、この処理を肩代わりしてくれるライブラリがほしいところです。


この手のライブラリは、PHPではPEAR::Pagerが有名かと思います。


簡単な例

とりあえず、使ってみましょう。(動作確認したVersionは2.4.4です)

require_once('Pager/Pager.php');
$params = array(
                'mode' => 'sliding',
                'delta' => 5,
                'perPage' => 5,
                'prevImg' => '<<',
                'nextImg' => '>>',
                'totalItems' => '1000'
                ); 
$pager =& Pager::factory($params);
echo $pager->links;

上記のphpスクリプトをブラウザで表示すると、以下のように表示されます。
pager_first.PNG

8ページ目に移動してみます。

pager_first8.PNG

表示するページ番号などもちゃんと変更されていて、前のページへのリンク(<<)もついています。とても便利です。しかし、ちょっと生成されるリンクテキストをよく見てみましょう。


[最初のページ] 前のページ n~m番目のページ 次のページ [最後のページ]


という順にならんでいます。もしかしたら、人によっては↓のように並んでいる方がわかりやすいかもしれません。

pager_next.PNG

PEAR::Pagerでは最初にインスタンスを生成する際にいろんなオプションを指定できるのですが、この並び順を入れ替えるオプションはありません。(多分)

でも、どうにかして順番を入れ替えたいので、うまい方法を探してみましょう。


PEAR::Pagerのソースを読んでみる


PEAR::Pagerのソースを読んでみると、Parger.phpのほかにCommon.php、HtmlWidgets.php、Jumping.php、Sliding.phpなどがあります。Common.phpはファイル名が抽象的なのに対して、ほかのファイル名はより具体的です。また、PEAR::Pagerはページングのためのライブラリです。よって、コアとなる処理はCommon.phpにあると考えられます。そして、そのままCommon.phpを眺めていくと、buildという関数があります。

function build()
{
    //reset
    $this->_pageData = array();
    $this->links = '';
    
    $this->_generatePageData();
    $this->_setFirstLastText();
    
    if ($this->_totalPages > (2 * $this->_delta + 1)) {
        $this->links .= $this->_printFirstPage();
    }
    
    $this->links .= $this->_getBackLink();
    $this->links .= $this->_getPageLinks();
    $this->links .= $this->_getNextLink();
    
    $this->linkTags .= $this->_getFirstLinkTag();
    $this->linkTags .= $this->_getPrevLinkTag();
    $this->linkTags .= $this->_getNextLinkTag();
    $this->linkTags .= $this->_getLastLinkTag();
    
    if ($this->_totalPages > (2 * $this->_delta + 1)) {
        $this->links .= $this->_printLastPage();
    }
}

linksという変数にgetにょろにょろLinksという関数の値をどんどん連結していってるところを見ると、これがリンクテキストを生成している部分だと想像できます。そして、_printFirstPage関数が呼ばれた後に_getBackLink関数が呼ばれていて、また、_getNextLink関数の後に_printLastPage関数が呼ばれているのが確認できます。ということはこの順序を入れ替えてやればうまくいきそうです。

書き換え後のbuild関数

function build()
{
    //reset
    $this->_pageData = array();
    $this->links = '';
    
    $this->_generatePageData();
    $this->_setFirstLastText();
    
    $this->links .= $this->_getBackLink();
    if ($this->_totalPages > (2 * $this->_delta + 1)) {
        $this->links .= $this->_printFirstPage();
    }
    
    $this->links .= $this->_getPageLinks();
    
    $this->linkTags .= $this->_getFirstLinkTag();
    $this->linkTags .= $this->_getPrevLinkTag();
    $this->linkTags .= $this->_getNextLinkTag();
    $this->linkTags .= $this->_getLastLinkTag();
    
    if ($this->_totalPages > (2 * $this->_delta + 1)) {
        $this->links .= $this->_printLastPage();
    }
    $this->links .= $this->_getNextLink();
}

これでリンクを並び替えることができます。

2007年10月31日

Webデザインする上でFireworksがステキな12のポイント
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

Webデザイナとして仕事をする上で、ここ数年、個人的にFireworksが手放せないツールになっています。
twitterで某人に「書いて」と言われたのもあるのですが(笑)、Web画像を作るのによいソフトをさがしている人、これから画像編集のためのソフトを選ぼうとしている人の参考に、ということで、個人的にFireworksの気に入っている点など一通りまとめてみようと思います。

ベクター画像とビットマップ画像が等しく扱えるので作業がスムーズ

Fireworksは、ベクター画像とビットマップ画像を同時に扱えます。ベクターでちょっとしたアイコンを作るとか、ビットマップ画像を読み込んで編集するとか、すべてが一つのソフトの中で完結できます。IllustratorとPhotoshopを行き来したりするような手間は不要ですし、また複数のソフトを同時起動しなくていいのでマシンにも優しいです。
ビットマップ&ベクター
ビットマップ&ベクター posted by (C)フォト蔵

画像作成からスライス作成、画像名を指定して書き出し、までが一つのソフトで完結できる

Web制作のワークフローでいくと、

カンプというかモックアップというか、「サイトのイメージ」を制作してデザインを詰める
  ↓
クライアントからOKが出たら必要なパーツをスライスして切り出して、HTMLを組み立てていく

みたいな流れが多いかなと思うのですが、この「モックアップ作成」から「スライス切り出し」までがFireworksであれば一つのソフトで完結します。
Photoshop,Illustrator,ImageReadyを組み合わせるフローよりはシンプルでスムーズに作業できるかな、と個人的には思います。
フロー1
フロー1 posted by (C)フォト蔵
フロー2
フロー2 posted by (C)フォト蔵
out3
out3 posted by (C)フォト蔵

角丸、矢印などのちょっと複雑なグラフィックが簡単に書ける&書いた後に数値指定などして変更可能

Fireworksには「矢印」「角丸矩形」「星形」「接続線」などのグラフィックが簡単に書ける「オートシェイプ」というツールが備わっています。
書けるものもWebサイトでそれなりに使いそうなものが多いですし、Illustratorで書こうとするとそれなりに面倒だったりするので重宝しています。
また、書いたグラフィックは、たとえば角丸の半径などを「書いた後に」自由に変更できます。
Illustratorだと角丸ツールで書いたものは後から角の半径を変えようとしても難しかったりするので、このあたりの使い勝手は非常によいと思います。

この機能が便利なので、ちょっとしたプレゼン向けのグラフィックとか遷移図みたいな資料書くときにも(印刷の前提がなければ、ですが)Fireworksを使ったりします。

オートシェイプ
オートシェイプ posted by (C)フォト蔵
オートシェイプ2
オートシェイプ2 posted by (C)フォト蔵

9スライス機能が地味に素晴らしい

こちらはFireworksCS3で追加された機能で、会社で使っているFireworks8では使用不能なので機能詳細はAdobeのサイトをご覧ください…。
角丸のボックスや装飾つきのボックスなど作るときに、非常に便利です。

ショートカットが直感的でよい

これは非常に個人的な趣味の問題ですが、AdobeのWebサイトなどには出てこない部分なので…。
画像を作っているとき、細かいところを詰めたり、細かいアイコンを作ったりするときには全体をズームさせたりズームアウトさせたり、といったことをよくやります。
で、そのショートカットが、
ctrl+1で100%表示
ctrl+2で200%表示
ctrl+4で400%表示
ctrl+8で800%表示
ctrl+5で50%表示
という感じで、非常に直感的なショートカットがデフォルトで設定されています。
その他「拡大縮小ツール(Q)」や「ポイント選択ツール(A)」など、個人的によく使うショートカットがキーボードの左半分にそろっています。
右手はマウスに置いたまま、左手だけでショートカットをガシガシ使いたい自分としては非常にありがたい初期設定になっています。
(※ま、そのあたりは環境設定で自分で設定すればいいといえばいいのですけれども…)

単位が「ピクセル」

Fireworksはあくまで「Webグラフィック作成」に特化しているおかげで、基本単位が「ピクセル」です。「ポイント」だとか「cm」とかいった単位は使われません。
移動もすべてピクセル単位で動いてくれるので、ピクセル幅に合わせた配置やスライスがしやすいです。
Illustratorでも基本単位をピクセルに設定できますが、いちいち設定するのも面倒ですし、適当に動かすと12.22pxみたいな半端な数字がでてしまったりして面倒に感じることもあるのでその点FireworksはWeb向けに最適だ、と思います

デフォルトのコピペ位置が「同位置」

これが本当に細かいけど個人的に好きな部分。
Illustratorだとなぜか普通にコピペするとずれた位置にペーストされるのですが、Fireworksの場合は基本的に同じ位置にコピーしてくれます。
Webサイト作りだと、同じものを縦や横にいくつか並べるシーンは結構あると思うのですが、同じ位置にコピーしてくれるとあとは矢印キーやマウス+シフトキーで意図した位置に動かせるのでポイントが高いです。
細かいことなんですが日々の生産性に結構貢献しているように思います。

テクスチャやエフェクト付けも簡単にできる

グラフィックにちょっとした質感を与えたい時、簡単にテクスチャづけや、べベル、エンボス、ドロップシャドウといったエフェクトを追加できます。もちろんベクター画像にもビットマップ画像にも等しく効果