2009年 05月 23日

memo

$ command git log --pretty=format:"%ad %an" --date=short | grep cho45 | awk '{ t[$1] += 1 } END { for (u in t) print u, t[u]}' |sort
$ gnuplot << EOF
set xdata time
set timefmt "%Y-%m-%d"
plot "/tmp/dt" using 1:2 with lines
EOF

2009年 05月 22日

コマンドラインのmp3 id3 タグ編集ツール

linux のコマンドラインで id3v2 を編集するやつってたくさんある割にろくなものがなくて、文字化けしたり正しいフォーマットで書きこめなかったりするのだけど、とりあえず使える方法を見つけたのでメモ

eyeD3 をとりあえず使う。python で書かれた id3 タグ編集ツール。そこそこよくできているけど、正しく文字コードを扱わない。

$ echo $LANG
ja_JP.UTF-8

$ eyeD3 --version
eyeD3 0.6.14 (C) Copyright 2002-2007 Travis Shirk <travis@pobox.com>

$ eyeD3 --set-encoding=utf16-LE --to-v2.3 --artist "ふー" --title "ばぁー" foo.mp3 
foo.mp3 [ 6.01 MB ]
--------------------------------------------------------------------------------
Time: 6:34      MPEG1, Layer III        [ 128 kb/s @ 44100 Hz - Joint stereo ]
--------------------------------------------------------------------------------
Setting artist: ふー
Setting title: ばぁー
Converting tag to ID3 version v2.3
Writing tag...
ID3 v2.3:
title: ã°ãã¼          artist: ãµã¼
album:          year: None
track:  

UserTextFrame: [Description: Tagging time]
2009-05-21T15:39:24

というふうに、頑張って書いてくれるのはいいけど、自分で書いたやつをちゃんと読みだせていない。

とりあえず決め打ちでちゃんと書けてくれさえすればいいので

#!/usr/bin/env python

import eyeD3
import os, sys
from optparse import OptionParser

parser = OptionParser(usage=u'%prog [opts] target.mp3')
parser.add_option("-T", "--title",
    dest   = "title",
    action = "store",
    type   = "string",
)
parser.add_option("-A", "--artist",
    dest   = "artist",
    action = "store",
    type   = "string",
)
parser.add_option("-L", "--album",
    dest   = "album",
    action = "store",
    type   = "string",
)

(options, args) = parser.parse_args(sys.argv[1:])
if not len(args) == 1:
    sys.stderr.write("requires target.mp3")
    exit();
target = args[0]

tag = eyeD3.Tag()
tag.link(target)
tag.header.setVersion(eyeD3.ID3_V2_3)
tag.setTextEncoding( eyeD3.UTF_16_ENCODING )

if options.title:
    tag.setTitle( unicode(options.title, 'UTF-8') )
if options.artist:
    tag.setArtist( unicode(options.artist, 'UTF-8') )
if options.album:
    tag.setAlbum( unicode(options.album, 'UTF-8') )

tag.update()

os.execlp("eyeD3", "", target)

というのを非常に頑張って書いた。Python 無理です。

なんかこれだと foobar2000 で場合によって文字化けする。なんなんだろ…… 判定に失敗するんだろうか。

firefly (mt-daap) だと大丈夫なんだけどなぁ。なんで id3 をまともに付けられる/読める環境になってないんだろ

2009年 05月 20日

Android 環境構築

やるだけやっとこうと重いました。

  • sdk を展開 → ~/sdk/android-sdk-mac_x86-1.5_r1
  • ~/sdk/android-sdk-mac_x86-1.5_r1/tools を PATH に追加

android コマンドが管理ツールらしい

$ android create avd --name test --target 2
# Android 1.5 ベースの AVD がつくられる
# 指定する id は android list でみれる

$ android list
Available Android targets:
id: 1
     Name: Android 1.1
     Type: Platform
     API level: 2
     Skins: HVGA (default), HVGA-L, HVGA-P, QVGA-L, QVGA-P
id: 2
     Name: Android 1.5
     Type: Platform
     API level: 3
     Skins: HVGA (default), HVGA-L, HVGA-P, QVGA-L, QVGA-P
id: 3
     Name: Google APIs
     Type: Add-On
     Vendor: Google Inc.
     Description: Android + Google APIs
     Based on Android 1.5 (API level 3)
     Libraries:
      * com.google.android.maps (maps.jar)
          API for Google Maps
     Skins: HVGA (default), HVGA-L, QVGA-P, HVGA-P, QVGA-L
Available Android Virtual Devices:
    Name: test
    Path: /Users/cho45/.android/avd/test.avd
  Target: Android 1.5 (API level 3)
    Skin: HVGA

$ emulator -avd test

するととりあえずエミュレータは起動する。コマンド名が攻めすぎててヒく

2009年 05月 19日

IMK 版の AquaSKK 場所 memo

/Library/Input Methods/AquaSKK.app/Contents/Resources

2009年 05月 18日

2週間連続で写真撮りにいってない。

外国の夢を見た。自分自身がそもそも日本人ではなく、しかも少年だった。近くの倉庫に「メリス」と名前がついた核爆弾を誘導するための装置があった。大勢の親戚が倉庫にやってきた。女の子がいた。

2009年 05月 17日

WAF

結局、アプリケーション (not Web App = WWW 非依存) なものを Web っぽい部分とつなぐ Dispatcher (Router) があればよくて、あとはおまけっぽいので、HTTP::Engine + Router で WAF っぽい部分は終わりになるような気がした。

uri path -> 実際の処理 の受け渡しが複数ファイルを見ないとわからないようなのはよくない。あっちいったりこっちいったりめんどうくさいし、ある uri へアクションを設定したいだけのためにファイル1個おいたり、とても無駄だ。

app 部分はまた別のものだ。

整理して github におきました: http://github.com/cho45/Chord/tree/master

#!/usr/bin/env perl
package FooRouter;

use Chord::Router::HTTP;
use base qw(Chord::Router::HTTP);

# define views
use JSON::XS;
sub json ($$) {
	my ($res, $stash) = @_;
	$res->header("Content-Type" => "application/json");
	$res->content(encode_json($stash));
}

use Text::MicroMason;
sub html ($%) {
	my ($res, $stash) = @_;
	my $m  = Text::MicroMason->new(qw/ -SafeServerPages -AllowGlobals /);
	$m->set_globals(map { ("\$$_", $stash->{$_}) } keys %$stash);

	my $content = $m->execute(text =>  q{
		<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
		<title><%= $title %></title>
		<p><%= $content %>
	});

	$res->header("Content-Type" => "text/html");
	$res->content($content);
}

# routing

route "/",
	action => sub {
		my ($req, $res) = @_;
		html $res, {
			title   => "Hello",
			content => "Hello",
		};
	};

route "/my/*path",
	action => sub {
		my ($req, $res) = @_;
		$res->code(302);
		$res->header("Location" => sprintf("/foo/%s", $req->param("path")));
	};

route "/:author/", author => qr/[a-z][a-z0-9]{1,30}/,
	action => sub {
		my ($req, $res) = @_;
		html $res, {
			title   => "Hello",
			content => sprintf("This is %s's page.", $req->param("author"))
		};
	};

route "/api/foo",
	action => sub {
		my ($req, $res) = @_;
		json $res, {
			foo => "bar"
		};
	};

route "/die",
	action => sub {
		die "Died";
	};


__PACKAGE__->run;
package Chord::Router::HTTP;
use Any::Moose;
use HTTP::Engine;

use Exporter::Lite;
our @EXPORT = qw(route);

our $routing = [];

sub route ($;%) {
	my ($path, %opts) = @_;
	my $regexp  = "^$path\$";
	my $capture = [];

	$regexp =~ s{([:*])(\w+)}{
		my $type = $1;
		my $name = $2;
		push @$capture, $name;
		sprintf("(%s)",
			$opts{$name} ||
			(($type eq "*") ? ".*": "[^\/]+")
		);
	}ge;

	push @$routing, {
		%opts,
		define  => $path,
		regexp  => $regexp,
		capture => $capture,
	};
}

sub dispatch {
	my ($self, $request) = @_;
	my $path   = $request->path;
	my $params = {};
	my $action;

	for my $route (@$routing) {
		if (my @capture = ($path =~ $route->{regexp})) {
			for my $name (@{ $route->{capture} }) {
				$params->{$name} = shift @capture;
			}
			$action = $route->{action};
			last;
		}
	}

	my $req = $request;
	$req->param(%$params);
	my $res = HTTP::Engine::Response->new(status => 200);
	$res->header("Content-Type" => "text/html");
	if ($action) {
		eval {
			$action->($req, $res);
		}; if ($@) {
			$res->code(500);
			$res->header("Content-Type" => "text/plain");
			$res->content($@);
		}
	} else {
		$res->code(404);
		$res->content("Not Found");
	}
	$res;
}

sub process {
	my ($self, $request) = @_;

	$self->dispatch($request);
}

sub run {
	my ($class, %opts) = @_;

	HTTP::Engine->new(
		interface => {
			module => 'ServerSimple',
			args   => {
				host => 'localhost',
				port =>  3001,
			},
			request_handler => sub {
				my $req = shift;
				$class->new->process($req);
			},
			%opts
		},
	)->run;
}


1;
__END__

Web App なのか App + Web なのか……

テストを考えなければどっちでもいいんだろうけどなぁ。

アプリケーションロジック (いくつかのモデルの結合) テストと、HTTP まで含めた結合テストは、はたして別れてたほうがいいのかなぁ。