2008-03-04 :-)
_ 朝ったー
0540 起床。ねむ
_ [植松伸夫][ファイナルファンタジーIV ケルティックムーン]通勤ったー
ファイナルファンタジーIV ケルティックムーン
FF4 アレンジです。アイリッシュ音楽でアレンジされてます。電子音ではなくて生の音ですってよ。民族楽器の暖かさというか、柔らかい音が心地よいです。FF 音楽を楽器でアレンジしたのはこれが初めてです。たぶん。長すぎずキレイにまとまっているので聴きやすいです。
B000058AB1
_ 仕事
0830 出勤。
_ ヴァルキリープロファイル レナス
- プレイ時間 2:30
- 最初のダンジョンをクリア
- どうやってダンジョンから出るんだ
_ [mixi][Plagger]mixi => Plagger => Publish::feed ってやってませんが
Publish する先によってはマイミクシィ限定公開してるひとの mixi 日記を web に置けるのかしら。やらないけど。
_ 絡まれ力
先日 IRC で友人が「絡まれた」と言ってて、そういえば私はその友人と対して変わらない行動してるはずなのに絡まれたことが無いことに気づいた。いままで絡まれなかったからといって今後も絡まれないとは言えないし、いまどきならば電車に乗ってるときに「ハロー、ジェントルメン。おまえの命を貰いにきた」とピエロの格好したひとに唐突に刺されることだってあるのだけど。とりあえず戦闘力は低いので逃げることだけ考えよう。そのためにも足腰は鍛えておくと嬉しい。
_ [コードリーディング][がらくた][高林哲]がらくたを読む - changelog2graph
http://0xcc.net/attic/changelog2graph
ChangeLog のヘッダごとの変更回数をグラフにします。
冒頭から読みます。
use strict; use Chart::PNGgraph::lines; use Time::Local;
使用するモジュールです。
Chart::PNGgraph はこちら。
詳しいことは GD::Graph を読めと書いてあります。GD::Graph はこちら。
ここを読むとプログラムで使っているメソッドなどの意味が分かります。Chart::PNGgraph は main で使っています。$my_graph->set では OPTIONS にあるオプションを設定してます。
main(); sub main { my %freqs = analyze_changelog(); # ChangeLog を何か解析した結果のハッシュ my $first_time = get_first_time(\%freqs); # ChangeLog 内の最初の日付? my $last_time = get_last_time(\%freqs); # ChangeLog 内の最後の日付? my @data = generate_data(\%freqs, $first_time, $last_time); # グラフ用のデータ作成? my $my_graph = new Chart::PNGgraph::lines(600,400); # グラフインスタンス作成 $my_graph->set( # オプション設定 transparent => 0, two_axes => 1, line_width => 2, x_label => 'Date', y_label => 'Changes', title => 'ChangeLog Graph', x_label_skip => int(@{$data[0]} / 8) + 1, y_label_skip => 2, r_margin => 20, textclr => "black", dclrs => [ qw(red blue green pink cyan) ], ); print $my_graph->plot(\@data); # グラフ書きませう }
main から呼び出しているメソッドはまだ読んでませんが変数名などからするとコメントに書いたような処理だと思います。
analyze_changelog を読みます。ChangeLog を解析してヘッダごとの変更回数を数えて ヘッダ=> 変更回数のハッシュにしています( ref. GNU コーディング規約 - 変更履歴の形式 )。
sub analyze_changelog () { my %freqs = (); my $date = undef; my $freq = 0; while (<>) { next if /^\s*$/; chomp; if (/^(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)\s+ (\w+)\s+(\d+)\s+(?:[\d:]+)\s+(\d+)(.*)/x) { # Old type format: # Wed Jun 2 17:55:44 1999 Foo Bar <foo@bar.jp> my $mon = $month_names{$1} + 1; my $mday = $2; my $year = $3; my $rest = $4; # Convert it to ISO 8601 type. $_ = sprintf "%4d-%02d-%02d%s", $year, $mon, $mday, $rest; } if (/^(\d{4}-\d{2}-\d{2})\s/) { # ISO 8601 format: # 1999-06-02 Foo Bar <foo@bar.jp> if (defined $date) { $freqs{$date} = $freq; } $date = $1; $freq = 0; } elsif (/^\s+\*/) { $freq++; } } $freqs{$date} = $freq; return %freqs; }
コメントにもありますが「Old type format」と「ISO 8601 format」の 2 種類の日付の形式を処理しています。「Old type format」ならば「ISO 8601 format」に変換しておき( これを「正規化する」といいます )「ISO 8601 format」として処理できるようになります。
日付を探している部分が
if (/^(\d{4}-\d{2}-\d{2})\s/)
となっていて $date の部分が
$date = $1;
になっています。結局 $date にはヘッダのうち日付の部分が格納されます。
これで %freqs に「日付 => 変更回数」のハッシュを作り、返します。
ところで「ISO 8601」ってなに?
YYYY-MM-DD や hh:mm:ss などの形式のことらしいです。
get_first_time を読みます。
sub get_first_time ($) { my ($freqs_ref) = @_; my $first_date = (sort keys %{$freqs_ref})[0]; return date_to_time($first_date); }
freqs_ref は analyze_changelog で作ったハッシュです。(sort keys %{$freqs_ref})[0]; を分解します。
sort keys %{$freqs_ref}
%{$freqs_ref} を key でソートします。key は日付です。
()[0]
ソートした結果の最初の要素です。
date_to_time を呼んでるので date_to_time を読みます。
sub date_to_time ($) { my ($date) = @_; if ($date =~ /^(\d+)-(\d+)-(\d+)/) { my $year = $1; my $mon = $2 - 1; my $mday = $3; return timelocal(0, 0, 0, $mday, $mon, $year); } else { die "$date: invalid date format"; } }
timelocal ってなに?
ということで日付からシステム起動時からの秒数へ変換します。bulkplot でも秒数に変換して処理してました。日付はシステム起動時からの秒数にして処理すると、ライブラリなどのインターフェース部分に渡すときに日付の形式を処理する手間が省ける( ISO 8601 なのかそれ以外なのか、異常な形式なのかとか ) という意図でしょうか。「日付クラス」というのが存在するならばそのインスタンスを受け渡しすると良さそうですがどうなんでしょう。
get_last_time を読みます。
sub get_last_time ($) { my ($freqs_ref) = @_; my $last_date = (reverse sort keys %{$freqs_ref})[0]; return date_to_time($last_date); }
get_first_time に似てますが reverse してるところが違います。処理は以下の手順です。
- 「日付 => 変更回数」のハッシュを日付でソート
- 逆順にする
- 最初の要素( 日付 )を取得
- 日付をシステム起動時からの秒数に変換
generate_data を読みます。
sub generate_data ($$$) { my ($freqs_ref, $first_time, $last_time) = @_; my @dates = (); my @indps = (); # independent my @cumls = (); # cumulative my $sum = 0; for (my $time = $first_time; $time <= $last_time; $time += 60 * 60 * 24) { my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime($time); $year += 1900; $mon++; my $date = sprintf "%4d-%02d-%02d", $year, $mon, $mday; push @dates, $date; if (defined $freqs_ref->{$date}) { push @indps, $freqs_ref->{$date}; $sum += $freqs_ref->{$date} } else { push @indps, 0; } push @cumls, $sum; } return ([ @dates ], [ @indps ], [ @cumls ]); }
グラフに使うデータを作ってます。作っているデータは以下の 3 つです。
- 日付( @dates )
- 日付ごとの変更回数( @indps )
- 累積変更回数( @cumls )
作ったデータを sub main で $my_graph->plot(\@data); してグラフを作成します。
for にある time を増加させる式に注目。
for (my $time = $first_time; $time <= $last_time; $time += 60 * 60 * 24) {
60 * 60 * 24 は 86400 です。ここに 86400 と書かずに 60 * 60 * 24 と書いてます。この数値の並びを見ると時間を扱ってるということが分かります。60 が秒数、60 が分、24 は 1 日の時間だと理解できます。結局 86400 は 1 日の秒数だということが分かります。慣れてるひとは 86400 という数値を見ただけで 1 日の秒数を表してるのだと分かるかもしれません。