about: S2PHP5
about: Io Language
2009/01/30
僕の本がでました(少しフライング)
僕の書いた本が発売になりました!例によって(?)PHPの入門書です。
これは、北海道にいたころにお世話になったPostgreSQL関係の方の紹介で、一冊の本を書くことができました。多謝
- PHP1 はじめてのPHPプログラミング (CD-ROM付)
-
- 発売元: 翔泳社
- 価格: ¥ 1,974
- 発売日: 2009/01/30
この本は僕の知っている知識で、精一杯、初心者(プログラミングを学ぼうとする人)に向けて分かりやすく書いたつもりですので、ぜひ手にとって読んでください。
また、この続きも近刊となっていますので、もうしばらくお待ちください。
ちなみに、読みづらいかもしれませんが。僕の名字のハタは、漢字の漢で「ハタ」と読みます。豆知識ですね。
この他にもプログラミング学習シリーズで、rubyとjavascriptが同時発売ですので、こちらも合わせて読みたい
- Ruby1 はじめてのプログラミング (CD-ROM付)
-
- 発売元: 翔泳社
- 価格: ¥ 1,974
- 発売日: 2009/01/30
- JavaScript1 はじめてのプログラミングとJavaScriptの基礎 (CD-ROM付)
-
- 発売元: 翔泳社
- 価格: ¥ 1,974
- 発売日: 2009/01/30
2009/01/04
Mecabをscalaで
ということで、cmecabはインストール出来なかったので、mecab-javaバインディングを使う。
下記のページに書かれている通りにやるとうまく良くと思う
んで、Mecabをjavaから呼ぶのはできたので、せっかくなのでscalaから呼べるようにする
こんなコードを用意
import org.chasen.mecab.{MeCab, Tagger, Node} object Test { def main(args: Array[String]){ System.loadLibrary("MeCab"); var tagger = new Tagger; println (tagger.parse ("すもももももももものうち")); var node:Node = tagger.parseToNode("隣の客はよく柿食う客だ"); while(node != null){ println(node.getSurface() + "\t" + node.getFeature()); node = node.getNext(); } } }
んで、scalac -cp で Mecab.jar と -Dava.library.path に libMeCab.dylib を通してあげればコンパイルできる。
でも、毎回コンパイルするたびにこのオプションを指定するのは面倒なので、antに設定しておく
<?xml version="1.0" encoding="utf-8" ?> <project name="mecab.scala" default="run.demo" basedir="."> <property name="lib" location="lib"/> <property name="jni" location="jni"/> <property environment="env" /> <property name="scala.home" value="${basedir}" /> <path id="scala.classpath"> <pathelement path="${basedir}"/> <fileset dir="${lib}"> <include name="*.jar" /> </fileset> <pathelement path="${java.class.path}"/> </path> <taskdef name="scalac" classname="scala.tools.ant.Scalac"> <classpath> <path refid="scala.classpath" /> </classpath> </taskdef> <taskdef name="scaladoc" classname="scala.tools.ant.Scaladoc"> <classpath> <path refid="scala.classpath" /> </classpath> </taskdef> <macrodef name="scala"> <attribute name="args"/> <sequential> <java classname="scala.tools.nsc.MainGenericRunner" fork="true" dir="."> <classpath> <path refid="scala.classpath" /> </classpath> <jvmarg value="-Xbootclasspath/a:${scala.home}/scala-library.jar}" /> <jvmarg value="-Xmx512M" /> <jvmarg value="-Xms64M" /> <jvmarg value="-Dscala.home=${scala.home}" /> <jvmarg value="-Djava.library.path=${jni}/osx_x64" /> <arg line="-Djava.library.path=${jni}/osx_x64/libMeCab.dylib @{args}" /> </java> </sequential> </macrodef> <target name="doc"> <mkdir dir="${doc.dir}"/> <scaladoc srcdir="${src.dir}" destdir="${doc.dir}" deprecation="yes" unchecked="yes" windowtitle="${doc.windowtitle}" doctitle="${doc.title}" classpathref="scala.classpath"> <include name="**/*.scala"/> </scaladoc> </target> <target name="run.demo"> <scalac srcdir="${basedir}" destdir="${basedir}" classpathref="scala.classpath" target="jvm-1.5" force="changed" /> <scala args="Test" /> </target> </project>
このbuild.xmlはscala-squib - Google Codeをパクってきた。
ここはいろいろと参考になるので好き
また、ディレクトリ構成としてはこんな感じ
|- Hoge.scala |- Test$.class |- Test.class |- Test.scala |- build.xml |- build.xml.mf |- lib |- libMeCab.dylib |- MeCab.jar |- scala-compiler.jar |- scala-dbc.jar |- scala-decoder.jar |- scala-library.jar
ちなみに、コンパイルされた scala コードは java から呼び出せるので、
java -cp .:lib/scala-decoder.jar scala.tools.nsc.MainGenericRunner Hoge
とかにしておけば、javaから呼び出せれる(もしかしたらscala-library.jarもいるかも)けど、問題はclasspathに指定したファイルのパスもちゃんと含めてあげないといけない(今回は ./ 大抵の場合は ./src )(当たり前と言えば当たり前だけど、ハマった。。。)
さてさて、肝心の実行結果はというと、こんな感じ
Buildfile: build.xml
run.demo:
[java] すもも 名詞,一般,*,*,*,*,すもも,スモモ,スモモ
[java] も 助詞,係助詞,*,*,*,*,も,モ,モ
[java] もも 名詞,一般,*,*,*,*,もも,モモ,モモ
[java] も 助詞,係助詞,*,*,*,*,も,モ,モ
[java] もも 名詞,一般,*,*,*,*,もも,モモ,モモ
[java] の 助詞,連体化,*,*,*,*,の,ノ,ノ
[java] うち 名詞,非自立,副詞可能,*,*,*,うち,ウチ,ウチ
[java] EOS
[java]
[java] BOS/EOS,*,*,*,*,*,*,*,*
[java] 隣 名詞,一般,*,*,*,*,隣,トナリ,トナリ
[java] の 助詞,連体化,*,*,*,*,の,ノ,ノ
[java] 客 名詞,一般,*,*,*,*,客,キャク,キャク
[java] は 助詞,係助詞,*,*,*,*,は,ハ,ワ
[java] よく 副詞,一般,*,*,*,*,よく,ヨク,ヨク
[java] 柿 名詞,一般,*,*,*,*,柿,カキ,カキ
[java] 食う 動詞,自立,*,*,五段・ワ行促音便,基本形,食う,クウ,クウ
[java] 客 名詞,一般,*,*,*,*,客,キャク,キャク
[java] だ 助動詞,*,*,*,特殊・ダ,基本形,だ,ダ,ダ
[java] BOS/EOS,*,*,*,*,*,*,*,*
BUILD SUCCESSFUL
Total time: 0 seconds
後は、scala のコードがもう少し綺麗にできれば、良さそう
cmecab-java を OSX で...
cmecab-java - Google CodeをOSXで使ってみるテスト
cmecab-java-1.0.tar.gzを展開して、jniディレクトリに含まれるMakeFile.unixを次のようにする
nowel@macbook: ~/tmp/cmecab-java> cat jni/Makefile.osx CMECAB_INCLUDE=-I/System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers/ CMECAB_SRC=mecab.cpp CMECAB_TARGET=libCMeCab.jnilib CXX=g++ CXXFLAGS=-Wall -g -O2 -fPIC $(CMECAB_INCLUDE) LDFLAGS=-dynamiclib -lmecab all: $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $(CMECAB_TARGET) $(CMECAB_SRC) install: cp $(CMECAB_TARGET) /usr/local/lib javah: javah -classpath ../bin/classes \ net.moraleboost.mecab.Tagger \ net.moraleboost.mecab.Node clean: rm -f $(CMECAB_TARGET)
もし、以下のようにでてしまっている場合は、コンパイルオプションが-sharedとなっている場合があるので、-dynamiclibとする
g++ -Wall -g -O2 -fPIC -I/System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers/ -shared -lmecab -o libCMeCab.jnilib mecab.cpp Undefined symbols: "_main", referenced from: start in crt1.10.5.o ld: symbol(s) not found collect2: ld returned 1 exit status make: *** [all] Error 1
んで、make -f Makefile.osx
nowel@macbook: ~/tmp/cmecab-java/jni> make -f Makefile.osx g++ -Wall -g -O2 -fPIC -I/System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers/ -dynamiclib -lmecab -o libCMeCab.jnilib mecab.cpp
ビルドするが、うまくコンパイルできない...
nowel@macbook: ~/tmp/cmecab-java> java -version java version "1.5.0_16" Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_16-b06-284) Java HotSpot(TM) Client VM (build 1.5.0_16-133, mixed mode, sharing) nowel@macbook: ~/tmp/cmecab-java> ant Buildfile: build.xml init: [mkdir] Created dir: /Users/nowel/tmp/cmecab-java/bin/classes compile: [javac] Compiling 15 source files to /Users/nowel/tmp/cmecab-java/bin/classes [javac] /Users/nowel/tmp/cmecab-java/src/net/moraleboost/mecab/MeCabException.java:35: シンボルを見つけられません。 [javac] シンボル: コンストラクタ IOException(java.lang.Throwable) [javac] 場所 : java.io.IOException の クラス [javac] super(e); [javac] ^ [javac] /Users/nowel/tmp/cmecab-java/src/net/moraleboost/mecab/MeCabException.java:40: シンボルを見つけられません。 [javac] シンボル: コンストラクタ IOException(java.lang.String,java.lang.Throwable) [javac] 場所 : java.io.IOException の クラス [javac] super(msg, e); [javac] ^ [javac] /Users/nowel/tmp/cmecab-java/src/net/moraleboost/solr/FeatureRegexFilterFactory.java:64: シンボルを見つけられません。 [javac] シンボル: メソッド isEmpty() [javac] 場所 : java.lang.String の クラス [javac] if (!regex.isEmpty()) { [javac] ^ [javac] 注:/Users/nowel/tmp/cmecab-java/src/net/moraleboost/solr/FeatureRegexFilterFactoryTest.java は推奨されない API を使用またはオーバーライドしています。 [javac] 注:詳細については、-Xlint:deprecation オプションを指定して再コンパイルしてください。 [javac] エラー 3 個 BUILD FAILED /Users/nowel/tmp/cmecab-java/build.xml:43: Compile failed; see the compiler error output for details. Total time: 4 seconds
見てみると、IOException関係のは、J2SE1.6系統からっぽい。
ref - http://java.sun.com/javase/6/docs/api/java/io/IOException.html
OSXのjavaを1.6にする。
Java Preferences.app が /Applications/Utilities/Java/Java Preferences.app にあるので、実行
概要から、JavaSE6を一番上にする
が、まだ、ビルドはできないので、JAVA_HOMEを1.6にする
export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home/
これで、ビルドはできるようになった
nowel@macbook: ~/tmp/cmecab-java> ant
Buildfile: build.xml
init:
compile:
[javac] Compiling 8 source files to /Users/nowel/tmp/cmecab-java/bin/classes
[javac] ??:/Users/nowel/tmp/cmecab-java/src/net/moraleboost/solr/FeatureRegexFilterFactoryTest.java ??????????? API ???g?p?????I?[?o?[???C?h???Ă?????B
[javac] ??:????????A-Xlint:deprecation ?I?v?V???????w???čăR???p?C?????Ă????????B
dist:
[jar] Building jar: /Users/nowel/tmp/cmecab-java/bin/cmecab-1.0.jar
BUILD SUCCESSFUL
Total time: 1 second
文字化けしてる...
とりあえず、jniをパスにコピーしておく
nowel@macbook: ~/tmp/cmecab-java> sudo cp jni/libCMeCab.jnilib /System/Library/Frameworks/JavaVM.framework/Versions/1.6/Libraries/
実行してみると
nowel@macbook: ~/tmp/cmecab-java> java -cp bin/cmecab-1.0.jar net.moraleboost.mecab.Tagger UTF-8 すもももももももものうち Exception in thread "main" java.lang.UnsatisfiedLinkError: /System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Libraries/libCMeCab.jnilib: at java.lang.ClassLoader$NativeLibrary.load(Native Method) at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1822) at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1723) at java.lang.Runtime.loadLibrary0(Runtime.java:823) at java.lang.System.loadLibrary(System.java:1030) at net.moraleboost.mecab.Tagger.<clinit>(Unknown Source)
うーん。もう一度jniをコンパイルしてみても。だめ
結局Makefileはこんな感じに。
CMECAB_INCLUDE=-I/System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers \ -I/opt/local/include CMECAB_SRC=mecab.cpp CMECAB_TARGET=libCMeCab.jnilib CMECAB_LIBS=-L/opt/local/lib -lmecab -lstdc++ CXX=g++ CXXFLAGS=-Wall -c -O3 -fPIC -dynamic $(CMECAB_INCLUDE) LDFLAGS=-lmecab -framework JavaVM all: $(CXX) $(CXXFLAGS) $(CMECAB_SRC) $(CXX) -dynamiclib mecab.o -o $(CMECAB_TARGET) $(CMECAB_LIBS) install: cp $(CMECAB_TARGET) /usr/local/lib javah: javah -classpath ../bin/classes \ net.moraleboost.mecab.Tagger \ net.moraleboost.mecab.Node clean: rm -f $(CMECAB_TARGET)
このMakefileだと、dSYMみたいなファイルができずに、jnilib作れるけど、結局読み込まれないみたいなのでダメっぽい。もう少し調べてみる。
2008/12/14
PHP で float と int に触れる
PHPでは数値をどうやって持っているのか。気になったので試してみる
「-1」はどうやっているのか。ということで、decbinで2進数表記にしてみた
$a = decbin(-1); var_dump($a); ==> string(32) "11111111111111111111111111111111"
32ビットで扱っているみたいだ。
逆にこの値を数値に戻してみる。
$b = bindec('11111111111111111111111111111111'); var_dump($b); ==> float(4294967295)
なるほど、int の最大値(?) を越えて float になった上で、それを整数値で持つのね。
ということは、これを int にすると、「-1」の値になる。と
$c = (float) 4294967295; var_dump((int) $c); ==> int(-1)
ふむふむ。じゃあ、intな「-1」をfloatにすると「4294967295」になる...
$d = -1; $e = (float) $d; var_dump($e); ==> float(-1)
だよね。PHPだとこうなるよね。つまり、「-1」なfloatの「4294967295」はintで作ったものからは作り出せそうに無い。と。
このあたりはソースを追ってみる必要がありそう。
んじゃ、調子に乗って浮動小数は...
var_dump(decbin(0.1)); ==> string(1) "0"
ここはまたの機会に調べる。浮動小数と負の浮動小数とか。
ちなみに、すごく手抜きだけど、ビットでの試行錯誤はbindecを使って試した。こんな感じ
$a = bindec(join(explode(' ', '1111 1111 1111 1111 1111 1111 1111 1110'))); var_dump($a); var_dump((int) $a);
ビット周辺は面白い。
PHP でバイナリから文字列を作る
よく「PHPはバイナリで文字列を持っている」とか言われているので、やってみた。
参考にしたのは、文字コードについて より、 Unicode対応 文字コード表
試しに、上記の表から「あ」の文字列をUTF-8なバイナリから作成してみる
// utf8 E38182 echo pack('C*', 0xE3, 0x81, 0x82), PHP_EOL; ==> あ
これは、コンソールで使っている端末もUTF-8なので、そのまま出力できた。EUCな端末なら、こんな感じ
// utf8 E38182 echo mb_convert_encoding(pack('C*', 0xE3, 0x81, 0x82), 'EUC-JP', 'UTF-8'), PHP_EOL; ==> あ
ということで、他の文字エンコードでのバイナリをいくつか作ってみた。(やっていることは、文字列バイナリをmb_convert_encodingで端末の文字エンコードであるUTF-8に変換して表示しているだけ)
// sjis 82A0 echo mb_convert_encoding(pack('C*', 0x82, 0xA0), 'UTF-8', 'Shift_JIS'), PHP_EOL; ==> あ // utf8 E38182 echo mb_convert_encoding(pack('C*', 0xE3, 0x81, 0x82), 'UTF-8'), PHP_EOL; ==> あ // eucjp A4A2 echo mb_convert_encoding(pack('C*', 0xA4, 0xA2), 'UTF-8', 'EUC-JP'), PHP_EOL; ==> あ // utf16 3042 echo mb_convert_encoding(pack('C*', 0x30, 0x42), 'UTF-8', 'UTF-16'), PHP_EOL; ==> あ
ということで、packを使えばバイナリから文字列を作れそう。ということはやっぱりバイナリで文字列を持っているというわけで。さらには、そのバイナリはmb_convert_encodingで他の値にもシフトできそう。と。
勉強になります。
2008/12/08
フラワーロック 2.0 と CruiseControl を連携させてみた の作成編を更新
と言うわけで(?)、書きかけだったあいつを更新
ref - フラワーロック 2.0 と CruiseControl を連携させてみた
俺、これでフラワーロックの売上が上がったら、もっと別の、プロジェクト以外のフラワーロックの利用方法考えるんだ...
(流石にフラワーロックが踊る「ビルド失敗の舞」は使い道が違うような気がする...)
2008/12/07
Q4MをPHP(PDO)で
Q4Mが無事インストールできたので、PHPから触ってみる。詳細なことは今度書く。とりあえず触りだけでも
テーブル定義
drop table if exists hoge_queue; create table hoge_queue( id int not null, name varchar(25) not null ) engine=queue;
こんなスクリプトをガンガン回して、監視
$conn = new PDO('mysql:host=localhost; dbname=hogetest', 'user', 'password'); $wait = $conn->prepare('SELECT queue_wait("hoge_queue", 10)'); $abort = $conn->prepare('SELECT queue_abort()'); $e = $conn->prepare('SELECT queue_end()'); $select = $conn->prepare('SELECT * FROM hoge_queue'); while(true){ $start = time(); // for epch tstmp // wait call query $wait->execute(); $end = time(); echo 'wait for: ', $end - $start, ' sec.', PHP_EOL; echo 'is_queue: ', $wait->fetch(PDO::FETCH_COLUMN), PHP_EOL; $select->execute(); while($row = $select->fetch(PDO::FETCH_OBJ)){ var_dump($row); // // delete しなくとも queue_end で消える // $e->execute(); continue 2; } // abort call $abort->execute(); echo 'next...', PHP_EOL, PHP_EOL; }
別の端末からmysqlの動いてるサーバに対して、insert
insert into hoge_queue values(1, 'hello world');
こんな感じになるよ
int(10) array(1) { ["queue_wait("hoge_queue", 10)"]=> string(1) "0" } next... int(10) array(1) { ["queue_wait("hoge_queue", 10)"]=> string(1) "0" } next... int(10) array(1) { ["queue_wait("hoge_queue", 10)"]=> string(1) "0" } next... int(2) array(1) { ["queue_wait("hoge_queue", 10)"]=> string(1) "1" } object(stdClass)#6 (2) { ["id"]=> string(2) "1" ["name"]=> string(11) "hello world" } next... int(10) array(1) { ["queue_wait("hoge_queue", 10)"]=> string(1) "0" } next... int(10) array(1) { ["queue_wait("hoge_queue", 10)"]=> string(1) "0" } next...
Q4Mの動きで、特徴的なの
- queue_wait で取れたレコードは、queue_end で消える。
- queue_wait で止まる時間を指定しても、queueが入ってきたときは、即レコードが取れる
- queue_wait を連発すると一行前のレコードが消える(?要確認だけど)
- queue_wait で取れたレコードは他のクライアントから queue_wait しても取れない
- queue_wait で取得したレコードは、他のクライアントからだとテーブル上に見えなくなってる
- queue_wait で、レコードが見つからない場合は、0 で、見つかったら 1 が帰ってくる
- queue_wait で取ったレコードは「ちゃんと処理をする」queue_abort すると消えるよ
Q4Mの動きですこしハマるやつ。その1
全レコード分 wait
mysql> select * from hoge_queue; +----+------+ | id | name | +----+------+ | 4 | foo4 | | 5 | foo5 | | 6 | foo6 | | 7 | foo7 | | 8 | foo8 | | 9 | foo9 | +----+------+ 6 rows in set (0.00 sec) mysql> select queue_wait('hoge_queue', 1); +-----------------------------+ | queue_wait('hoge_queue', 1) | +-----------------------------+ | 1 | +-----------------------------+ 1 row in set (0.00 sec) mysql> select queue_wait('hoge_queue', 1); +-----------------------------+ | queue_wait('hoge_queue', 1) | +-----------------------------+ | 1 | +-----------------------------+ 1 row in set (0.06 sec) mysql> select queue_wait('hoge_queue', 1); +-----------------------------+ | queue_wait('hoge_queue', 1) | +-----------------------------+ | 1 | +-----------------------------+ 1 row in set (0.06 sec) mysql> select queue_wait('hoge_queue', 1); +-----------------------------+ | queue_wait('hoge_queue', 1) | +-----------------------------+ | 1 | +-----------------------------+ 1 row in set (0.05 sec) mysql> select queue_wait('hoge_queue', 1); +-----------------------------+ | queue_wait('hoge_queue', 1) | +-----------------------------+ | 1 | +-----------------------------+ 1 row in set (0.05 sec) mysql> select queue_wait('hoge_queue', 1); +-----------------------------+ | queue_wait('hoge_queue', 1) | +-----------------------------+ | 1 | +-----------------------------+ 1 row in set (0.05 sec) mysql> select queue_wait('hoge_queue', 1); +-----------------------------+ | queue_wait('hoge_queue', 1) | +-----------------------------+ | 0 | +-----------------------------+ 1 row in set (1.05 sec)
最後は、waitで 1sec 止まって、結果は0に
selectすると
mysql> select * from hoge_queue; Empty set (0.00 sec)
abort すると...?
mysql> select queue_abort();
+---------------+
| queue_abort() |
+---------------+
| 1 |
+---------------+
1 row in set (0.00 sec)
その後、select すると...
mysql> select * from hoge_queue; Empty set (0.00 sec)
全部消えてる...
wait して取り出せたレコードは、レスキューできないのか。残念。
Q4Mの動きですこしハマるやつ。その他
Q4Mは面白いので、別の機会にまとめて書く
Q4Mのビルド(CentOS 5.2 と OSX)
Q4Mのアイディアがとても面白そうなので、使ってみることにしました。
が、ビルドに色々つまづいたので、メモ。かれこれ2週間くらい前のログなので、微妙にバージョンが違ってたら申し訳ないです。
CentOS 5.2 に入れる
CentOS を使っているので、これに入れるログ
既にインストール済みのMySQLをアンインストール
とりあえず、キレイにしておきました。
hata@local ~/local/rpms/mysql5> sudo yum remove mysql Resolving Dependencies --> Running transaction check ---> Package mysql.x86_64 0:5.0.45-7.el5 set to be erased --> Processing Dependency: libmysqlclient.so.15()(64bit) for package: mysql-devel --> Processing Dependency: libmysqlclient.so.15()(64bit) for package: libdbi-dbd-mysql --> Processing Dependency: libmysqlclient.so.15()(64bit) for package: mysql-server --> Processing Dependency: libmysqlclient.so.15()(64bit) for package: perl-DBD-MySQL --> Processing Dependency: libmysqlclient.so.15(libmysqlclient_15)(64bit) for package: libdbi-dbd-mysql --> Processing Dependency: libmysqlclient.so.15(libmysqlclient_15)(64bit) for package: mysql-server --> Processing Dependency: libmysqlclient.so.15(libmysqlclient_15)(64bit) for package: perl-DBD-MySQL --> Processing Dependency: libmysqlclient_r.so.15()(64bit) for package: mysql-devel --> Processing Dependency: libmysqlclient_r.so.15()(64bit) for package: mysql-server --> Processing Dependency: libmysqlclient_r.so.15(libmysqlclient_15)(64bit) for package: mysql-server --> Processing Dependency: mysql = 5.0.45-7.el5 for package: mysql-devel --> Processing Dependency: mysql = 5.0.45-7.el5 for package: mysql-server --> Processing Dependency: mysql for package: libdbi-dbd-mysql --> Running transaction check ---> Package mysql-devel.x86_64 0:5.0.45-7.el5 set to be erased ---> Package mysql-server.x86_64 0:5.0.45-7.el5 set to be erased ---> Package libdbi-dbd-mysql.x86_64 0:0.8.1a-1.2.2 set to be erased ---> Package perl-DBD-MySQL.x86_64 0:3.0007-1.fc6 set to be erased --> Finished Dependency Resolution Dependencies Resolved ============================================================================= Package Arch Version Repository Size ============================================================================= Removing: mysql x86_64 5.0.45-7.el5 installed 7.5 M Removing for dependencies: libdbi-dbd-mysql x86_64 0.8.1a-1.2.2 installed 54 k mysql-devel x86_64 5.0.45-7.el5 installed 6.3 M mysql-server x86_64 5.0.45-7.el5 installed 22 M perl-DBD-MySQL x86_64 3.0007-1.fc6 installed 328 k Transaction Summary ============================================================================= Install 0 Package(s) Update 0 Package(s) Remove 5 Package(s) Is this ok [y/N]: y Downloading Packages: Running rpm_check_debug Running Transaction Test Finished Transaction Test Transaction Test Succeeded Running Transaction Erasing : mysql-devel ######################### [1/5] Erasing : mysql ######################### [2/5] Erasing : mysql-server ######################### [3/5] warning: /var/log/mysqld.log saved as /var/log/mysqld.log.rpmsave Erasing : libdbi-dbd-mysql ######################### [4/5] Erasing : perl-DBD-MySQL ######################### [5/5] Removed: mysql.x86_64 0:5.0.45-7.el5 Dependency Removed: libdbi-dbd-mysql.x86_64 0:0.8.1a-1.2.2 mysql-devel.x86_64 0:5.0.45-7.el5 mysql-server.x86_64 0:5.0.45-7.el5 perl-DBD-MySQL.x86_64 0:3.0007-1.fc6 Complete!
MySQL ABのバイナリをインストールする
MySQL ABはここから落としてきて、とりあえず rpm を使いました。
hata@local: ~/local/rpms/mysql5> sudo rpm -ivh MySQL-*.rpm 準備中... ########################################### [100%] 1:MySQL-shared-compat ########################################### [ 20%] 2:MySQL-client-community ########################################### [ 40%] 3:MySQL-devel-community ########################################### [ 60%] 4:MySQL-server-community ########################################### [ 80%] ERROR: 1136 Column count doesn't match value count at row 1 081121 10:59:56 [ERROR] Aborting 081121 10:59:56 [Note] /usr/sbin/mysqld: Shutdown complete Installation of system tables failed! Examine the logs in /var/lib/mysql for more information. You can try to start the mysqld daemon with: shell> /usr/sbin/mysqld --skip-grant & and use the command line tool /usr/bin/mysql to connect to the mysql database and look at the grant tables: shell> /usr/bin/mysql -u root mysql mysql> show tables Try 'mysqld --help' if you have problems with paths. Using --log gives you a log in /var/lib/mysql that may be helpful. The latest information about MySQL is available on the web at http://www.mysql.com/. Please consult the MySQL manual section 'Problems running mysql_install_db', and the manual section that describes problems on your OS. Another information source are the MySQL email archives available at http://lists.mysql.com/. Please check all of the above before mailing us! And remember, if you do mail us, you MUST use the /usr/bin/mysqlbug script! Starting MySQL.[ OK ] Giving mysqld 2 seconds to start 5:MySQL-shared-community ########################################### [100%]
Q4M-0.8.3を落としてきて make
q4m.31tools.comから無印の q4m-{version}.tar.gz だと、なぜかエラーが沢山(下記)でたので、mysql-{version}-*q4m-{version}.tar.gz を使った。
gcc/x86_64-redhat-linux/4.1.2/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -lstdc++ -lm -lgcc_s -lc -lgcc_s /usr/lib/gcc/x86_64-redhat-linux/4.1.2/crtendS.o /usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/crtn.o -Wl,--hash-style=both -o .libs/libqueue_engine.so.0.0.0
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/crti.o: In function `_init':
(.init+0x0): multiple definition of `_init'
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/crti.o:(.init+0x0): first defined here
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/crti.o: In function `_fini':
(.fini+0x0): multiple definition of `_fini'
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/crti.o:(.fini+0x0): first defined here
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/crtbeginS.o:(.data.rel.ro+0x0): multiple definition of `__dso_handle'
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/crtbeginS.o:(.data.rel.ro+0x0): first defined here
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/crtendS.o:(.dtors+0x0): multiple definition of `__DTOR_END__'
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/crtendS.o:(.dtors+0x0): first defined here
collect2: ld returned 1 exit status
make[2]: *** [libqueue_engine.la] Error 1
make[2]: Leaving directory `/home/vmdev/local/src/q4m-0.8.3/src'
make[1]: *** [all] Error 2
make[1]: Leaving directory `/home/vmdev/local/src/q4m-0.8.3/src'
make: *** [all-recursive] Error 1
かなりハマった...。
んで、他の人も書いてるけど、configure オプションを注意しつつ、make
僕は、CXXFLAGS に /usr/include/mysql として、AB の rpm が入れたヘッダを指定するようにしました。
--with-mysql=/home/hata/local/src/mysql-5.1.29-rc CXXFLAGS="-I/usr/include/mysql
hata@local: ~/local/src> wget http://q4m.31tools.com/dist/mysql-5.1.28-rc-linux-x86_64-glibc23-with-fast-mutexes-q4m-0.8.3.tar.gz hata@local: ~/local/src> tar xzvf mysql-5.1.28-rc-linux-x86_64-glibc23-with-fast-mutexes-q4m-0.8.3.tar.gz q4m-0.8.3-linux-x86_64/ q4m-0.8.3-linux-x86_64/ChangeLog q4m-0.8.3-linux-x86_64/config/ q4m-0.8.3-linux-x86_64/config/config.sub q4m-0.8.3-linux-x86_64/config/depcomp q4m-0.8.3-linux-x86_64/config/missing q4m-0.8.3-linux-x86_64/config/compile q4m-0.8.3-linux-x86_64/config/install-sh q4m-0.8.3-linux-x86_64/config/config.guess q4m-0.8.3-linux-x86_64/config/ac_mysql.m4 q4m-0.8.3-linux-x86_64/config/ltmain.sh q4m-0.8.3-linux-x86_64/examples/ q4m-0.8.3-linux-x86_64/examples/crawler/ q4m-0.8.3-linux-x86_64/examples/crawler/crawler.pl q4m-0.8.3-linux-x86_64/examples/crawler/initdb.sql q4m-0.8.3-linux-x86_64/examples/crawler/README q4m-0.8.3-linux-x86_64/Makefile.in q4m-0.8.3-linux-x86_64/Makefile.am q4m-0.8.3-linux-x86_64/t/ q4m-0.8.3-linux-x86_64/t/02-queue.t q4m-0.8.3-linux-x86_64/t/05-multireader-read.c q4m-0.8.3-linux-x86_64/t/05-multiwait-core.c q4m-0.8.3-linux-x86_64/t/Makefile.in q4m-0.8.3-linux-x86_64/t/04-blob-cond.t q4m-0.8.3-linux-x86_64/t/Makefile.am q4m-0.8.3-linux-x86_64/t/08-forward.t q4m-0.8.3-linux-x86_64/t/02-queue-cond.t q4m-0.8.3-linux-x86_64/t/05-multireader.t q4m-0.8.3-linux-x86_64/t/09-pqueue-single-table.t q4m-0.8.3-linux-x86_64/t/07-trans.t q4m-0.8.3-linux-x86_64/t/02-queue-owned-delete.t q4m-0.8.3-linux-x86_64/t/05-multiwait.t q4m-0.8.3-linux-x86_64/t/06-multi.t q4m-0.8.3-linux-x86_64/t/03-queue-error-wait.t q4m-0.8.3-linux-x86_64/t/04-blob.t q4m-0.8.3-linux-x86_64/t/01-base-rnd_pos.t q4m-0.8.3-linux-x86_64/t/09-pqueue-single-table-wake-listener.t q4m-0.8.3-linux-x86_64/t/05-multirw-core.c q4m-0.8.3-linux-x86_64/t/05-multirw.t q4m-0.8.3-linux-x86_64/t/01-base.t q4m-0.8.3-linux-x86_64/t/03-queue-error.t q4m-0.8.3-linux-x86_64/run_tests.pl q4m-0.8.3-linux-x86_64/libqueue_engine.so q4m-0.8.3-linux-x86_64/configure.in q4m-0.8.3-linux-x86_64/aclocal.m4 q4m-0.8.3-linux-x86_64/configure q4m-0.8.3-linux-x86_64/INSTALL q4m-0.8.3-linux-x86_64/COPYING q4m-0.8.3-linux-x86_64/src/ q4m-0.8.3-linux-x86_64/src/dllist.h q4m-0.8.3-linux-x86_64/src/Makefile.in q4m-0.8.3-linux-x86_64/src/Makefile.am q4m-0.8.3-linux-x86_64/src/queue_cond.h q4m-0.8.3-linux-x86_64/src/queue_config.h.in q4m-0.8.3-linux-x86_64/src/ha_queue.h q4m-0.8.3-linux-x86_64/src/queue_cond.cc q4m-0.8.3-linux-x86_64/src/adler32.c q4m-0.8.3-linux-x86_64/src/ha_queue.cc q4m-0.8.3-linux-x86_64/TODO q4m-0.8.3-linux-x86_64/AUTHORS q4m-0.8.3-linux-x86_64/doc/ q4m-0.8.3-linux-x86_64/doc/style.css q4m-0.8.3-linux-x86_64/doc/top.jpg q4m-0.8.3-linux-x86_64/doc/install.html q4m-0.8.3-linux-x86_64/doc/index.html q4m-0.8.3-linux-x86_64/doc/q4m-modes.gif q4m-0.8.3-linux-x86_64/doc/tutorial.html q4m-0.8.3-linux-x86_64/README q4m-0.8.3-linux-x86_64/support-files/ q4m-0.8.3-linux-x86_64/support-files/install.sql q4m-0.8.3-linux-x86_64/support-files/install-exec-hook.txt q4m-0.8.3-linux-x86_64/support-files/q4m-forward q4m-0.8.3-linux-x86_64/NEWS
hata@local: ~/local/src> cd q4m-0.8.3-linux-x86_64/
hata@local: ~/local/src/q4m-0.8.3-linux-x86_64> ./configure --prefix=/usr --with-mysql=/home/hata/local/src/mysql-5.1.29-rc CXXFLAGS="-I/usr/include/mysql"
:
:
:
configure: creating ./config.status
config.status: creating Makefile
config.status: creating src/Makefile
config.status: creating t/Makefile
config.status: creating src/queue_config.h
config.status: executing depfiles commands
hata@local: ~/local/src/q4m-0.8.3-linux-x86_64> make
hata@local: ~/local/src/q4m-0.8.3-linux-x86_64> make install
プラグインのインストール
sudo make install後
/usr/lib64/mysql の下に、libqueue_engine.* がおかれているので、プラグインディレクトリにコピーする
もしくは、configure オプションの libdir を指定してみる
./configure --with-mysql=/home/vmdev/local/src/mysql-5.1.29-rc CXXFLAGS="-I/usr/include/mysql" --libdir=/usr/lib64/mysql/plugin
これでやると、なぜか mysql/plugin にコピーされる(libdirの動きとしていいのか...?)
OSX(10.5.5)に入れる
port から MySQL5.1.29を入れる
MySQL AB のものだとハマったので、今回は port を使う
hata@mac.local > sudo port install mysql5-devel
Q4M のインストール
linux と同じように無印は使わず、mysql-5.1.28-rc-osx10.4-i686-without-fast-mutexes-q4m-0.8.3.tar.gzを使う
hata@mac.local ~/local/src/q4m> ./configure --prefix=/opt/local --with-mysql=/Users/yusukehata/tmp/mysql-5.1.29-rc CFLAGS="-I/opt/local/include/mysql5/mysql -I/opt/local/include" CPPFLAGS="-I/opt/local/include/mysql5/mysql -I/opt/local/include"
また、以下のようにシンボリックリンク貼っておく必要がある
> sudo ln -s /opt/local/include/mysql5/mysql/ /opt/local/include/mysql > sudo ln -s /opt/local/lib/mysql5/mysql/ /opt/local/lib/mysql
MySQL AB のバイナリで、ビルド時に発生するエラーとか
もしかしたら、portのでも出たかも
source='05-multireader-read.c' object='05_multireader_read-05-multireader-read.o' libtool=no \ depfile='.deps/05_multireader_read-05-multireader-read.Po' tmpdepfile='.deps/05_multireader_read-05-multireader-read.TPo' \ depmode=gcc3 /bin/sh ../config/depcomp \ gcc -DHAVE_CONFIG_H -I. -I. -I../src -I/Users/yusukehata/tmp/mysql-5.1.29-rc/sql -I/Users/yusukehata/tmp/mysql-5.1.29-rc/include -I/Users/yusukehata/tmp/mysql-5.1.29-rc/regex -I/Users/yusukehata/tmp/mysql-5.1.29-rc -I/opt/local/include/mysql5/mysql -I/opt/local/include -I/opt/local/include/mysql5/mysql -I/opt/local/include -Wall -c -o 05_multireader_read-05-multireader-read.o `test -f '05-multireader-read.c' || echo './'`05-multireader-read.c /bin/sh ../libtool --preserve-dup-deps --mode=link gcc -I/opt/local/include/mysql5/mysql -I/opt/local/include -Wall -L/usr/local/mysql/lib -o 05-multireader-read 05_multireader_read-05-multireader-read.o -lmysqlclient mkdir .libs gcc -I/opt/local/include/mysql5/mysql -I/opt/local/include -Wall -o 05-multireader-read 05_multireader_read-05-multireader-read.o -L/usr/local/mysql/lib /usr/local/mysql/lib/libmysqlclient.dylib -lm ld: warning in /usr/local/mysql/lib/libmysqlclient.dylib, file is not of required architecture Undefined symbols: "_mysql_real_connect", referenced from: _main in 05_multireader_read-05-multireader-read.o "_mysql_store_result", referenced from: _do_select in 05_multireader_read-05-multireader-read.o "_mysql_init", referenced from: _main in 05_multireader_read-05-multireader-read.o "_mysql_free_result", referenced from: _main in 05_multireader_read-05-multireader-read.o _main in 05_multireader_read-05-multireader-read.o "_mysql_query", referenced from: _do_select in 05_multireader_read-05-multireader-read.o "_mysql_close", referenced from: _main in 05_multireader_read-05-multireader-read.o "_mysql_fetch_row", referenced from: _main in 05_multireader_read-05-multireader-read.o _main in 05_multireader_read-05-multireader-read.o "_mysql_num_rows", referenced from: _main in 05_multireader_read-05-multireader-read.o _main in 05_multireader_read-05-multireader-read.o ld: symbol(s) not found collect2: ld returned 1 exit status make[1]: *** [05-multireader-read] Error 1 make: *** [all-recursive] Error 1
この状態だと、PHPとかビルドするときにエラーになる...
ld: warning in /usr/local/mysql/lib/libmysqlclient.dylib, file is not of required architecture ld: warning in /usr/local/mysql/lib/libmygcc.a, file is not of required architecture Undefined symbols: "_mysql_get_server_info", referenced from: _pdo_mysql_get_attribute in mysql_driver.o "_mysql_stmt_close", referenced from: _pdo_mysql_stmt_dtor in mysql_statement.o _pdo_mysql_stmt_cursor_closer in mysql_statement.o "_mysql_stmt_fetch", referenced from: _pdo_mysql_stmt_fetch in mysql_statement.o "_mysql_next_result", referenced from: _pdo_mysql_stmt_dtor in mysql_statement.o _pdo_mysql_stmt_next_rowset in mysql_statement.o _pdo_mysql_stmt_cursor_closer in mysql_statement.o "_mysql_stmt_errno", referenced from: __pdo_mysql_error in mysql_driver.o "_mysql_stmt_store_result", referenced from: _pdo_mysql_stmt_execute in mysql_statement.o "_mysql_real_escape_string", referenced from: _mysql_handle_quoter in mysql_driver.o "_mysql_stmt_init", referenced from: _mysql_handle_preparer in mysql_driver.o "_mysql_affected_rows", referenced from: _mysql_handle_doer in mysql_driver.o _pdo_mysql_stmt_execute in mysql_statement.o _pdo_mysql_stmt_next_rowset in mysql_statement.o "_mysql_stmt_prepare", referenced from: _mysql_handle_preparer in mysql_driver.o "_mysql_stmt_sqlstate", referenced from: __pdo_mysql_error in mysql_driver.o "_mysql_fetch_fields", referenced from: _pdo_mysql_stmt_execute in mysql_statement.o _pdo_mysql_stmt_execute in mysql_statement.o _pdo_mysql_stmt_next_rowset in mysql_statement.o "_mysql_get_host_info", referenced from: _pdo_mysql_get_attribute in mysql_driver.o "_mysql_get_server_version", referenced from: _mysql_handle_preparer in mysql_driver.o "_mysql_free_result", referenced from: _pdo_mysql_stmt_dtor in mysql_statement.o _pdo_mysql_stmt_dtor in mysql_statement.o _pdo_mysql_stmt_execute in mysql_statement.o _pdo_mysql_stmt_next_rowset in mysql_statement.o _pdo_mysql_stmt_cursor_closer in mysql_statement.o _pdo_mysql_stmt_cursor_closer in mysql_statement.o "_mysql_options", referenced from: _pdo_mysql_handle_factory in mysql_driver.o _pdo_mysql_handle_factory in mysql_driver.o _pdo_mysql_handle_factory in mysql_driver.o _pdo_mysql_handle_factory in mysql_driver.o _pdo_mysql_handle_factory in mysql_driver.o _pdo_mysql_handle_factory in mysql_driver.o "_mysql_close", referenced from: _mysql_handle_closer in mysql_driver.o "_mysql_stmt_affected_rows", referenced from: _pdo_mysql_stmt_execute in mysql_statement.o "_mysql_fetch_row", referenced from: _pdo_mysql_stmt_fetch in mysql_statement.o "_mysql_num_fields", referenced from: _pdo_mysql_stmt_execute in mysql_statement.o _pdo_mysql_stmt_execute in mysql_statement.o _pdo_mysql_stmt_next_rowset in mysql_statement.o "_mysql_store_result", referenced from: _pdo_mysql_stmt_dtor in mysql_statement.o _pdo_mysql_stmt_execute in mysql_statement.o _pdo_mysql_stmt_next_rowset in mysql_statement.o _pdo_mysql_stmt_cursor_closer in mysql_statement.o "_mysql_get_client_info", referenced from: _zm_info_pdo_mysql in pdo_mysql.o _pdo_mysql_get_attribute in mysql_driver.o "_mysql_real_query", referenced from: _mysql_handle_doer in mysql_driver.o _pdo_mysql_stmt_execute in mysql_statement.o "_mysql_errno", referenced from: __pdo_mysql_error in mysql_driver.o _mysql_handle_preparer in mysql_driver.o _pdo_mysql_stmt_fetch in mysql_statement.o "_mysql_error", referenced from: __pdo_mysql_error in mysql_driver.o __pdo_mysql_error in mysql_driver.o "_mysql_stmt_bind_result", referenced from: _pdo_mysql_stmt_execute in mysql_statement.o "_mysql_sqlstate", referenced from: __pdo_mysql_error in mysql_driver.o "_mysql_stmt_result_metadata", referenced from: _pdo_mysql_stmt_execute in mysql_statement.o "_mysql_insert_id", referenced from: _pdo_mysql_last_insert_id in mysql_driver.o "_mysql_use_result", referenced from: _pdo_mysql_stmt_execute in mysql_statement.o _pdo_mysql_stmt_next_rowset in mysql_statement.o "_mysql_stmt_bind_param", referenced from: _pdo_mysql_stmt_execute in mysql_statement.o "_mysql_stmt_attr_set", referenced from: _pdo_mysql_stmt_execute in mysql_statement.o "_mysql_num_rows", referenced from: _pdo_mysql_stmt_execute in mysql_statement.o "_mysql_init", referenced from: _pdo_mysql_handle_factory in mysql_driver.o "_mysql_real_connect", referenced from: _pdo_mysql_handle_factory in mysql_driver.o "_mysql_more_results", referenced from: _pdo_mysql_stmt_dtor in mysql_statement.o _pdo_mysql_stmt_dtor in mysql_statement.o _pdo_mysql_stmt_cursor_closer in mysql_statement.o _pdo_mysql_stmt_cursor_closer in mysql_statement.o "_mysql_stmt_execute", referenced from: _pdo_mysql_stmt_execute in mysql_statement.o "_mysql_ping", referenced from: _pdo_mysql_check_liveness in mysql_driver.o "_mysql_stmt_param_count", referenced from: _mysql_handle_preparer in mysql_driver.o "_mysql_stmt_free_result", referenced from: _pdo_mysql_stmt_next_rowset in mysql_statement.o _pdo_mysql_stmt_cursor_closer in mysql_statement.o "_mysql_stat", referenced from: _pdo_mysql_get_attribute in mysql_driver.o "_mysql_fetch_lengths", referenced from: _pdo_mysql_stmt_fetch in mysql_statement.o ld: symbol(s) not found collect2: ld returned 1 exit status make: *** [libs/libphp5.bundle] Error 1
なぞ
ちなみに、MySQL AB は
Mach-O 64-bit で x86_64 となってるのだが
> file /usr/local/mysql/lib/libmysqlclient.16.0.0.dylib /usr/local/mysql/lib/libmysqlclient.16.0.0.dylib: Mach-O 64-bit dynamically linked shared library x86_64 > file /usr/local/mysql/lib/libmysqlclient.dylib /usr/local/mysql/lib/libmysqlclient.dylib: Mach-O 64-bit dynamically linked shared library x86_64
/usr/local/mysql/bin/mysqlbug
>> CFLAGS='-g -Os -arch x86_64 -fno-common' CXX='gcc -static-libgcc' CXXFLAGS='-g -Os -arch x86_64 -felide-constructors -fno-common'
/usr/local/mysql/bin/mysql_config
Usage: /usr/local/mysql/bin/mysql_config [OPTIONS]
Options:
--cflags [-I/usr/local/mysql/include -g -Os -arch x86_64 -fno-common -D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DIGNORE_SIGHUP_SIGQUIT -DDONT_DECLARE_CXA_PURE_VIRTUAL]
--include [-I/usr/local/mysql/include]
--libs [-L/usr/local/mysql/lib -lmysqlclient -lz -lm -lmygcc]
--libs_r [-L/usr/local/mysql/lib -lmysqlclient_r -lz -lm -lmygcc]
--plugindir [/usr/local/mysql/lib/plugin]
--socket [/tmp/mysql.sock]
--port [0]
--version [5.1.29-rc]
--libmysqld-libs [-L/usr/local/mysql/lib -lmysqld -lz -lm -lmygcc]
まとめ
無事、試行錯誤しながら何とかインストール出来た。もしかしたら wassr でその時の苦悩の様子がライブ中継してるかもしれないけど、何度、試行錯誤したことか...。
環境が違ったときにインストール方法とか微妙に違うのが面倒だねぇ
ま、インストールにハマると長引くので危険。誰かがやってた環境と同じのに合わせるのが一番早いのかもね
2008/12/05
フラワーロック 2.0 と CruiseControl を連携させてみた
CruiseControlとLEDの組み合わせが海外でも流行っている(?)みたいですが、日本ならフラワーロック2.0だろ!ってことでやってみた。
CruiseControl を使ったもう一つのソリューション
↑ビルドに失敗して FAILED のときの様子。エラーになってると踊って光っちゃいます。
作り方
まずは、フラワーロックを買ってくる
これが無いと始まりません。
近所のおもちゃ屋さん、電気店、アマゾンなどで購入しましょう
フラワーロックの仕様を確認する
フラワーロック 2.0 の主な仕様を確認します。
- フラワーロック 2.0 (コスモスtype)
-
- 発売元: タカラトミー
- レーベル: タカラトミー
- スタジオ: タカラトミー
- メーカー: タカラトミー
- 価格: ¥ 3,999 (34% OFF)
- 発売日: 2008/10/31
- 売上ランキング: 548
- インプットは電源の On/Off と、モードボタン、入力切り替え(Line/マイク)と音声入力のラインしかない
- その内、フラワーロックを操作できるのは、音声入力の LINE しかない(音に反応するため)
- フラワーロックは、何も入力が無いと 5分後(5分間経過後) スリープする
- スリープしたフラワーロックを起こすには、電源の On/Off ボタンを押すしかない
- フラワーロックのLEDを任意の色で発色させることはできない
- フラワーロックの踊りを任意のインプットで踊らせることができない
ちなみに、フラワーロックは単3電池 4本、もしくは AC の専用電源が必要です。長時間使うなら電池よりも AC を買うことをおすすめします。
CruiseControl で動かす方法を検討する
CruiseControl(以下、CC) に組み込む方法として、今回は音声入力を主として動かすため、以下のようにしました。
- CruiseControl でビルドログを、jabber でメッセージを飛ばす
- jabber クライアントがメッセージの内容を読み取り、ビルドに失敗(BUILD FAILED)となっていた場合は、エラーミュージックを流す。
- jabber クライアントがメッセージの内容を読み取り、ビルドに成功(Build passed)となっていた場合は、何もしない
- 5分でフラワーロックは眠ってしまうので、定期的(5分毎)に keepalive (というかwakeon) を ping する。(実際には「ポーン」とか「ピンポン」みたいな音を流す)
CC に組み込む
CC のプラグインjabber があるので、それを使ってみます。
<project>
<publishers>
:
:
<jabber
host="talk.google.com"
port="5223"
username="<flower.sender@gmail.com>"
password="<flower.sender.password>"
recipient="<flower.receiver@gmail.com>"
ssl="true"
buildresultsurl="true"
/>
:
:
</publishers>
:
:
</project>
ここで、注意しなければならないのは、<onsuccess>や<onfailure>で囲ってしまうと、送信されたメッセージをクライアント側で振り分けることができなくなってしまうので、とにかく全部のメッセージをクライアントに送ってしまうようにします。
jabber メッセージを読み込んで音を流す
僕は、ここの部分は手抜きしています。なぜなら最近のメッセンジャー的なものには、メッセージをフィルタリングしておくことが可能で、フィルタリングしたメッセージに応じてアクションを書くことも簡単にできるため。
ということで、Kopeteを使ってみるサンプルを置いておきます。
Kopete の「設定」から「プラグインの設定」へ
その後「強調」より、フィルタリングすぐ文字列を設定(今回は「FAILED」)して、「サウンドの再生」よりBuild Failed な音楽を指定します。
これで後は、CC が勝手にエラーになったらメッセージを流してくれます。failed になっている間はずっと音楽を流して、「エラーの舞」をフラワーロックに踊らせちゃいましょう。
それ以外の方法
実は、上のCCでメッセージを送信して、Kopete などで受信するという方法は、フラワーロックと少し相性が悪いです。
なぜなら、フラワーロックは「5分間何もしないと、スリープする」という省電力設計。しかも復帰するには、On/Off ボタンを押さなければ復帰できない(音を流すだけでは復帰できない)ので、定期的に「起こして」あげる必要があります。
上記方法だと、ビルドにすごく時間がかかってしまって、CCが300秒に一回メッセージを流していたとしても、失敗してしまうことがあります。
なので、今回は ruby スクリプトで、定期的にフラワーロックを起こしてあげる keepalived なスクリプトを投げやりに書きました。
メッセージを送信するヤツ
#!/usr/bin/env ruby require 'rubygems' require 'xmpp4r' require 'kconv' class Message def initialize(user, password) @user = user @password = password @client = nil end def connect(server, port) @client = Jabber::Client.new(Jabber::JID.new(@user)) @client.connect(server, port) @client.auth(@password) end def send(to, body) @client.send(Jabber::Message.new(to, body)) puts body._to_s + Time.now.to_s end attr_accessor :user, :password end
yaml に色々設定を書いておく
# # config.yml # # flowerrock: # jabber: # user: <flower.sender@gmail.com> # password: <flower.sender.password> # server: talk.google.com # port: 5222 # post: # members: # - <flower.receiver@gmail.com> # - <hoge.foo.bar@gmail.com> # feed: # urls: # - http://hoge.foo.bar/rss # - http://qwerty/rss # interval: 250 # config = YAML.load_file(File.dirname(File.expand_path(__FILE__)) + '/config.yml') settings = config['flowerrock'] jabber = settings['jabber'] post = settings['post'] feed = settings['feed'] user = jabber['user'] pass = jabber['password'] server = jabber['server'] port = jabber['port'] to_users = post['members'] feed_urls = feed['urls'] interval = feed['interval']
RSS(cruisecontrol/rss)を読み込んで、メッセージを飛ばすヤツ
#!/usr/bin/env ruby require 'rubygems' require 'yaml' require 'open-uri' require 'rexml/document' message = Message.new(user, pass) message.connect(server, port) loop do to_users.each{|user| message.send(user, 'initialize...') } feed_urls.each{|feed| page = open(feed) doc = REXML::Document.new(page) REXML::XPath.each(doc, '//item') {|item| REXML::XPath.each(item, 'description') {|desc| if desc.text =? /FAILED/i REXML::XPath.each(item, 'title') {|title| to_users.each{|user| message.send(user, title.text) } } end } } } to_users.each{|user| message.send(user, 'end...') } sleep interval end
ruby スクリプトは汚い。でも動いているうちは良しとする。
CC と フラワーロック 2.0 を連携させる
後は、PC のライン出力にコードをぶっ刺して、フラワーロックにつなぐだけ!
ビルドに失敗しているときに、正しく「ビルド失敗の舞」をフラワーロックが踊ってくれれば OK
ちなみに、フラワーロックが持っている省電力機構のおかげで、夜中はCCを動かさない。とか、音を出さないようにするだけで、夜な夜なフラワーが踊ると言うことはないので、警備員さんにも安心設計!
ぜひ、あなたのプロジェクトの継続的インテグレーションの一貫として、フラワーロックを組み込んでみませんか?
花が増えて、プロジェクトの和ませ役にピッタリの一台です!
その他雑感
ここ最近、海外のCC連携ガジェットを何個もみてきたけど、やっぱあっちのはwifiがついていたり、LEDがもう少し簡単に操作できたりと、面白いのが多い。
フラワーロックはそれに比べると、ライン入力だけと言うシンプルなもの。もう少し弄れるようにすると、海外の市場でも売れるんじゃないかなぁ。ガジェット市場では特に。
だって、変なウサギ(あえてリンクは張らないけど)が売れて、インターネットランプなんてものが売り出されるなら、フラワーロックはもっとイケるハズ!インタフェースがもう少し多ければ。だけど。
近いうちに Arduino とかにも挑戦して見ようと思う。年末か年明けにでも。。
2008/11/16
PHP の self と parent に気をつけろ
これまた、どうでもいいことシリーズ
php の self と parent は予約語ではないため、以下のようなことが行えます。
define('self', 123); var_dump(self); // int(123) define('parent', 456); var_dump(parent); // int(456)
しかしながら、class 内でこれら self
parentを使っても問題なく利用できます。
define('self', 'Foo'); class Hoge { const A = 123; static function getA(){ return self::A; } } class Foo { const A = 456; } var_dump(Hoge::getA()); //123
ってか、これ正しく動いてるのだろうか...
class Hoge { static function foo(){ return new self; } } class Foo extends Hoge { static function bar(){ return new parent; } } define('self', 'Foo'); define('parent', 'Foo'); $a = spl_object_hash(Hoge::foo()); $b = spl_object_hash(Foo::bar()); var_dump($a, $b); $a = Hoge::foo(); $b = Foo::bar(); var_dump($a, $b); var_dump(spl_object_hash($a), spl_object_hash($b));
結果としては
string(32) "af5c83e899a2154cfdf3e4ff093419e7" string(32) "af5c83e899a2154cfdf3e4ff093419e7" object(Hoge)#1 (0) { } object(Hoge)#2 (0) { } string(32) "af5c83e899a2154cfdf3e4ff093419e7" string(32) "2c04186690093c93e846c3dee1064aca"
うーん。。。
追記
ってか、最後のはselfとかそういうの関係なかった。objectのhashを取るには一度ちゃんと変数に入れる必要があるんだね。
class Hoge { static function foo(){ return new self; } } var_dump(spl_object_hash(Hoge::foo()), spl_object_hash(Hoge::foo())); $a = Hoge::foo(); $b = Hoge::foo(); var_dump(spl_object_hash($a), spl_object_hash($b));
string(32) "af5c83e899a2154cfdf3e4ff093419e7" string(32) "af5c83e899a2154cfdf3e4ff093419e7" string(32) "af5c83e899a2154cfdf3e4ff093419e7" string(32) "2c04186690093c93e846c3dee1064aca"
勉強になった。


S2Container/S2Dao.PHP5を使っていて困ったこと・質問などがありましたら、S2Container-PHP5のMLにてお願いします。