レンタルサーバーだと CGI しか使えなくてイライラ感が募り、でも家にサーバーは置きたくない。だけど root 権限で Linux を動かしたい。わがまま。
EC2 より VPS の方が現実的だなということで、ホスティング先を調べ CPI との二択になり少し悩んでいたけど、初期導入費用が無料になっていたので、釣られて使えるねっとにしてみました。
デイリーバックアップ付きで月額 3505 円。高い感じがするけど家にサーバーを置いて電気代、放熱、バックアップする手間を考えると決して高くないと思います。時折パフォーマンスが落ちるようですが、まず試してみます。
で、すぐにというわけではないですが、検証含めてこの日記を VPS に移行します。怒られちゃうけど Movable Type のブログのほうは消そうと思います。とはいえ、さすがに書いたエントリは日記のほうに起こすつもりです。
MT 重いです。再構築がつらい。それから MarkDown 記法を使っていましたが、 tDiary 記法が数倍書きやすいです。慣れなんでしょうが、気軽に書けることが大事だなと再認識させてくれました。 MT が自分とは合わなかったというだけです。
なお VPS の OS は CentOS みたいです。 Debian/Ubuntu でないけど RPM は業務で使うだろうし、これもまた勉強だなと。
時間が取れたので使えるねっと VPS の構築を開始。深夜にものすごく応答が悪くなって寝た。
今回の目的の一つである Redmine の構築を始める。 BTS では Trac より人気が出てきているため、使用感を押さえておく必要があること、それから自分で作るアプリケーションのタスク管理もしたいのでまずはプライベートで使用してみようという試み。最近 Git 人気に乗って使っているので Git をサポートしてくれているのも大きい。リポジトリが bare である必要があり一緒のサーバーに置いてしまおうという試み。
そんなわけで構築をし始めると、使えるねっとの Apache の Options の設定が SymLinksIfOwnerMatch を指定していた。シンボリックリンク元と先で所有者が違うとエラーになる。ということを知りました。処理が増えるけどセキュリティを向上させたい場合に使うみたい。何も考えず FollowSymLinks を使っていた。
シンボリックリンク先の所有者を変えたいけど、シンボリックリンク元の所有者が root だった場合、シンボリックリンク先の所有者をすべて root にするみたいで、そんな設定でアプリケーションを実行したらきっといけない。
Redmine は root はいけないみたいだし、これはまずいなあということでシンボリックリンク元の所有者を変えようと
chown apache:apache redmine
やってみても変わらない。あーシンボリックリンク先を変えてるだけorz
chown のヘルプを見ると -h, --no-dereference をつけてあげればいいみたいです。
chown -h apache:apache redmine
シンボリックリンク元の所有権が無事 apache になり、無事実行された。つまらないことではまりつつ、なんとか Apache + Passenger + Redmine + MySQL な環境を構築できた。
ふう・・・しかし早い早い。これなら使い続ける気になる。
それにしても構築の道は長いなあ。
使えるねっと VPS に Redmine を構築後にメモ。
インストールしたときのバージョンは以下の通り。
OS のバージョンを調べる。
$ cat /etc/redhat-release
CentOS release 5.3 (Final)
CPU アーキテクチャを調べる。
$ uname -m
x86_64
5.3 のリポジトリから yum をインストール。 yum-fastestmirror が yum に依存しているけど、まだ yum が入っていないので強制的にインストールする。
rpm -ivh yum-fastestmirror-1.1.16-13.el5.centos.noarch.rpm --nodeps
それから CentOS のリポジトリや rpmforge の ruby には 1.8.5 までしか入っていないので Redmine を動かすためのバージョンを満たせない。 ruby 1.8.7 をソースからインストール。 --prefix=/usr/bin で configure した。
Ruby をインストールできたところで gems もインストールして、必要なライブラリをインストール。
Ruby/passenger に必要なライブラリを yum からインストール。 gcc は Ruby をインストールするよりも前に入れた。でないと make できない。 zlib/openssl は $RUBY_SRC/ext で make install するため。
sqlite はおまけ。依存関係がクリアできたところで passenger の apache モジュールを作成する。
$ sudo passenger-install-apache2-module
Redmine に必要な Apache 設定ファイルを作成する。 httpd.conf の設定をみてみると
Include conf.d/*.conf
という記述があり conf.d に入れておけば勝手に include してくれるみたいなので redmine.conf ファイルを conf.d に作成。多分 httpd.conf には修正だけで追加はするなってことだと思う。
LoadModule passenger_module /usr/lib/ruby/gems/1.8/gems/passenger-2.2.2/ext/apache2/mod_passenger.so PassengerRoot /usr/lib/ruby/gems/1.8/gems/passenger-2.2.2 PassengerRuby /usr/bin/ruby RailsBaseURI /redmine
サブドメインで運用するわけではないので、 VirtualHost を利用せず直接 RailsBaseURI で Rails アプリケーションのルートを指定。今のままだと他の Rails アプリケーションは同時に運用できないんだろうなあ。
そして MySQL にログインして redmine データベースをつくって権限を与える。その前に /etc/my.cnf に encoding の設定をしておくと Redmine の言語対応するときにエラーにならない。
それから Redmine の database.yml を設定。
production: adapter: mysql database: redmine host: localhost username: hoge password: hoge encoding: utf8 socket: /var/lib/mysql/mysql.sock
socket の生成場所を指定する。 my.cnf で変更したらそれに合わせる。
DB を構築。それから言語に対応したデータをテーブルにロードする。
$ rake db:migrate RAILS_ENV=production $ rake load_default_data RAILS_ENV=production
ENV['RAILS_ENV'] ||= 'production'
production で動作するようにコメントアウト。
/var/www/vhosts/default/htdocs 直下に redmine アプリケーションの public ディレクトリへシンボリックリンクを作成する。所有者には apache ユーザー/グループを割り当てる。
Apache を再起動して多分動く。色々試行錯誤しながらだったので、何か抜けていて動かなくてもごめんなさい。仕事なら怒られますね。
急にスターウォーズをシリーズ通して見たくなったので、 TSUTAYA DISCAS からレンタルすることにしました。このサービスにはシリーズ機能というものがあって、有効にすると 1 巻から順に配送してくれるようになり、いちいちユーザーがレンタル順位を並び替える必要がなくなるという便利な機能です。また通常指定の場合必ずしも順位通りに配送されるわけではありません。
今回初めてこの機能を使ってみたのですが、シリーズのイメージのところがトグルになっています。この画像の状態では有効になっていないと思ってクリックして切り替えてみたのですが、実際に発送が行われてみると EP2, EP3 が送られ涙目に。なおスターウォーズは 4 からだろ・・・というツッコミはなしです。

今回へまってしまいヘルプを見なかった(あるのか知りません)自分に非はあるとは思いますが、その場で分かる方が嬉しいです。例えばイメージを「ON 中」とする。またはツールチップで「有効にします」といった情報を乗せることで、自分みたいな勘違いが減るのかなと思います。毎回出るのもうざいのでマウスオーバーして 500ms 経ったら表示するぐらいが親切?
アイコンなどでビジュアル化すると、ページの見た目が鮮やかになったり、メニューなどの表示がすっきりします。その反面少しでもあいまいな部分があれば、使うユーザーによって受け取り方もそれぞれになります。
一回のミスで学習はするので、良いといえばそれまでですが、一回もミスさせないつくりのほうがいいですよね。
Cubby 2.0 が OVal をサポートして入力検証をアノテーションでできるようになったということですが、 OVal を使ったことがなかったので触ってみました。バージョンは 1.31 です。
OVal - the object validation framework for Java™ 5 or later -
使ってみるとオブジェクトにアノテーションをつけて、インスタンスを validate するだけというシンプルなもので終わってしまいました。せっかくなので郵便番号の検証アノテーションを実装してみます。
今回作成する必要があるものは以下のものになりました。
まず ZipCode アノテーションを定義します。ここで実装ロジックのクラスを指定しますが、まだ存在しないためコンパイルエラーになります。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Constraint(checkWith = ZipCodeCheck.class)
public @interface ZipCode {
String format() default "^\\d{3}(?:\\-\\d{4})?$";
}
つづいて検証ロジックを実装します。アノテーションとお互いに依存しあっているため、アノテーションと同時に作成する必要があります。ロジックは AbstractAnnotationCheck クラスを継承します。
public class ZipCodeCheck extends AbstractAnnotationCheck<ZipCode> {
private static final long serialVersionUID = 1L;
private Pattern pattern;
@Override
public void configure(ZipCode constraintAnnotation) {
requireMessageVariablesRecreation();
pattern = Pattern.compile(constraintAnnotation.format());
}
public boolean isSatisfied(Object validatedObject, Object valueToValidate, OValContext context, Validator validator)
throws OValException {
if (!(valueToValidate instanceof String)) {
return false;
}
String value = (String) valueToValidate;
if (value == null) {
return true;
}
return pattern.matcher(value).find();
}
@Override
protected Map<String, String> createMessageVariables() {
Map<String, String> messageVariables = new HashMap<String, String>();
messageVariables.put("pattern", pattern.pattern());
return messageVariables;
}
}
指定したメッセージを出力するために createMessageVariables をオーバーライドし、メッセージで表示したいパラメーターを Map に登録します。 configure メソッドで requireMessageVariablesRecreation() を呼び出さないと createMessageVariables メソッドが呼ばれません。
カスタムメッセージを出力するプロパティファイル、ここでは messages.properties を作成します。キーは検証ロジック名の Check を取り除いた文字列 + .violated または 検証ロジック名 + .violated になります。
net.pshared.sandbox.oval.ZipCode.violated = {context} は郵便番号の形式になっていません。 :{pattern}
メッセージに含む {pattern} と createMessageVariables メソッドで返す Map の pattern が結びつきます。ファイルは作成せず configure メソッドで message プロパティに直接埋め込んでもよいみたいです。
エントリポイントを含むクラスです。
追加したプロパティファイルを登録し、後は対象インスタンスを validate することでエラー内容がリストで返ってきます。
public class OvalClient {
public static void main(String[] args) {
ResourceBundleMessageResolver resolver = (ResourceBundleMessageResolver) Validator.getMessageResolver();
resolver.addMessageBundle(ResourceBundle.getBundle("messages"));
Hoge h = new Hoge();
h.name = "hoge";
h.age = -1;
h.zipCode = "0";
h.date = new Date();
Validator validator = new Validator();
List<ConstraintViolation> list = validator.validate(h);
for (ConstraintViolation cv : list) {
FieldContext ctx = (FieldContext) cv.getContext();
System.out.println(ctx.getField().getName() + ":" + cv.getMessage());
}
}
private static class Hoge {
@NotBlank
@MaxLength(24)
public String name;
@NotNull
@NotNegative
public Integer age;
@ZipCode
public String zipCode;
public Date date;
}
}
age:net.pshared.sandbox.oval.OvalClient$Hoge.ageは負の数ではいけません。
zipCode:net.pshared.sandbox.oval.OvalClient$Hoge.zipCode は郵便番号の形式になっていません。 :^\d{3}(?:\-\d{4})?$
validate をかけた後にどのフィールドでエラーが発生したのかが ConstraintViolation から取得できず、 FieldContext から取得しています。
お試しで使っていましたがバリデーションフレームワークとして、かなり柔軟なものだと感じました。 Cubby で作っているアプリケーションでは、 OVal を使ってみようかなと思います。
http://www.pshared.net/pub/greasemonkey/ldr_vi_move_entry_comman.user.js
あるフィードの貯まった未読エントリを読み終わって移動した後に、直前のフィードの終わり間際のエントリが見たいと思うことがまれにあります。戻って j を連打しても遠く、結局スクロールして移動してしまうのが辛いので移動できるコマンドを実装しました。
LDR 上で : を打った後に中の人のメッセージ内でコマンドが打てます。
:gg
:G 50
:G
なお a/s で移動した直後に実行すると一番下まで移動してくれません。いったん j/k で移動した後にコマンドを実行すると正しく一番下まで移動します。調べる気力がなかったこと、だいたい合ってればよかったので諦めました。
[追記]
最初のエントリにも移動できるようにしました。
[追記]
vi は小文字の g では移動しないので G の後に数字を指定するようにしました。
むしゃくしゃして 1TB を買った。今も後悔していない。
何にびっくりしたのかって Time Capsule の電源を入れた後に、ノート PC に AirMac ユーティリティをインストールすると自動的に Time Capsule を探し出してセットアップを開始してくれることでした。 LAN ケーブルを繋げずルーター用のパスワードを入力し、後はプロバイダーのアカウント、パスワードを入れればそのままネットに接続できることに感動しました。
ただ Time Capsule の電源を入れてから、ルーター用のパスワードを入れるまでは危険な気もしましたがどうなんでしょうか。
使用感としてはノート PC から Time Capsule まで 2m ぐらい離れているんですが、 HDD に書き込んでいるときの音は少し聞こえる程度です。エアコンと同じぐらいの音量と言えば、そこまで五月蠅くないのが伝わるでしょうか。
ただ今 Time Machine でバックアップ中で、初回は半日かかるレベルらしいので放置しています。結構発熱しています。
自分が Mac 関連の製品を買うと、次の WWDC で購入した製品に何らかのアップグレードが発表されますので、 9 月あたりに 2TB が出るんじゃないのかなあと思っていますw
引数を指定することでコピーするフォーマットを変えられるようにしてみました。
copy-title-url tdiary
_templates に定義することで、拡張が自由に行えます。
tDiary, hatena, MT(Markdown), pukiwiki, HTML に対応しています。
試しにこのエントリのタイトルと URL を tDiary 形式でコピーしてみます。
copy-title-url tdiary
[[タイトルと URL をコピーする Ubiquity コマンド - Ussy Diary(2009-06-22)|http://www.pshared.net/diary/20090622.html#p03]]
今回は文字列をフォーマットするようにしましたが、見やすくする目的だけであれば Array で join したほうがパフォーマンス的にもよいと思います。
Ubiquity の最新版が出ていたのでアップデートしてみたところ、既存スクリプトのいくつかが動かなくなってしまいました。
調べてみると引数を受け取ることを指定する takes プロパティが原因みたいで、 argument, arguments に置き換えることで動くようになりました。 0.5 ではスクリプト名も複数つけられるようになっていて、キーワードショートカットっぽいこともできて API も使いやすくなった感じです。
ところで今回ソースを見ていて知ったのですが、 Firefox の JavaScript は仮引数に連想配列っぽく指定できるんですね。これが分割代入というやつですか。
function hoge({name, age, address}) {
console.log(name, age, address);
}
hoge({age: 18, name: "foo"});
foo 18 undefined
それから今回のアップデートで日本語が対応したみたいです。
「英語から日本語に翻訳して」日本語で命令 - Fierfox Ubiquity | エンタープライズ | マイコミジャーナル
コマンド「訳して」
これはすごい。
http://www.pshared.net/pub/greasemonkey/reload_youtube_simple_url.user.js
Youtube のリンクには feature であったり key といった様々なパラメーターが URL にくっついてきます。
そんなリンクから面白い動画を見つけて delicious にブックマークしようとしても URL が周りと共有(一致)できていないことが多々あります。 http://{country}.youtube.com/watch?v={video_id} の形式でみんな保存していて、ブックマークするたびに手動で URL を削る作業には疲れてしまいます。そんなわけで自動でパラメーターが v だけにしてリロードするグリモンを書きました。 (delicious と youtube が canonical 属性に対応してくれれば解決する問題でしょうか)
ただしこのままだと fmt パラメーターのついた高画質の動画が見られないので、自分はこちらのグリモンを併用しています。
YouTube HD Ultimate for Greasemonkey
Flash Player にパラメーターを渡しているためブラウザの URL はそのままという便利なグリモンです。もし使う場合は YouTube HD Ultimate の優先度(位置)をこれより上げておく必要があります。
http://www.pshared.net/pub/greasemonkey/sbmcounter_comment_command.user.js
コメントをみたいときにいつもマウスを右下まで持って行きコメント表示していましたが、キー操作のほうが早くみられるかなということで Minibuffer からショートカットで見られるようにしてみました。
スクロールはなるべく視点を同じところに保っていられると思う量にしています。人によっては少ないと感じる量なので調整してください。
http://www.pshared.net/pub/greasemonkey/upper_directory_command.user.js
初めて Minibuffer にローカル機能を追加してみます。コードを見てみると open コマンドの後の引数に target を指定できるみたいで、 Minibuffer 上で確認できました。
upper-directory | open _self
現在のタブに開くものはこれからも使える気がするので、コマンドとして登録しておきます。後はショートカットキーを登録するだけです。
[2010/08/29 追記]
Open External で検索される方がこられるみたいなので。
今は google code にプロジェクトが置かれています。 http://code.google.com/p/plug-ins/
なお僕の環境だと jar ファイルをインストールしても、認識してくれませんでした。そこでソースから自分でプラグインを作成したところ、認識してくれました。
[/2010/08/29 追記]
Open External はパッケージ、ディレクトリ、ファイルといったところで右クリックすると、対象の指定したパスで Explorer やコマンドプロンプトを開いてくれるプラグインです。
どうやらプラグインの update site が一時的に移動したみたいです。 サイトのコメントより。
http://update.eclipsegeek.com/ でなく http://update2.pragmatic.kr/ で。
Windows のエクスプローラーだけでなく Mac の Finder やターミナルにも対応してくれていて、 Mac のターミナルも新しいウィンドウでなく新しいタブで開くことができる、痒いところに手が届くプラグインで、今はないと困るプラグインです。
# 雷悶 [使い慣れてくると :gg で一番上まで行きたい気分です ><]
# Ussy [1g って打ってました>< 実は :G もつい最近知りました。 vi 難しい。。。]