日曜日, 12月 06, 2009

[haXe] haxelibが変?

haXeでは、haxelibコマンドを使ってライブラリを簡単にインストールすることができるハズだが、Windows環境ではhscriptがうまく入れられなった。メッセージはこちら。

In project: Unexpected element tag


この原因は2つある模様。

1つはhaxelibのバグ。本家では解決済なので、最新ソースをCVSで取得後、コンパイルすることで無事入るようになります(一応、このコンパイル後haxelib.exeを置いておきます)。

2つめはmライブラリパスの問題なようで、以下設定をすることで動くようになるハズ。

set HAXE_LIBRARY_PATH=c:\Program Files\Motion-Twin\haxe\std


パスは完了ごとに変えて下さい(\は実際は¥で指定します)。

火曜日, 11月 24, 2009

[HIVE] Solrのexample/books.csvを

以下スキーマで(Solrのexamplesにある)books.csvをHIVEに取り込むことができる。

create table books (
  id STRING,
  cat STRING,
  name STRING,
  price DOUBLE,
  inStock BOOLEAN,
  author_t STRING,
  series_t STRING,
  sequence INT,
  genre_s STRING)
 ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
 LINES TERMINATED BY '\n';

取りこむのは以下コマンド。
LOAD DATA INPATH '/tmp/books.csv' overwrite into table books ;

月曜日, 11月 09, 2009

[HIVE] 日本語が。。。

jdkのエンコードのせいだと思うのだけど(コマンドラインでUTF8は見えるから)、HIVEのコンソールでは日本語が使えない。直接cygwinのコマンドラインでなら使えるので、まぁいいのだけど。

$ /cygdrive/d/work/apache-hive/build/dist/bin/hive -hiveconf hadoop.bin.path="bash /cygdrive/d/work/apache-hadoop-0.19.2/bin/hadoop" -e "FROM zip z insert overwrite directory '/tmp/gina3' SELECT z.zip, z.pref, z.city, z.town  WHERE z.ver = '2008-12-26' AND z.town REGEXP '銀座';"

@ITの記事を参考に練習中。。

日曜日, 11月 08, 2009

[HIVE] HIVE上からHDFS操作

HIVE上からファイルを見るには。

hive> dfs  -ls /tmp;
Found 10 items
drwxr-xr-x   - 00962724 mkgroup          0 2009-11-24 02:27 /tmp/00962724
drwxr-xr-x   - 00962724 mkgroup          0 2009-11-03 03:24 /tmp/cy
-rw-r--r--   1 00962724 mkgroup       2740 2009-11-23 23:44 /tmp/FirstTest.jar
drwxr-xr-x   - 00962724 mkgroup          0 2009-11-09 01:21 /tmp/gina3
drwxr-xr-x   - 00962724 mkgroup          0 2009-11-09 01:13 /tmp/ginza
drwxr-xr-x   - 00962724 mkgroup          0 2009-11-24 02:25 /tmp/hadoop-00962724

drwxr-xr-x   - 00962724 mkgroup          0 2009-11-09 01:21 /tmp/hive-00962724
drwxr-xr-x   - 00962724 mkgroup          0 2009-11-09 00:16 /tmp/localfiles
drwxr-xr-x   - 00962724 mkgroup          0 2009-11-09 01:08 /tmp/prefff.dat
-rw-r--r--   1 00962724 mkgroup    6687150 2009-11-22 21:54 /tmp/sample.war
hive>

土曜日, 11月 07, 2009

[HIVE] HQLの関数を確認

意外に説明が充実してる。

hive> DESCRIBE FUNCTION EXTENDED substr;
OK
substr(str, pos[, len]) - returns the substring of str that starts at pos and is
 of length len
pos is a 1-based index. If pos<0 the starting position is determined by counting
 backwards from the end of str.
Example:
   > SELECT substr('Facebook', 5) FROM src LIMIT 1;
  'book'
  > SELECT substr('Facebook', -5) FROM src LIMIT 1;
  'ebook'
  > SELECT substr('Facebook', 5, 1) FROM src LIMIT 1;
  'b'
Time taken: 0.156 seconds
hive>

金曜日, 11月 06, 2009

[HIVE] select出来た!

cygwinだと、HIVEからhadoopを呼び出すところで失敗する。なのでこのためにはhiveconfオプションにて、hadoopのまるママの実行文を書いておくべし。

00962724@XXX /cygdrive/d/work/apache-hive/build/dist/conf
$ /cygdrive/d/work/apache-hive/build/dist/bin/hive -hiveconf hadoop.bin.path="bash /cygdrive/d/work/apache-hadoop-0.19.2/bin/hadoop" -e "SELECT a.foo FROM invites a WHERE a.ds='2008-08-15';"

また、以下のようなエラーがでるときはmetadataが壊れていた様子。

Job Submission failed with exception 'java.lang.NullPointerException(null)'

"drop table"して(このコマンドも失敗したけど、その後"show tables"してテーブルが無いようなら"create table"してloadすれば、うまく動くようになった!

Hive history file=/tmp/00962724/hive_job_log_00962724_200911060205_2037141967.txt
Total MapReduce jobs = 1
Number of reduce tasks is set to 0 since there's no reduce operator
09/11/06 02:05:32 INFO exec.ExecDriver: Number of reduce tasks is set to 0 since there's no reduce operator
09/11/06 02:05:32 INFO exec.ExecDriver: Using org.apache.hadoop.hive.ql.io.HiveInputFormat
09/11/06 02:05:32 INFO exec.ExecDriver: Processing alias a
09/11/06 02:05:32 INFO exec.ExecDriver: Adding input file file:/user/hive/warehouse/invites/ds=2008-08-15
09/11/06 02:05:34 INFO jvm.JvmMetrics: Initializing JVM Metrics with processName=JobTracker, sessionId=
09/11/06 02:05:34 WARN mapred.JobClient: Use GenericOptionsParser for parsing the arguments. Applications should implement Tool for the same.
09/11/06 02:05:34 INFO mapred.FileInputFormat: Total input paths to process : 1
Job running in-process (local Hadoop)
09/11/06 02:05:35 INFO exec.ExecDriver: Job running in-process (local Hadoop)
09/11/06 02:05:35 INFO mapred.FileInputFormat: Total input paths to process : 1
09/11/06 02:05:35 INFO mapred.MapTask: numReduceTasks: 0
09/11/06 02:05:35 INFO ExecMapper: maximum memory = 1040515072
09/11/06 02:05:35 INFO ExecMapper: conf classpath = [file:/D:/tmp/hadoop-00962724/hadoop-unjar3921453707640367881/, file:/D:/work/apache-hive/build/dist/lib/hive_exec.jar, file:/D:/tmp/hadoop-00962724/hadoop-unjar3921453707640367881/classes]
09/11/06 02:05:35 INFO ExecMapper: thread classpath = [file:/D:/tmp/hadoop-00962724/hadoop-unjar3921453707640367881/, file:/D:/work/apache-hive/build/dist/lib/hive_exec.jar, file:/D:/tmp/hadoop-00962724/hadoop-unjar3921453707640367881/classes]
09/11/06 02:05:35 INFO exec.MapOperator: Adding alias a to work list for file /user/hive/warehouse/invites/ds=2008-08-15/kv2.txt
09/11/06 02:05:35 INFO exec.MapOperator: dump TS struct<foo:int,bar:string,ds:string>
09/11/06 02:05:35 INFO ExecMapper:
<MAP>Id =10
  <Children>
    <TS>Id =0
      <Children>
        <FIL>Id =1
          <Children>
            <FIL>Id =2
              <Children>
                <SEL>Id =3
                  <Children>
                    <FS>Id =4
                      <Parent>Id = 3 <\Parent>
                    <\FS>
                  <\Children>
                  <Parent>Id = 2 <\Parent>
                <\SEL>
              <\Children>
              <Parent>Id = 1 <\Parent>
            <\FIL>
          <\Children>
          <Parent>Id = 0 <\Parent>
        <\FIL>
      <\Children>
      <Parent>Id = 10 <\Parent>
    <\TS>
  <\Children>
<\MAP>
09/11/06 02:05:35 INFO exec.MapOperator: Initializing Self 10 MAP
09/11/06 02:05:35 INFO exec.TableScanOperator: Initializing Self 0 TS
09/11/06 02:05:35 INFO exec.TableScanOperator: Operator 0 TS initialized
09/11/06 02:05:35 INFO exec.TableScanOperator: Initializing children of 0 TS
09/11/06 02:05:35 INFO exec.FilterOperator: Initializing child 1 FIL
09/11/06 02:05:35 INFO exec.FilterOperator: Initializing Self 1 FIL
09/11/06 02:05:35 INFO exec.FilterOperator: Operator 1 FIL initialized
09/11/06 02:05:35 INFO exec.FilterOperator: Initializing children of 1 FIL
09/11/06 02:05:35 INFO exec.FilterOperator: Initializing child 2 FIL
09/11/06 02:05:35 INFO exec.FilterOperator: Initializing Self 2 FIL
09/11/06 02:05:35 INFO exec.FilterOperator: Operator 2 FIL initialized
09/11/06 02:05:35 INFO exec.FilterOperator: Initializing children of 2 FIL
09/11/06 02:05:35 INFO exec.SelectOperator: Initializing child 3 SEL
09/11/06 02:05:35 INFO exec.SelectOperator: Initializing Self 3 SEL
09/11/06 02:05:35 INFO exec.SelectOperator: SELECT struct<foo:int,bar:string,ds:string>
09/11/06 02:05:35 INFO exec.SelectOperator: Operator 3 SEL initialized
09/11/06 02:05:35 INFO exec.SelectOperator: Initializing children of 3 SEL
09/11/06 02:05:35 INFO exec.FileSinkOperator: Initializing child 4 FS
09/11/06 02:05:35 INFO exec.FileSinkOperator: Initializing Self 4 FS
09/11/06 02:05:35 INFO exec.FileSinkOperator: Writing to temp file: FS file:/tmp/hive-00962724/1005059804/_tmp.10001/_tmp.attempt_local_0001_m_000000_0
09/11/06 02:05:35 INFO exec.FileSinkOperator: Operator 4 FS initialized
09/11/06 02:05:35 INFO exec.FileSinkOperator: Initialization Done 4 FS
09/11/06 02:05:35 INFO exec.SelectOperator: Initialization Done 3 SEL
09/11/06 02:05:35 INFO exec.FilterOperator: Initialization Done 2 FIL
09/11/06 02:05:35 INFO exec.FilterOperator: Initialization Done 1 FIL
09/11/06 02:05:35 INFO exec.TableScanOperator: Initialization Done 0 TS
09/11/06 02:05:35 INFO exec.MapOperator: Initialization Done 10 MAP
09/11/06 02:05:35 INFO exec.MapOperator: 10 forwarding 1 rows
09/11/06 02:05:35 INFO exec.TableScanOperator: 0 forwarding 1 rows
09/11/06 02:05:35 INFO exec.FilterOperator: 1 forwarding 1 rows
09/11/06 02:05:35 INFO exec.FilterOperator: 2 forwarding 1 rows
09/11/06 02:05:35 INFO exec.SelectOperator: 3 forwarding 1 rows
09/11/06 02:05:35 INFO ExecMapper: ExecMapper: processing 1 rows: used memory = 2369824
09/11/06 02:05:35 INFO exec.MapOperator: 10 forwarding 10 rows
09/11/06 02:05:35 INFO exec.TableScanOperator: 0 forwarding 10 rows
09/11/06 02:05:35 INFO exec.FilterOperator: 1 forwarding 10 rows
09/11/06 02:05:35 INFO exec.FilterOperator: 2 forwarding 10 rows
09/11/06 02:05:35 INFO exec.SelectOperator: 3 forwarding 10 rows
09/11/06 02:05:35 INFO ExecMapper: ExecMapper: processing 10 rows: used memory = 2388056
09/11/06 02:05:35 INFO exec.MapOperator: 10 forwarding 100 rows
09/11/06 02:05:35 INFO exec.TableScanOperator: 0 forwarding 100 rows
09/11/06 02:05:35 INFO exec.FilterOperator: 1 forwarding 100 rows
09/11/06 02:05:35 INFO exec.FilterOperator: 2 forwarding 100 rows
09/11/06 02:05:35 INFO exec.SelectOperator: 3 forwarding 100 rows
09/11/06 02:05:35 INFO ExecMapper: ExecMapper: processing 100 rows: used memory = 2388056
09/11/06 02:05:36 INFO exec.MapOperator: 10 finished. closing...
09/11/06 02:05:36 INFO exec.MapOperator: 10 forwarded 500 rows
09/11/06 02:05:36 INFO exec.MapOperator: DESERIALIZE_ERRORS:0
09/11/06 02:05:36 INFO exec.TableScanOperator: 0 finished. closing...
09/11/06 02:05:36 INFO exec.TableScanOperator: 0 forwarded 500 rows
09/11/06 02:05:36 INFO exec.FilterOperator: 1 finished. closing...
09/11/06 02:05:36 INFO exec.FilterOperator: 1 forwarded 500 rows
09/11/06 02:05:36 INFO exec.FilterOperator: PASSED:500
09/11/06 02:05:36 INFO exec.FilterOperator: FILTERED:0
09/11/06 02:05:36 INFO exec.FilterOperator: 2 finished. closing...
09/11/06 02:05:36 INFO exec.FilterOperator: 2 forwarded 500 rows
09/11/06 02:05:36 INFO exec.FilterOperator: PASSED:500
09/11/06 02:05:36 INFO exec.FilterOperator: FILTERED:0
09/11/06 02:05:36 INFO exec.SelectOperator: 3 finished. closing...
09/11/06 02:05:36 INFO exec.SelectOperator: 3 forwarded 500 rows
09/11/06 02:05:36 INFO exec.FileSinkOperator: 4 finished. closing...
09/11/06 02:05:36 INFO exec.FileSinkOperator: 4 forwarded 0 rows
09/11/06 02:05:36 INFO exec.FileSinkOperator: Committed to output file: file:/tmp/hive-00962724/1005059804/_tmp.10001/attempt_local_0001_m_000000_0
09/11/06 02:05:36 INFO exec.SelectOperator: 3 Close done
09/11/06 02:05:36 INFO exec.FilterOperator: 2 Close done
09/11/06 02:05:36 INFO exec.FilterOperator: 1 Close done
09/11/06 02:05:36 INFO exec.TableScanOperator: 0 Close done
09/11/06 02:05:36 INFO exec.MapOperator: 10 Close done
09/11/06 02:05:36 INFO ExecMapper: ExecMapper: processed 500 rows: used memory = 2459320
09/11/06 02:05:36 INFO mapred.TaskRunner: Task:attempt_local_0001_m_000000_0 is done. And is in the process of commiting
09/11/06 02:05:36 INFO mapred.LocalJobRunner:
09/11/06 02:05:36 INFO mapred.TaskRunner: Task attempt_local_0001_m_000000_0 is allowed to commit now
09/11/06 02:05:36 INFO mapred.FileOutputCommitter: Saved output of task 'attempt_local_0001_m_000000_0' to file:/tmp/hive-00962724/384798627
09/11/06 02:05:36 INFO mapred.LocalJobRunner: file:/user/hive/warehouse/invites/ds=2008-08-15/kv2.txt:0+5791
09/11/06 02:05:36 INFO mapred.TaskRunner: Task 'attempt_local_0001_m_000000_0' done.
2009-11-06 02:05:36,156 map = 100%,  reduce = 0%
09/11/06 02:05:36 INFO exec.ExecDriver: 2009-11-06 02:05:36,156 map = 100%,  reduce = 0%
Ended Job = job_local_0001
09/11/06 02:05:36 INFO exec.ExecDriver: Ended Job = job_local_0001
09/11/06 02:05:36 INFO exec.FileSinkOperator: Moving tmp dir: file:/tmp/hive-00962724/1005059804/_tmp.10001 to: file:/tmp/hive-00962724/1005059804/_tmp.10001.intermediate
09/11/06 02:05:36 INFO exec.FileSinkOperator: Moving tmp dir: file:/tmp/hive-00962724/1005059804/_tmp.10001.intermediate to: file:/tmp/hive-00962724/1005059804/10001
OK
Time taken: 27.86 seconds

00962724@XXX /cygdrive/d/work/apache-hive/build/dist/conf

木曜日, 11月 05, 2009

[HIVE] 準備が結構。。。

Hadoopも、JavaのScalaと同様に楽をしたいためHIVEを使おうと思って準備。したのだけど結構はまったのでメモ。

・Hadoopをインストール
HIVEにするといってもHadoopは事前に入れておく必要がある様子。このときおとなしくcygwinを入れるべし。中でdfとか使うのでbash.exeなどを入れていても(それだけでは)途中でこける。

・HIVEをインストール

ivy(というmavenみたいな構成管理ツール)が曲者。というかtrunkをsvnで取ってきたのだけど、中でもう古い、たとえばv0.19.0みたいなHadoopをdownloadしようとしてしまう。なので以下2ファイルを書き替える必要があった。
apache-hive\shims\ivy.xml
apache-hive\shims\build.xml
これらの中で、使いたいHadoopバージョンだけを残せばOK(私はv0.19.2だけを入れました)。あと、普通に入れると途中のHadoopダウンロードが遅いので、
D:\work>ant -Dhadoop.mirror="http://www.meisei-u.ac.jp/mirror/apache/dist" -Dhadoop.version=0.19.2 package
のとおり、ダウンロードサイトを指定すると吉。

補足:
cygwinのv1.7をUTF8化する方法はこちら

日曜日, 10月 25, 2009

[Solr] tikaを簡単に

curlを2回つなげると、簡単にウェブページを検索対象にできる。

konpyuta:~/work tf0054$ curl -s http://lucene.apache.org/tika/ | curl 'http://localhost:8983/solr/update/extract?literal.id=doc5&literal.url=doc5&commit=true' -F "myfile=@-"
<?xml version="1.0" encoding="UTF-8"?>
<response>
<lst name="responseHeader"><int name="status">0</int><int name="QTime">76</int></lst>
</response>
konpyuta:~/work tf0054$ 

ちなみに、curlの"-F"オプションで指定ファイルをPOSTすることができる(ココでは前のcurlから受け取ったSTDINを流すために"-"で受けている)。

土曜日, 10月 03, 2009

[Android] BlueLoggerを公開しました

まだまだお恥ずかしいレベルですが、AndroidでBluetooth通信を使って疑似的に「すれちがい通信」ぽいことを行うアプリを作ってADC2に出していたので、マーケットにも公開してみました(もちろんScalaで書いています)。


Twitter連携としては「すれちがったー」さんが抜群のバランス感なのでアレですが、一応Twidroidを入れてあると連携してTweetも打てます。

ただ、、いかんせんHT-03A同士で実験をしていないので、、お互いうまく発見できるか分かりません。。が。ぜひ使えたら、また使えなかったりバグっていたら教えて下さい!

木曜日, 9月 24, 2009

[Linux] フィード取得の偽装に関して

blogspotユーザのフィード(atomで吐いている)を解析、画像のソースを本文に引っ付けて戻す事で、その記事ページに行かなくてもリーダ上で画像を見られるようにしたい。のだけど、atomで<img src="〜">〜</img>をきちんと処理してもらうには、どうすれば良いのか分からない。。。atom:contentでcdata付けてみたけどダメ。あ、cdata付けるからだめなのかな。

木曜日, 9月 10, 2009

[Solr] GoSenをまた修正!

Luceneが2.9-rc2になったからか、またSolrでgosenが動かなくなっていたので修正しました。
lucene-ja-gosen-1.0.2.zipとして置いておきます。

土曜日, 8月 29, 2009

[Android] サブメニューの作成

androidでメニューをXMLで書くときの、サブメニュー(クリックしたら更にその中から表示されるメニュー。選択肢だけが画面中央にでる)は以下のように書きます。

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/main_Sort" android:title="ソート"
android:icon="@android:drawable/ic_menu_more">
<menu> 
<item android:id="@+id/main_Sort_1" android:title="すれ違い日時" />
<item android:id="@+id/main_Sort_2" android:title="すれ違い回数" />
    </menu> 
</item>
<item android:id="@+id/main_Input" android:title="入力" />
<item android:id="@+id/main_Stop" android:title="停止" />
<item android:id="@+id/main_Exit" android:title="終了"
android:icon="@android:drawable/ic_menu_close_clear_cancel" />
</menu>

木曜日, 8月 27, 2009

[Scala] Antでfscを

Scalaはコンパイルが遅いので(Javaに比べて遅いかどうかは、Java開発をほぼしたことがないので不明)、Antでscalacタスクではなくfscタスクを使えるようにした。段どりは以下。

fscだけをコマンドで実行し常駐させる(helpが出る)
・上がったデーモンのポート番号を調べる(※1)
・それをファイルに書く(※2)
・build.xmlのfscタスクでそれを指定(serverオプションにて)

(※1)は以下にポート番号でファイルができるのでそれを見ます。
d:\scala-2.7.5.final\var\scala-devel\scalac-compile-server-port

不思議なことに、fscのデーモンさんはPCをスタンバイにすると死んでしまうようなので、そうなると(※2)を毎回やらなくてはならず不便。。

今日AntでJavascript実行ができることに気がついたので、(※1)も(※2)も、それで何とかできると思います。

追伸:
今のところ致し方無い。そもそもWindowsじゃなければ、こんな面倒なことはないのだけど。

追伸2:
以下でポート番号を動的にantから取れそうです(参考にさせて頂いたページ)。
 <target name="fileList">
<script language="javascript">
<![CDATA[

ls();

function ls() {
var curDir = (new java.io.File("/scala-2.7.5.final/var/scala-devel/scalac-compile-server-port"));
var list = curDir.listFiles();
for (var i = 0; i < list.length; i++) {
print(baseName(list[i].toString()));
}
}

function baseName(path) {
// var sep = environment["file.separator"];
var sep = "\\";
var i = path.lastIndexOf(sep);
return path.substring(i + 1);
}

]]>
</script>
</target>

月曜日, 8月 17, 2009

[Scala] AndroidのHandlerとか

Scalaでのコーディングにおいては、特別な処理をしないならopsfutureメソッドで別スレッドで処理を実行、結果は(Android的に正しく)Handlerのpostでメインスレッドに戻すのが正解な気がしています。

、、と思っていたのですが、(futureで作ったかにかかわらないと思うけど)スレッド側でExceptionしててもログに出ない様子?

日曜日, 8月 09, 2009

[Scala] UriMatcher

ScalaでAndroidプログラミングをして、UriMatcherのmatchメソッドが使えず困った。
結局、matchが予約語だからバッククオート(`)で括ればOKでした。

ふつう、URLのマッチをとってそれを(Scalaだから)さらにmatchでcaseしてゆく、、ので確かに、書きながらややこしいなぁ、とは思っていましたが。

今はAndroid的売り(だと思う)ContentProviderを作ろうとしておりハマり中。マニフェストへ記述したら、なぜかClassNotFoundといわれてアプリごと起動不能に。。

日曜日, 7月 19, 2009

[Scala] JavaからScalaを

JavaからScalaで作ったクラスを使うサンプル。簡単すぎてか、以外にサンプルが無かったので載せてみる。
konpyuta:~/work/j2s asummer$ cat javaMain.java 
class javaMain {
public static void main(String[] args){
scalaConv objScala = new scalaConv(args[0]);
System.out.println(objScala.getResult());
System.out.println(objScala);
}
}
konpyuta:~/work/j2s asummer$ cat scalaConv.scala
class scalaConv(tmpStr:String){
val tmpPre = "xxx>";
def getResult = {
tmpPre + tmpStr;
}
override def toString = {
tmpPre + tmpStr;
}
}
konpyuta:~/work/j2s asummer$ javac javaMain.java
konpyuta:~/work/j2s asummer$ scalac scalaConv.scala
konpyuta:~/work/j2s asummer$ java -cp ~/work/scala/lib/scala-library.jar:. javaMain test
xxx>test
xxx>test
konpyuta:~/work/j2s asummer$
おもいきりシームレス。

火曜日, 7月 14, 2009

[Scala] HT-03AのUSB接続…

HT-03AをPCにUSBでつなげる際、普通にやるディスクドライブとして自動認識されてしまい、少しはまります。こんな時は、Android開発者MLに流れていたメッセージを参考に、
 ・レジストリを消して
 ・端末で"設定>アプリケーション>開発>デバッグ"をONに
することで、無事SDK(r2)のUSBドライバにて接続し、デバイス番号が確認できるところまで進みました。でも、もしかすると初めて端末を接続する前に、端末のデバッグをONにしておけばよかったのかも、と思います。

火曜日, 7月 07, 2009

[Scala] Androidアプリ!(センサーの実験など)

せっかくAndroid端末をGDDでもらったので、yamashitaさんのアプリを以下改造しました。
・せっかくなので売りのセンサーを使って(これは元から)
・自前式では動きが気に食わなかったので物理エンジンを入れて
・最近お気に入りのScalaで焼き直し
・SDKも1.5にして
そして、せっかくなので(汚いソースままですが)公開しておこうと思います(MoveCircle)。

物理エンジンはAPEある程度Androidに移植されていた(testape2d.zip)ので取り込んでいます)。

でも、SDK1.5のセンサーって、今はシミュレータで実験できないんですね(シミュレータといってもライブラリを入れるタイプで、そのライブラリが1.1仕様ママ)。実機じゃないとテストできないってちょっと。。

木曜日, 6月 25, 2009

[Scala] RichString!

動作は遅いのかもしれませんが、
      val tmpStr:String = '^'+args(0)+".*";
val objStr = tmpStr.r;
println(aryTmp.filter{w => {
w match {
case objStr() => { true;}
case _ => { false; }
}
}}(0));
というのが、一行で書けるScalaのRichStringは、やはり魅力です。
      println(aryTmp.filter{x => x.startsWith(args(0))});
特に意識せずに使う文字列型がコレ、というのはしかし、考えようによってはやり過ぎですが。。まぁLLと捉えればまったくありかと。

追伸:
 きちんとsplitなんかもあって。本当にLL感覚でいけて嬉しいです。

日曜日, 6月 21, 2009

[Scala] GAE/JのMemcacheサービス

Scalaで、なぜかGAE/JのMemcacheサービスをJCacheを経由して使う方法が分からない。
直接APIを使ってよいなら下のソースな感じで大丈夫なのだけど。
import com.google.appengine.api.memcache._

class memcached {
val cache:MemcacheService = MemcacheServiceFactory.getMemcacheService();

def setValue(strKey:String,strValue:String) = {
cache.put(strKey,strValue);
}

def getValue(strKey:String):String = {
cache.get(strKey).asInstanceOf[String];
}

}

JCache経由にしようとしたら、出てしまうエラー。Kってjava.util.MapのKっぽいんだけど解決方法が分からない。。
 ~snip~
[scalac] D:\work\workspace\test\src\com\digipepper\memcached.scala:51: error:
type mismatch;
[scalac] found : String
[scalac] required: K
[scalac] cache.put(key, value);
[scalac] ^
 ~snip~
お分かりの方は是非コメントください。一部ではGAE/JをPythonで使うべきかJavaで使うべきか、から発展した大変な議論が巻き起こったようですが、私はのんびりとScalaでがんばります。

土曜日, 6月 20, 2009

[Scala] GAE/JのMailサービス

本文は普通に日本語文章を与えたらOK。サブジェクトだけ自分でいじることにしました。
import java.util.Properties;

import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.MessagingException;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeUtility;

class sendmail(strFrom:String) {

var props:Properties = new Properties();
var session:Session = Session.getDefaultInstance(props, null);

def send(strTo:String, strSubject:String, strBody:String) {
try {
var msg:Message = new MimeMessage(session);
msg.setFrom(new InternetAddress(strFrom));
msg.addRecipient(Message.RecipientType.TO,
new InternetAddress(strTo, "Mr. User"));

msg.setSubject(MimeUtility.encodeText(strSubject,"iso-2022-jp","B"));
msg.setText(strBody+"\n");

Transport.send(msg);

} catch {
case e:AddressException => printf("Exp_A(%s)\n", e.getMessage)
case e:MessagingException => printf("Exp_B(%s)\n", e.getMessage)
case e => e.printStackTrace
}
}
}
エラー処理とかとても適当ですが、何かの参考に。

[Scala] Eclipse+GAE/Jで最初にやること

GoogleAppEngineのアプリをEclipse+Scalaで開発するとき、ScalaとGAEのアドオンを入れた最初の状態では、GAEのEnhancerが失敗する(ファイルを保存する度にコンソールで「エンハンスするクラスファイルが見つからない/CLASSPATH変えろ」と言われ続ける)。
そんなときには、"eclipse\plugins\com.google.appengine.eclipse.sdkbundle_1.2.1.v200905131143\appengine-java-sdk-1.2.1\lib\tools\orm"など、GAEのプラグイン内のライブラリフォルダにScalaのライブラリを入れておくことで解決できます。

日曜日, 6月 14, 2009

[Solr] GoSenを修正!

たぶん、全文検索ライブラリluceneに入った修正(LUCENE-1636)のために、先のgosenセットがtrunkのSolrが起動すら出来なくなっていました(IllegalAccessExceptionがPosFilter初期化時に発生!)。今日までupdateしてなかったので気が付かず。

で、読めないJavaをなんとなく眺め、結局、本体の似たようなFilterのソースと同じ初期方法にかえる(superを呼ぶだけにする)ことで解消できている様子。なので、新lucene-ja-gosenセットとして置いておきます。

よかったー。と直したのはいいけど、結局(Solrの)v1.4はいつ出るんだろう。。。

月曜日, 6月 08, 2009

[Linux] libproxy

ブラウジングでロケーションが変わるとよく問題となる"Proxy情報(どうやったらインターネットにつなげるの?)の取得"は、当然アプリを自作するときもとても手間な部分です。これをサポートするライブラリが有りました。
http://code.google.com/p/libproxy/

via kwout

WPADって規格もあるんですね。

日曜日, 5月 31, 2009

[Scala] GAE/JでJDO!

GoogleAppEngine/Javaではディスクが無いことからJDO/JPAでのデータ保存が必須です。

これをピュアScalaで(Javaクラスを使わず)やっている例題scalagaeを見つけたのだが、うまく動かず苦労。

原因は「java.lang.VerifyError」が出てしまうことだったのだが、これはJDO実装であるDataNucleusのバグである様子。v1.1.3に入れ替えたら無事に動きました。
具体的には、D:\appengine-java-sdk-1.2.1\lib\tools\ormにあるdatanucleus-enancer-1.1.0.jarが悪いのでdatanucleus-enhancer-1.1.3.jarに入れ替えます。

あと、コマンドラインからGAEにuploadするとき、app_idはscalagae\WEB-INF\appengine-web.xmlに書かれるので、適宜書き換えましょう。

土曜日, 5月 30, 2009

[Scala] GAE/J上でコンパイル!?

GAE/J上でコンパイル、JDOでバイトコードを保存、それを引き出して実行する、という機構を作ろうプロジェクトを見つけた。動くのかな。

金曜日, 5月 29, 2009

[Scala] PulpCore!

Javaの2DレンダライブラリであるPlupCoreのScala版があった。何故ソース的に焼き直したのかまったく不明。。

水曜日, 5月 27, 2009

[Scala] Rail@GAE/J!

JRubyがあるわけなので、出来そうではありますが、普通にありました。すごい。

ちなみに、Python版ではブログアプリ@GAEを見つけたのだが、これのJava版、もっというとScala版は無いものでしょうか。

日曜日, 5月 24, 2009

[Solr] WebService::Solrが

自前でSolrのレスポンスを、XML::Simple使って解析しようとして四苦八苦していたところ、、ふと思いついて調べてみたら、案の定WebService::Solrなるものが。。

早速書き直してみたところ、SolrのレスポンスのクセxXML::Simpleのクセにやられていた(例外処理ばかりだったコード)が、シンプルにんありました。

最初から調べておけば。。。

追伸:
XMLじゃなくJSONのレスポンスを解析してますね、、なるほどー。そういえば、確かにJSON用CPANモジュールをいっぱいダウンロードしていました(StrawberryPerlさいこうです)。

追伸:
英語の解説ページを発見。

日曜日, 5月 17, 2009

[Lift] より簡素に!

Liftの勉強をしてます。Webなフレームワークって便利ですね。
snippetで多用するbindについて、The Loopさんを参考に確認を。

まず、以下の書き方がサンプル的に分かりやすいモノ。

VIEW:
    <lift:helloDB.tstForm form="post">
    <testBox:lines>Lines</testBox:lines>
    <testBox:desc>To Do</testBox:desc>
    <testBox:submit>submit</testBox:submit>
    </lift:helloDB.tstForm>
SNIPPET:
    def tstForm(argForm: NodeSeq) = {
// とりあえずモデルオブジェクトを作成(!)
val hellom = HelloModel.create;

// 入力を受け取り保存するかを判断
def checkAndSave(): Unit = hellom.validate match {
// S.noticeでに値を出力
case Nil => hellom.save ; S.notice("Added "+hellom.desc)
case xs => S.error(xs) ; S.mapSnippet("helloDB.tstForm", doForm)
// S.redirectTo("/")は不要
// →何にせよ最後にdoFormしているから(再描画される)
}

// テンプレートへバインドする関数
def doForm(argForm: NodeSeq) = {
bind("testBox", argForm,
//"lines" -> toShow.toString,
"lines" -> toShow, // toShowでXMLを返すようにするから
"desc" -> hellom.desc.toForm,
"submit" -> submit("SAVE", checkAndSave)); // ボタンもタグ必要
}

// バインド実行(上の関数を)
doForm(argForm);
}

で、これをより簡単に書くと(HTML的な変更点はlabelで囲むこと)。

VIEW:
    <lift:helloDB.tstForm form="post">
    <testBox:lines>Lines</testBox:lines>
    <label for="desc">
        <testBox:desc>To Do</testBox:desc>
    </label>
    <testBox:submit>submit</testBox:submit>
    </lift:helloDB.tstForm>
SNIPPET:
    def tstForm(argForm: NodeSeq): NodeSeq = {
val hellom = HelloModel.create;

bind("testBox",argForm,
"lines" -> toShow, // toShowでXMLを返すようにするから
"desc" -> SHtml.text(hellom.desc, hellom.desc(_)), // descカラムへ書込み
"submit" -> SHtml.submit("SAVE", hellom.save)
)
}

なるほどー。かっこいい。

月曜日, 5月 04, 2009

[Scala] DynamicVariableとは

ScalaでDSLということで、DynamicVariableについて勉強中。あの記事においては、大体以下の流れであろうと思う。

DynamicVariableのインスタンスであるoutは、withValueメソッドの引数で与えられたインスタンスを示すようになる(そのインスタンスに成り代わってしまうイメージ)
・だから、outさんは共に与えられたパスでファイルを開いた_outさんになってしまう
・そして、その与えられたブロック内で呼ばれたwriteメソッドは、オーバライドされたout.value.writeであるので、結局_outさんが書く事になる

うーん。分かったような、分からんような。。withValueメソッドがset(そしてvalueがget)に相当していることは分かった。

なお、ここでwriteが書かれているような、メソッドに渡されるブロック(=クロージャ?/この表現も間違いな気がします)は、マニュアルではthunkとなっていた。

金曜日, 5月 01, 2009

[Lift] 作ってゆく流れは

基本的には以下流れ(yoroyoroさんライブコーディング資料から)。

0.コアとなるデータモデルを定義(MappedLongIndexとかをextendsする)
1.そのデータを記入するためのテンプレートを作成(webapp以下)
2.そのテンプレートで使うsnippetを作成(=入力フォーム)
3.それをBootにPath登録(メニュー化+ACL)
4.見るページのテンプレートを作る
5.そこで必要となるsnippetを作る
6.それをBootにPath登録

1,2,3と4,5,6みたいに、テンプレート作ってsnippet当ててBootに入れる。

追伸:
Liftはやっぱり大きめですね。
sweetというScalaで書かれたフレームワークもあるようで。。

水曜日, 4月 29, 2009

[Scala] jettyが止まらない!?(netbeans)

ScalaのサポートはEclipseのpluginよりnetbeansのそれのほうが優れている(v6.5.1で見たとき)。
が、netbeansでlift開発をするとき、起動したjettyを落とすことができない、、と思っていたら、やはりissueとして登録されており、暫定対処もある様子なのでメモ。
http://wiki.netbeans.org/TaT_ShutdownJettyStartedByMavenUsingNB

via kwout

土曜日, 4月 25, 2009

[Scala] システムトレイで

システムトレイにアイコンを表示して、さらにメッセージボックスに日本語を出す実験。

import java.awt.AWTException;
import java.awt.Image;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.SystemTray;
import java.awt.TrayIcon;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.util.Calendar;
import java.util.Date;

import javax.imageio.ImageIO;

object Alarm2 {
var clockImage:Image = ImageIO.read(new File("clock.png"));
var alarmImage:Image = ImageIO.read(new File("alarm.png"));;
var icon:TrayIcon = new TrayIcon(clockImage);

var alarmTime:Date = new Date();

def main(args : Array[String]){
var tray:SystemTray = SystemTray.getSystemTray();

var menu:PopupMenu = new PopupMenu();
var item:MenuItem = new MenuItem("表示");
item.addActionListener(new ActionListener() {
def actionPerformed(event:ActionEvent):Unit = {
icon.displayMessage("Alarm", "メッセージ!", TrayIcon.MessageType.INFO);
println("message was displayed.");
}
});
menu.add(item);
item = new MenuItem("終了");
item.addActionListener(new ActionListener() {
def actionPerformed(event:ActionEvent):Unit = {
System.exit(0);
}
});
menu.add(item);

icon = new TrayIcon(clockImage, "アラーム", menu);
icon.setImage(alarmImage);

tray.add(icon);
}
}

じゃじゃ馬さんを参考に。ちなみに画像も使わせて頂きました(*)。

日曜日, 4月 19, 2009

[Scala] NB6.7とScala

v6.5ではmavenとの連携が悪い(環境変数を渡せない)ので、まだβではあるがv6.7へ移行。
当初Scalaプラグインが動かず困っていたが、暫定対応版(!?)を発見。

updates.xml.gzはダウンロードするものではなく、NetBeansのツール>プラグイン>設定>追加、で足して使う(使用可能なプラグインにScalaが出てくる)。

今のところv6.5でやれていたメソッド補完などは無事に動いている(Jettyが止まらない現象は(ある意味当然)v6.7にしても出続けているのでかっこ悪いがカスタムターゲットでjetty:stopする作戦をまま踏襲)。

土曜日, 4月 18, 2009

[Solr] GoSenを使う

Javaで形態素解析ライブラリはもうSenしかない状況、、だと思っていましたが、(ちょっと途中で投げ出されている感はあるものの)GoSenのほうが辞書作成もJavaだけでできる等、整備されていて良さそうです。
ただ、Senはトークナイザだけを提供しているので、Solrで使うにはLucene-jaというのを別途取ってきて、そこに入っている"アナライザ"経由で使わなくてはなりません。
つまり、(Lucene-jaの)アナライザが使うトークナイザを、SenからGoSenに変えればよい。。のですが、GoSenはSenから多少構成が変わっているため「ただjarを入れ替え」るだけでは動きません。

細かくはまた別に書こうと思いますが、hideakiさんのブログを参考に、
・Lucene-ja(のSenTokenizer.javaを)書き換え
・無いと不便なbuild.xmlを作成
としたlucene-ja-gosenセットを作りましたので、上げておきます(JDK6で作ったので5で使うならlib以下にあるgosen.jarとか作り直しかも)。

ちなみに、GoSenでもsen.xmlは必要ですが(厳密にはこれはLucene-ja側で使うファイルなので当たり前)、testdata/dictionary/dictionary.xmlをコピーして使えばOKです。

簡単に使い方を。

1.Lucene-ja-gosenをダウンロードして解凍(DIR-Aとする)
2.中のGoSen.tgzをさらに解凍(DIR-Bとする)
4.DIR-B/testdata/dictionaryへ移動してant(辞書作成)
3.sen/confとディレクトリを掘る
5.そのディレクトリへdictionaryで出来たファイルをコピー
 cp *.sen sen/conf
6.そのディレクトリへ以下リネームしてコピー
 mv dictionary.xml sen/conf/sen.xml
7.動かしたいSolrのWEB-INF/libへ移動して以下コピー(※追加参照)
 cp DIR-A/lucene-ja-gosen*.jar (Solrの)WEB-INF/lib
 cp DIR-B/lib/gosen*.jar (Solrの)WEB-INF/lib
8.ココを参考にSolrのschema.xmlへ組込み(senの場合と全く同じで)

/sen/confは起動時の"-Dsen.home"指定を使いたくないからココにしているだけなので変更は可能です。が、辞書とsen.xmlは同じ場所に置きましょう。

追加:
 手順の7は、Solr自体がbuildできる状態なら、build.xmlと同じディレクトリにあるlib以下にこれらjarを入れておけば、適当に(WEB-INF/libに)はいるようなwarを作ってくれます。

[Lift] JavaRebelを使う

Liftのアプリに対しても、コンテナをTomcatにすれば、今はやりの(?)JavaRebelを使ってホットデプロイを実現できるらしい。
http://wiki.liftweb.net/index.php?title=JavaRebel#Tomcat

via kwout

これで開発生産性(この単語は意味を持たなくなってきたけど)はあがりそうです、、、が、よく見るとJavaRebelって商用なんですね。残念。。。

補足:
日本の方が、thick4というのを開発中な様子。

金曜日, 4月 17, 2009

[Life] Liftのサンプル

ScalaのフレームワークなLiftと格闘中。GAE/Jで動くのはいつの日か。

なかなか説明を読んでも難しく(ゆろよろさんのが一番分かり良いと思う)、かつシンプルなサンプルが少ない(すぐDB連携とか見せちゃう)ので、シンプルなサンプルソースをmvn出来る形でまるっと置いておきます。
特にbootstrapのMenuはくせ者なので(ACL機能の代わりもしちゃう)、その部分、ソースにコメントしてあります。

ちなみに、Mavenでfscを使うには以下です(本家にありました)。
\apache-maven-2.0.9\bin\mvn scala:cc -Donce=true

木曜日, 4月 16, 2009

[Solr] Nutchでサイトクロール

Solrを使ってサイトクロールを行う方法が、公開されていたので、

やってみた。

Nutchはウェブスパイダーとしてのクロール機能を提供している。内部に分散ファイルシステムたるHadoopを持っていのだが、今回はこれは使わない方法(のようだ)。

- - - -

1. Nutchを<a href="http://hudson.zones.apache.org/hudson/job/Nutch-trunk/">ダウンロード</a>し、解凍する。

 tar xzf apache-nutch-1.0.tar.gz

2. Solrの設定を行う

Nutchの中にはschema.xmlなどSolrを連携して使うためのサンプルの設定ファイルが含まれています。

a. schema.xmlの配置
apache-nutch-1.0/conf to directory apache-solr-1.3.0/example/solr/conf

b. “content”フィールドの設定変更

<field name=”content” type=”text” stored=”true” indexed=”true”/>

c. クローラ用リクエストハンドラの作成

以下をsolrconfig.xmlに追記します。

<requestHandler name="/nutch" class="solr.SearchHandler" >
<lst name="defaults">
<str name="defType">dismax</str>
<str name="echoParams">explicit</str>
<float name="tie">0.01</float>
<str name="qf">
content^0.5 anchor^1.0 title^1.2
</str>
<str name="pf">
content^0.5 anchor^1.5 title^1.2 site^1.5
</str>
<str name="fl">
url
</str>
<str name="mm">
2&lt;-1 5&lt;-2 6&lt;90%
</str>
<int name="ps">100</int>
<bool hl="true"/>
<str name="q.alt">*:*</str>
<str name="hl.fl">title url content</str>
<str name="f.title.hl.fragsize">0</str>
<str name="f.title.hl.alternateField">title</str>
<str name="f.url.hl.fragsize">0</str>
<str name="f.url.hl.alternateField">url</str>
<str name="f.content.hl.fragmenter">regex</str>
</lst>
</requestHandler>

3. Solrを起動しておきます。

cd apache-solr-1.3.0/example
java -jar start.jar

4. Nutchの設定を行います。

a. apache-nutch-1.0/confにあるnutch-site.xmlの中身を以下のものにまるっと入れ替えます。
ここでは、クローラの名前や、有効化するプラグイン、ドメイン単位でみたときの最大同時接続数などを指定します。

<?xml version="1.0"?>
<configuration>
<property>
<name>http.agent.name</name>
<value>nutch-solr-integration</value>
</property>
<property>
<name>generate.max.per.host</name>
<value>100</value>
</property>
<property>
<name>plugin.includes</name>
<value>protocol-http|urlfilter-regex|parse-html|index-(basic|anchor)|query-(basic|site|url)|response-(json|xml)|summary-basic|scoring-opic|urlnormalizer-(pass|regex|basic)</value>
</property>
</configuration>

b. apache-nutch-1.0/confにあるregex-urlfilter.txtの中身を書き換えます。

-^(https|telnet|file|ftp|mailto):
 
# skip some suffixes
-\.(swf|SWF|doc|DOC|mp3|MP3|WMV|wmv|txt|TXT|rtf|RTF|avi|AVI|m3u|M3U|flv|FLV|WAV|wav|mp4|MP4|avi|AVI|rss|RSS|xml|XML|pdf|PDF|js|JS|gif|GIF|jpg|JPG|png|PNG|ico|ICO|css|sit|eps|wmf|zip|ppt|mpg|xls|gz|rpm|tgz|mov|MOV|exe|jpeg|JPEG|bmp|BMP)$
 
# skip URLs containing certain characters as probable queries, etc.
-[?*!@=]
 
# allow urls in foofactory.fi domain
+^http://([a-z0-9\-A-Z]*\.)*lucidimagination.com/
 
# deny anything else
-.

5. 初期URLリスト(クロール起点)ファイルを作成します。

mkdir urls
echo "http://www.lucidimagination.com/" > urls/seed.txt

6. 初期URLのページをクロールしてNutchのcrawldbに格納します。

bin/nutch inject crawl/crawldb urls

konpyuta:~/work/nutch tf0054$  bin/nutch inject crawl/crawldb urls
Injector: starting
Injector: crawlDb: crawl/crawldb
Injector: urlDir: urls
Injector: Converting injected urls to crawl db entries.
Injector: Merging injected urls into crawl db.
Injector: done
konpyuta:~/work/nutch tf0054$

7. 取得したページを解析してコンテンツを抜き出します。

bin/nutch generate crawl/crawldb crawl/segments

konpyuta:~/work/nutch tf0054$ bin/nutch generate crawl/crawldb crawl/segments
Generator: Selecting best-scoring urls due for fetch.
Generator: starting
Generator: segment: crawl/segments/20090416032246
Generator: filtering: true
Generator: jobtracker is 'local', generating exactly one partition.
Generator: Partitioning selected urls by host, for politeness.
Generator: done.
konpyuta:~/work/nutch tf0054$

上のコマンドで、crawl/segments以下に新たなクロール対象のディレクトリを作成します。 that at this point contains files that store the url(s) to be fetched. In the following commands we need the latest segment dir as parameter so we’ll store it in an environment variable:

export SEGMENT=crawl/segments/`ls -tr crawl/segments|tail -1`

クロールを開始します。

bin/nutch fetch $SEGMENT -noParsing

konpyuta:~/work/nutch tf0054$ bin/nutch fetch $SEGMENT -noParsing
Fetcher: Your 'http.agent.name' value should be listed first in 'http.robots.agents' property.
Fetcher: starting
Fetcher: segment: crawl/segments/20090416032246
Fetcher: threads: 10
QueueFeeder finished: total 1 records.
fetching http://www.lucidimagination.com/
-finishing thread FetcherThread, activeThreads=1
-finishing thread FetcherThread, activeThreads=1
-finishing thread FetcherThread, activeThreads=1
-finishing thread FetcherThread, activeThreads=1
-finishing thread FetcherThread, activeThreads=1
-finishing thread FetcherThread, activeThreads=1
-finishing thread FetcherThread, activeThreads=1
-finishing thread FetcherThread, activeThreads=1
-finishing thread FetcherThread, activeThreads=1
-activeThreads=1, spinWaiting=0, fetchQueues.totalSize=0
-activeThreads=1, spinWaiting=0, fetchQueues.totalSize=0
-finishing thread FetcherThread, activeThreads=0
-activeThreads=0, spinWaiting=0, fetchQueues.totalSize=0
-activeThreads=0
Fetcher: done
konpyuta:~/work/nutch tf0054$

コンテンツをパースします。

bin/nutch parse $SEGMENT

konpyuta:~/work/nutch tf0054$ bin/nutch parse $SEGMENT
konpyuta:~/work/nutch tf0054$

Then I update the Nutch crawldb.
updatedb コマンドを使うと、先にとってきたページのパースと、もうパースされて見つかっているURLページの取得をパイプライン的に並行して行わせることができます。なお、Nutchは取得した各ページの状態を覚えているため、同じページを何度も取得しに行ってしまうことはありません。

bin/nutch updatedb crawl/crawldb $SEGMENT -filter -normalize

konpyuta:~/work/nutch tf0054$ bin/nutch updatedb crawl/crawldb $SEGMENT -f
ilter -normalize
CrawlDb update: starting
CrawlDb update: db: crawl/crawldb
CrawlDb update: segments: [crawl/segments/20090416032246]
CrawlDb update: additions allowed: true
CrawlDb update: URL normalizing: true
CrawlDb update: URL filtering: true
CrawlDb update: Merging segment data into db.
CrawlDb update: done
konpyuta:~/work/nutch tf0054$

これまでが、クロールの1サイクルとなります。

8. linkdbを作る

bin/nutch invertlinks crawl/linkdb -dir crawl/segments

konpyuta:~/work/nutch tf0054$ bin/nutch invertlinks crawl/linkdb -dir crawl/segments

LinkDb: starting
LinkDb: linkdb: crawl/linkdb
LinkDb: URL normalize: true
LinkDb: URL filter: true
LinkDb: adding segment: file:/Users/tf0054/work/nutch-2009-04-15_04-01-57/crawl/segments/20090416032246
LinkDb: done
konpyuta:~/work/nutch tf0054$

9. 全セグメントからSolrにコンテンツを送る

bin/nutch solrindex http://127.0.0.1:8983/solr/ crawl/crawldb crawl/linkdb crawl/segments/*

10. Solrにて検索可能となったか確認する。

http://127.0.0.1:8983/solr/nutch/?q=solr&amp;version=2.2&amp;start=0&amp;rows=10&amp;indent=on&amp;wt=json

- - - - -

水曜日, 4月 15, 2009

[Scala] スクリプト実行!

Javaで要求される杓子定規な、というか精緻な記述が省けるだけでもScalaを利用する価値はあるというものだが、さらにスクリプト実行(コンパイルして.classを作ってからじゃなく)できるとその価値はより高くなる。

以下、Windowsでスクリプト実行する場合(test.batなどとして保存されることを想定)。
::#!
@echo off
call c:\scala-2.7.4.final\bin\scala %0 %*
goto :eof
::!#

class HelloFunction {
def apply() = "hello"
def apply(name: String) = "hello " + name
}

// メソッド省略の例
val hello = new HelloFunction
println(hello()) // => "hello"
println(hello("Dean")) // => "hello Dean"

// コマンドライン引数処理の例
for(i <- 1 to (args.length)){
print(i + ",");
}

日曜日, 4月 12, 2009

[Java] SenよりもGoSen?

ちょっと前に見たSenは、しかしバグ付きだという噂だし、どうしたものかと思っていたら、GoSenというのもあるらしい。

PerlやJCLからの依存性を排除したとのことだが、しかし、これも本家のURLがNotFoundで、、どうもJavaでこの手のアプリは保守するのが面倒になるものなのか(CMeCabの中にあるような、辞書不要のタイプもある)。


書きながら調べていたら、早速(Senよか治ってるようだけど)バグ情報も。あとLucene対応の書換えについて。

土曜日, 4月 11, 2009

[Life] GAE/Javaとは

Javaのアカウントが来たので、Liftの稼働実験をしつつ、@ITの記事を読む。
昨日まで「負荷による拡張はgoogleさんがよしなにやってくれる」という言説の意味(どうやって水平分散に回せているのか)が、まったく分からなかったのだけど、やっと理解。
シングルスレッドだからですね。
ウェブからの各アクセスを一筆的に考えると、確かに途中で抜けられたりしなければ、筐体が分かれてても(2本の干渉が無いから)ざーっと勝手に流れて行って問題ないんですね。。なるほど。というか確かに。

追伸:
面白い潜入調査をしている方がいた。あと、mavenからの操作も出来るようになった。

木曜日, 4月 09, 2009

[Lift] derbyの中を調べる

Liftの例(todo)では、標準ではapacheのderbyが使われており、この中にテーブルなどが自動生成される。この、自動生成されたテーブル定義やらを見る方法を調べたのでメモ。

D:\work\Scala\todo>"d:\Documents and Settings\00962724\デスクトップ\db-derby-10.5.1.1-bin\bin\ij.bat"
ij バージョン 10.5
ij> connect 'jdbc:derby:d:\work\scala\todo\lift_example';
ij> describe users;
COLUMN_NAME |TYPE_NAME|DEC&|NUM&|COLUM&|COLUMN_DEF|CHAR_OCTE&|IS_NULL&
------------------------------------------------------------------------------
ID |BIGINT |0 |10 |19 |AUTOINCRE&|NULL |NO
FIRSTNAME |VARCHAR |NULL|NULL|32 |NULL |64 |YES
LASTNAME |VARCHAR |NULL|NULL|32 |NULL |64 |YES
EMAIL |VARCHAR |NULL|NULL|48 |NULL |96 |YES
LOCALE |VARCHAR |NULL|NULL|16 |NULL |32 |YES
TIMEZONE |VARCHAR |NULL|NULL|32 |NULL |64 |YES
PASSWORD_PW |VARCHAR |NULL|NULL|48 |NULL |96 |YES
PASSWORD_SLT |VARCHAR |NULL|NULL|20 |NULL |40 |YES
TEXTAREA |VARCHAR |NULL|NULL|2048 |NULL |4096 |YES
SUPERUSER |SMALLINT |0 |10 |5 |NULL |NULL |YES
VALIDATED |SMALLINT |0 |10 |5 |NULL |NULL |YES
UNIQUEID |VARCHAR |NULL|NULL|32 |NULL |64 |YES

12 行が選択されました
ij> describe todo;
COLUMN_NAME |TYPE_NAME|DEC&|NUM&|COLUM&|COLUMN_DEF|CHAR_OCTE&|IS_NULL&
------------------------------------------------------------------------------
PRIORITY |INTEGER |0 |10 |10 |NULL |NULL |YES
ID |BIGINT |0 |10 |19 |AUTOINCRE&|NULL |NO
DESC_C |VARCHAR |NULL|NULL|128 |NULL |256 |YES
DONE |SMALLINT |0 |10 |5 |NULL |NULL |YES
OWNER |BIGINT |0 |10 |19 |NULL |NULL |YES

5 行が選択されました
ij> show tables;
TABLE_SCHEM |TABLE_NAME |REMARKS
------------------------------------------------------------------------
SYS |SYSALIASES |
SYS |SYSCHECKS |
SYS |SYSCOLPERMS |
SYS |SYSCOLUMNS |
SYS |SYSCONGLOMERATES |
SYS |SYSCONSTRAINTS |
SYS |SYSDEPENDS |
SYS |SYSFILES |
SYS |SYSFOREIGNKEYS |
SYS |SYSKEYS |
SYS |SYSROLES |
SYS |SYSROUTINEPERMS |
SYS |SYSSCHEMAS |
SYS |SYSSTATEMENTS |
SYS |SYSSTATISTICS |
SYS |SYSTABLEPERMS |
SYS |SYSTABLES |
SYS |SYSTRIGGERS |
SYS |SYSVIEWS |
SYSIBM |SYSDUMMY1 |
APP |TODO |
APP |USERS |

22 行が選択されました
ij> exit
> ;
D:\work\Scala\todo>

木曜日, 4月 02, 2009

[Scala] 遅延評価の例

Scalaで遅延評価。引数の型指定部分で":"の後ろに"=>"を挟み込むことで指示できる(参考)。
#!/bin/bash
exec ~/work/scala/bin/scala "$0" "$@"
!#

def until(f: => Boolean)(p: => Unit) {
while (!f) p
}

var i = 0
until (i > 10) {
print(i + " ")
i += 1
}
println
この例で遅延評価を外す("until(f:Boolean)"とやる)と、
・最初に"i>10(でi=0)"がfalseと評価される
・その結果(false)がuntil関数に渡ってしまう
ため、(trueと渡って来たものを再評価できるわけもなく)無限ループに陥ってしまいます。

なお、"(p: => Unit)"もその意味では遅延評価の指定がなされている、つまり「関数とは要するに引数付き遅延評価式で」ということで、具体的にはココを"(p:Unit)"とすると、
・1回だけuntilに渡したブロック(printとか)を処理して
・戻値が無い(Unitな)whileが回り続ける(iは1になったが以後そのまま)
状態に陥ってしまう。なのでここでも遅延評価が活躍している(んだと思う)。

月曜日, 3月 30, 2009

[Linux] JMX/REST変換

TomcatのManagerにもJMXProxyがあるのでそれで良いような気はしますが、こんなのもあるようです。
http://code.google.com/p/polarrose-jmx-rest-bridge/

via kwout

ダウンロードからは何も取れないですが、ソースのところをくだるとありそう。

日曜日, 3月 22, 2009

[Life] ScalaでSolrj!

下のソースで、以下条件下にて、
 ・Solr(v1.4-dev/今のtrunk)のサーバ相手に
 ・Solr(v1.3)のsolrjライブラリで
実行すれば、ABROADのスポット情報1件をインターネットから取得してうまく日本語も投入してくれることを確認しました。

なぜv1.4のsolrjを組み込むとうまく動かないのか。。(補足:SOLR-973にタイムリーにはまっていたようで、今updateしたらサーバもsolrjもv1.4で正常動作しました!)


// >\scala-2.7.3.fin\bin\scalac -cp c:\apache-solr-1.3.0\dist\solrj-lib\commons-httpclient-3.1.jar;c:\apache-solr-1.3.0\dist\apache-solr-solrj-1.3.0.jar;c:\apache-solr-1.3.0\dist\apache-solr-core-1.3.0.jar;c:\apache-solr-1.3.0\dist\apache-solr-common-1.3.0.jar getAB.scala
// >\scala-2.7.3.fin\bin\scala -cp .;c:\apache-solr-1.3.0\dist\solrj-lib\commons-httpclient-3.1.jar;c:\apache-solr-1.3.0\dist\apache-solr-solrj-1.3.0.jar;c:\apache-solr-1.3.0\dist\apache-solr-core-1.3.0.jar;c:\apache-solr-1.3.0\dist\apache-solr-common-1.3.0.jar;c:\apache-solr-1.3.0\dist\solrj-lib\commons-logging-1.0.4.jar;c:\apache-solr-1.3.0\dist\solrj-lib\commons-codec-1.3.jar getAB

import java.util.ArrayList;
import java.util.Collection;

import scala.xml.parsing.ConstructingParser;
import scala.io.Source;
import scala.xml.PrettyPrinter;

import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.CommonsHttpSolrServer;
import org.apache.solr.common.SolrInputDocument;

object getAB {
def main(args : Array[String]) {

var solr = new CommonsHttpSolrServer("http://localhost:8983/solr");
val url = "http://webservice.recruit.co.jp/ab-road/spot/v1/?key=xxx4e359bbbbe6f4&spot=000921";

val data = Source.fromURL(url,"UTF-8");
val elem = ConstructingParser.fromSource(data,true).document().docElem;

var tmp1:String = (elem\"spot"\"description").text;
//var tmp1:String = new PrettyPrinter(80 /*width*/, 2 /*indent*/).format(elem);
//String変数(tmp1)から(UTF8エンコードな)バイトストリームで取り出し(そこから)UTF8のStringを作る
var tmp2:String = new String(tmp1.getBytes("UTF-8"),"UTF-8");
var tmp3:String = new String(tmp2.getBytes("MS932"),"MS932");

//System.out.println( "ORG:\n"+tmp1 );
System.out.println( "UTF8:\n"+tmp2 );
System.out.println( "SJIS:\n"+tmp3 );

var doc1 :SolrInputDocument = new SolrInputDocument();
doc1.addField("id", "id1", 1.0f);
doc1.addField("name", "doc1", 1.0f);
doc1.addField("price", 10);

var doc2 :SolrInputDocument = new SolrInputDocument();
doc2.addField("id", "id2", 1.0f);
doc2.addField("name", "doc2", 1.0f);
doc2.addField("price", 20);
doc2.addField("desc_t", tmp2);

var docs :Collection[SolrInputDocument] = new ArrayList[SolrInputDocument]();
docs.add(doc1);
docs.add(doc2);

solr.add(docs);
solr.commit();
}
}

お恥ずかしくも、Scalaっぽくはまったく無い書きっぷりですが、これでもJavaよりはだいぶ記述量が少ない気がします。

追伸:
 リクルートwebAPIを使うときのキーは、(ソースには)ダミーを入れています。

金曜日, 3月 20, 2009

[Life] ScalaでJSP!

ScalaのXMLサポートを実装した"Burak Emir"さんの書かれた"ScalaでJSP(@Tomcat)"(改題)を参考に。ソースにはantのbuildが付いているので、これを使うと楽に準備できる。私は、

tomcat.home = D:\\apache-tomcat-5.5.27
servlet-api.jar = ${tomcat.home}/common/lib/servlet-api.jar

scala.home = D:\\scala-2.7.2.final
scala-library.jar = ${scala.home}/lib/scala-library.jar
scala-compiler.jar = ${scala.home}/lib/scala-compiler.jar

として実行しました。なお、以下ライブラリは「1フォルダにまるっと集めて、そこにCLASSPATH通してantしてね」とあったのでその通りに。

 ・fjbg.jar(これは何?→何故か入っていなかったのでダウンロード)
 ・tools.jar(JDKの中にあるライブラリ)
 ・scala.jar(不明→scala-compiler.jarをコピーした)

結構すんなり。ScalaでウェブといえばWebFlavorliftまで行ってしまう感がありましたが、これならお手軽ですね。

木曜日, 3月 19, 2009

[Linux] EC2の管理ツール

メモっていたつもりが、書いていなかったので今更ながら。

RightScaleでは、動的にサーバ台数を増やしてゆく仕組み(RightScriptというマクロ的なもので実現する様子)を提供。
そのOSSとしてScalarというのが公開(元は商用)されているので、こっちをカスタマイズするのとどっちが便利か。

でもどちらにせよ"遠い向こうでインスタンスを上げる"というのが普通な世界になってきましたね。

水曜日, 3月 18, 2009

[Java] commons-fileuploadで受け取る

curlを使って、apacheのcommon-uploadで受信できる形で送信する方法。
D:\work\curl-7.16.2>curl -F "name=@test.xml" http://192.168.11.150:20050/uploader

nameのところは何でもよい(参考)。Windows版のcurlはここからダウンロードできます。

金曜日, 3月 13, 2009

[Solr] wgetでPOSTする

以前Solrにデータ投入をする際にはcurlを使っていた(本家でもそうしていた)。
が、これは普通にwgetでも出来るんですね。
wget -q -O - --header "Content-type:text/xml; charset=utf-8" --post-file="/var/tmp/test.xml" http://localhost:20050/apache-solr-1.3.0/update

curlって、いっても標準では入っていない環境も多いので(参考ページ)。

月曜日, 3月 09, 2009

[GoogleMap] マイマップとGoogleMapAPIと

GoogleMapのマイマップ機能はとても使いやすく、ちょろっとしたイベントの地図を作るのにベスト。だけれど、中にルート案内と作者(のマイマップへのリンク)が表示されてしまうのが玉に傷か。
これが嫌なときは、一度rss(georss/マイマップのツールバー、"GoogleEarthで表示"の左隣にある)を経由して、それをAPIで使えばよい、、のだけど、そうするとせっかく変えたアイコンが、全て同じ青いピンのに変えられてしまう様子(でもこれは仕様っぽい)。
うーん。やっぱりキチンと自前ですしょうか。

日曜日, 3月 08, 2009

[MT] カスタムフィールド

MovableType4.1から入ったカスタムフィールドは、エクスポート機能では取り出せない様子。DBのmt_entryテーブルからとろうとしたのだが、バイナリ列で連結されており。。

ただ、入力値は普通に入っているので、Perlなどで丸呑みし、無理やり置き換えは可能。
手動で投入したときは(mt_entry_idの)シーケンス上げを忘れずに。

土曜日, 3月 07, 2009

[Scala] Twitterの移行について

ずいぶん前の話題だが、TwitterのバックヤードScala化に関する記事の要点整理をしてみた。

>>前提

Twitterは、フロントはRailsに依存しており、逆にOffload観点から、キャッシュの失効処理等に、キューイングの仕組みを使った非同期処理が多数あり、それだけデーモンアプリが必要となるシステム構成。

>>なぜ移行?(システム的理由)

RubyはGreenThreadでカーネルスレッドを使うことはできず、プロセッサに依存してしまい、マルチコア環境での性能が出ない。これに対処するため複数プロセスを上げる方向に行くのだが、そうなるとメモリが大量に必要となり、さらにRubyのガベコレ性能が(Javaのそれに比べて)悪いこともあり、限界を感じていた。

(これに対し)JVMは、スクリプト言語が苦手とする長時間動かし続けるデーモンアプリを書く環境として適切。

また、動的型付けにより必要となる「型確認」の計算量が莫大になっていたという問題もあった。たとえば障害復旧時の処理時間が長くなりすぎていた。

JRubyへの移行も考えたが、オリジナルレベルのパフォーマンスは出ないこと、またそもそもRailsが動かなかったことから不採用とした。ただし将来的に再考の余地はあると考えている。

パフォーマンスという観点では、mutableとimmutableに注意すること。JITコンパイラはimmutableなオブジェクト(状態変化がない≒必然的にスレッドセーフとなる)であれば、最適化してゆくことができる。

>>なぜ移行?(その他の理由)

これまでのエンタープライズな職場を去ったあと、楽しく書いてゆきたい(表現してゆきたい)という理由から、(書いていてつまらない言語(C++など)を卒業し)Ruby等の高級言語に転向するプログラマをたくさん見てきた。

>>移行してどうだったか

とても上手くいった(性能向上及び動作安定化の観点から)。

静的型付けは、(Rubyでもわざわざ型宣言を使っていた位だから)まったく手間ではなかった。

actor部分とハイスケーラビリティを確保するところでいくつか問題が出たが、致命的なものはまったく無かった(良い意味で想定外)。

actorでの並列処理の記述はクライアントからの接続を受ける部分などを中心に極めて有効であった。

(中を再考している過程で)逆にactorまでは必要とせず、逆にthreadのほうが適している場合もあることが分かった。そしてこのときでも、(actorを)threadに書き戻すことは置換するレベルでありとても簡単だった(書き換えでいうと、普通にlockすればいいだけという場合も)。

いくつかパフォーマンス観点からJavaのクラスを直接利用する場面があったが、このようなことができることもScalaの利点だ。

>>切り替えで気をつけることは

関数型という考え方になれること(メンタリティ)。ただしこれは使っているうちに慣れてくる部分が大きい。その意味でもすぐにビジネスが絡むシステムに使うのではなくスタートアップで利用してゆくべき。

(型やその中身ベースでの)パターンマッチを使いこなせることは、効率的記述を行うためにとても重要だ。

IDEがモノによっては(Scalaの)サポートが完全ではないため注意が必要。TwitterではIntelliJとEmacsのそれを使っている。

インタプリタではなくcompile-deployが必要になることも、(慣れの問題かもしれないが)いらいらさせる原因となりうる。この点はProjectごとにケアが必要だとはいえ、JavaRebelを使えば解決できる。

>>その他

Scalaを選択する決断をするまでには煩悶してきた。でも(Rubyを使ってきた我々が)C++などの中級言語に移行することは、とても大きなリスクを負うことになり、かつ困難を伴うと判断した。

2009年度内には、メインどころのトラフィックを稼いでいるAPIをScalaベースに切り替える予定。

日曜日, 2月 22, 2009

[Perl] デーモンプログラムを書くには

今まで全く読んだ事がなかった"perlfaq8"より。

psコマンドなど、外部から見えるコマンドラインを実際に書き換えるには、$0変数を書き換える。

例えばsendmailのようなデーモンプログラムは以下ように状態を設定する:
$0 = "orcus [accepting connections]";

なるほどー。そんなことができるんだ。。

ちなみに、デーモンプログラムというかapache的なデーモンを書くためには、Parallel::Preforkがとても便利です(中で使われているProc::Wait3というのは初めて知りました)。

金曜日, 2月 20, 2009

[Life] XMLをコマンドラインで

GUIが使えるときは、折り畳めるエディタを使えばよいのだが、ターミナル操作のときにXMLで書かれたファイルの記述を確認するのは、とても難儀する。。。

と思っていたらxpathコマンドを発見。以下のように使う。
D:\apache-solr-trunk\example\solr\conf>xpath schema.xml "(//fieldtype|//fieldType)/@name"


これにより、この例ではsolrのスキーマに設定されいてるフィールドに与えられる型一覧を取得することが出来る。便利!

木曜日, 2月 19, 2009

[Java] Senのバグ

Javaで形態素解析をするときに、使われるSenだが本家からダウンロードできるオリジナルソースはバグ付き。これはgnarlさんのページに修正方法が詳しく記載されている様子。

土曜日, 2月 14, 2009

[Linux] googleクローラはJavascriptが読める

googleのクローラがJavascriptに対応していそう、という記事を発見。
http://searchengineland.com/an-update-on-javascript-menus-and-seo-16060

via kwout

常識でしょうか。私は知りませんでした。。当然の流れとは言え、すごいことだと思います。Flashが読まれるようになったことは知っていて、こちらは奏すべきだろうと思いましたが。。

金曜日, 2月 13, 2009

[Flash] PixelBlender

Flasherな人にしたらいまさらな話なのだと思うが、PixelBlenderがすごい。

画像にぷるん、とした動きをさせたいと思っていたのが、もろできるようです。
というかこういうのを思いのままに作れるというのであれば(センスは相当必要とされそうだけど)、かなり勉強する価値ありそう。

日曜日, 1月 25, 2009

[Linux] Kirin

相当今更感があるのですが、Kirinという画像のリサイズなどが行える、画像変換のWebAPIを使ってみました。アプリキーをもらってから使うものなのですが、、説明に書かれている"呼び出し元サーバ名"って、、変換したい元画像が置いてあるサイトのドメイン名を書くのですね。。。うーん。
http://kirin.tatamilab.jp/

via kwout

たまたまGIF画像のリサイズをしてみたので気がついたのですが、戻しはJPGなんですね(JPGのコメントにはしっかり"Kirin Library 1.11 2009/01/25 0"と入っていました)。

火曜日, 1月 20, 2009

[Scala] TwitterもScalaで

Twitterでユーザ間のメッセージ送受信を実装するために使っている(のであろう)、キューイングシステムが、Rubyから(!)いつのまにかScalaにて書き直された、とのこと。その上これはソースも公開されているので、ぜひ勉強がてら読んでみたい(最近githubが増えてきましたね9。

[Perl] 携帯サイトのアクセス分析!

MovableTypeを携帯対応する一番簡単な方法は、mt4iなわけですが、このアクセス解析をapacheログでやるのも面倒に思いました。
なので、最近出たGA4Kという、GoogleAnalyticsに携帯アクセスを流すPHPライブラリ(まぁ原理的にはココでも紹介されているとおり、たいしたことはないのですが)を、Perlモジュールに作り変えてみました(以下ソース。ウェブプロパティID(utmac)とウェブサイトURL(utmhn)は書き換えてください!)。
#
# This code is test module for k-tai web site (ex mt4i)
#
package Onamon;

sub accessGoogleAnalystics{

use Sys::Syslog;
require HTTP::Request;
require LWP::UserAgent;

my $utmac = 'UA-179xxxx-2';
my $utmhn = 'http://onamon.com';
my $utmn = 1000000000 + rand(9999999999 - 1000000000);
my $cookie = '';
my $uservar = '';
my $random = 1000000000 + rand(2147483647 - 1000000000);
my $today = time();
my $referer = $ENV{'HTTP_REFERER'};
my $utmp = $ENV{'REQUEST_URI'};

if($ENV{'HTTP_X_UP_SUBNO'}){
$uservar = $ENV{'HTTP_X_UP_SUBNO'};
}elsif($ENV{'HTTP_X_DCMGUID'}){
$uservar = $ENV{'HTTP_X_DCMGUID'};
}elsif($ENV{'HTTP_X_JPHONE_UID'}){
$uservar = $ENV{'HTTP_X_JPHONE_UID'};
}
$cookie = $uservar;

my $urchinUrl = 'http://www.google-analytics.com/__utm.gif?utmwv=1&utmn='.$utmn.'&utmsr=-&utmsc=-&utmul=-&utmje=0&utmfl=-&utmdt=-&utmhn='.$utmhn.'&utmr='.$referer.'&utmp='.$utmp.'&utmac='.$utmac.'&utmcc=__utma%3D'.$cookie.'.'.$random.'.'.$today.'.'.$today.'.'.$today.'.2%3B%2B__utmb%3D'.$cookie.'%3B%2B__utmc%3D'.$cookie.'%3B%2B__utmz%3D'.$cookie.'.'.$today.'.2.2.utmccn%3D(direct)%7Cutmcsr%3D(direct)%7Cutmcmd%3D(none)%3B%2B__utmv%3D'.$cookie.'.'.$uservar.'%3B';

my $ua = LWP::UserAgent->new;
my $request = HTTP::Request->new(GET => $urchinUrl);
if ($ENV{'HTTP_ACCEPT_LANGUAGE'}) {
$request->header('Accept-language' => $ENV{'HTTP_ACCEPT_LANGUAGE'});
}
if ($ENV{'HTTP_USER_AGENT'}) {
$request->header('User-Agent' => $ENV{'HTTP_USER_AGENT'});
}
my $response = $ua->request($request);

openlog(__FILE__, 'cons,pid', 'local4');
if ($response->is_success) {
syslog('debug', 'OK('
.$ENV{'REQUEST_URI'}
.'^'.$ENV{'HTTP_USER_AGENT'}
.'^'.$ENV{'HTTP_X_DCMGUID'}
.')'
);
} else {
syslog('debug', 'NG');
}
closelog();
}
1;
汚い、というか何も考えていないソースで恥ずかしいですが、一応。mt4iに適用するなら、mt4i.cgiと同じディレクトリに上記ソースをOnamon.pmとして保存し、mt4i.cgiの最初のほうに、
~略~
use FindBin qw($Bin);
use List::Util qw(first);
use HTTP::Date;
use CGI::Carp qw(fatalsToBrowser);

# ★ここから
use Onamon;
if($ENV{'REQUEST_URI'} !~ /(png|jpg)$/){
Onamon::accessGoogleAnalystics();
}
# ★ここまで

my $bin;
my $log_pl;
our %cfg;

BEGIN {
~以下略~
と足します。お名紋贈り物ブログに適用してみたのですが、、果たして動くことやら。

日曜日, 1月 18, 2009

[Perl] CTPP2テンプレートエンジン

CPANのPerlモジュールがひたすらupdateされていて、頑張っている感のあるテンプレートエンジン(C++で書かれていて各種言語でバインディング可能なもの)。
http://freshmeat.net/projects/ctpp2/

via kwout

気になるのでメモ(Perlのモジュールはコチラ)。

土曜日, 1月 10, 2009

[Flash] JPEG格納フォーマット

以下ページに良くまとまっている。
http://pwiki.awm.jp/~yoya/?Flash/JPEG

via kwout

こられとやまさんページのFlashをswfmillで解析中(珍しくFlashLite1.1で出来たスライドショー)。

月曜日, 1月 05, 2009

[Life] XMLファイルをきちんと扱う

最近ミドルウェアの設定ファイルをXMLで書かなくてはならないことが多くなってきた。
可読性が意外と低いので、きちんとXMLを解釈して折りたたみなどができるエディタを探していたのだが、とりあえずjEditでできることまでわかった。

Pluginが1つ必要(その名もXMLというやつ)なのだが、PluginマネージャというGUIでさくっとインストールできる。

希望していた動きをするので、今しばらくはこれで行こうと思う。