2008年 06月 18日

Tree Style Tab + Mac OS X

Firefox3 がリリースされましたね! Mac OS X 版ではテーマが Safari 系になったりして結構変わっています。 (プロトタイプ段階では Proto という名前のテーマでした)

でもってリリース (と、Tree Style Tab の最近の変更?) でちょっと変わったりしているっぽいので Tree Style Tab (縦置き) の見た目をそれに合せる userstyle を更新しました。

http://userstyles.org/styles/4677

2008年 06月 17日

zsh の exntended_glob と HEAD^^^ を共存させる。

extended_glob すると ^ が特殊文字になって HEAD^^^ とかできなくなって UZEEE のでやってみた。

typeset -A abbreviations
abbreviations=(
	"L"    "| $PAGER"
	"G"    "| grep"

	"HEAD^"     "HEAD\\^"
	"HEAD^^"    "HEAD\\^\\^"
	"HEAD^^^"   "HEAD\\^\\^\\^"
	"HEAD^^^^"  "HEAD\\^\\^\\^\\^\\^"
	"HEAD^^^^^" "HEAD\\^\\^\\^\\^\\^"
)

magic-abbrev-expand () {
	local MATCH
	LBUFFER=${LBUFFER%%(#m)[-_a-zA-Z0-9^]#}
	LBUFFER+=${abbreviations[$MATCH]:-$MATCH}
}

magic-abbrev-expand-and-insert () {
	magic-abbrev-expand
	zle self-insert
}

magic-abbrev-expand-and-accept () {
	magic-abbrev-expand
	zle accept-line
}

no-magic-abbrev-expand () {
	LBUFFER+=' '
}

zle -N magic-abbrev-expand
zle -N magic-abbrev-expand-and-insert
zle -N magic-abbrev-expand-and-accept
zle -N no-magic-abbrev-expand
bindkey "\r"  magic-abbrev-expand-and-accept # M-x RET はできなくなる
bindkey "^J"  accept-line # no magic
bindkey " "   magic-abbrev-expand-and-insert
bindkey "."   magic-abbrev-expand-and-insert
bindkey "^x " no-magic-abbrev-expand

こうすると

git reset HEAD^ # までうって RET をおすと
git reset HEAD\^ # に展開されて実行される

git di HEAD^^^..HEAD^ # とうつと、
git di HEAD\^\^\^.
git di HEAD\^\^\^..HEAD\^ # と展開されていく

git は引数に割とファイルとったりするので glob の機能自体は残しておきたいわけです!

2008年 06月 15日

feature name

def feature_name(class_name)
	class_name.split(/::/).map {|const|
		const.scan(/[A-Z](?:(?![A-Z][a-z])[A-Za-z])*/).map {|i| i.downcase }.join("_")
	}.join("/")
end


require "rubygems"
require "spec"

describe "feature_name" do
	it "should generate filename from class_name" do
		feature_name("A").should           == "a"
		feature_name("Foo").should         == "foo"
		feature_name("FooBar").should      == "foo_bar"
		feature_name("FOOBar").should      == "foo_bar"
		feature_name("Foo::Bar").should    == "foo/bar"
		feature_name("Foo::BarBaz").should == "foo/bar_baz"
	end
end

def feature_name_(class_name)
	class_name.split(/::/).map {|const|
		const.downcase
	}.join("/")
end

require "rubygems"
require "spec"

describe "feature_name_" do
	it "should generate filename from class_name" do
		feature_name_("A").should           == "a"
		feature_name_("Foo").should         == "foo"
		feature_name_("FooBar").should      == "foobar"
		feature_name_("FOOBar").should      == "foobar"
		feature_name_("Foo::Bar").should    == "foo/bar"
		feature_name_("Foo::BarBaz").should == "foo/barbaz"
	end
end

アンダースコアださいなぁ…… どうせ逆変換できないなら後者でいい感じかなぁ。。

2008年 06月 08日

RAID

500GB * 2 をデータディスクに

> n
> p
> 1 #パーテーション番号
> 1 #最初のシリンダ

> +500000M
> t # タイプ変更
> fd # Linux raid auto detect

> p
Disk /dev/sdb: 500.1 GB, 500107862016 bytes
255 heads, 63 sectors/track, 60801 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Disk identifier: 0x6c4fc740

   Device Boot      Start         End      Blocks   Id  System
/dev/sdb1               1       60789   488287611   fd  Linux raid autodetect

sdb, sdc に、

$ sudo mdadm --create /dev/md0 --level=1 --raid-devices=2 /dev/sdb1 /dev/sdc1
mdadm: array /dev/md0 started.

$ sudo mkfs.ext3  /dev/md0

データディスクのマウントポイントに悩む。/srv と /home はデータディスクにしたいけど、パーティションをきりたくない。/home は symlink にしたくないし、普通にマウントするようにしたい。

調べてみるとう mount --bind old new みたいにすればできるみたいだ。なので

  • /mnt/data に /dev/md0 をマウント
  • mount --bind /mnt/data/home /home
  • mount --bind /mnt/data/srv /srv

にしてみる。

$ sudo mount -l
/dev/md0 on /mnt/data type ext3 (rw) []
/mnt/data/home on /home type none (rw,bind)
/mnt/data/srv on /srv type none (rw,bind)

みたいになった。できたっぽい。

fstab に書く

/dev/md0                                  /mnt/data       ext3    defaults,errors=remount-ro 0       1
/mnt/data/home                            /home           none bind
/mnt/data/srv                             /srv            none bind

mysql

どうやるのがいいのかよくわからないけど、もとのサーバのファイルをそのままコピることにしてみた

sudo tar cpf /tmp/mysql.tar /var/lib/mysql
scp charlotte:/tmp/mysql.tar /tmp
cd /var/lib/mysql
sudo tar xpf /tmp/mysql.tar

しかしながら

ERROR 1045 (28000): Access denied for user 'debian-sys-maint'@'localhost' (using password: YES)   

とかでるので http://ubuntuforums.org/showthread.php?t=112505 にしたがって

GRANT ALL PRIVILEGES ON *.* TO 'debian-sys-maint'@'localhost' IDENTIFIED BY '<password>' WITH GRANT OPTION;

した。password は /etc/mysql/debian.cnf

バックアップとか

最終的なこうせい

  • 500GB (RAID1) -> /backup (pdumpfs で一日一回)
  • 250GB -> /home
  • 80GB -> /

データディスク以外は RAID かけないようにした。/home も一日一回バックアップあれば壊れたとき復元できるので RAID かけない。

2008年 06月 06日

サーバセットアップ

todo list

  • sshd
  • bind
  • apache
  • tiarra
  • plagger
  • mysql
  • openfl
  • iptables

めんどくさいな

とりあえず付属してきた 80GB の HDD をシステムディスクにするので ubuntu LTS をインスコ。

  • apt-get install
    • openssl-server
    • openssl
    • ssh
    • sshfs
    • gcc
    • libc6-dev
    • make
    • autoconf
    • ruby
    • subversion
    • apache2
    • bind9
    • git
    • git-svn
    • lv
    • screen
    • libxml2-dev
    • libssl-dev
    • vim (あとで入れなおす)
wget http://svn.coderepos.org/share/dotfiles/setup/cho45-setup.rb
ruby cho45-setup.rb

でだいたい自分の作業環境は整う。過去のじぶん++

  • cpan
    • Bundle::CPAN
    • CPAN
    • App::Ack
    • Catalyst::Devel
    • Plagger
    • ↑ だいたいこれで依存モジュールはいる
2008年 06月 05日

Io みたいな async を Ruby でやってみる

http://subtech.g.hatena.ne.jp/secondlife/20080605/1212634318 みてふと思いついたのでやってみた。

class Foo
	def heavy(n)
		sleep n
		n
	end
end

f = Foo.new

p :a
foo = f.async(:heavy, 2) # 即座にかえる
p :b
p foo # まつ
p :c
p foo # 即座にかえる
p :d

foo = f.async(:heavy, 2)
bar = f.async(:heavy, 5)
p :e
p [foo, bar] #=> 5秒まってから [2, 5]

foo = f.async(:heavy, 2)
bar = f.async(:heavy, 5)
p :f
sleep 5 # 5秒間カレントスレッドをとめてスイッチ
p :g
p [foo, bar] #=> 即 [2, 5]

Io の foo @heavy の雰囲気そのままな感じ。

スレッドなのでどこで実行されるかは確実ではない。Ruby のスレッドは IO 待ちとか sleep とかでスイッチする。

実装:

class Future
	def initialize(obj, name, args, block)
		@obj, @name, @args, @block = obj, name, args, block
		@th  = Thread.start do
			Thread.pass # 一応明示的に pass しておく
			@obj.send(@name, *@args, &@block)
		end
	end

	def method_missing(name, *args, &block)
		@th.value.send(name, *args, &block)
	end

	# 全部委譲してなりすます
	Object.instance_methods.each do |m|
		next if %w|__send__ __id__ object_id|.include? m.to_s
		undef_method m
	end
end

class Object
	def async(name=nil, *args, &block)
		Future.new(self, name, args, block)
	end
end

Thread をラップした Future をつくるだけなのでたいしたことはやってない。この方法だとどんなメソッドでも非同期にできる。

undef_method しまくって method_missing に飛ばしているので、パっと見もとのオブジェクトを変わらない Future インスタンスができる。(inspect も書きかえているということなので、p は信じてはいけない)
p は inspect をよんでるし、#{} は to_s をよんでいるので、透過的に扱えるようにみえる。このオブジェクトにメッセージがおくられた結果を使う限り、Future は見えない。

Lazy と似てるけど違うのは、呼ぶのが確定した時点でもう評価を開始するところ (Ruby のスレッドは暇になるまでスイッチしないけど)。最終的に準備ができていないと待たされるけど、準備できていれば待たされない。


あとでもこれだと symbol をわたしてなんかカッコわるいのでもう一個中間オブジェクトをかましてみる。

class Object
	def async(name=nil, *args, &block)
		name ? Future.new(self, name, args, block) : AsyncObject.new(self)
	end

	class AsyncObject
		def initialize(obj)
			@obj = obj
		end

		def method_missing(name, *args, &block)
			Future.new(@obj, name, args, block)
		end

		Object.instance_methods.each do |m|
			next if %w|__send__ __id__ object_id|.include? m.to_s
			undef_method m
		end
	end
end
p :a
foo = f.async.heavy(2) # 即座にかえる
p :b
p foo # まつ
p :c
p foo # 即座にかえる
p :d

a = f.async.heavy(1)
b = f.async.heavy(2)
c = f.async.heavy(3)

p :e
sleep 3 # カレントスレッドやすむ
p :f
p [a, b, c] # 即座にかえる

アクターモデルについては今調べたりしてみてるけど、まだよくわかってない……

コールバックは instance_eval

p [
	Kernel.async.sleep(3).async.instance_eval { p "done #{self}"; self },
	Kernel.async.sleep(2).async.instance_eval { p "done #{self}"; self },
	Kernel.async.sleep(1).async.instance_eval { p "done #{self}"; self },
]
__END__
"done 1"
"done 2"
"done 3"
[3, 2, 1]

最初の定義で、Object#async を Future よりあとに定義していることに注意が必要です。Future#async は method_missing よばれません (よばれるとこういうふうに書けないですね)。


サブテクの日記の最新タイトルをとってきてみる

require "net/http"
require "uri"

def aget(uri)
	puts "getting => #{uri}"
	Net::HTTP.async.get(uri).async.instance_eval {
		p "done #{uri}"
		self
	}
end

require "rubygems"
require "hpricot"

base = URI("http://subtech.g.hatena.ne.jp/diarylist")
doc = Hpricot(aget(base))

doc.search(".hatena-body .day .refererlist ul li a").map {|a| aget(base + a[:href] + "rss") }.map {|body|
	doc = Hpricot(body)
	[doc.at("//dc:creator").inner_text, doc.at("//item/title").inner_text]
}.each do |id, title|
	puts "id:%s : %s" % [id, title]
end

実行してみると getting と done がまざって実行されているのがわかると思う。一旦全部 async しないといけないから map が二回でてきてるのはかっこわるいかも……

2008年 06月 03日

typo しにくい id を自動生成

hiveminder のタスク id とかってidの16進数の下位4ケタみたいな感じになっているのですが、あれが激しくうちにくくて、ついでに連番っぽいので間違えて違うタスクを done しちゃったりします。そゆことにならないような id を生成するのをつくってみました。

  • 数字は遠いし typo しやすいので使わない
  • qwert キーボードに限定しない

というかんじにしたいので、aiueo 以外の文字 + aiueo を連番で出すようにしてみました。こういう配列は日頃からうっているのでうちやすいはず!!

class TypableMap < Hash
	Roma = "a i u e o k g s z t d n h b p m y r w j v l q".split(/ /).map {|k|
		%w|a i u e o|.map {|v| "#{k}#{v}" }
	}.flatten

	def initialize(size=2)
		@seq = Roma
		@map = {}
		@n   = 0
		@size = size
	end

	def generate(n)
		ret = []
		begin
			n, r = n.divmod(@seq.size)
			ret << @seq[r]
		end while n > 0
		ret.reverse.join
	end

	def push(obj)
		id = generate(@n)
		self[id] = obj
		@n += 1
		@n = @n % (@seq.size ** @size)
		id
	end
	alias << push

	def clear
		@n = 0
		super
	end

	private :[]=
	undef update, merge, merge!, replace
end

map = TypableMap.new
id = map.push(:foo)
p id #=> "aa"

map << :bar
map << :baz
p map #=> {"aa"=>:foo, "ai"=>:bar, "au"=>:baz}

かなり適当ですが結構うちやすいかなと思います。

でもって tig.rb に組み込んで自由に、確実に fav れるようにしてみました。( http://coderepos.org/share/changeset/13144 )

CTCP ACTION で fav ai などを送ると、目的のメッセージが fav できます。CTCP ACTION はクライアントによって送りかたが違いますが、irssi だと /me です。/me fav eita などなど

2008年 05月 29日

ERB binding layouts

http://d.hatena.ne.jp/m_seki/20080528#1211909590 を呼んでて、ナルホドナーと思いつつ、こうすることにした

body, *layouts = [<<EOB, <<EOL1, <<EOL2]
<%= foo %> and <%= bar %>
EOB
<div id="content">
	<%= content %>
</div>
EOL1
<html>
	<head>
		<title><%= title %></title>
	</head>
	<body>
		<%= content %>
	</body>
</html>
EOL2

stash = {
	:title => "foobar",
	:foo => "aaaaaaaaaa",
	:bar => "bbbbbbbbb",
}

require "ostruct"

s = OpenStruct.new(stash)
def s._render(_template)
	_template.result(binding)
end

puts layouts.inject(s._render(ERB.new(body))) {|r,i|
	s.content = r
	s._render(ERB.new(i))
}

def のシンタックス使うと内部の binding が変わってくれるので特異メソッドを def で定義してよんでみた。s._render で変数を極力使わないようにすれば、ERB 側でありがちな変数を書いてダメぽとかになりにくい