JaikuEngineをインストールする

備忘録 jaikuengine install

基本的には上記サイトの手順通りにします。
ただ、GAEはあれから仕様がどんどん変わり、JaikuEngineオープンソースとはいえ長いことメンテナンスされていません。そのままでは動かないです。

直したところ

appengine_django/__init__.py の212行目あたりをこんな感じに。

-appconfig, unused_matcher = dev_appserver.LoadAppConfig(PARENT_DIR, {})
+appconfig, unused_matcher, from_cache = dev_appserver.LoadAppConfig(PARENT_DIR, {})

あと .google_appengine はディレクトリごと削除。

ドメインに"-"(ハイフン)とか使ってる場合はアバターアイコンがアップロードできないので、
common/validate.py の21行目をこんな感じに。

-AVATAR_PARTIAL_PATH_RE = r'(default|(?P<nick>#?\w+@[\w\.]+))/(?P<path>.*)'
+AVATAR_PARTIAL_PATH_RE = r'(default|(?P<nick>#?\w+@[\w\.-]+))/(?P<path>.*)'

現状はとりあえずこれで何とか動いています。

cloudControlで.htpasswdの設定とphpMyAdminのインストール

無料で使えるらしいPHPのPaas、cloudControlのアカウントを作ってみました。
参考:PHPのPaaSを提供する「cloudControl」と「PHP Fog」 − Publickey

Tutorialに従ってあれこれ設定すればとりあえずデプロイまではいけます。Bazaarとか初めて使うよ。
MySQLのaddonの追加の仕方まで載ってるので親切。データベース苦手なヘタレなのでとりあえずphpMyAdminを入れてみようと思いました。

まずphpMyAdminでごにょごにょしたり、phpinfoを表示するためのディレクトリを掘って、.htaccessと.htpasswdを置いてパスワード制限を掛けようと考えてやり方をググってみました。
.htaccess:

AuthUserFile /data/local//current/<作業ディレクトリ>/.htpasswd
AuthGroupFile /dev/null
AuthName "Please enter username and password"
AuthType Basic

require valid-user

このAuthUserFileのパスはgetcwdを表示するだけのPHPファイルをアップして調べました。ルートは /data/local//current/ なんですね。.htaccessと同一ディレクトリに.htpasswdを置いてパスワード制限が完成です。

作業ディレクトリにphpinfoを表示するだけのPHPファイルをアップして眺めてみます。PHPのVersionは5.3.2、mysqlが有効になっています。GDも使える。素敵!

作業ディレクトリにphpMyAdminディレクトリを掘ってconfig.inc.phpを設定します。ここで気をつける必要があって、TutorialにもあったようにMySQLの各種パラメータは以下のような感じになっています。

Addon                    : mysql.free

 Settings
   mysql_password           : w12XYabcdefg3uHG
   mysql_hostname           : 127.0.0.1
   mysql_user               : dep12ab34xyz
   mysql_database           : dep12ab34xyz
   mysql_dbsize             : 5

config.inc.phpの$cfg['Servers'][$i]['host']にはデフォルトで'localhost'って書いてますが'127.0.0.1'に直さないといけないんですね。ここで少しハマりました。

$cfg['Servers'][$i]['host'] = '127.0.0.1';

これでデプロイして、めでたくphpMyAdminにログインできました。他所のサーバでPHPで動かしていたTwitterBotとかをこっちに移植できたらな、と考えていますが、今日はここまで。

Eclipse3.6(Helios)に乗り換え

Eclipse3.5(Galileo)でPHP,JavaScript,Ruby,Python,Perlの開発環境構築っていうのを昔やったので、Eclipse3.6でも同じようにやってみたら問題なく移行できました。
今回は気分を変えて英語のままで、あとEclipse Classicをベースに後からPDTをインストールしてみました。
PDTを"Install New Software..."からインストールするときのURLは http://download.eclipse.org/tools/pdt/updates/2.2/milestones です。
RadRailsRubyとあわせてRailsごとインストールしたけど問題なく動いてますね。昔やったときは競合して動かなくなったのでRailsは外しましたが今回は問題なさそうです。これを機にRails覚えてみようかな…。いや、その前にJavaか…。

Google App Engineで画像処理するためにpypngを使ってみた

Google App Engineで画像処理をしようと思ったのですが、公式で提供されているAPIは機能が少なすぎます。
http://code.google.com/intl/ja/appengine/docs/python/images/

Pythonの画像処理で有名なライブラリにPIL(Python Imaging Library)というのがあるらしいのですがGoogle App Engineでは使えないそうです。
http://www.pythonware.com/products/pil/

そこでPure Pythonのライブラリであるpypngを使うことにしました。

GIFが対象の場合はpygifで頑張ってる方がいらっしゃったのでリンクを張っておきます。

やりたいこと

PNGの左上(x,y)=(0,0)のドットと同じ色を透過色にする

PHPでGDを使えばこれだけで済むんだけど…
https://gist.github.com/824781

今までは外部サーバにこれを設置して処理を丸投げしていたのですが、諸事情で使えなくなりそうなので、頑張ってpypngでやります。

pypng

Google Code
http://code.google.com/p/pypng/
Document
http://packages.python.org/pypng/

説明がシンプルすぎます。
詳細な使い方を知るにはソース読むしかないです…。

とりあえず読み込む

read()でもいいのですがasRGB8()っていうメソッドを見つけたのでこれを使います。
8bitPNGとして読み込んで統一しておいたほうが書き込む時にRGBAの範囲を0-255に決め打ちできて後々楽だと考えました。

GAEのことは忘れてファイルの読み書きをしますよ。

import png

pr = png.Reader(file=open('before.png', 'rb'))
x,y,pixels,meta = pr.asRGB8()

print x,y,pixels,meta
16 16  {'bitdepth': 8, 'colormap': False, 'interlace': 0, 'planes': 3, 'greyscale': False, 'alpha': False, 'size': (16, 16)}

x,y,metaの型はわかった。generator objectってなんぞ?(・ω・`)

http://www.panopticon.jp/blog/2007/02/152332.html

なるほど。for文で回せるオブジェクトを関数みたいに定義して作成したもの、という理解であってるかな?
ピクセル全部を配列に入れて保持してるとメモリが大変でしょ、っていう配慮だろうか?

"イテレータ"っていうのを知るともっと賢くなれそうなので後で調べてみる。
http://jutememo.blogspot.com/2008/06/python.html

とりあえずforで回してみた

for p in pixels:
	print p
[125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55]
[125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55]
[125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 56, 125, 82, 58, 125, 82, 58, 125, 82, 57, 125, 81, 55, 125, 81, 55]
[125, 81, 55, 125, 81, 55, 125, 81, 56, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 82, 56, 125, 80, 52, 125, 73, 41, 125, 74, 42, 125, 76, 45, 125, 82, 57, 125, 81, 55]
[125, 81, 55, 125, 82, 57, 125, 79, 51, 125, 80, 53, 125, 82, 57, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 82, 56, 125, 79, 50, 125, 86, 65, 127, 126, 142, 128, 134, 153, 126, 107, 105, 125, 77, 46, 125, 82, 56]
[125, 81, 56, 125, 76, 46, 125, 88, 69, 125, 85, 63, 125, 77, 47, 125, 82, 56, 125, 81, 55, 125, 81, 55, 125, 81, 54, 125, 82, 59, 129, 154, 195, 127, 124, 138, 126, 101, 90, 129, 155, 197, 127, 117, 124, 125, 74, 43]
[125, 76, 46, 127, 119, 128, 128, 142, 173, 129, 144, 177, 126, 106, 104, 125, 77, 46, 125, 82, 57, 125, 82, 58, 125, 74, 41, 127, 118, 125, 129, 149, 186, 124, 68, 31, 125, 71, 36, 126, 99, 90, 129, 160, 206, 125, 78, 49]
[126, 90, 73, 129, 158, 202, 125, 80, 53, 126, 98, 87, 129, 155, 197, 125, 79, 51, 125, 81, 55, 125, 83, 58, 125, 72, 38, 128, 130, 150, 128, 136, 160, 125, 74, 42, 125, 83, 59, 125, 90, 72, 129, 161, 207, 125, 84, 62]
[126, 98, 87, 129, 153, 194, 125, 69, 32, 125, 84, 62, 129, 157, 199, 125, 83, 59, 125, 80, 54, 125, 83, 58, 125, 74, 42, 127, 115, 119, 129, 152, 191, 125, 69, 32, 124, 69, 32, 126, 103, 98, 129, 158, 204, 125, 77, 47]
[125, 80, 52, 128, 146, 180, 127, 120, 132, 128, 134, 156, 128, 133, 155, 125, 75, 43, 125, 81, 55, 125, 80, 53, 125, 80, 53, 125, 80, 54, 129, 150, 187, 128, 131, 152, 127, 108, 106, 129, 158, 202, 127, 111, 113, 125, 75, 44]
[125, 79, 51, 125, 84, 62, 127, 119, 129, 127, 114, 118, 125, 76, 46, 126, 102, 97, 128, 139, 162, 128, 137, 160, 127, 127, 142, 125, 80, 53, 125, 82, 58, 127, 120, 131, 128, 128, 145, 126, 99, 91, 125, 76, 46, 125, 82, 56]
[125, 81, 56, 125, 80, 53, 125, 74, 41, 125, 75, 43, 125, 81, 54, 125, 84, 60, 125, 87, 67, 125, 87, 67, 125, 86, 64, 125, 81, 56, 125, 80, 54, 125, 74, 41, 125, 73, 40, 125, 77, 47, 125, 82, 57, 125, 81, 55]
[125, 81, 55, 125, 81, 56, 125, 82, 58, 125, 82, 57, 125, 81, 55, 125, 80, 54, 125, 79, 52, 125, 79, 52, 125, 80, 53, 125, 81, 55, 125, 81, 56, 125, 82, 58, 125, 83, 58, 125, 82, 57, 125, 81, 55, 125, 81, 55]
[125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55]
[125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55]
[125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55, 125, 81, 55]

3つずつのペアになっていて、左から順にRGB値になってるっぽいですね。
用意した画像が16x16なので16x16個、ちゃんとあります。

とりあえず書き込む

何も加工せずそのまま書き込めば画像のコピーができるはず。

pw = png.Writer(
	x,
	y,
	interlace=False,
	bitdepth=meta['bitdepth'],
	planes=meta['planes'],
	alpha=False
)
pw.write(open('after.png', 'wb'), pixels)

よしよし、before.pngがafter.pngにコピーされました。

本題

透過するには書き込み時にalpha=Trueとすれば良いわけですが、3つずつのペアになっていたピクセルのデータを4つのペアにする必要があります。
4つ目がアルファ値ですね。0が透過、255が透過無し、のようです。
左上のドットのRGB[r,g,b]を覚えておいてそれに一致するドットは[0,0,0,0]とかにしたいわけです。
それ以外は[r,g,b,255]にすれば元のままです。

import png

pr = png.Reader(file=open('before.png', 'rb'))
x,y,pixels,meta = pr.asRGB8()
new_pixels = []
i = -1
for ps in pixels:
	if i == -1:
		r = ps[0]
		g = ps[1]
		b = ps[2]
	i = 0
	new_p = []
	new_p_set = []
	for p in ps:
		new_p_set.append(p)
		i += 1
		if i >= 3:
			new_p_set.append(255)
			if new_p_set == [r, g, b, 255]:
				new_p_set = [0, 0, 0, 0]
			new_p.extend(new_p_set)
			i = 0
			new_p_set = []
	new_pixels.append(new_p)
pw = png.Writer(
	x,
	y,
	interlace=False,
	bitdepth=meta['bitdepth'],
	planes=meta['planes'],
	alpha=True
)
pw.write(open('after.png', 'wb'), new_pixels)

な、なんかPythonなのに汚いな!でも動いたからよし!
ところでwriteするときにリスト渡しちゃってるけどせっかくreadでgenerator返ってきてるのに意味なくね?
generatorにして引数に渡しましょう。勉強にもなるし。

import png

pr = png.Reader(file=open('before.png', 'rb'))
x,y,pixels,meta = pr.asRGB8()
def new_pixels(pixels):
	i = -1
	for ps in pixels:
		if i == -1:
			r = ps[0]
			g = ps[1]
			b = ps[2]
		i = 0
		new_p = []
		new_p_set = []
		for p in ps:
			new_p_set.append(p)
			i += 1
			if i >= 3:
				new_p_set.append(255)
				if new_p_set == [r, g, b, 255]:
					new_p_set = [0, 0, 0, 0]
				new_p.extend(new_p_set)
				i = 0
				new_p_set = []
		yield new_p
pw = png.Writer(
	x,
	y,
	interlace=False,
	bitdepth=meta['bitdepth'],
	planes=meta['planes'],
	alpha=True
)
pw.write(open('after.png', 'wb'), new_pixels(pixels))

できました。
ここでGAEのことを思い出します。

GAEはファイルの読み書きができないのでStringIOを使うのが定石らしいです。

from StringIO import StringIO
import png

#前略

pr = png.Reader(file=StringIO(image_binary_data))

#中略

o = StringIO()
pw.write(o, new_pixels(pixels))
new_image_binary_data = o.getvalue()

#後略

こんな感じで変換後のバイナリデータを取り出せます。

画像処理って難しいですね!

Google App Engine/PythonではてなOAuth

AppEngine-OAuth-Libraryを拡張

はてなハイクでOAuthがサポートされたので、Google App Engine/Pythonから利用しようと思ったのですが、
Twitterでも実績のあるAppEngine-OAuth-Libraryが全然動きませんでした。
厳密な仕様に準拠していないっぽいです。なので、はてなでも動くように修正してみました。
以下から入手できます。

https://github.com/nikolat/AppEngine-OAuth-Library

注意点

はてなで利用する際はアクセストークン取得時にscopeパラメータを指定しないといけません。
以下のように第四引数に指定してください。コールバックURLは必須です。

import oauth

CONSUMER_KEY = 'xxxx'
CONSUMER_SECRET = 'xxxx'
CALLBACK_URL = 'xxxx'
SCOPE = 'read_public,write_public'
client = oauth.HatenaClient(CONSUMER_KEY, CONSUMER_SECRET, CALLBACK_URL, scope=SCOPE)
redirect_url = client.get_authorization_url()

Eclipse3.5(Galileo)でPHP,JavaScript,Ruby,Python,Perlの開発環境構築

Eclipse 3.4(Ganymede)からの移行

今までLLはEclipse 3.4に各種プラグインを入れて書いていたのですが、Eclipse 3.5を試してみたくなったので、その過程を記録しておきます。
環境はWindows Vista 32bitです。
Apache 2.2, PHP 5.2.9, Ruby 1.8.7, RubyGems 1.3.4, Python 2.5.2, Perl 5.10.0 がインストール済です(Program Filesの中にインストールするのはやめた方がいいと思います)。

Eclipse 3.5のダウンロード

Enabling Open Innovation & Collaboration | The Eclipse Foundationの右上のDownload Eclipseに進みます。

Eclipse for PHP DevelopersのWindows 32bitを選択します。
(Eclipse ClassicからPDTを入れようとすると苦労するのでやめた方がいいです)

ダウンロードを開始します。

適当なディレクトリに展開してインストールが完了します。

日本語化

Ecipseを起動する前にさっさと日本語化してしまいます(必要ない場合はすっとばして構いません)。
Eclipse 日本語化 | MergeDoc Projectから日本語化のプラグインをダウンロードします。
「最新版」と書かれたリンクに進みます。

「Links to HEAD」の「download」からダウンロードを開始します。

適当なディレクトリに展開し、中にある「plugins」「features」の2つのフォルダをEcipseのディレクトリにコピーして統合します。
eclipse.iniの最後に「-javaagent:plugins/jp.sourceforge.mergedoc.pleiades/pleiades.jar」の一行を追加して完成です。
eclipse.exeをダブルクリックすると日本語化された状態で起動します。
eclipse.exe -clean.cmdというファイルもeclipseディレクトリにコピーしておいたほうが良いです。後で何度も使います。

Eclipseの設定

このへんはお好みで。「ウィンドウ」>「設定」>「一般」>「ワークスペース」で「テキスト・ファイル・エンコード」を「UTF-8」に。

あとは「一般」>「エディター」>「テキストエディター」で「行番号の表示」をONに、「一般」>「外観」>「色とフォント」>「基本」>「テキスト・フォント」で「MS ゴシック」サイズを「9」に、など。

PHPの設定

Xdebug: DownloadsからXdebug 2.0.5の5.2 VC6 (32 bit)をダウンロードしてきます(今回のPHPのバージョンが5.2なので)。そしてPHPのインストールされたディレクトリ内のextフォルダにコピーして、php.iniに以下の記述を加えます。
(PHP 5.3の場合は"zend_extension_ts"でなく"zend_extension"と書きます)

[xdebug]
zend_extension_ts="C:\****\ext\php_xdebug-2.0.5-5.2.dll"
xdebug.remote_enable=1
xdebug.remote_handler="dbgp"
xdebug.remote_mode=req
xdebug.remote_host="localhost"
xdebug.remote_port=9000
xdebug.remote_log="C:\****\logs\xdebug.log"
xdebug.manual_url = http://jp2.php.net
xdebug.collect_params = On
xdebug.dump.GET = *
xdebug.dump.POST = *

xdebug.remote_logにはApacheのlogsフォルダ内を指定しておきます。
Apacheが起動している場合は再起動してください。
Eclipseに戻って、「ウィンドウ」>「設定」>「PHP」>「PHP実行ファイル」で以下のような感じで追加します。

PHP」>「デバッグ」でPHPデバッガーにXDebugを指定しておきます。

これでPHPの設定は完成です。適当なプロジェクトを作成して実行してみます。

ブレークポイントを置いてデバッグの動作確認もしておきます。

無事に動きました。

Aptanaの設定

JavaScriptやHTML、CSSコーディングのためにAptana Studioのプラグインをインストールします。
「ヘルプ」>「新規ソフトウェアのインストール」で http://download.aptana.org/tools/studio/plugin/install/studio を追加します。

ナビゲーションに従ってインストールが完了したら、一度Eclipseを終了し、-cleanオプション付きで起動し直します(eclipse.exe -clean.cmdをコピーしていた場合はそれをダブルクリックするだけで良いです)。
起動したら「ウィンドウ」>「設定」>「Aptana」>「Startup Page」で始動後に表示しないにチェック。

パースペクティブを切り替えてプロジェクトを作ってみます。

JavaScriptライブラリーのインポートについて訪ねられますので必要ならインストールしておきます。

今回はとりあえずjQuery 1.3.2だけにしておきます。


インストールが終わったらEclipseを終了し、-cleanオプション付きで起動します。
再びプロジェクトの作成からやり直します。今度はjQueryが選択出来るようになっています。

jQueryのサンプルを含んだプロジェクトができました。

今後.jsファイルはAptana JS エディターで編集したいので、「ウィンドウ」>「設定」>「一般」>「エディター」>「ファイルの関連付け」で.jsファイルをAptana JS エディターに関連付けておきます。

Rubyの設定

「ヘルプ」>「新規ソフトウェアのインストール」で http://download.aptana.com/tools/radrails/plugin/install/radrails-bundle を追加します。
「項目をカテゴリー別にグループ化」のチェックを外し、「Ruby 開発ツール」のみを選択します。

インストールが完了したらEclipseを終了して-cleanオプション付きで起動します。
少し経つとgemの自動インストール画面が開きます。必要なモジュールをgemで勝手にインストールしてくれます(初めて利用する場合はもっとたくさんのモジュールが表示されるはずです)。

必要なgemのインストールが終わったら「ウィンドウ」>「設定」>「Ruby」以下、必要なパスを入力していきます。



設定が完了したら、適当なプロジェクトを作成して実行してみます。

デバッグの動作確認もしてみます。

ruby-debug-ideが古いっぽいです。さっき自動でインストールされた方は問題ないですが私の場合は自分でアップデートする必要がありそうです。
しかし >gem install ruby-debug-ide とか打ってもエラーが出てインストールに失敗してしまいます。色々ググったところ、ruby\lib\ruby\1.8\i386-mswin32\config.hの一行目を以下のように書き換えて、ruby-debug-baseからインストールすると良いとのこと。

修正前
#if _MSC_VER != 1200
#error MSC version unmatch: _MSC_VER: 1200 is expected.
修正後
#if _MSC_VER < 1200
#error MSC version unmatch: _MSC_VER: 1200 is expected.


上手くいきました。これでRubyでもデバッグが可能になります。

Pythonの設定

「ヘルプ」>「新規ソフトウェアのインストール」で http://pydev.org/updates を追加します。

PyDevの方にチェックを入れてインストールします。

インストールが完了したらEclipseを終了して-cleanオプション付きで起動します。
起動したら「ウィンドウ」>「設定」>「Pydev」>「インタープリター - Python」で新規にPythonのパスを指定。

パースペクティブを切り替えて、適当なプロジェクトを作成して実行してみます。

デバッグの動作確認もしてみます。

コンソールに何かwarningが出てますがまあいいでしょう。

Perlの設定

「ヘルプ」>「新規ソフトウェアのインストール」で http://e-p-i-c.sourceforge.net/updates/ を追加します。

EPICにチェックを入れてインストールします。

インストールが完了したらEclipseを終了して-cleanオプション付きで起動します。
起動したら「ウィンドウ」>「設定」>「Perl EPIC」でPerl 実行ファイルのパスを指定。

パースペクティブを切り替えて、適当なプロジェクトを作成して実行してみます。

デバッグの動作確認もしてみます。

無事に動きました。