« 2007年4月 | メイン | 2007年6月 »

2007年5月31日

簡単Ajaxライブラリ「jQuery」と便利なプラグインたち
このエントリーをはてなブックマークに追加 このエントリーをlivedoorクリップに追加

こんにちわ、hideです。
最近は、jQueryというJavaScriptライブラリを使ってAjax関連の処理を書くことが多いです。なんといっても軽量で高速、XPathによる要素の指定がとても便利です。今回は、その便利なjQueryをもっと便利にするプラグインをいくつか紹介します。



ThickBox

LightBoxのようなもので、画像の他にHTMLの表示も可能です。難点は、$()を使って書かれているので、他のライブラリと混ぜて使えないこと。僕はソース内の$()をすべてjQuery()に書き換えて使っています。

JSON for jQuery

AjaxでJSONを取得して、処理できるようにするプラグイン。これは必須とも言っていいと思います。CallBack関数を指定してのJSONPも簡単。

BlockUI Plugin

画面の一部や全体を半透明のレイヤーで覆って操作できなくするものです。Ajaxでの読み込み中にメッセージを表示したり等に利用できます。

quickSearch jQuery plug-in

インクリメンタル・サーチできるようにします。大きなデータから検索しても、けっこう動作が軽いです。

Round Corners Plugin

画像をいっさい使わずに角丸を実現します。角丸の他にもいろいろな装飾が用意されています。

CSS Dock Menu

MacのDockのようなインタフェースを実現します。実際にWebページのどの場所で活用するかは疑問ですが…

Star Rating Plugin

スターレイティングを実現するプラグインは他にもいろいろあるのですが、0.5刻みで設定できるこれが気に入っています。

jQuery Dashboard Widget

これはプラグインではないのですが、Macのダッシュボードに登録できるjQueryのリファレンスです。ちょっと参照したい時に便利です。


それから、おまけなのですが、過去に書いたコードでどうしても prototype.js を同時に使わなければならない場合などは、jQueryと衝突が発生してしまいます。なので、次のように記述してコンフリクトを避けています。

<script src="jquery.js" type="text/javascript"></script>
<script type="text/javascript">var $j = jQuery.noConflict();</script>

2007年5月30日

CSSをデバッグしよう
このエントリーをはてなブックマークに追加 このエントリーをlivedoorクリップに追加

こんにちは、Sashaです。CSSって、誰でも比較的簡単に始めることが出来るくせに、何年たってもつまらないバグにハマったりするものです。今日は、CSSをデバッグする手順を紹介します。特にCSS初心者の方々に参考にしていただければ光栄です。ただ、ここで紹介しているのは、CSSの問題解決の方法ではありません。CSS上の問題点の原因を、自分で見つけるためにとるべき手段です。見つかった問題点を、どうやって解決するかは、ここでは触れないのでがっかりしないでくださいね。

※以下の手順は、下記のサイトをパクッ・・・、じゃなくて、翻訳しつつ簡単にまとめたものです。
参考: http://www.subcide.com/tutorials/debuggingcss/

まず、問題あるって認めましょう。

見なかったフリをしたい気持ちはよくわかります、が。

人的ミスをつぶそう

  • スペルをチェックしよう
    • HTMLとCSSとで、スペルは一致していますか?
  • パスをチェックしよう
    • CSSファイルや、CSSファイルの中で指定されている背景画像などのパスは、適切ですか?
  • 大文字・小文字をチェックしよう
    • #myAwsomeID と #myawesomeidは、CSSでは異なったIDとして扱われます。

Validateしよう

タグの閉じ忘れやquotaitonの閉じ忘れなど、目をシバシバさせて見つけようとしても見つけられなかったしょうもないミス、拾ってくれます。

よくある現象を把握しよう
CSSで頻発するバグは、既にほかの人によって見つけられていることがほとんどです。 問題となっている現象をじっくり把握したら、大体あとはgoogleなんかで解決法が見つかるはずです。その問題が、当然のことですが、ブラウザ限定なものなのか、全ブラウザで共通して起こる現象なのかもチェックしましょう。

継承しているものを把握しよう
問題となっている要素そのものに指定されているスタイルを検証してみても、問題が解決されないとき、十中八九問題は、その要素の親要素以上のレベルにあります。継承されているスタイルを全部検証するには、Firefoxの拡張、Fire Bug が超便利です。要素に継承される全てのスタイル定義を、ズラーっと順番に並べてくれる上、例えばその要素のfont-size指定が、親要素のfont-size指定を上書きしている場合は、親要素のfont-sizeには打ち消し線を入れてくれます。CSSの一つ一つの定義をon/offできる上、その場でCSSを編集して試せたりもします。んー、手放せない一品です。

測ってみよう
ズレいているならズレの幅を、隙間が生じているなら隙間の幅、横幅縦幅がブラウザ間で違うなら、その差を、とにもかくにも測ってみましょう。測るのには、やっぱりものさし。Web Developer (Firefoxの拡張)や、IE Developer Toolbar のような開発者、デザイナー向けのツールにもものさしはありますが、さっき山岡さんに教えてもらったものさしツール が便利そうです。ピクセル単位できれいにそろっているか、チェックするのに便利です。そして、そのズレや隙間や幅の違いが、どこから来ているものなのかCSSで捜索です。たとえば、隙間が15pxだったら、marginとpaddingを足したら15pxになるのかもしれないし、二つ並んでいるdivのmargin-leftとmargin-rightの合計が、15pxなのかもしれない。どこかで指定したborderの幅かもしれませんし、IEのバグを踏んでいるのかもしれません。数字が与えてくれるヒントは、結構ありますよ!

Doctypeを確認しよう
適切なDoctypeを使っていますか?CSSは、Doctypeにしたがって解釈されるので、誤ったDoctypeを使用していたりDoctypeをまったく使用していなかったりすると、CSSのデバッグは、バスケのルールを参照して、サッカーの審判をしているようなもんです(んあ?)。
参考: http://hxxk.jp/2006/12/19/2100

問題を隔離しよう
もし、それでも問題が解決されなかったら、大胆な行動に出るべし。CSSやHTMLを少しずつ、削っていきましょう。削ってはリフレッシュ!削ってはリフレッシュ!こうして、問題が再現しないところまで来たら、フフフ、そこなんですね。

人の助けを借りよう
フォーラム、コミュニティ、リアルな人の輪、ネットで働く人間だったら駆使できるはず。活発なコミュニティだったら、即効返事が返ってきますよ。その際、気をつけることは、『上記の全てを検証したうえで』、どのブラウザ、どのDoctypeでそのようなバグが出ているのかをなるべく具体的に記述すること。何がどこで問題となっているか、を明確にせずに質問しようとしても、忙しいプロはなかなか救いの手を差し伸べてくれようとはしてくれません。「問題を隔離」して、問題が出ている箇所と、問題に影響を与えているかもしれない親要素と、そのそれぞれに指定されているスタイルも、忘れずに記述しましょう。

「オマケ」息抜きしよう
CSSのデバッグをしていると、たまに発狂したくなります。だんだん目が画面よりに吸い付いていって、隣に座っている営業の女の子に「ねぇ、こわいよ。」と静かにたしなめられたりします。で、そんなときに外の空気を吸いに行ったりして、戻ってくると、なんか知らないけど問題が解決したり・・・。そんなこと、ありませんか?私には多々あります。問題が不可解に思われれば思われるほど、人はそこに吸いつけられるものです。気がついたらトイレを我慢してたり、息吸うの忘れてたり!お願いです、覚えていてください。行き詰ったら、一呼吸・・・。ふぅ~。


それでは、私も一呼吸入れてきますー。





2007年5月29日

Twitterが醸す「今の空気」とフォト蔵の「視覚」のコラボレーション
このエントリーをはてなブックマークに追加 このエントリーをlivedoorクリップに追加

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

先日、ウノウの開発合宿が行われたのですが
今日は、そのとき自分が試作したものをご紹介させていただきます。

巷で話題のTwitterと弊社フォト蔵のAPIを使ったマッシュアップです。

Phoitter

Twitterを流れるコメントの数々とフォト蔵の写真をマッチングさせ、まった~~りと表示するダラ見系コンテンツです。
マッチしている(ようなしていないような)言葉と写真の組み合わせを、イマジネーションを膨らませてご覧いただければと思います。

Phoitter
Phoitter posted by (C)フォト蔵


使い方
基本的に眺めて楽しむだけです。
一時停止したいときは、Pauseボタンを押してください。

ご意見ご要望などございましたら、お気軽にお聞かせください。

2007年5月25日

ベンチャー流のスパムメール対策術(後編)
このエントリーをはてなブックマークに追加 このエントリーをlivedoorクリップに追加

今日もあいにくの雨で、最近めっきり自転車通勤が減っている naoya です。

今日は、前回の続き「 ベンチャー流のスパムメール対策術」と題した後編のエントリです。前編では、オープンソースで提供されているスパムフィルターの設定方法を紹介しました。

前編の設定を行った後、約2週間ほど僕宛に届く全てのメールでスパムの学習をさせるため、受信したメールをスパムフィルターに通して、スパムメールは spam ディレクトリに、スパムではないメールは Inbox のディレクトリに残しておきました。

この手作業の後、さっそくスパムフィルターの選定をするため、それぞれのスパムフィルターがどの程度効果があるのか測定することにしました。

測定する方法は、僕宛のメールに対して3種類のスパムフィルターをかけて、それぞれのスパムフィルターでスパムと判定されたメールを、どのスパムフィルターにかかったのか分かるようにそれぞれ別のディレクトリに自動的に振り分けるようにしました。

自動的に振り分けるツールは、procmail を使いました。まず、メール受信の時点で procmail を実行するため、$HOME/.forward を作成して、次の内容を記述しておきました。naoya となっているところは、ユーザ名に該当するので環境に応じて置き換えてください。

"|IFS=' ' && exec /usr/bin/procmail -f- || exit 75 #naoya"

procmail を実行されるようになったところで、procmail の振り分けルールを $HOME/.procmail.rc に次のように記述します。

#
# .procmail.rc 振り分けルール
#

PATH=/bin:/usr/bin
MAILDIR=$HOME/Maildir
DEFAULT=$MAILDIR/
LOGFILE=$MAILDIR/.procmail.log

SPAMDIR=$MAILDIR/.spam/cur
SA_SPAMDIR=$MAILDIR/.spam.spamassassin/cur
BS_SPAMDIR=$MAILDIR/.spam.bsfilter/cur
BG_SPAMDIR=$MAILDIR/.spam.bogofilter/cur
TRASHDIR=$MAILDIR/.Trash/cur

# 受信メールに対して
# SpamAssassin をかける
:0fw
| /usr/bin/spamc

# 受信メールに対して、
# bsfilter をかける
:0fw
| /opt/bsfilter/bsfilter/bsfilter
     --pipe --insert-flag --insert-probability

# 受信メールに対して、
# bogofilter をかける
:0fw
| /usr/bin/bogofilter -u -e -p -l
:0e
{ EXITCODE=75 HOST }

# SpamAssassin でスパムと判定されたメールを 
# .spam.spamassassin ディレクトリにコピーする
:0c:
* ^X-Spam-Status: Yes
$SA_SPAMDIR

# bsfilter でスパムと判定されたメールを
# .spam.bsfilter ディレクトリにコピーする
:0c:
* ^X-Spam-Flag: Yes
$BS_SPAMDIR

# bogofilter でスパムと判定されたメールを
# .spam.bogofilter ディレクトリにコピーする
:0c:
* ^X-Bogosity: Spam, tests=bogofilter
$BG_SPAMDIR

#
# 以下は、それぞれのスパムフィルターで
# スパムと判定されたメールを削除する
#
:0
* ^X-Spam-Flag: Yes
/dev/null

:0
* ^X-Spam-Status: Yes
/dev/null

:0
* ^X-Bogosity: Spam, tests=bogofilter
/dev/null

上の procmail の振り分けルールにより、それぞれのディレクトリにスパムが蓄積されていきます。この状態で約2週間ほど、それぞれのスパムフィルターにかかるメールの数を調査しました。また、このときはスパムメールは手作業で spam ディレクトリに、誤ってスパムメールと判定されてしまったメールは Inbox ディレクトリに移動するようにして、随時スパム学習をさせていました。スパム学習は、前編で紹介したシェルスクリプトで自動実行しています。

さて、この期間の間にスパムフィルターでスパムとして判定したメール数は、次の通りでした。

スパムフィルタースパムと判定したメールの数
SpamAssassin857通
bsfilter866通
bogofilter44通

SpamAssassin と bsfilter が非常に優秀でした。bogofilter はおそらく日本語周りの設定不備で判定率が低いと思います。 約二週間で、こんなに多くのスパムメールを社員全員が受信していたかと思うとぞっとしますね。

ということで、SpamAssassin か bsfilter で迷ったのですが、世間の使用状況も考慮して SpamAssassin を採用することにしました。

次に、SpamAssassin を mailman でメール配送される手前でフィルターするように設定しました。mailman での設定方法ですが、Mailman FAQ Entry に3つの方法が書かれています。 この中で、特定のスパムフィルターに依存しない3番目の方法で設定しました。設定手順は、次の通りです。

1. /etc/aliases に定義されている mailman の alias を次のように変更します。次は、test というメーリングリストが設定されている例です。

test: "|/usr/bin/procmail -m /etc/postfix/ml_procmailrc"

2. /etc/postfix/ml_procmailrc を、次の内容で作成します。

SPAM_TO=[スパムを送るモデレータの宛先]

#
# SpamAssassin を実行する
#
:0fw
| /usr/bin/spamc

#
# SpamAssassin でスパムと判定された
# メールをモデレータに送る
#
:0
* ^X-Spam-Status: Yes
! $SPAM_TO


#
# 宛先が test のときは、
# mailman で通常配送する
#
:0
* ^.*test
| /etc/smrsh/mailman post test

3. 最後に、次のコマンドを実行します。

# newaliases
# /etc/init.d/mailman restart

この振り分けルールでは、test 以外の宛先のメールが配送先不明になってしまうので、十分注意して設定してください。運用中の環境に設定するときには、まずテスト用のメーリングリストを作成して確認することをお薦めします。

ウノウのメールサーバは SpamAssassin + mailman でメールの配送を行っています。あわせて、定期的にスパム用のモデレータのメールを確認して、誤判定がある場合にはメールを再送するようにしていますが、今のところ誤判定はほとんどありません。

というわけで、二回に分けて「ベンチャー流のスパムメール対策術」と題してスパムメールのメールサーバ側で対策する方法を紹介しました。 サーバ側で対策するのは敷居が高いという方には、クイックPOPFileがお薦めです。

2007年5月24日

rubyで手軽に暗号化文字列やハッシュ値を生成
このエントリーをはてなブックマークに追加 このエントリーをlivedoorクリップに追加

こんにちは django派閥とrails派閥の争いが激しい最近のウノウです。ちなみに若干railsが優勢です。

require 'openssl'
def encrypt(aaa, solt = 'solt')
  enc = OpenSSL::Cipher::Cipher.new('aes256')
  enc.encrypt
  enc.pkcs5_keyivgen(solt)
  ((enc.update(aaa) + enc.final).unpack("H*")).to_s
  rescue
    false
end
def decrypt(bbb, solt = 'solt')
  dec = OpenSSL::Cipher::Cipher.new('aes256') 
  dec.decrypt 
  dec.pkcs5_keyivgen(solt)
  (dec.update(Array.new([bbb]).pack("H*")) + dec.final)
  rescue  
    false 
end 
def hash(ccc)
    OpenSSL::Digest::SHA1.new(ccc)
end 
    
secret = "himitsu"
solt   = "unoh"
enc = encrypt(secret, solt) 
p enc 
dec = decrypt(enc, solt)
p dec 
p hash(secret)

#--
#"2906e1eca22b8b74ab2a14cbf185185c"
#"himitsu"
#c44ade485240212403b41eba503fcb222d190cd0

便利ですね。
http://www.ruby-lang.org/ja/man/?cmd=view;name=openssl
http://www.ruby-lang.org/ja/man/?cmd=view;name=OpenSSL%3A%3ACipher%3A%3ACipher

2007年5月21日

Wii対応サイト向けコマンド入力ライブラリ
このエントリーをはてなブックマークに追加 このエントリーをlivedoorクリップに追加

尾藤正人 a.k.a BTO です。

先週末開発合宿に行ってきました。 開発合宿のレポートはまた後日書きますので、しばしお待ちを。

僕は今回の開発合宿でWii対応サイト向けのコマンド入力ライブラリを作りました。 まずはデモをご覧ください。

wii.js デモ

別にWiiでなくても、ちゃんと普通のブラウザでも動作しますので、恐れずにカーソルキーでコマンドを入力してもらえればと思います。

WiiでWebにアクセスしているとパスワードの入力にかなり抵抗を感じます。 通常PCからWebにアクセスするときは一人でアクセスしますが、 Wiiでアクセスするときは一緒にみる事が多いのでパスワードをあまり入力したくありません。 インターネットチャンネルが正式版になってから、 入力した文字が「*」で隠されるようになりましたが、 それでも入力している動作は丸見えです。 そこでコマンドでパスワードが入力できればいいのではないかと思い、 今回のライブラリを作成しました。

使い方

  • prototype.jsを組み込む
  • wii.jsを組み込む
  • wii_command = new Wii.Command('password_field'); // "password_field"はパスワードフィールドのid
  • wii_command.replace();

newしてreplace()を実行します。 replace()を実行するとパスワードフィールドをリンクに置き換えてくれます。

メッセージを変更する

デフォルトだと英語のメッセージが表示されます。 メッセージは"linkMessage", "promptMessage"で変更できます。 "linkMessage"にパスワードフィールドを置き換えるアンカータグのメッセージを、 "promptMessage"にウィンドウに表示するメッセージを指定します。


  var wii_command = new Wii.Command('password_field');
  wii_command.linkMessage = "クリックしてパスワードコマンドを入力してください"
  wii_command.promptMessage = "パスワードコマンドを入力してAボタンを押してください"
  wii_command.replace();

別のウィンドウライブラリを使用する

wii.jsではデフォルトでウィンドウを表示する簡単なクラスWii.Windowを使っています。 これは外部から変更可能です。 ウィンドウの表示、非表示には、それぞれshowWindow(), hideWindow()というメソッドを呼んでいますので、これを上書きしてください。


  var wii_command = new Wii.Command('password_field');
  wii_command.showWindow = function() {
    // ウィンドウを表示する
  }
  wii_command.hideWindow = function() {
    // ウィンドウを隠す
  }
  wii_command.replace();

対応する文字を変更する

実はwii.jsで入力されたコマンドは、単にそれぞれのキーを文字に対応させているだけです。 デフォルトのキーマーップは次のようになってます。


  keyMap: {
    Up:    'k', Down:  'j', Left:  'h', Right: 'l', A:     'a', B:     'b',
    1:     '1', 2:     '2', Plus:  '+', Minus: '-'},

つまり"上上下下左右左右"と入力するとパスワードフィールドには"kkjjhlhl"が入力されます。 このキーマップは次のようにして変更可能です。


  var wii_command = new Wii.Command('password_field');
  wii_command.keyMap = {
    Up:    'u', Down:  'd', Left:  'l', Right: 'r', A:     'a', B:     'b',
    1:     '1', 2:     '2', Plus:  '+', Minus: '-'};
  wii_command.replace();

このキーマップの場合、"上上下下左右左右"というコマンドで"uuddlrlr"が入力されます。

毎回設定するのが面倒なのでサブクラスを作る

毎回設定するのが面倒な場合はサブクラスを作ることができます。 サブクラスを作ると毎回上書きしなくてすむようになって便利です。


MyWiiCommand = function() {
  Wii.Command.apply(this, arguments);
};
MyWiiCommand.prototype = new Wii.Command;
Object.extend(MyWiiCommand.prototype, {
  // ここで適当に上書き
});

// MyWiiCommandを使う
(new MyWiiCommand('password_field')).replace();

Wiiリモコンイベント処理クラス - Wii.Controller

wii.jsにはWiiリモコンのイベントを扱うクラスWii.Controllerがあります。 WiiだけでなくIE, Firefox, Operaにも対応していて、 "上", "下", "左", "右", "A", "B", "1", "2", "+", "-"のイベントを扱う事ができます。

Wii.Controllerはnewして、handlerにキーイベントを扱うハンドラーを登録することで使う事ができます。 newするとすぐにキーイベントの取得ができるようになります。 キーイベントの取得を中止したい時はend()を呼んで、 再開したい時はstart()を呼びます。


  var wii_controller = new Wii.Controller;
  wii_controller.handler = function(event, keyCode) {
    alert('keyCode');
  };

  // キーの読み取りを中止する
  wii_controller.end();

  // キーの読み取りを再開する
  wii_controller.start();

まとめ

開発合宿でWii対応サイト向けコマンド入力ライブラリを作成しました。 このライブラリに関しては特に権利は主張する気は全くないので、ご自由に使用していただければ幸いです。 一応、修正BSDライセンスにしておきます。

ダウンロード

wii.js

2007年5月17日

色選びのコツ
このエントリーをはてなブックマークに追加 このエントリーをlivedoorクリップに追加

こんにちは! yamazakiです。
高度なプログラミング話だらけのこのブログには全く馴染まない話題でアレですが、今回は「色」について書いてみようと思います。

Webサイトを作っているとき、ちょっとした書類を作るとき、「どんな色を使おうかなぁ」というのは毎度結構迷うところです。今回はそんなときにもしかしたら少しは役に立つかもしれない、色選びのTipsです。

色の「トーン」を意識してみよう

色の基本、というと大抵どんな本を見ても「色相」「彩度」「明度」という三つのパラメータがまず出てきます。「色相」「彩度」「明度」というのは

色相…その色が「赤」なのか「青」なのか「緑」なのか、その色の「色味」
彩度…色の「あざやかさ」。
明度…色の「明るさ」。黒がもっとも暗く(明度が低く)、白がもっとも明るい(明度が高い)。

なのですが、この三つのパラメータをもとに色を考えていても、いまいち「どの色にしようか」を決める手助けにはなってくれません。

色を選ぶときにはその三つのパラメータよりも「トーン」というものを意識したほうが、見た目や印象のコントロールの役に立ちます。

「トーン」ってなんですか

「トーン」というのは「色調」、つまり色の「印象」をもとにした色の分類で、色に厳しい人々が、いろんな色を、「見た目の印象」に基づいて分類したものです。

「ダークトーン」「ペールトーン」「ビビッドトーン」など基本的とされるトーンには12パターンくらいあって、それぞれに「このトーンならこんな印象」というのがちゃんと紐付けされています。

下記のサイトにその例が非常によくまとまっていましたのでぜひ参考にしてみてください。
(※p、ltなどと書かれた色の輪の部分をクリックするとそれぞれのトーンに含まれる色と印象などの情報が見られます)
http://www.geocities.jp/net_t3/iro-uzu/harmony03_2.html

トーンによって印象をコントロールする

もともと「見た目の印象によって分類されている」、というのもあり、「この印象を出したいならこのトーン」というのがセオリー化されています。
たとえば女性向けのサイトであれば、メインで使う色を「女性的」とされる「ペールトーン」の色の中から色を選んでやると、見た目の印象を「女性的」にしやすくなります。

また、複数の色を使う場合には、トーンが同じ色を選んでおくと、全体的なまとまりがよくなりますので、そういった意味でもトーンを意識するのは役に立ちます。

色のトーン
色のトーン posted by (C)フォト蔵

PC上で表示させる色を選ぶコツ

経験上、PC上で扱える色の中には「どうしても安っぽく見えてしまう色」というのがあるように感じます。
もちろんどんな色も使い方しだいで活きてくる場面はあるので、要は使い方、といえば使い方なのですが、それでもやはり「難しい色」というのはあります。
主だったものとしては以下の色でしょうか。

PC上の色
PC上の色 posted by (C)フォト蔵

基本的に、「普段身の回りで目にすることの少ない色」に人の目は「違和感」のようなものを感じることが多く、若干彩度などを落としめにしたような、日常的に目にすることの多い色のほうが違和感を感じず、チープ感などを感じないように思います。

#00FF00の緑や#FFFF00の黄色、などはコンピュータ上以外では滅多に見ることのない色ですし、
また、このあたりの色は昔のあまり色を表示できなかった時代のコンピュータの表示を思い出させる、というのも「安っぽさ」の原因かもしれません。

といったわけで、たとえばエクセルの表を作るときなどでも、セルの背景色などでこのあたりの色を避けると、見た目にちょっといい感じになります。


色のセンスを磨くには

ひとまず色彩センスを磨くには、まずは身の回りにあるいろんな色に関心を持つことです。
電車内や駅などの広告、ファッションや店舗のディスプレイなど、色々な「色」をたくさん見て、ただ見るだけではなくて「これはこういうトーンで、こういう印象を出すことを狙ったものなんじゃないかな」「この色は気持ちいい」「この色の組み合わせはなんか気持ち悪い」など、自分なりに分析してみると、だいぶ色に対する感覚が鋭くなっていくと思います。

もちろんセンスのいい人の色の組み合わせを拝借するのもひとつのテです。
Adobeが運営しているKulerというサービスがありまして、ここでは「色の組み合わせ」を世界中の色々な人が公開して、評価しあっています。
こういったサイトに公開されているものの中で、気に入った色、自分の作りたいもののイメージに近そうなものを選んで使ってみるのもよいと思います。
Kulerの他にも、色の組み合わせを紹介しているサイトがウェブ上には色々とあるようですので、そんなサイトをあれこれ参考に、色に対するセンスを磨いていくのもいい方法だと思います。

以上、非常に大雑把な内容で恐縮ですが、色選びのコツなど書いてみました。
色については、他にも色が与える心理的な効果だとか、色の組み合わせかたなど、さまざまなコツや技術があるので、そのあたりも今後少しずつ書いていければと思っています。

2007年5月16日

オープンソース戦略により、無償で使えるようになった負荷テストツール
このエントリーをはてなブックマークに追加 このエントリーをlivedoorクリップに追加

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

ウノウラボのコメント欄まで熟読されている慧眼な方は既にお気づきかもしれませんが、WebLOADという商用の負荷テストツールがオープンソース化され、無料で利用出来るようになりました。
http://www.webload.org/

以前自分が書いた WEBアプリのテストに必須なツール7種のエントリにsaltysonicさんがコメントで教えてくださいました。ありがとうございました!

souceforge.net を探してみたところ、見つかりました。
WebLOAD
早速触ってみていますが、さすがに元商用だけあって多機能なようです。

関連記事も探してみたところ、以下のものが見つかりました。
http://news.earthweb.com/ent-news/article.php/3670176
http://www.testingreflections.com/node/view/5306

元が商用のものですので、オープンソース版では機能が限定されていて、
どうやら本格的な負荷を掛けることは出来ないようです。その場合は製品版を購入してね、ということですね。
制限される機能についてはこちらに表がありました。
http://www.radview.com/product/Editions-Comparison.aspx
軽い用途にならこれでも役に立つでしょう。

負荷テストツール(含自動実行ツール)は高価なツールなので、
各社が体験版を使用できるようにしていますが、習熟するのに時間を要するので
オープンソースという形で落ち着いて使えるようにしてくれるのはとてもありがたいと思います。
こういった試みがもっと増えてくれるといいですね。

WebLOAD_IDE
WebLOAD_IDE posted by (C)フォト蔵
 
 

その他、オープンソースのテストツールについては以下のサイトも参考になります。
opensourcetesting.org
興味のある方はご一読ください。
#お、Bugzilla 3.0が出たんですねー。

2007年5月15日

Pythonのテンプレートエンジン
このエントリーをはてなブックマークに追加 このエントリーをlivedoorクリップに追加

こんにちは、chihiroです。今回はPythonのテンプレートエンジンを紹介したいと思います。

Pythonを使い始めた頃、PHPのSmartyや、JavaのVelocity/FreeMarkerに相当するテンプレートエンジンとして、Pythonにはどんなものがあるのか、どれを使えばよいのかよく分からなかった経験があるので、これからPythonを始める方の参考になれば幸いです。

テンプレートエンジンを使う目的の一つに、Webサイト構築・運営の容易化ということがあると思いますが、今回はテンプレートエンジンの性格をざっと紹介したいと思いますので、HTMLの出力ではなく、次のような単純なテキストの出力を例にとって話を進めていきます。

* Hello unoh!!
** Unoh services
- photozou
- eiga seikatu
- video pop
- sugu.cc

Cheetah

Pythonにおいては、もっとも実績のあるテンプレートエンジンです。テンプレートをPyhtonコードに変換するタイプのテンプレートエンジンで、一部はCで実装されているので、なかなか高速です。構文はVelocityに似ています。

from Cheetah.Template import Template

tmpl = Template("""\
#if $user
* Hello $user
#else
* Hello guest!!
#end if
** Unoh services
#for $service in $services
- $service
#end for""", searchList=[{'user'    : 'unoh',
                        'services': ['photozou',
                                     'eiga seikatu',
                                     'video pop',
                                     'sugu.cc']}])
print tmpl.respond()

Mako

実行速度が売りのテンプレートエンジンです。Cheetahと同じくテンプレートをPythonコードに変換するタイプのテンプレートエンジンですが、さらに機能は豊富で、使いやすく感じます。

同じ作者によるMyghtyというテンプレートエンジンもあり、こちらもなかなか高速なのですが、Makoの方が開発が活発のようです。Pythonで書かれたWebフレームワークPylonsを使うならば、このMakoテンプレートを使うことになるでしょう。

Makoと他のテンプレートエンジンの実行速度の比較については、Makoのサイトに掲載されているベンチマーク結果(ページ中ほどのFeaturesの項)をご覧下さい。

from mako.template import Template

tmpl = Template("""\
%if user:
* Hello ${user}
%else:
* Hello guest!!
%endif
** Unoh services
%for service in services:
- ${service}
%endfor
""")

print tmpl.render(**{'user'    : 'unoh',
                     'services': ['photozou',
                                  'eiga seikatu',
                                   'video pop',
                                   'sugu.cc']})

Jinja

後述のDjangoとほぼ同じ構文をもったテンプレートエンジンです。Djangoをインストールせずに、単体でDjango風のテンプレートエンジンを使いたい場合にはよい選択肢かもしれません。

from jinja import Environment

env = Environment()
tmpl = env.from_string("""\
{% if user %}* Hello {{ user }}!!{% else %}* Hello guest!!{% endif %}
** Unoh services
{% for service in services %}\
- {{ service }}
{% endfor %}""")

print tmpl.render(**{'user'    : 'unoh',
                     'services': ['photozou',
                                  'eiga seikatu',
                                  'video pop',
                                  'sugu.cc'] })

Django

WebフレームワークDjangoに組み込まれているテンプレートエンジンで、単体で使うこともできます。テンプレート内にロジックを書くのが難しいのですが、逆にこれが利点となって、読みやすいテンプレートになります。

import os
os.environ['DJANGO_SETTINGS_MODULE'] = '__main__'

from django.template import Template, Context

tmpl = Template("""\
{% if user %}* Hello {{ user }}!!{% else %}* Hello guest!!{% endif %}
** Unoh services
{% for service in services %}\
- {{ service }}
{% endfor %}""")

print tmpl.render(Context({'user'    : 'unoh',
                           'services': ['photozou',
                                        'eiga seikatu',
                                        'video pop',
                                        'sugu.cc'] }))

Djangoのテンプレートエンジンを単体で使う場合には、DJANGO_SETTINGS_MODULEという環境変数を設定しなくてはならないので、それがやっかいかも知れません。ただ、DjangoでWeb開発を行う分には、この制限は気になりません。Djangoに興味のある方は、日本の有志による「Django オンラインドキュメント和訳」をご覧になることをお勧めします。

Kid

WebフレームワークTurboGearsで採用されているテンプレートエンジンで、XMLでテンプレートを記述することに特徴があります。テンプレートの継承機能など、Webページの作成に役に立つ機能を持っています。

KidはXML/(X)HTMLの出力には便利なのですが、上と同じ例で比較することは難しいことから、割愛させていただきます。Kidに興味をもたれた方は、柴田淳氏による『TurboGears×Python』をご覧になることをお勧めいたします。

Genshi

Kidに触発されて開発されたXMLベースのテンプレートエンジンです。Tracで有名なEdgewallがオープンソースで開発を行っています。xpathの多用により、KidよりもさらにXML/XSLTっぽいテンプレート構文を使用します。最初はとっつきにくいテンプレートエンジンだとは思うのですが、Kidより構文エラーが把握しやすいことや、高速であることから、注目を集めています。次期TurboGears, 次期Tracでの採用が表明されています。

GenshiとKidの速度の比較に関しては、Genshiのサイトに掲載されているベンチマーク結果(英語)が参考になります。

GenshiもKidと同じくXML/(X)HTMLの出力を主たる目的としたテンプレートエンジンですが、テキストベースのテンプレートを扱うこともできます。ただ、Genshiの特徴がよく現れないと思いますので、やはり割愛させていただきます。

そのほか

個人的にあまり使ったことがないので紹介できないのですが、他にも次のようなテンプレートエンジンがあります。

2007年5月13日

PHP最適化tipsまとめサイト
このエントリーをはてなブックマークに追加 このエントリーをlivedoorクリップに追加

こんにちは。親知らずを抜いて離乳食三昧のyukiです。GWの暴飲暴食から脱し、ダイエットするには好都合ですね。すいません。負け惜しみです。
さて、今回は「PHPのちょっとしたコツ」の続きネタで、PHP最適化Tipsまとめサイトの紹介です。
これらは既に有名なサイトで紹介されていたり、常識の範囲かもしれませんが、ひとつでも有用に感じていただければ幸いです。
そして英語が極端に苦手なため、意訳突っ込み等あれば宜しくお願い致します。

PHPの最適化 12 PHP Optimization tips

(元ネタはこちらでしょうか? http://www.ilia.ws/files/zend_performance.pdf)
  • staticが使えるなら、staticを使う。速度は4倍になる。
  • __get, __set, __autoload は避ける。
  • require_once() はコストがかかる。
  • include や require では絶対パスで指定する。
  • スクリプトの開始時間は $_SERVER[’REQUEST_TIME’] で得る。
  • 正規表現は、文字列関数で代用できないか探る。(文字を見つけるだけならstrposなどでもよい)
  • str_replace は preg_replace より早いが、strtr は str_replace の4倍早い。
  • 文字列/配列両方を受け入れる柔軟さを持つ関数は避ける。変わりに個別の関数を用意する。
  • @によるエラー制御は遅い
  • $row[’id’] は $row[id] より7倍早い
  • エラーメッセージはコストがかかる
  • for ($x=0; $x < count($array); $x) の count() のようにループの度に呼ばれる関数はさけ、変数に格納する。

また、次のサイトでは実際に色々試した結果が乗っています。

PHP Benchmark test


「echo VS print」「for VS while VS foreach」「ダブルクォート VS シングルクォート」など、素朴な疑問から始まり、実際に計測し結果を公表しています。

ここのサイトでも実証を行っています。
Optimizing PHP Through Habits

  • requireはrequire_once()より3-4倍遅い?
    空ファイルを forループで1万回呼んだ結果、4倍程度早かった。
  • __get, __set, __autoload は遅い?
    new Foo() と require_once('foo.php'); new Foo() で試した結果、__autoload() 3.7倍早かった。__getは差が見られなかった。

Optimizing PHP object

主にオブジェクトでのパフォーマンスが記述されています。

概要

  • すべての変数は最初に初期化すべき
  • メソッドで2回以上参照されるすべてのグローバル/オブジェクト変数はは、ローカル変数に格納したほうがよい。
  • よく使うメソッドは派生クラスに定義する。

詳細

  • メソッドでのローカル変数のインクリメントがもっとも早い。通常関数でのローカル変数のインクリメントもほぼ同じ。
  • グローバル変数のインクリメントはローカル変数のインクリメントより2倍遅い
  • オブジェクト変数のインクリメント($this->hoge++)よりローカル変数インクリメント($hoge++)の方が3倍早い
  • 未定義の変数のインクリメントよりも、初期化した変数のインクリメントの方が9-10倍早い
  • 宣言なしに使われるグローバル変数もローカル変数が増えるのと同じくらいコストがかかる(たぶんPHPはグローバル変数の存在を調べるため)
  • クラス内に10以上のメソッドがあってもパフォーマンスは変わらない
  • 派生クラスメソッドはスーパークラスメソッドより早い
  • 1つの引数と空の関数の呼び出しは、ローカル変数のインクリメント7-8回分のコスト。同じようなメソッドの呼び出しは 15回分のコストがかかる

このTipsはだいぶザックリしたレベルのチューニングですので、お試しになる際は鵜呑みにせずご自身の環境でテストしてみることをおすすめします。
また、もちろんすべてのコードを見直すとなれば非現実的なコストがかかることもあると思います。
必ずこうしなければならないわけではありませんし、「この程度なら…」という場合ももちろんあるかと思いますので、一概には言えません。
もしあなたのサイトのパフォーマンスに不満がある場合、一度見直してみるとか、新たにコードを記述する際にちょっとだけ気をつけてみるという程度で構わないでしょう。

2007年5月11日

かわいい犬や猫の写真をダラ見する
このエントリーをはてなブックマークに追加 このエントリーをlivedoorクリップに追加

こんにちは、matsudaです。

今回、フォト蔵で公開されている犬・猫の写真をダラ見するサービスを作りましたのでご案内いたします。HOT or NOT の犬・猫版という感じでご理解いただけるとわかりやすいかと思います。

『Cute or Not』
cute or not

ゴールデンウィークも終わった今週、恋に仕事にテンションが上がらない方も、かわいい犬や猫の写真で癒されてみてはいかがでしょうか。

カワイイをポチポチしながら眺めていってください。

このCute or Not はフォト蔵APIを利用しています。
フォト蔵にアップされている写真は検索エンジンのイメージ検索とは異なり、とてもかわいい犬・猫写真ばかりでいいですね。

最後に、フォントはTeardrops in Aquablueの【あくあフォント】を利用させていただきました。
すばらしいフォントを作成・公開していただきありがとうございました。

2007年5月10日

PHPによるテキストファイルへのロギング
このエントリーをはてなブックマークに追加 このエントリーをlivedoorクリップに追加

yamaokaです。

PHPでwebアプリケーションを作成するとき、 皆さんはロギング(ログの出力)をどうされているでしょうか。 今回は、テキストファイルへロギングする方法をいくつか紹介したいと思います。

error_log関数

PHPでは、標準の関数として error_log関数が用意されています。 使い方はとてもシンプルです。2番目の引数に「3」を指定することで、 テキストファイルにログを出力することができます。

error_log('message', 3, '/var/tmp/app.log');

syslog関数

また、syslog関数も 標準で用意されている関数です。syslog経由でテキストファイルにログを出力することができます。Windowsの場合は、イベントログでエミュレートされます。

define_syslog_variables();
openlog('App log', LOG_PID | LOG_PERROR, LOG_LOCAL0);
syslog(LOG_INFO, 'message');
closelog();

error_log関数とsyslog関数を紹介しましたが、 もちろん、通常のファイル書き込みと同じように ファイルシステム関数を利用してロギングしてもいいですね。 いずれにせよ、ログのフォーマットやログレベルの設定ができないので、 必要な場合は自分でライブラリとして実装しなくてはいけません。

PEAR::Log

PEARで利用できるロギングユーティリティとして、 PEAR::Logがあります。 テキストファイルへのロギングの他に、Eメールやデータベースなどへのロギングに対応しています。 ロギングのフォーマットによっては他のPEARライブラリに依存していることがあるので、注意が必要です。

$conf = array('mode' => 0644);
$log =& Log::singleton('file', '/var/tmp/app.log', 'ident', $conf, PEAR_LOG_INFO);
$log->log('message');

log4php

Javaにlog4jというロギングの定番ライブラリがありますが、 log4phpはそのPHP版です。 ApacheのLogging Service Projectで開発されています。 log4jと同じように、ログの出力フォーマットの制御を細かく行うことができるのが特徴です。 テキストファイルへのロギングの他に、Eメール、データベース、ソケット経由などへのロギングに対応しています。

// 設定
define('LOG4PHP_DIR', 'lib/log4php');
define('LOG4PHP_CONFIGURATION', './log4php.properties');

$logger =& LoggerManager::getLogger('App');

// ログ出力
$logger->info('message');

LoggerManager::shutdown();

ログの出力フォーマット、出力先などはすべて設定ファイル(上記例なら「log4php.properties」)で指定します。 設定ファイルの記述は以下のようになります。

# ログ出力設定(テキストファイル、ログレベルはDEBUG)
log4php.rootLogger=DEBUG, R

# サイズベースのテキストログローテート
log4php.appender.R=LoggerAppenderRollingFile
log4php.appender.R.File=app.log
log4php.appender.R.Append=true
log4php.appender.R.MaxBackupIndex=5
log4php.appender.R.MaxFileSize=1000
log4php.appender.R.layout=LoggerPatternLayout
log4php.appender.R.layout.ConversionPattern="%d %5p [%x] - %m%n"

Zend_Log

Zend Frameworkの中に、 Zend_Logというモジュールがあります。 テキストファイルへのロギングの他に、標準出力、データベースなどへのロギングに対応しています。 Zend Frameworkの1モジュールですが、単体でも問題なく利用することができます。 PHP5以上でないと動作しません。

ログレベルを自分で定義できたり、フォーマッタやフィルタの機能が備わっているので、 カスタマイズが自由にできるという点でいいかもしれません。 それぞれ用意されている抽象クラスを継承して、必要な実装をすれば自由に機能を追加することができます。

// 出力フォーマット
$format = '%timestamp% %priorityName% (%priority%): %message%' . PHP_EOL;
$formatter = new Zend_Log_Formatter_Simple($format);

$writer = new Zend_Log_Writer_Stream('/var/tmp/app.log');
$writer->setFormatter($formatter);

// 出力レベル
$filter = new Zend_Log_Filter_Priority(Zend_Log::INFO);

$logger = new Zend_Log();
$logger->addWriter($writer);
$logger->addFilter($filter);

// ログ出力
$logger->info('message');

最後に

何かしらのフレームワークを利用する場合、 そのフレームワークに付属するロギングモジュールを利用することが多いかと思います。 しかし、PEAR::Logやlog4phpなどのようなロギングユーティリティを使うと、 よりきめ細かなロギングが可能になることもあるのではないでしょうか。 車輪の再発明をしないために、いくつかロギングユーティリティを知っておくのも悪くないと思います。

※syslog関数に関する記述を追記しました(2007年5月11日)。

2007年5月 8日

【書評】フューチャリスト宣言 梅田望夫/茂木健一郎
このエントリーをはてなブックマークに追加 このエントリーをlivedoorクリップに追加

こんにちわ、江本です。

良き本との出会いは、最高の友人との巡り会いに等しいと言いますが、
僕が巡り会えて本当に良かったと思ういくつかの書籍の中に
梅田望夫さんの「ウェブ進化論 本当の大変化はこれから始まる」
茂木健一郎さんの「脳とクオリア―なぜ脳に心が生まれるのか」
の2冊があります。

今、WEBの世界で起こっている大変動を快活に述べている「ウェブ進化論」
を読んで、僕はプログラミングの勉強を始めました。

かつての偉人達が挑んで止まなかった心脳問題に対して、
己が確実に信ずる物を基にして大胆に切り込んでいく「脳とクオリア」
を読んで、僕は物理と脳科学の勉強も始めました。

こうして僕は、一度も会ったことの無い梅田さんと茂木さんに、
最高の書を通して情熱を突き動かされたのです。

その二人の対談誌「フューチャリスト宣言」が
出たというのだから、読まないわけにはいきません。

この本は、これからの世界が歩む道筋に関して、
二人がそれぞれの視点を交えながら非常に明快に述べている本です。

しかし、僕はその"明快さ"を、
単に"楽観的"という言葉で表すことを好みません。

彼らの瞳には、紛れも無く明るい未来が移っていますが、
決して、単に明るい未来を待ち望んでいるだけではありません。
彼らは自分の"意思"を持って、明るい未来を"創り出そう"としています。

その真っ直ぐな意思こそが彼らの本質だと感じます。

「フューチャリスト宣言」は、
そんな二人が全力疾走して作り上げられた風のようなものです。

読者は、WEBを伝って彼らに触れた者は、
その風に後押しされ、その風に乗って走り出し、
そうして彼らを通じて走りだした人々が創りだす新しい風が重なって、
想像も出来ないような楽しい未来を届けてくれるでしょう。


Let's Enjoy Our Future !!


補足:書籍中にURLが出てきたサイトを纏めておきます。
My Life Between Silicon Valley and Japan
茂木健一郎 クオリア日記
Creative Commons Japan - クリエイティブ・コモンズ・ジャパン
CNET Japan Blog - 梅田望夫・英語で読むITトレンド
My Life Between Silicon Valley and Japan - The Economics of Abundance
青空文庫 Aozora Bunko
The Qualia Journal


フューチャリスト宣言
梅田 望夫 茂木 健一郎
筑摩書房 (2007/05/08)
売り上げランキング: 47


RackでWebアプリのWebサーバー依存を無くす
このエントリーをはてなブックマークに追加 このエントリーをlivedoorクリップに追加

rack-logo
rack-logo posted by (C)komagata

komagataです。

仕事でも使う必要が出てきたのでRubyの勉強をしています。WebアプリケーションでRubyを使おうとしていきなり躓いたのがApache、WEBrick、Mongrel等、実行環境毎の設定やAPIの違いです。

Rubyを普段使っている人には常識過ぎるのか情報が少なく、FastCGIで単に「Hello, World」を表示させるのにも一苦労でした。(Railsでは簡単に動くのが悔しい)

そんな実行環境毎のAPIの差を吸収してくれるRackというライブラリを知ったので試してみました。

RackはRuby版WSGIと呼ばれているそうです。WSGIとはWeb Server Gateway Interfaceの略でWeb ServerとWeb Applicationの間のInterfaceを定めたPython界の仕様だそうです。

Web ApplicationはWSGIの仕様に沿ったAPIを使って作ればWeb Serverが変っても問題無いようになるはずです。

まずはこちらを参考に最低限のものを書いてみました。

インストール:

$ gem install rack

hello-rack.rb:

#!/usr/bin/env ruby
require 'rubygems'
require 'rack'
include Rack
 
class HelloRack
  def call(env)
    [200, {"Content-Type" => "text/plain"}, ["Hello, Rack"]]
  end
end
 
Handler::WEBrick.run HelloRack.new, :Port => 3000

これを起動してみます。

$ ruby hello-rack.rb
[2007-05-07 18:43:31] INFO  WEBrick 1.3.1
[2007-05-07 18:43:31] INFO  ruby 1.8.5 (2006-08-25) [i486-linux]
[2007-05-07 18:43:31] INFO  WEBrick::HTTPServer#start: pid=19600 port=3000

ブラウザから3000番にアクセスしてみると・・・

hello_rack
hello_rack posted by (C)komagata

動きました!

HandlerにはWEBrickの他にCGI, FastCGI, Mongrelがあります。それぞれのHandlerを使うことで環境を切り替えることができます。

RequestやResponseはそれぞれRack::Request, Rack::Responseに分かりやすい感じで抽象化されているので環境差を気にせず使えそうです。

しかし、

「結局プログラムを変えなきゃいけないなら意味無いじゃないか、Railsならオプションや設定だけで変えられるのに!」

などと思われたかもしれません。

それを解決するためにRackではrackupというコマンドがあります。rackupとDSL風な設定ファイルを使ってWebサーバー依存をプログラムから追い出すことが出来ます。

rackupコマンド:

$ rackup --help
Usage: rackup [ruby options] [rack options] [rackup config]
 
Ruby options:
  -e, --eval LINE          evaluate a LINE of code
  -d, --debug              set debugging flags (set $DEBUG to true)
  -w, --warn               turn warnings on for your script
  -I, --include PATH       specify $LOAD_PATH (may be used more than once)
  -r, --require LIBRARY    require the library, before executing your script
 
Rack options:
  -s, --server SERVER      serve using SERVER (webrick/mongrel)
  -o, --host HOST          listen on HOST (default: 0.0.0.0)
  -p, --port PORT          use PORT (default: 9292)
  -E, --env ENVIRONMENT    use ENVIRONMENT for defaults (default: development)
 
Common options:
  -h, --help               Show this message
      --version            Show version

まずアプリケーションの方からサーバー依存を取ります。

hello-rackup.rb:

require 'rack/request'
require 'rack/response'
 
module Rack
  class HelloRackup
    def call(env)
      Response.new.finish do |res|
        res.write "Hello, Rackup"
      end
    end
  end
end

(hello-rack.rbの例もそうですが、要はcallできてResponseっぽいものを返すものならば何でもいいみたいです。)

Rackのexampleについているlobstericiousというふざけたアプリケーションを参考にして設定を書きます。(拡張子はrbではなくruです。rackupだからでしょうか?)

lobstericious:

lobstericious
lobstericious posted by (C)komagata

hello-rackup.ru:

require 'hello-rackup'
run Rack::HelloRackup.new

rackupコマンドをこの設定ファイルを指定して起動します。

$ rackup -s webrick -p 9292 hello-rackup.ru
[2007-05-07 19:27:29] INFO  WEBrick 1.3.1
[2007-05-07 19:27:29] INFO  ruby 1.8.5 (2006-08-25) [i486-linux]
[2007-05-07 19:27:29] INFO  WEBrick::HTTPServer#start: pid=22015 port=9292

これでブラウザから9292番にアクセスすると、

hello_rackup
hello_rackup posted by (C)komagata

動きました!

-sオプションにmongrelを指定すればmongrelで起動します。アプリケーション本体には手を入れずに済むようになりました。

更に設定ファイルでは下記のようにProxyのように透過的に動作するMiddlewareを簡単に追加することが出来ます。(このuseというメソッド、Rubyに慣れていないのでPerlみたいに普通にあるのかと思ってKernelモジュールや予約語一覧を探し回ってしまいました・・・)

require 'hello-rackup'
 
use Rack::ShowExceptions
use Rack::CommonLogger
use Rack::Lint
 
run Rack::HelloRackup.new

例えば、Rack::ShowExceptionsを追加するとはエラーをPythonのフレームワークDjango風に表示にし、Rack::CommonLoggerを追加するとApache風のログを出力します。Rack(棚)にMiddlewareを積んでいって機能を追加していくイメージなのかもしれません。

Djangoにそっくり:

traceback_ruby
traceback_ruby posted by (C)komagata

ところでCGIやFastCGIはどうするのかというと、正しいやり方がわかってません・・・。今は苦肉の策でこんなファイルを置いています・・・。

hello-rackup.fcgi:

#!/bin/sh
rackup hello-rackup.ru -s fastcgi

これはかなりヘボいのでどなたか正しいやり方を教えていただければ幸いです・・・。

このようにRackを使うことでRailsのようにWebサーバごとのエントリポイントやrackup用の設定ファイルを用意しておくだけで本体のアプリには手を入れずに様々な環境で動作するWebアプリケーションが書けます。オープンソースで配布するアプリケーションを作る場合などには役に立つのではないでしょうか。

2007年5月 7日

PHPの画像処理の紹介と簡単な比較
このエントリーをはてなブックマークに追加 このエントリーをlivedoorクリップに追加

Keita です。

僕は、フォト蔵チームではないので、フォト蔵の画像処理については見ていませんが、個人的に画像処理に興味があるためPHPにおいての画像処理を簡単に調べたことがあります。

その時の結果をお話させていただきたいとおもいます。
この他に、もし、こういう選択肢があるよというのがあれば、教えていただけると大変うれしいです。

主要なライブラリの一覧


GDで処理

LibGDを操作するPHP標準のライブラリです。
ほぼ、レンタルサーバなどで利用できる反面、対応形式が、JPEG,GIF,PNG,WBMP,GD{,2}にしか対応していないなどのいくつか機能的に制限があります。
(WBMPは、Wireless Bitmapという、WindowsBitmapとは別の形式です)

imagick

ImageMagick/GraphicsMagickという画像編集ソフトのPECLの拡張で非常に多くの形式に対応しています。
最近まで2004で、更新がとまっており、今後も絶望的でした。
しかし、最近、2007-04-13にバグを修正したバージョンが出て、もしかすると今後は期待できるかもしれません。


MagickWandForPHP

上記のimagickと同じ系統、ImageMagickのAPIであるMagickCoreを利用するためのPHP拡張で、残念ながらPHP公式のPECLではありませんが、同じ形式で、配布されています。
APIの数が、400個以上で、対応形式も、ImageMagickのコンパイル時に利用できるライブラリに依存するため一定ではありませんが、非常に多くの形式に対応しています。


imagick2

「今後は期待できるかもしれません。」
とかいってたら、この資料を書いてる間に、imagick2.0.0a1が出ていました。
ほとんどが書き直しされたもののようで、非常に多機能かつクラスベースです。
残念ながら、PHP5.1の特定のバージョン以降しか対応していないようです。
MagickWandForPHPと同じく400個以上のAPIをサポートしているようで、さらに、Classベースで実装されているので、操作が比較的簡単です。


そんなわけでどうすればいいのか


最初、僕のほうでは、GDを使っていたのですが、アニメーションGIFやWindows Bitmapファイルが扱えなかったので、気合をいれてMagickWandForPHP差し替えました。

先に結論だけ述べておくと、今の段階では、MagickWandForPHPで将来的には、PHP4の環境もしくは細かい制御がしたいなら、MagickWandForPHP、PHP5の環境なら新しいimagickを使うのが健康的だと思います。

そんなわけで、将来的には、imagick2にしていきたいのですが、さすがに、GWの前日に出たものを、ちゃんとは検証できなかったので、それぞれの簡単なコード比較と、そのベンチマークを紹介したいとおもいます。

まず、ファイルの読み込み比較です。
MagickWandForPHPと、GDについては、簡単にクラス化した、ライブラリを作ったのでそれを抜粋します。

GD:
class Image_Converter_GD
{
    .....(省略
    function loadFromFile($filename)
    {
        if (! file_exists($filename)) {
            return false;
        }
    
        $size = @getimagesize($filename);
        
        if ($size === false) {
            return false;
        }
    
        list($width, $height, $type, $attr) = $size;
    
        $this->type = $type;
        $this->width = $width;
        $this->height = $height;
    
        switch($this->type) {
           case IMAGETYPE_GIF:
               $this->handle = imagecreatefromgif($filename);
               break;
           case IMAGETYPE_JPEG:
               $this->handle = imagecreatefromjpeg($filename);
               break;
           case IMAGETYPE_PNG:
               $this->handle = imagecreatefrompng($filename);
               break;
           case IMAGETYPE_WBMP:
               $this->handle = imagecreatefromwbmp($filename);
               break;
           default:
               return false;
        }
        return true;
    }
    .....(省略
}

$image = new Image_Converter_GD();
$image->LoadFromFile($filename);
GDではファイルを読み込む場合には、各形式ごとに別々の関数があるのでこれを分ける必要があります。

MagickWandForPHPの場合はこんな感じです。
class Image_Converter
{
    .....(省略
    function Image_Converter()
    {
        $this->image = NewMagickWand();
    }

    function LoadFromFile($filename){
        if (! MagickReadImage($this->image, $filename)) {
            return $this->_returnError();        
        }
        return true;
    }
    .....(省略
}

$image = new Image_Converter();
$image->LoadFromFile($filename);
関数がひとつなので、(まぁ対応形式が多いかつ不確定なので、一個一個関数作ったら追いつきませんし。)簡単に見えます。

さらに、Imagick 2はすでに、Classになっているのでこんな感じになります。
    $image =& new Imagick();
    $image->readImage($filename);
次に、僕は、実際画像のリサイズがしたかったので、
リサイズ処理を書いてみました。
GD:
class Image_Converter_GD
{
    function resize($width, $height)
    {
        if ($width > $this->width &&  $height > $this->height ){
            return ;
        }
        switch($this->type) {
           case IMAGETYPE_GIF:
                $work_handle = imagecreate($width, $height);
                
                $tcolor = imagecolorallocate($work_handle , 255, 255, 255);
                imagecolortransparent($work_handle , $tcolor);
                imagefilledrectangle ($work_handle , 0, 0, $width, $height ,$tcolor);
               break;
           case IMAGETYPE_JPEG:
           case IMAGETYPE_PNG:
           case IMAGETYPE_WBMP:
                $work_handle = imagecreatetruecolor($width, $height);
               break;
        }

        imagecopyresized($work_handle, $this->handle, 0,  0, 0, 0, $width, $height, $this->width, $this->height);
        imagedestroy($this->handle);

        $this->handle = $work_handle;
    }
}
ちゃんとは検証してないですが、だいたい上記のような感じでうごくとおもいます。
次にMagickWandForPHPです。
MagickWandForPHP:
class Image_Converter
{
    function resize($width, $height, $filter = null, $blur = 1)
    {
        if (is_null($filter)) {
            $filter = MW_HammingFilter;
        }
        if (! MagickResizeImage($this->image, $width, $height, $filter, $blur) ) {
            return $this->_returnError();        
        }
        
        return true;
    }
}
ちょっと比較対象が違いますが、すでにclass化されてるimagick2の場合

imagick2:
    $image =& new Imagick();
    $image->readImage('test2.jpg');
    $image->ResizeImage(100, 100, 0, false);

MagickWandとimagick2には、それぞれ、フィルタを使わないScaleと、さらに、imagick2には縦横比率を保存する、thumbnailがありますので、適時使い分ける必要がありそうです。

上記の機能を使って、簡単ですがベンチマークを図ってみました。
require_once "Benchmark/Timer.php";
require_once "../Image_Converter.php";
require_once "../Image_Converter_GD.php";

$timer =& new Benchmark_Timer();

$timer->start();
for ($i = 0; $i < 100; $i++) {
    $image =& new Image_Converter();
    $image->LoadFromFile('test2.jpg');
    $image->resize(100, 100);
    $image->SaveToFile('test_file.jpg');
}
$timer->setMarker('MagickWandResize');

for ($i = 0; $i < 100; $i++) {
    $image =& new Image_Converter();
    $image->LoadFromFile('test2.jpg');
    $image->scale(100, 100);
    $image->SaveToFile('test_file.jpg');
}
$timer->setMarker('MagickWandScale');

for ($i = 0; $i < 100; $i++) {
    $image =& new Image_Converter_GD();
    $image->LoadFromFile('test2.jpg');
    $image->resize(100, 100);
    $image->SaveToFile('test_file.jpg');
}
$timer->setMarker('GD');

for ($i = 0; $i < 100; $i++) {
    $image =& new Imagick();
    $image->readImage('test2.jpg');
    $image->thumbnailImage(100, null);
    $image->writeImage('test_file3.jpg');
    $image->destroy();
}
$timer->setMarker('imagick2Thum');
for ($i = 0; $i < 100; $i++) {
    $image =& new Imagick();
    $image->readImage('test2.jpg');
    $image->ResizeImage(100, 100, 0, false);
    $image->writeImage('test_file3.jpg');
    $image->destroy();
}
$timer->setMarker('imagick2Resize');


for ($i = 0; $i < 100; $i++) {
    $image =& new Imagick();
    $image->readImage('test2.jpg');
    $image->scaleImage(100, 100);
    $image->writeImage('test_file3.jpg');
    $image->destroy();
}
$timer->setMarker('imagick2Scale');

$timer->stop();  
$timer->display();
画像は、50kの450x337のjpeg画像を使いました。

結果:
---------------------------------------------------------------
marker             time index            ex time         perct   
---------------------------------------------------------------
Start              1178505987.83615100   -                0.00%
---------------------------------------------------------------
MagickWandResize   1178505991.81219600   3.976045        19.52%
---------------------------------------------------------------
MagickWandScale    1178505995.10683000   3.294634        16.17%
---------------------------------------------------------------
GD                 1178505997.10204700   1.995217         9.79%
---------------------------------------------------------------
imagick2Thum       1178506002.06985900   4.967812        24.39%
---------------------------------------------------------------
imagick2Resize     1178506004.92157200   2.851713        14.00%
---------------------------------------------------------------
imagick2Scale      1178506008.20629400   3.284722        16.13%
---------------------------------------------------------------
Stop               1178506008.20636800   0.000074         0.00%
---------------------------------------------------------------
total              -                     20.370217      100.00%
表だけ見ると、GDが早いような気がしますが、対応形式などを考えると、他の選択肢のほうがよさそうな気もしますが、そこらへんは好みの問題だと思います。

あとはリサイズの画像の美しさですが、フィルタにどれを使うかなどいろいろ選択肢がありますので、またそのうち紹介したいと思います。
最近、画像周りは、讃容日記 - PHP で JPEG ロスレス回転とかされている方もいらっしゃったりして、僕のなかで非常に熱い分野なんですが、そもそも、最近、PHP勉強会で、PECLのライブラリをわりと簡単に公開するライブラリの紹介などもあったりして、PHPの拡張周りの話が、非常に面白そうだと思っています。

もし、画像操作周りで面白いライブラリなどがあったら、PHPに限らず教えていただけると幸いです。 個人的には、PythonのPILが気になっています。

2007年5月 2日

Googleのサービスをケータイでも使い倒す
このエントリーをはてなブックマークに追加 このエントリーをlivedoorクリップに追加

こんにちわ、hideです。
ゴールデンウィークの真っただ中、皆さんいかがお過ごしでしょうか?この時期、旅行に出かけたり、実家に帰省したりして、いつものインターネット接続環境が使えないことも多いかと思います。今日は、そんなあなたにGoogleのサービスを携帯電話で使う方法を紹介したいと思います。

※一緒にQRコードも載せておきますので、バーコードリーダーで読み取ってご利用ください。

  1. Google検索 Google検索
    携帯電話でもGoogleの検索エンジンが利用できます。このサービスの便利なところは、PC用のサイトを検索できるだけでなく、携帯電話での表示に適した形に変換してくれるところです。画像サイズの変換、長いページの分割、簡単なJavaScriptの描画などもしてくれるようです。




  2. Google proxyGoogle Mobile Proxy

    PC用のサイトを携帯電話での表示に適した形に変換してくれます。Google検索を使うと、このGoogle Mobile Proxyが自動で有効になるので、直接利用することはあまりないかもしれません。




  3. gmailGmail

    Gmailのアカウントを持っている方も多いと思いますが、最近、このGmailも携帯電話から利用できるようになりました。閲覧がメインの使い方になりそうですが、PDFなども閲覧できるようです。緊急時にPCメールが確認できるだけでも大きなメリットになるのではないでしょうか。




  4. GCMGGoogle Calendar Mobile Gateway

    Web上で手軽にスケジュール管理ができるGoogle Calendarですが、残念ながらこちらのモバイル版は今のところ提供されていないようです。しかし、Google Calendar Mobile Gatewayという携帯電話からスケジュール情報を閲覧するためのゲートウェイが公開されています(ウノウ社員ではありませんが、私の友人が作っています)。スケジュールの新規登録こそできませんが新規登録/編集/削除もでき、外出先などで手軽に予定を確認することができます。




  5. Google ReaderGoogle Reader

    いつもPCで使っているRSSリーダも携帯電話から使えます。移動中などのちょっとした時間に情報のサプリメントを摂取してみてはどうでしょうか?ただし、残念ながら、私が使っているauの携帯電話では文字化けしてしまうようです…




以上、Googleのサービスを携帯電話から活用する方法を紹介させて頂きましたが、ゴールデンウィークの休暇中に限らず、このようなサービスを使って、ちょっとした隙間時間を有効活用してください。

ウノウの携帯電話で使えるメーリングリスト『sugu.CC』もよろしくお願いします。

それでは、皆さん、よい休日を!