2011年 07月 01日


gerry++

2011年 07月 02日


2011年 07月 03日


2011年 07月 04日

gerry++

gerry++

自分は色の数が少ない写真のほうが多いものより好きだってことがよくわかった。

2011年 07月 05日

2011年 07月 06日


2011年 07月 05日

gerry++

2011年 07月 07日

2011年 07月 08日

神社にはよく行くけれど、自身としてはあまり信仰心がない(仏教よりはあるかも)ので、御参りして形式的に2拝2拍1拝はするものの、2拍のあとに何も思わないことが多かった。願いがないというわけではなくて、いない神様にそれを祈るぐらいなら、口に出して人に言ったりして、直接行動したほうが願いは叶いやすいと思っているからで、つまりどちらかというと積極的に祈らないということです。翻って考えてみると、祈らない代わりにお参りする度に自分の中で行動を起こす誓いを立ている感じに近い。

しかしちょっと考えかたを変えて、全く自分の行動の影響が及ばないことについて、例えば単純に運でしかないものについては祈ることにした。それ自体に全く意味がなくても、ある種の、運のみに依存している理不尽さに対抗するために効果があると考えた。これは暗い小説を読むのと似ていて、暗い小説なんて読んでも何の意味もないどころか辛い気持ちになりがちだけど、場合によっては溜飲を下げたり、現実において自分のネガティブな行動を抑えたりする効果があるなと思うわけです。

神社によく行くのは、前にも書いたかもしれないけど、雰囲気が良いから(大抵街中でも鎮守の森があるし)というのと、建築が面白いからというのと、だいたいどこの駅で降りても歩けばあるし、散歩とか外出の目標地点にするにはちょうどいいからという理由です。目標地点がないと外に出ないので……

自分の考えかたの起源みたいなのに強い関心があって、つまりいろいろ自分の中に価値観ってものがあるけれど、それがどこ由来なのか、遺伝的によるものなのか、環境(教育、文化)によるものなのか、よく無駄に考えてしまう。

特に遺伝なのか環境なのかっていうのは、子供のころからよく考えることがあるけど、結局殆どよくわからない。

  • 掃除機の紙パックがない
  • 髪を切る必要がある

gerry++

2011年 07月 09日

2011年 07月 08日

JSを編集してエディタで保存するとき、JSHint でコーディングバリデーションをかける

errormaker.vim を使って JS 保存時に末尾カンマチェックとかをやっていたのだけれど、今までチェックに使っていた Spidermonkey の最近のバージョンだと、strict モードにしても末尾カンマを warn しなくなって意味がなくなっていたので、JSHint でやるようにした。

setlocal makeprg=$HOME/.vim/vimparse.js\ %\ $*
setlocal errorformat=%f:%l:%m

は今までのままにして、vimparse.js を以下のようにした。JSHintJSLint よりはマイルドというか偏執さがないのだけど、まだ癖が強くて「実害のある」という警告と「単に好み」という警告がごっちゃになっていてうざいので、できるだけ自分でカスタマイズできるようにした。

node.js を実行環境にしているのは、node.js のインストールが特に依存もなく簡単だから (clone して make するだけでいいから) です。

#!/usr/bin/env node


var JSHINT = require("./jshint.js").JSHINT;
var fs = require("fs");

var argv = process.argv;
argv.shift();
argv.shift();

argv.forEach(function (filename) {
	var source = fs.readFileSync(filename, 'utf-8');
	var result = JSHINT(source, {
		browser : true,
		jquery  : true,
		evil    : true,
		passfail : false
	});
	if (!result) {
		JSHINT.errors.forEach(function (error) {
			if (!error) return;

			if (error.reason.indexOf('Stopping, unable to continue.') != -1) return;

			// 何これ?
			if (error.reason.indexOf("Confusing use of '!'.") != -1) return;

			// for (var i...) は何度も書きたい
			if (error.reason.indexOf("'i' is already defined.") != -1) return;
			if (error.reason.indexOf("'it' is already defined.") != -1) return;

			// 可読性のために意図的にそうしているのでうざいし、そういう最適化は実行エンジンがすべきこと
			if (error.reason.indexOf('is better written in dot notation') != -1) return;

			// 根拠がわからないので保留
			if (error.reason.indexOf("Don't make functions within a loop") != -1) return;

			if (error.evidence) {
				error.evidence = error.evidence.replace(/\t/g, '    ');

				// 明示的に抑止されてるなら無視
				if (error.evidence.indexOf('no warnings') != -1) return;

				// やたら長い行は圧縮されたJSコードとみなす
				if (error.evidence.length > 1000) return;

				// 閉じブレース前のセミコロンは省略可能に
				if (error.reason.indexOf('Missing semicolon') != -1 && error.evidence.substring(error.character).match(/^\s*\}/)) return;
			}

			console.log([filename, error.line, error.character].join(':') + "\t" + error.reason);
		});
	}
});
2011年 07月 09日

一週間長い……

メモ 新規作成時のテキストエリアおかしい

2011年 07月 10日

gerry++

2011年 07月 11日

2011年 07月 12日

2011年 07月 13日


2011年 07月 12日

gerry++

2011年 07月 14日


ほげ~

スマフォ編集~

編集~

てすとー

2011年 07月 15日

どうもこうも不安である。自分はどうしようもなくコミュニケーション能力に欠けた人間であり、人をひっぱる力がまるでない。加えて一般的な教養スキルがないため、いろんな点においてうまく立ち回ることができない。普通の人が行くような場所に行かず、自分と直接関係ない・興味のない施設を認識の外に置いてしまうので、いざそれらが必要になったときに、全く引き出しにものがない。

2011年 07月 16日

2011年 07月 17日

2011年 07月 18日

2011年 07月 20日

gerry++

2011年 07月 21日

2011年 07月 22日

2011年 07月 21日

HTML メール

どうやって作るのが簡単なんでしょうか… 以下のようにしがちですがよくわかりません

use Encode;
use Email::MIME;
use Email::MIME::CreateHTML;

my $html = <<EOS;
<!DOCTYPE html>
<head>
<title>タイトル</title>
</head>
<body>
	<h1>ああああ</h1>
</body>
</html>
EOS

my $text = <<EOS;
テスト
EOS

my $email = Email::MIME->create_html(
	header => [
		From    => 'from@example.com',
		To      => 'cho45@lowreal.net',
		Subject => encode("MIME-Header-ISO_2022_JP", 'タイトル'),
	],

	body => encode('iso-2022-jp', $html),
	body_attributes => {
		content_type => 'text/html',
		charset      => 'iso-2022-jp',
		encoding     => 'base64',
	},

	text_body => encode('iso-2022-jp', $text),
	text_body_attributes => {
		content_type => 'text/plain',
		charset      => 'iso-2022-jp',
	},
);

print $email->as_string;

#use Email::Send;
#my $sender = Email::Send->new({mailer => 'SMTP'});
#$sender->send($email);
2011年 07月 22日

TODO

  • ドメイン更新
2011年 07月 23日

2011年 07月 25日

gerry++

2011年 07月 26日

昨日の写真と全く同じ構図だ。ピントあわせてる位置も一緒ですごいクセがついててよくない気がする。花の写真結構頭使わないで撮ってしまって良くないなー……

2011年 07月 25日

AnyEvent::setTimeout

AE::timer のインターフェイスが覚えられないなーと思うので、JS の setTimeout に似たものを書きました。

use AnyEvent::setTimeout;

setTimeout(sub {
  warn "1sec!";
}, 1000);

とか書けます。ちょっと細工をしていて、ファイルの最後に AnyEvent->condvar->recv とかおまじないを書かなくても、終了時に全てのタイマーの終了を待ちます (node.js 風にしたいけどできないのか的なことを言ってたら id:motemen:detail 先生ができそうなことを言ってくれたのでやってみた感じです)

ただ、このモジュールの管理下にあるタイマーしか終了時に待てないのがいまいち感あります……

とりあえず setTimeout さえあれば JSDeferred をそのまんま移植できるなーと思った感じなんですが、それやって意味があるのか謎なのでやめました。

まぁこういうの書いてるうちに AE::timer のインターフェイスとか覚えちゃうんですけど……

2011年 07月 26日

おなかいたい

環境変数で設定を変える的なモジュール Config::ENV

なんかもっと簡単なのがあればいいなー と思ったのでつくりました。

package MyConfig;

use Config::ENV 'FOO_ENV';

common +{
	name => 'foobar',
};

config development => +{
	dsn_user => 'dbi:mysql:dbname=user;host=localhost',
};

config test => +{
	dsn_user => 'dbi:mysql:dbname=user;host=localhost',
};

config production => +{
	dsn_user => 'dbi:mysql:dbname=user;host=127.0.0.254',
};

config production_bot => +{
	parent('production'),
	bot => 1,
};

#

use MyConfig;

MyConfig->param('dsn_user');

みたいに書くと、$ENV{FOO_ENV} の値によって別の値をつかうようにするってだけです。

設定ファイルを別にわけたいみたいなのは適当に do したらいいだけだし、切替える機能だけほしいのです。

2011年 07月 27日

写真コンテストは選外という結果がでました。残念ですがまあまあ細々とやっていきます。

2011年 07月 26日

gerry++

2011年 07月 27日

gerry++

Maildir のメールを Gmail にそのままインポートしたい

手元に昔使っていた Maildir 形式で保存されているメールがたくさんあるのを、Gmail にインポートしたいと思った。

残念ながら、いくら手元に完全な MIME のメッセージがあっても、Gmail にはそのままアップロードするみたいな機能がないために、簡単にそのままインポートすることができない。とはいえ Gmail には Mail Fetcher 機能 (POP3 で外部サービスのメールをとりにいく) というのがあるので、それを利用することにした。(メールで送ってしまう、という手もあるけど、From/To が書きかわったり、時刻が狂ったりして嫌だった)

いろいろ試した (Perl で Net::Server::POP3 を使ったり) した結果、結局必要な実装だけ自力で書いた。なんとなく TCP のサーバ実装を書くみたいなときは Ruby 使うのが手に馴染むので Ruby で書いた。割と簡単だったのでさっさと自力で書けばよかったと思った……

  • 以下のスクリプトの冒頭をいい感じに設定
  • パブリックなサーバでポート1110をあけて、起動する
    • telnet [server] 1110 とかで接続できることを確認
  • [設定] → [アカウントとインポート] → [POP3 を使用したメッセージの確認] から [POP3 のメールアカウントを追加] を選ぶ
  • [メールアドレス] にインポートしたメールのメールアドレスを入れる (間違ってると正しくインポートされない)
  • [ユーザ名] [パスワード] にスクリプト冒頭に設定したものを入れる
  • [POP サーバー] に立ち上げたサーバのホスト名を入れる
  • [ポート] は 1110 にする
  • [アカウントを追加] ボタンをおすとたぶんうまくいく
#!/usr/bin/env ruby

USER = 'cho45'
PASS = 'xxxxxx'
MESSAGES = Dir.glob('./path/to/Maildir/cur/*')

require 'socket'
class POP3Session
	def self.messages=(messages)
		@@messages = messages
	end

	def initialize(s)
		@s = s
		authorization
	end

	def authorization
		p :authrization
		post "+OK POP3 server ready"
		session do |command, args|
			case command
			when 'USER'
				@user = args[0]
				if @user == USER
					post "+OK name is a valid mailbox"
				else
					post "-ERR never heard of mailbox name"
				end
			when 'PASS'
				pass = args[0]
				if pass == PASS
					post "+OK maildrop locked and ready"
					transaction
				else
					post "-ERR invalid password"
				end
			when 'QUIT'
				@s.close
			else
				post "-ERR unknown command"
			end
		end
	end

	def transaction
		p :transaction
		session do |command, args|
			p [command, args]
			case command
			when 'CAPA'
				post "+OK capability list follows."
				post "USER"
				post "UIDL"
				post "."
			when 'STAT'
				nom  = @@messages.size # number of messages
				size = @@messages.inject(0) {|r,i| r + i.size }  # size of the maildrop in octets
				post "+OK #{nom} #{size}"
			when 'LIST'
				if args.size.nonzero?
					msg = args[0].to_i - 1
					size = @@messages[msg].size
					post "+OK #{msg} #{size}"
				else
					post "+OK scan listing follows"
					@@messages.each_with_index do |m,i|
						post "#{i+1} #{m.size}" unless m.deleted
					end
					post "."
				end
			when 'UIDL'
				if args.size.nonzero?
					msg = args[0].to_i - 1
					post "+OK #{msg} #{@@messages[msg].hash}"
				else
					post "+OK message-id listing follows"
					@@messages.each_with_index do |m,i|
						post "#{i+1} #{m.hash}" unless m.deleted
					end
					post "."
				end
			when 'RETR'
				msg = args[0].to_i - 1

				m = @@messages[msg]
				if m
					post "+OK message follows"
					post m.content
					post "."
				else
					post "-ERR no such message"
				end
			when 'DELE'
				msg = args[0].to_i - 1
				m = @@messages[msg]
				if m
					m.deleted = true
					post "+OK message deleted"
				else
					post "-ERR no such message"
				end
			when 'NOOP'
				post "+OK"
			when 'RSET'
				@@messages.each do |m|
					m.deleted = false
				end
				post "+OK"
			when 'QUIT'
				update
			end
		end
	end

	def update
		p :update
		post "+OK"
		@@messages.reject! {|i| i.deleted }
		@s.close
	end

	private
	def post(msg="")
		puts msg
		@s.write("#{msg}\r\n")
	end

	def session(&block)
		while line = @s.gets
			line.chomp!
			puts line
			command, *args = *line.split(/\s+/)
			res = yield command, args
		end
	end

	class Message
		attr_accessor :deleted

		def initialize(file)
			@file = file
		end

		def content
			File.read(@file)
		end

		def size
			File.size(@file)
		end
	end
end

server = TCPServer.open(nil, 1110)
puts "User: #{USER}"
puts "Pass: #{PASS}"
puts "POP3: %3$s Port: %2$s" % server.addr

POP3Session.messages = MESSAGES.map {|f|
	POP3Session::Message.new(f)
}

loop do
	begin
		POP3Session.new(server.accept) # コネクションを1つずつしか受けつけないように
	rescue => e
		p e
	end
end

Mail Fetcher の挙動メモ

  • アカウント追加時に CAPA コマンドで UIDL コマンドが使えるかを見ている
  • TCPセッションごとのメッセージ番号が 1 から順番の数値になっていないダメ
  • 200件ごとにわけてインポートしようとする。200件ごとに STAT / LIST / RETR / DELE が走る
  • (Gmail 的に) 同じ Message-ID のメールは重複しないので、何度実行しても大丈夫
  • TRANSACTION フェーズで QUIT を発行したあと、こちらの応答を待たずに接続を切るっぽい
    • うまくメッセージの削除が行われないうちに次のセッションがはじまるので困る → 接続を1ずつにすることで解決
2011年 07月 28日


2011年 07月 29日

2011年 07月 30日

2011年 07月 29日

今週あったよかったことさがし

  • POP3 に詳しくなった

gerry 可視化再び

use strict;

use LWP::Simple qw($ua);
use HTML::TreeBuilder::XPath;

my $res = $ua->get('http://subtech.g.hatena.ne.jp/keyworddiary/gerry');
$res->is_success or die "Failed to GET: $res";

my $data = [];
my $doc = HTML::TreeBuilder::XPath->new_from_content($res->content);
my $nodes = $doc->findnodes('id("refered-diary")//ul/li[@class="diary-listitem"]/a');
for my $node (@$nodes) {
	my $href = $node->findvalue('@href');
	if (my ($year, $month, $day) = ($href =~ m{/cho45/(\d{4})(\d\d)(\d\d)})) {
		push @$data, [$year, $month, $day] ;
	}
}

$doc->delete;


use WebService::Hatena::Graph;
use IO::Prompt;
use Perl6::Say;

my $password = prompt "Password:", -echo => '';

my $graph = WebService::Hatena::Graph->new(
	username => 'cho45',
	password => $password,
);

my $count = 1;
for my $date (reverse @$data) {
	$graph->post_data(
		graphname => 'gerry',
		date      => join('-', @$date),
		value     => $count++,
	);
	say join('-', @$date);
}

use DateTime;
use IO::File;
my $fh = IO::File->new('gerry_access_log', 'w');

for my $date (@$data) {
	my ($year, $month, $day) = @$date;
	my $dt = DateTime->new(year => $year, month => $month, day => $day, time_zone => 'Asia/Tokyo')->strftime('%d/%b/%Y:00:00:00 +0900');

	$fh->write(qq|0.0.0.0 - - [$dt] "GET /gerry HTTP/1.1" 200 26768 "-" "Gerry"\n|);
}

$fh->close;
2011年 07月 31日

Hatena::Counter IRC Gateway

を書きました

  • PASS に javascript:alert(document.cookie.match(/rk=(\S+)/)[1]); を指定
  • /join #counter-{userid}-{counterid} する

と適当にクロールして IRC ログにアクセスがながれてきます。

UA とリモートホスト (を削ったもの) を元に ua_id というのを作って nick にしているほか、リモートホスト部分に色をつけるようにしてます。