D-7 <altijd in beweging>

Day to day life of a Perl/Go/C/C++/whatever hacker. May include anything from tech, food, and family.

2007年11月

今日は突然出かけたくなったので(この前のエントリー参照)、地図を見始めて近くに歩けるところはないかとチェック。目黒に自然教育園はっけーん。ってことでひとっぱしり行ってきた。

入園料300円!さすが白金。園内は要は森だった。悪くないんだけど、東京都下の公園としてはどうしても清澄庭園と比べてしまう。清澄庭園は本当によく整備されてるんだなぁ。まぁともあれ、小一時間ほど森の中を散歩してきた。さぁあとはどこの公園/庭園にいこうかなぁ。

  • 清澄庭園
  • 六義園
  • 砧公園
  • 駒沢オリンピック公園
  • 新宿御苑
  • 浜離宮
  • 有栖川宮記念講演
  • 皇居周辺
  • 代々木公園
あたりはだいたい行ったが、あとキレイなとこっていうとどこかなぁ。

後で調べようhttp://www.tokyo-park.or.jp/search/index.html
    このエントリーをはてなブックマークに追加 mixiチェック

テレビの「働きマン」、シンジと別れる回だったわけだが。いやぁ、仕事できる女性と付き合うとそういう劣等感あるよねぇ、って「あるある」言いながら見てましたよ。相手も年上だと色々あんだろうなぁ、とかおもいつつ、さらに「あるある」と。

でも本当ね、最近「あるある」というか、「あ、そうかぁ、これかぁ」ってことがとても多くて。特に実感してるのが若い輩のにむかついてしょうがない事が多い。今年ですでに3人も20代前半の若者に雷を落としたよ。なんかそれもさぁ、すごいこっちも悲しいのよね。だってくっだらない事なんだもん。「ごちそうさま」が言えない、とかね。でもくだらないからこそ、許せない。その程度の気遣いもできないのか、と。それを見過ごすのも簡単なんだけど、見過ごすとためにならないしさ・・・。怒られた事のない人ってかわいそうだと思うよ。俺ごときが偉そうかもしれんけどね。

さて、某ドキュメンテーションもある程度できた。次はGunghoのドキュメントでも書くか・・・
その前にちょっと遊びに行ってもいいですか。
    このエントリーをはてなブックマークに追加 mixiチェック

speedtest1.pngid:amachangのところに載ってたヤツ。取り急ぎ一発目のトライは280ポイント、380文字/分。なんかかってがよくわからないので今からもう一回やる。
speedtest2.pngで、2回目305ポイント396文字/分。
speedtest3.png3回目266ポイント431文字/分。7個も間違えた。
speedtest4.png7回目のトライで333ポイント464文字/分。id:miyagawaにとりあえず勝ったので満足。
    このエントリーをはてなブックマークに追加 mixiチェック

http://www.nicovideo.jp/watch/sm1416191

これをテレビで見る度に萌えてます。視線がエロい。

さて、今日はPoCo::MQのバグを山のように直しました。Swarmageも結構アップデートした。Gungho::Provider::Throttledが必要な事もわかった。

http://drrobertepstein.com./index.php?option=content&task=view&id=24&Itemid=43

こんなリンクにぶちあたった。

夜は軽く鮭、味噌汁、ご飯を食べた。

ロンハーおもしろかった。

mysql は嫌いだ。

今週来週は忙しい。
    このエントリーをはてなブックマークに追加 mixiチェック

鰤の照り焼き、おかゆ、それにカブの煮物。カブは立派な葉っぱがたくさんついていたので、こちらは軽く炒めて醤油、砂糖、出汁で味付け。カブはちゃんと隠し包丁もいれていい感じで味もしみた。葉っぱはおかゆにとってもあってグー。
    このエントリーをはてなブックマークに追加 mixiチェック

作者であるところのDavid Snopekさんと話し合って、PoCo::MQに統計情報を表示させるように色々とハックしはじめてる。

これにbzrを使ってるんだが、これいいな。集中管理型のVCSは企業等比較的大人数で作業するにはとても合ってるのでこれが廃れる事はないと思うが、このbazaarのような完全分散型のVCSは全く違うタイムゾーンにいる二人がお互いのコミットをマージし合う、という形にとても合ったツールだと思う。

ちなみに今の俺のPoCo::MQブランチはここです:

  http://users.endeworks.jp/~daisuke/code/bzr/perl_mq

ここに対して

  bzr branch http://users.endeworks.jp/~daisuke/code/bzr/perl_mq perl_mq

とかすると、自分用のブランチ(checkoutとは違う事に注意)ができて、それに対して作業もできるし、それからさらにブランチもできるし・・・これはよろしい。

ちなみに今の状態では、PoCo::MQの統計情報が色んなところでデバッグ的に垂れ流しになっているので少々うざいと思う。が、結構数はリアルに使える数なのであなたのPoCo::Mqのパフォーマンスが心配だったら上記ブランチをウォッチしていてくだされ。
    このエントリーをはてなブックマークに追加 mixiチェック

先日書いたGunghoX::FollowLinksのサンプルアプリだが、あのままではリンクの多いサイトではPOEエンジンが死ぬ、ということがわかった。POE::Component::Client::HTTPは意外と弱い。

取り急ぎProvider側でタイムアウトを入れてみて遅いながらも動く事は確認したが、どうもkeepaliveの設定とかも関係してそうだ。とりいそぎ。
    このエントリーをはてなブックマークに追加 mixiチェック

http://japanese.engadget.com/2007/11/12/gibson-robot-guitar/

便利そうだけど気持ち悪い〜〜〜〜〜。ブリッジのイントネーションまでチューニングを教えてくれるのかい・・・
    このエントリーをはてなブックマークに追加 mixiチェック

ここ2年くらいの間ず〜っととげのようにおいらの心に刺さっていた案件がありまして。某社の決済システムなんだけどね。まぁよくあることだとは思うんだけど、なんか上から突然「これ、来月までに作ってくださいね(はぁと」って言われて、よく見たらそれまでやったことのない内容の事で。しかもお金が直に絡まるし。

でまぁ作った訳ですよ、一生懸命に。慣れないDB(なぜかDB2だった)を使って。

テストも色々したけど不安で不安でねぇ。えいや、っと公開してオープンの日に社長の決済が通るところのログを裏で見てたりしてまぁ大丈夫だろう、ということでそのプロジェクトは終わらせたんだけどさ。

そのシステムのその後について2年もたった頃のこの間初めて聞けたわけです。まぁ少しずつ手を加えられてはいるらしいのだけど、いわゆるトランザクション系の所は全部そのまんま動いているそうで。いや〜嬉しくて、安堵して、俺ぁ泣くかと思ったね。頭のどこかでシステムのせいでン千万円の損害を受けたからどーのとか色々言われるかもしれないとか思いながら書いてたわけだが、とりいそぎ問題はないということがわかってよかったよ。

とまぁ、落ちはないのだが、安心した、という話。
    このエントリーをはてなブックマークに追加 mixiチェック

あ、そうか

あとあと、なんでdmaki wareなのにGungho::Handler::Swarmageがないのかが謎http://blog.yappo.jp/yappo/archives/000540.html
そう言われりゃそうだ。Gungho::Provider::Queueとかもっと抽象化した物を考えてたけど、よく考えりゃそのままGungho::Provider::Swarmageにすりゃええじゃん。

ういーっす。

エンジンは基本POEしかちゃんと作ってないよ!パッチくださいプリーズ!
    このエントリーをはてなブックマークに追加 mixiチェック

何個か前のエントリーで書いた、ページ内のリンクを辿って行く機能をGunghoX::FollowLinksで実装したよ。

まだちょっといけてない部分があるので多少の書き直しはあると思うけど、とりあえずうpしたさ。使い方はこんな感じ。このクローラーはあるURL(例:http://www.example.com/)を与えると、そのURLから辿れる、そのURL階層以下のページを全部取ってくるデス。長いからエントリーの後のほうでで説明もつけますよ
#!/usr/local/bin/perl # $Id$ # # Copyright (c) 2007 Daisuke Maki <daisuke@endeworks.jp> # All rights reserved. use strict; use warnings; use Gungho; use Gungho::Request; use GunghoX::FollowLinks; use URI; main(); sub main { my $site = $ARGV[0]; $site = URI->new($site) unless eval { $site->isa('URI') } && !$@; Gungho->run({ provider => sub { my ($p, $c) = @_; if (! $p->{started}) { $c->send_request( Gungho::Request->new( GET => $site ) ); $p->{started} = 1; } else { my $requests = $p->requests; while (my $request = shift @$requests) { $request->uri->fragment(undef); # Make sure to use the original hostname my $original_uri = $request->original_uri; if ( $p->{seen}{$original_uri->as_string}++ ) { next; } $c->send_request( $request ); } } return 1; }, handler => sub { my ($h, $c, $req, $res) = @_; $c->follow_links($res); print STDERR "Fetched ", $res->request->uri->as_string, "\n"; }, components => [ '+GunghoX::FollowLinks', 'RobotRules', 'Throttle::Simple', ], throttle => { simple => { max_items => 1000, interval => 3600, } }, follow_links => { parsers => [ { module => "HTML", config => { merge_rule => "ALL", rules => [ { module => "HTML::SelectedTags", config => { tags => [ qw(a link) ] } }, { module => "URI", config => { match => [ { scheme => qr/^http$/i, host => $site->host, path => "^" . ($site->path || "/"), action_nomatch => "FOLLOW_DENY" } ] } }, { module => "MIME", config => { types => [ qw(text/html) ], unknown => "FOLLOW_ALLOW", } }, ] } } ] } }); }


まずGunghoを普通にセットアップ。23行目から47行目はproviderとhandlerのセットアップしてます。Gungho 0.09003からGungho::Inlineを使わなくてもprovider/handlerを別クラスで定義する必要はないので、普通に関数を定義してそのまま渡してます。動作的には、ただ最初にもらったURLから始まって、その後$p->requestsに入れられるURLを端から取りに行くproviderと、とってきたURLをprintするhandlerというだけ。

48行目から使うコンポーネントの定義。ここではURLを辿って行くためのGunghoX::FollowLinksと、robots.txtを勝手に処理してくれるRobotRules、それにアクセス数を単純にカウントアップして、一定時間以内にアクセス数を設定値以上にいかないように抑えるThrottle::Simpleを使います。

53行目からはコンポーネント毎の定義。まずThrottle::Simple。3600秒以内に1000件のリクエストを最大値として設定

59行目からGunghoX::FollowLinksの設定。HTMLパーサーを使う。merge_rule => "ALL"で、これから定義するルールの全てがFOLLOW_ALLOWにならないとリンクを辿るのを許さない。上から見て行くと、

  1.  aタグかlinkタグで
  2.  URLがhttpで、ホストがスクリプトとして与えたURLのホストと一緒、なおかつ階層はそのURLの下で
  3.  URLから推測されるMIMEタイプがHTMLであること(わからない場合はとりあえず辿る事を許す)
という設定。

providerとhandler以外はYAMLで書く事もできるけど、今回はとりあえずそのままPerlで書いてみた。

まだ使い方はこれで決定というわけではないのでご要望等ありましたらブクマなりコメントなりでご意見をくださいまし。
    このエントリーをはてなブックマークに追加 mixiチェック

最近のユニクロのCMが個人的に超ヒットです。夏は「金麦」でしたが、秋から冬にかけてはユニクロですよ。佐藤江梨子と麻生久美子のヤツ。

がっちりわしづかみされました。買わないけど。
    このエントリーをはてなブックマークに追加 mixiチェック

URL毎になんかする、みたいな事を書きたいと思ったので(アーカイブ参照)、URIオブジェクトに対して任意のテストを実行できるモジュール書きました。ドキュメントを入れても153行の小さなモジュールですよ。

使い方はこんな感じ
use URI; use URI::Match; my $uri = URI->new("http://www.endeworks.jp"); if ($uri->match_parts( host => qr{^.+\.endeworks\.jp$},, path => qr{^/$} ) ){ # match }


ポイントは、

  • URLのパーツ毎にマッチングができる
  • マッチするのに、正規表現、関数、オブジェクトのどれでも使える
の二つ。

もちろん正規表現一発で事足りるケースも多いんだけど、どんな正規表現にするのか前もって知らなかったり、ロジックを組み合わせなければいけない時(ホストはこの数個の中のどれでも良いけど、パスは全部これね、みたいな)に使えると思うよ!

先ほどCPANうpしますた。
    このエントリーをはてなブックマークに追加 mixiチェック

Gunghoなんてソフトウェアをアクティブに書いているものだから色々とクローリングするソフトを書く事がとても多い。しかしそれでもやっぱりプロジェクト毎に微妙に条件が違ったり、クロール対象が違ったりするのであまり一般化できない仕組みが結構ある。

やっぱり一番難しいのが「このリンクはフォローしない」ルールで、まぁrobots.txtとかメタタグに書かれてるならやりやすいのだけれども問題は別にリンクを辿る事自体は誰にも禁止されてないんだけど、あるパターンのURLを辿って行くと最終的に集めてくるデータセットが汚染される、というケース。

これ、正直どうしようもない気がするんだけど・・・できれば一般化したい。

今特に対処しようと思っているのは「外部からリンクされている最初のページには用があるんだけれども、それ以降はそのドメインには用がないページ」。これは一般化できるかもしれん。

取り急ぎまず実装したいのは、超一般的な「あるサイトにあるリンクを抽出して、それらに対して一定のルールでその後クロールするかどうか」を簡単にかけるコンポーネントかな。イメージとしては
# config components: - FollowLink follow_link: strategies: - module: IgnoreHost sites: - regex: \.amazon\.co.\.jp$ - module: FollowIfAnotherConditionMet # Handler code sub handle_response { my ($self, $c, $req, $res) = @_; $c->follow_link($res); }

みたいな感じ。ちょっとこれは後で考える。
    このエントリーをはてなブックマークに追加 mixiチェック

例えばGD::Barcode::EAN13の表示方法を少々(ピクセル単位で)調整したいとなると、継承してplot()をほげほげするのが一番ラクなんだが、よーくソースコードを読むと
sub new($$) { my($sClass, $sTxt) = @_; $errStr =''; my $oThis = {}; bless $oThis; return undef if($errStr = $oThis->init($sTxt)); return $oThis; }

ぐはあああ。引数1個のbless()だ。自動的にblessするパッケージ名を判別してくれない・・・。

ということで、MyBarcodeサブクラスを作る時は、

package MyBarcode; use strict; use base qw(GD::Barcode::EAN13); sub new { my $class = shift; my $self = $class->SUPER::new(@_); bless $self, $class; return $self; }
とするのが吉。

ちなみに今回はGD::Font->Tinyを使いたかったのと、その後1ピクセルだけ隙間をあけたかったので、こうなる:
sub plot($;%) { my($oThis, %hParam) = @_; #Barcode Pattern my $sPtn = $oThis->barcode(); #Create Image my $iHeight = ($hParam{Height})? $hParam{Height} : 50; my($oGd, $cBlack); if($hParam{NoText}) { ($oGd, $cBlack) = GD::Barcode::plot($sPtn, length($sPtn), $iHeight, 0, 0); } else { my($fW,$fH) = (GD::Font->Tiny->width,GD::Font->Tiny->height); my $iWidth = length($sPtn)+$fW+1; ($oGd, $cBlack) = GD::Barcode::plot($sPtn, $iWidth, $iHeight, $fH + 1, $fW+1); $oGd->string(GD::Font->Tiny, 0, $iHeight - $fH, substr($oThis->{text}, 0, 1), $cBlack); $oGd->string(GD::Font->Tiny, $fW +8 , $iHeight - $fH, substr($oThis->{text}, 1, 6), $cBlack); $oGd->string(GD::Font->Tiny, $fW +55, $iHeight - $fH, substr($oThis->{text}, 7, 6), $cBlack); } return $oGd; }
    このエントリーをはてなブックマークに追加 mixiチェック

カレー屋にいったんですよ。カレーって大好きなんだけど、いわゆる普通〜のカレーだと少し物足りない。本当はこれのあと1.3倍くらい欲しい(飯だけじゃなくてルーも)。だからわりとカレーをわざわざ外食で食べる時は大盛りを頼む事が多いです。

で、今日カレー屋に行った訳です。まぁ普通のカレー屋さんなんで(うちの事務所の近くにはありえない量がデフォルトで出てくるカレー屋もあるので、そこと比べて「普通」)いつもの感覚で「大盛り」と頼んだんですね。そうしたらさ、ハンパじゃない量なわけですよ。ご飯3合?みたいな勢い。恐ろしい。あああ、そういえばこの店で大盛りは頼んだ事なかった・・・しまった・・・メニューもよく見たら「中盛り」っていうオプションもあった・・・

かと言って、もう目の前に持ってこられてしまった。しょうがないので食べました。食べましたけど、すげぇ後悔してます。ちくしょう。あまり知らない店で食べるとこれだ・・・

今夜は晩飯抜きにしますかね・・・

ちなみに。

今日出社したら知らない人がいました。いや、知ってました。うちのスタッフのO澤君です。ダム好きです。いや、そうじゃなくて。髪の毛がなくなってました。本人はもう一人の373君との差別化だとか言ってたけど、あれは絶対出家する予定だと思っております。
    このエントリーをはてなブックマークに追加 mixiチェック

もうアホか、っていうくらいウェブから持ってきたデータを文字コードを解析してutf-8に正規化するみたいなコードを書いてきたので、いい加減飽きてきた。今使ってるモジュールでもそう言う事してくれるのでいいのだけど、なんかそれぞれのモジュールでそれぞれ別の書き方するのもなんだかなぁ・・・と思って、Data::Decode書いたですよ。

Data::Decodeは中身が完全にプラッガブルなので基本はインターフェースを提供するだけなのです。残りは中に指定するオブジェクトをつなげて行く感じ。

use Data::Decode; use Data::Decode::Chain; use Data::Decode::Encode::Guess; use Data::Decode::Encode::HTTP::Response; my $response = $ua->get($url); my $decoder = Data::Decode->new( strategy => Data::Decode::Chain->new( Data::Decode::Encode::HTTP::Response->new(), decoders => [ Data::Decode::Encode::Guess->new( encodings => [ qw(euc-jp sjis jis utf8) ] ), ] ) ); my $decoded_content = $decoder->decode( $response->content, { response => $response } );


HTTP::Response::Encodingとかもあるの知ってるけど、どういうふうにしたところで最後にもう一回デコードがちゃんとできてるのか調べるようなスクリプトばっか書いてるきがするのよねぇ。あとData::Decode::Encode::HTTP::ResponseはちゃんとHeaderとMETAタグ両方みてくれるよ!
    このエントリーをはてなブックマークに追加 mixiチェック

ここ数日では今日だけ晴れというのでさくさくっと青梅まで行って御岳渓流沿いを歩いてきましたよ。

軍畑から御岳美術館のあるあたりまで歩いて、沢井まで戻るコース。10キロあったかなぁ。途中椎茸と里芋を無人販売所で買って、これは夕飯用。沢井ではもちろん澤之井酒造でおでんを肴に日本酒を2合ばかし。真っ赤な顔で中央線に乗るのはちょっとはずかしかったわぁ。

夕飯はぴょん子にレシピを教えてもらったザワークラウトもどきと、チキンカツ(チーズ入り)、あとは今日買ってきたさといもを茹でたものを塩で食べたのと、俺の手のひらより大きい椎茸を軽く焼いて、醤油で。うまかったわぁ
    このエントリーをはてなブックマークに追加 mixiチェック

MacBook (黒)の2GBに入ってたTigerをアップグレード。正直パフォーマンス的には特に良くなったとも悪くなったとも。

なんか便利そうなんだが、まだつかいこなせてないなー
    このエントリーをはてなブックマークに追加 mixiチェック

このページのトップヘ