2011年 09月 28日

VPS に移設するものなどのメモ

自宅サーバをやめたい。

  • irssi
  • tiarra
  • irssw
    • perl + Plack のセットが必要
  • irc gateway 系
    • ruby1.8 と ruby1.9 系のいろいろが必要

使っているけど移設しない/できないの

  • OpenFL → やめて LDR に戻った。あんまり困らない
  • daap → 移設できないので無視する。必要な音楽ファイルは別途持ち歩く

時代を遡ってる気がする……

さくら VPS セットアップメモ

  • カスタムOSインストールで Ubuntu 10.04 amd64 をインストール
    • Chrome だと Java が起動しないので Safari で
    • 手順に従って情報を入力していく
    • Ubuntu の場合 root ログインはデフォルトで無効で安心
    • インストール中にユーザをつくるのでつくる
  • DNS を設定しておき、コンソールから逆引き設定をかえておく。
$ ssh hostname
$ sudo vi /etc/hostname
# かえたホスト名に
$ mkdir .ssh
$ chmod 0700 .ssh
$ ssh-keygen -t dsa
$ exit
# ログインしたいマシンで
$ cat ~/.ssh/id_dsa.pub | ssh hostname "cat >> ~/.ssh/authorized_keys"
$ ssh hostname # パスワードを訊かれないことを確認 (公開鍵認証でログインしたことを確認)
$ sudo vi /etc/ssh/sshd_config
PasswordAuthentication no
PermitRootLogin no
UsePAM no
$ sudo restart ssh
# 別のターミナルを開いて ssh できることを再度確認
$ sudo reboot # ホスト名反映のため一旦リブート
$ sudo apt-get install language-pack-ja # warning: setlocale: LC_ALL: cannot change locale (ja_JP.UTF-8) とかでるので……
$ sudo ufw default deny
$ sudo ufw allow 22
$ sudo ufw allow 80
$ sudo ufw allow 60000:61000/udp 
$ sudo ufw enable
$ sudo ufw status

すぐやるべきことはやったので作業環境をつくる

$ sudo apt-get install zsh
$ chsh -s /bin/zsh
$ sudo apt-get install screen
$ sudo apt-get install ruby
$ sudo apt-get install git-core
$ git clone git@github.com:cho45/dotfiles.git # github につくった id_dsa.pub を登録しておく
$ cd dotfiles
$ ruby setup.rb
$ exec zsh
$ screen -S main

$ sudo apt-get install gcc
$ sudo apt-get install libncurses5-dev

$ mkdir tmp
$ cd tmp
$ wget ftp://ftp.vim.org/pub/vim/unix/vim-7.3.tar.bz2
$ tar xjvf vim-7.3.tar.bz2
$ cd vim73
$ ./configure --prefix=/usr/local/vim7 --enable-multibyte --enable-gpm --enable-cscope --with-features=huge --enable-fontset --disable-gui --without-x --disable-xim --disable-perlinterp
$ make -j 2
$ sudo make install

tiarra を設定する

$ sudo apt-get install daemontools
$ sudo apt-get install daemontools-run
$ sudo ln -s /etc/service /service
$ cd ~/bin
$ cd
$ mkdir app
$ cd app
$ wget http://clovery.jp/tiarra/archive/2010/02/tiarra-20100212.tar.gz
$ tar xzvf tiarra-20100212.tar.gz
$ ln -s ~/app/tiarra-20100212/tiarra ~/bin
$ sudo mkdir -p /var/log/tiarra/{cho45,chokan}
$ sudo chown cho45 /var/log/tiarra/{cho45,chokan}   
$ sudo ln -s ~/dotfiles/services/tiarra /service/
2011年 09月 27日

gerry++

DBI で dsn パースしてオプションを一部奪いとる

dsn ごとに接続オプションを独自で追加したいみたいなとき、別途設定を増やしたりするのが嫌なので、dsn の中の仕組みを利用したい。

Plack::Session::Store::MySQL

Plack::Session::Store::DBI というのがあって、最初とりあえずそれを使っていたのだけれど、もうちょいクエリの数を減らしておきたいと思い、以下のようなものを書いた。実際のところセッションのストレージに MySQL を使うべきかはよくわからないのですが…

変更点として

  • セッションの内容が不変だったら UPDATE を発行しない
    • ただしシリアライザがハッシュに関しても常に同じシリアライズ結果を返す必要がある (Data::MessagePack や JSON の場合 canonical オプションがあるので有効にする)
  • セッションキーの存在を確認せず、ON DUPLICATE KEY UPDATE する (アトミックになる + クエリの数が減る)
package Plack::Session::Store::MySQL;
use utf8;
use strict;
use warnings;
use parent qw(Plack::Session::Store::DBI);

sub fetch {
    my ($self, $session_id) = @_;
    my $table_name = $self->{table_name};

    my $sth = $self->_dbh->prepare_cached("SELECT session_data FROM $table_name WHERE id = ?");
    $sth->execute( $session_id );

    my ($data) = $sth->fetchrow_array;

    $self->{$session_id}->{_prev_data} = $data;

    $sth->finish;

    $data ? $self->deserializer->( $data ) : ();
}

sub store {
    my ($self, $session_id, $session) = @_;
    my $table_name = $self->{table_name};

    my $data = $self->serializer->($session);

    if ($self->{$session_id}->{_prev_data} ne $data) {
        my $sth = $self->_dbh->prepare_cached("INSERT INTO $table_name SET id = ?, session_data = ? ON DUPLICATE KEY UPDATE session_data=VALUES(session_data)");
        $sth->execute($session_id, $data);
    }
}

1;
__END__

Sample schema:

    CREATE TABLE session (
        `id`           CHAR(72) NOT NULL,
        `session_data` BLOB,
        `modified` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
        PRIMARY KEY (id)
    ) ENGINE=InnoDB;
use Plack::Builder;
use Data::MessagePack;
use Plack::Session::State::Cookie;
use Plack::Session::Store::MySQL;

my $MessagePack = Data::MessagePack->new();
$MessagePack->canonical;

builder {
    enable
        "Plack::Middleware::Session",
        state => Plack::Session::State::Cookie->new(),
        store => Plack::Session::Store::MySQL->new(
            get_dbh      => sub { DBI->connect_cached(config->param('dsn_session'), 'foo', 'bar') },
            table_name   => 'session',
            serializer   => sub { $MessagePack->pack(+shift) },
            deserializer => sub { eval { $MessagePack->unpack(+shift) } || +{} },
        );
        
        $app
};

シリアライザ

Storable

  • 常に同じシリアライズ結果にできる ($Storable::canonical)
  • 可読性なし
  • データサイズ大
  • データ形式が Perl 限定 (Ruby でもパースできるという噂が)
  • bless 状態を保持できる

Data::Dumper

  • 常に同じシリアライズ結果にできる ($Data::Dumper::Sortkeys = 1)
  • 可読性あり
  • データ形式が Perl 限定
  • bless 状態を保持できる

JSON::XS

  • 常に同じシリアライズ結果にできる ($json->canonical(1))
  • 可読性あり
  • バイト列を保存できない
    • JSON の仕様上文字列しかないのでバイト列を保存したければ Base64 したりしなくてはいけなくて使いにくい
  • Storable よりは早い

Data::MessagePack

  • 常に同じシリアライズ結果にできる ($mp->canonical(1))
  • データサイズ小
  • バイナリ
  • 可読性ほぼなし (Storable と違って文字列は読める)
  • 早い
2011年 09月 26日

OSX のマウスの加速度がムカつく

// #!gcc -framework Cocoa -framework IOKit mouse.c
// code from http://lists.apple.com/archives/usb/2004/aug/msg00057.html

#include <stdio.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/hidsystem/IOHIDLib.h>
#include <IOKit/hidsystem/IOHIDParameter.h>
#include <IOKit/hidsystem/event_status_driver.h>

int main () {
	NXEventHandle h = NXOpenEventStatus();
	if (!h) return 1;
	IOHIDSetAccelerationWithKey( h, CFSTR(kIOHIDMouseAccelerationType), -1.0);
	return 0;
}

を実行すれば一応加速はきれる。けど速度が固定になってしまう (遅い…)

defaults write .GlobalPreferences com.apple.mouse.scaling -1

ってやればいいだけかもしれないけど、こっちは再起動がいる。(上のコードだと即時で反映される)

2011年 09月 14日

gerry++

2011年 09月 12日

Universal Block Protocol

2011年 09月 08日

ACE のシンタックスハイライトルールを独立で使う

function dependon (check, src) {
	return function () {
		var ret = Deferred();
		check = new Function('try { return !!(' + check + ') } catch (e) { return false }');
		if (check()) {
			Deferred.next(function () { ret.call() });
		} else {
			var script = document.createElement('script');
			script.charset = 'utf-8';
			script.src = src;
			document.body.appendChild(script);
			setTimeout(function () {
				if (!check()) {
					setTimeout(arguments.callee, 100);
				} else {
					ret.call();
				}
			});
		}
		return ret;
	};
}

var Supported = {
	'perl' : 'Perl',
	'javascript' : 'JavaScript',
	'css' : 'Css'
};

function highlight (container) {
	container.find('pre.code').each(function () {
		if (/lang-(\S+)/.test(this.className)) {
			var lang = Supported[RegExp.$1.toLowerCase()];
			if (!lang) return;
			var pre  = $(this);
			var code = pre.text();

			Deferred.chain(
				dependon('ace', '/js/editor/ace/ace-uncompressed.js'),
				dependon('require("ace/mode/' + lang.toLowerCase() + '_highlight_rules")', '/js/editor/ace/mode-' + lang.toLowerCase() + '.js')
			).
			next(function () {
				var Tokenizer = require("ace/tokenizer").Tokenizer;

				var rules = require("ace/mode/" + lang.toLowerCase() + "_highlight_rules")[lang + 'HighlightRules'];
				var tokenizer = new Tokenizer(new rules().getRules());

				var parent = document.createDocumentFragment();

				var state = 'start';
				var lines = code.split(/\n/);

				return Deferred.repeat(lines.length, function (i) {
					var line = document.createElement('span');
					line.className = 'line';

					var tokens = tokenizer.getLineTokens(lines[i], state);
					for (var j = 0, it; (it = tokens.tokens[j]); j++) {
						if (it.type == 'text') {
							line.appendChild(document.createTextNode(it.value));
						} else {
							var span = document.createElement('span');
							span.className = it.type;
							span.appendChild(document.createTextNode(it.value));
							line.appendChild(span);
						}
					}

					line.appendChild(document.createElement('br'));
					parent.appendChild(line);

					state = tokens.state;
				}).
				next(function () {
					pre.empty().append(parent);
				});
			}).
			error(function (e) {
				alert(e);
			});

		}
	});
}