Sunday, November 8, 2009

Google's OAuth doesn't seem to support wave as a scope yet?

After releasing Unofficial Google Wave Notifier, many people have claimed it may steal gogle password.
They are right. you should not trust me nor the app. From beginning I know the issue, I'm sorry, but I'v neglected the security concern as I hasten to release the app.
(A poor execuse to prove my innocence. I open the source. Suspicious users should review the source and build a binary from reviwed source.)

Current version (0.4) of the app uses ClientLogin for Installed Applications for authentication. In the process, apps handles passwords immediatly.

By contrast with ClientLogin, apps which uses OAuth for Installed Application handles oauth tokens instead of precisous passwords.

It is obvious that I should choose OAuth. However I can't get it so far. At OAuth Playground, I tried to get oauth_token. The paramerters I specified are:
scope: https://wave.google.com/wave/
oauth_signature_method: HMAC-SHA1
oauth_consumer_key: anonymous
consumer secret: anonymous
And the response is:
Invalid scope: https://wave.google.com/wave/


By choosing other scope, I can get a oauth_toke.... I missed something? or Google doesn' support wave as a oauth scope (yet)?

Tuesday, November 3, 2009

Unofficial Google Wave Notifier for mac 0.4 and the notification wave



I'v just released version 0.4 of Unofficail Google Wave Notifier for mac.
Also, if you wanna be notified about new releases, join The "unoffical google wave notifier for mac" notification wave.

CHANGELOG
* Open a specific wave immediately by clicking a wave in the menu
* Display "Checked N min ago" biside "Check Now" like "Google Notifier"

Friday, October 23, 2009

Queuing ruby background processes with Ernie and BERT-RPC

僕のようにインフラ系が弱い Rails プログラマにとっては、 GitHub のインフラ担当? Tom Preston-Werner (aka mojombo) の GitHub ブログポスト How We Made GitHub Fast - GitHub は非常に参考になります。なかでも興味を引いたのは続くポスト Introducing BERT and BERT-RPC で紹介されている BERT-RPC とその実装の Ernie ですね。

過去には Rails アプリケーションのバックグラウンド処理で苦労した思い出があるので今度ツールを選ぶときは以下の課題を解決してくれるやつがほしいなと思ってました。
1. 重たい処理が連続してリクエストされたときに並列で実行せずに1タスクごとキューイングして実行してほしい
2. worker が死んでも自動で代わりを起動してほしい
3. 非同期も同期(終了するまでブロック)も両方OK

1 は Ernie の -n オプションで同時実行される handler の数は制限できるので -n 1 にすれば queue になるはず。

2 は BERT-RPC は call (同期), cast (非同期), info (コールバック情報などの送付) 3つの request が定義されていて、 ernie (v0.1) では call と cast の両方をサポートしているので同期/非同期両方OK。

3 はうろ覚えだけど Erlang でふつうにサーバーを実装すれば wroker (handler) の再起動とかはかってにやってくれるはず。実際に handler の ruby プロセスを kill してもすぐ代わりが起動するので大丈夫そうだ。

実際に queue になるか試してみた。 erlang ernie をインストール、簡単な handler を書いて、サーバーを handler 1つで起動。

$ sudo port install erlang +ssl # 時間かかります
...
$ sudo gem install ernie -s http://gemcutter.org

$ cat > sleep.rb
require 'rubygems'
require 'ernie'
mod(:sleep) do
fun(:wait) do |idx, sec|
sleep sec
print "#{idx}: awake from #{sec} sec.\r\n"
end
end
^d

$ ernie -p 9999 -n 1 -h sleep.rb
erl -boot start_sasl -detached +Bc +K true -smp enable -pz /Library/Ruby/Gems/1.8/gems/ernie-1.0.0/bin/../ebin \
-ernie_server_app port 9999 -ernie_server_app handler '"sleep.rb"' -ernie_server_app number 10 -ernie_server_app log_level 2 -run ernie_server_app boot
...

別 shell の irb で 2秒スリープ指定 で 10回 cast。

$ irb -r bertrpc
>> svc = BERTRPC::Service.new('localhost', 9999)
=> #
>> 10.times{|i| svc.cast.sleep.wait(i, 2) }
=> 10

$ ernie を実行した erlang shell では

0: awake from 2 sec.
1: awake from 2 sec.
2: awake from 2 sec.
3: awake from 2 sec.
4: awake from 2 sec.
5: awake from 2 sec.
6: awake from 2 sec.
7: awake from 2 sec.
8: awake from 2 sec.
9: awake from 2 sec.

実際に見てると2秒ごとに出力されていたので、ちゃんと queuing されてますね。

Sunday, October 18, 2009

Unofficial Google Wave Notifier for mac

2009-11-17: If you have any idea, feel free to issue a feature request, or vote them (the small triangle at bottom-left corner of a item)
2009-11-3: version 0.4 released



I wolud like to know whether I have unread messages at Google Wave or not, like Google Notifier for Mac for GMail and Google Calendar. I could find Google Wave Add-on for Firefox at That Smith. So I implemented one as referencing the add-on. Thank you Chad at That Smith.

You can download it form Downloads for hiroshi's Unofficial-Google-Wave-Notifier - GitHub. Before download it, be sure that is makes NO WARRANTY.

Google Wave の新着通知も Google Notifier for Mac のように通知されたいのですが、探しても Google Wave Add-on for Firefox at That Smith しか見つからなかったので、その Add-on のソースを参考にして作ってみました。

Downloads for hiroshi's Unofficial-Google-Wave-Notifier - GitHub からダウンロードできます。

Tuesday, September 1, 2009

routes_cov to reveal untested actions


I'v released a new rails plugin, routes_cov. This plugin tells you whether untested controller action there or not against routes. I'll be happy if you think it it useful.

routes_cov というRailsプラグインを作ってみました。テストで実際に実行されたアクションと routes (rake routes で表示されるやつ) を比較してテストされてないアクションを列挙します。まだまだ改善の余地はありますが、使ってみて下さい。



$ rake test:functionals
....
Finished in 13.932317 seconds.

121 tests, 307 assertions, 0 failures, 0 errors

There are unperformed actions here:
groups#index
groups#show
users#member
...

Monday, August 17, 2009

port install subversion+unicode_path

git-svn を試してみようと思って macports で git-core +svn をインストールするときに、何気に subversion port の info を見たら unicode_path という variant があるじゃないですか。
パッチファイルのコードを見るとなんだか見覚えがあります。
例の subversion の issue のコメント (by Philip Kime)を見るとやっぱり僕のパッチがもとになってるようです。

というわけで、前回の記事で紹介した方法のように面倒なことしなくても、

$ sudo port install subversion +unicode_path

で OK です。MacPorts 万歳。

ちなみに、 +unicode_path のパッチファイルは以下のパスにあるハズです。

/opt/local/var/macports/sources/rsync.macports.org/release/ports/devel/subversion/files/patch-path.c.diff

ソースコードコメントのインチキな英語もそのままだ...。

Friday, August 7, 2009

Cutting a git commit off a branch, and pasting it on another

git のトピックブランチでの作業中にバグ修正をコミットしたんですけど、そいつをリリースしようとしたときに、まだリリースできない変更を含むトピックブランチにコミットしてたことに気づくことがあります。
Subversion ならトピックブランチのコミット済みの履歴をもとに戻すことできないので、そのコミットのリビジョンだけを trunk にマージしますね。
Git でも同様にその変更をだけをマージすれば簡単なんですけど、 git の rebase とかでトピックブランチへのコミットを無かった事にして、 master に移動できるのではないかと考え頑張ってみました。

作業前の状態はこんな感じです。 i18n ブランチの b1ad369 が移動したい commit です。

$ git log --oneline -5 i18n
431120e localize filters#new in Japaense
b1ad369 handling EOFError in Feed.open()
4d4dac5 Japanese localizing top page
c04524f I18n support
2688536 Down rails version form 2.3.3 because of Hoptoad doesn't work.

"git rebase --onto newbase upstream [branch]" の構文に当てはめると、

$ git rebase --onto 4d4dac5 b1ad369 i18n

これで、バグ修正のコミットは i18n ブランチから削除されました。
$ git log --oneline -4 i18n
51a74d5 localize filters#new in Japaense
4d4dac5 Japanese localizing top page
c04524f I18n support
2688536 Down rails version form 2.3.3 because of Hoptoad doesn't work.

ここで、注意するべきは b1ad369 のあとの commit のハッシュが 431120e から 51a74d5 に変更されていることです。歴史を変えたのでタイムパラドックスが発生、同じように見える現在が微妙に変わる感じですかね。また、 b1ad369 は i18n ブランチからは削除されましたが、 commit は存在しています。

$ git log --oneline -4 b1ad369
b1ad369 handling EOFError in Feed.open()
4d4dac5 Japanese localizing top page
c04524f I18n support
2688536 Down rails version form 2.3.3 because of Hoptoad doesn't work

ちなみに、このケースでは master ブランチには i18n が分岐してからは何もコミットされていないので、

$ git log --oneline -1 master
2688536 Down rails version form 2.3.3 because of Hoptoad doesn't work.

i18n ブランチの履歴にも登場した 2688536 が master HEAD になります。
ここから commit b1ad369 をマージするためにはこの無名ブランチから b1ad369 と 2688536 の間2つ commit を削除しなければならないかと思ったのですが、 cherry-pick (つまみ食い) という便利なコマンドで任意の commit の変更だけマージできます。

$ git checkout master
$ git cherry-pick b1ad369

これで期待通りの結果になりました。

$ git log --oneline -2 master
92244c5 handling EOFError in Feed.open()
2688536 Down rails version form 2.3.3 because of Hoptoad doesn't work.


2008-8-8: 更新


コメントの指摘により cherry-pick を使うように変更しましたので不要になった部分は以下 display:none してます。

b1ad369 を無名ブランチの HEAD として考えて、 master HEAD との間にある2つの commit を rebase で削除してから master にマージすれば期待している結果になるはずです。(ここで早まってマージするとその要らない2つの commit もマージされてしまいます。)

$ git rebase --onto 2688536 4d4dac5 b1ad369
$ git log --oneline -2
0960a76 handling EOFError in Feed.open()
2688536 Down rails version form 2.3.3 because of Hoptoad doesn't work.

ここでも、過去を変更した以降の commit は別の hash になるのでそれを指定して master にマージ

$ git checkout master
$ git merge 0960a76
$ git log --oneline -2 master
0960a76 handling EOFError in Feed.open()
2688536 Down rails version form 2.3.3 because of Hoptoad doesn't work.

結果は期待通りですが、正直、二度とこんなことしたく無い感じですね。一発でできるコマンドありそう。

Thursday, July 30, 2009

Passenger: Keeping ApplicationSpawner alive speeds up spawning an instance (updated)

前回 passenger プロセスの起動時間について書いたとき passenger のバージョンは 2.0.3 でしたが、あれから 9ヶ月、 2009-07-29 現在の最新バージョンは 2.2.4 になってます。

そのときは passenger の constants.rb を直接変更するという荒技で FrameworkSpawner と ApplicationSpawner のタイムアウト時間を長くしてましたが、いつのまにか RailsFrameworkSpawnerIdleTimeRailsAppSpawnerIdleTime という Apache の設定で変更できるようになってます。こいつらを 0 にすれば FrameworkSpawner は Apache を再起動するまで、 ApplicationSpawner は Apache を再起動するか、 touch restart.txt するまで持続します。

また、前回の記事 では Capistrano でデプロイしたときに (タイムアウトを延ばしているときは特に) ApplicationSpawner を KILL しないと古いデプロイの ApplicationSpawner がずっと残ると書いたんですけど、 2.2.0 の "Support for Capistrano-style deployments" により、 Capistrano 使ってても touch restart.txt で ApplicationSpawner が再起動するので KILL する必要は無くなりました。
(でも、2.2.0 から 2.2.2 までは 2.2.3 の "Fixed restarting of the ApplicationSpawner server" が修正されてなかったので worker process がみんなタイムアウトしている間に restart すると古い ApplicationSpawner が残っちゃってたみたいです。)

ちなみに、Apache 再起動直後の FrameworkSpawner も ApplicationSpawner もいないときと、 worker process だけ fork するときの速度をブラウザのページロード時間で測ると、(僕の環境では)5.6秒が1.0秒になるので、デフォルト設定で FrameworkSpawner がタイムアウトする時間30分に一度アクセスがあるかどうかわからないようなサービスではこの設定は必須かと思われます。

2009-7-30 10:00 追記


結論だけ言うと、 passenger-install-apache2-module を実行した直後に追加する apache の設定に1行追加すればOKです。

PassengerRoot /opt/ruby-enterprise-1.8.6-20090610/lib/ruby/gems/1.8/gems/passenger-2.2.4
PassengerRuby /opt/ruby-enterprise-1.8.6-20090610/bin/ruby
+ RailsAppSpawnerIdleTime 0

ApplicationSpawner が常駐することによるメモリ消費は僕の小さなアプリケーションREE を使っていれば private メモリで 25M 程度でした。これだけのコストでアプリケーションのレスポンスタイムの5秒ぐらいのロスが無くなるなら大歓迎でしょう。 Passenger のデフォルト設定でもいいかと思うぐらい。

Friday, July 24, 2009

a bookmarklet which loaded external script and open in another window


I updated the bookmarklet for FeedKraft. Changes are:
* Now it work even alternate links have relative path (URI).
* Open feedkraft in another window.

To keep maintainability, I decided to split complex part of the scripts into a external js file. However, Safari 4 seems to just ignore window.open() in a external loaded script, and Firefox 3.5 asks users whether popup a window or not.

To get those features work for Safari and Firefox, I struggled with javascript, but I got it.

FeedKraftbookmarklet を更新して
* alternate link の href が相対パス(URL) でも登録できるように
* 別 window で開くように
しました。

"/feed/atom.xml" のようなパスをURLに変換するコードはそれなりに長くなるので bookmarklet の javascript: 以下に続けて書くメンテしずらいので、外部 js ファイルをロードするようにしました。
しかし、外部 js ファイルからでは 別 window で開くための window.open() を実行しても Safari 4 では何も起きないし、 Firefox 3.5 では ポップアップブロックの確認が生じてしまいます。

試行錯誤の末、以下のようなコードになりました(見やすいように空白や改行を入れてます)。



javascript:
void(w = window.open());
void(e = document.createElement('script'));
void(e.src = 'http://feedkraft.com/bookmarklet.js');
void(e.addEventListener('load', function(){ w.location = FeedKraft.bookmarkURL()}, false));
void(document.body.appendChild(e));



Why does window.open() first is to avoid calling it in load event handler which behave like external file (I mean can't open a window). Annoying void() is for Firefox. Without enclosing a sentence with void(), the script will return with result of the sentence.

I'm not a Javascript ninja. I never think that this is the best solution. Please give me advice if you have idea.

load イベントで直接 window.open() すると外部 js ファイルで実行したときと同じ挙動になってしまうため、あらかじめ window を開いてから location を変更してます。
理屈わかってませんが、 void() で囲っていない文があると Firefox ではそこでストップして、その文の結果が表示されてしまいます。

Javascript は苦手なのでもっと良い方法があったら教えて下さい。

Friday, July 17, 2009

FeedKraft prototype version


I just announce that my new application service, FeedKraft, is available. As you notice from the name, it deals RSS and Atom feeds. I said it deals feeds, but for now, there is one function, feed filtering.

As for the filter function, we know there are many other filter services out there. I think FeedKraft is easier to use than Yahoo! Pipes, and little bit more powerful than FeedRinse.

The source code, implemented in Ruby on Rails, is also available here on GitHub.

Anyway, give it a try.


FeedKraft という RSS や Atom フィードを扱うサービスを公開しました。
が、今のところは外部のフィードにフィルターをかける機能しかありません。

フィードのフィルターに関しては、同様の機能を提供するサービスはいくつかありますが、Yahoo Pipe より簡単で、 FeedRinse よりちょっと強力かと思います。

特徴としては、
* 入力フィードを解析してファイルター可能な候補を選択できる (例: このブログの Atom フィードをカテゴリ Rails でフィルター)
* 作成したフィルターは公開され、他のユーザーが作成したフィルターも利用できる
* フィルター結果の feed はログイン状態での購読(subscribe)により生成されるURLにより参照する必要があるので、何人購読しているか分かる

どんだけ意味があるかわかりませんが、フィルター結果などのフィードが公開されることで、フィード提供側と利用側によるコミュニティ的な要素が広がるといいかなと思ったりもしてます。

ちなみに、Rails で実装してます。ソースも GitHub にありますので興味があったらどうぞ。

Thursday, July 16, 2009

A meta data table structure Force.com is using

InfoQ に salesforce.com の Chief Software Architect, Craig Weissman が Force.com の内部設計を語るプレゼンテーション InfoQ: The Internal Design of Force.com’s Multi-Tenant Architecture が上がってました。

こういう巨大なサービスの内部構造には興味があるので見てみました(英語をほとんど聴き取れませんでしたが)。Force.com - Multitenant Architecture Under the Covers « Blog - Dayspring Web Design and Development にも第三者による要約があります。

全体の指針として、
* 1つのバージョンだけで顧客毎のカスタマイズはしない
* 開発者は現在のバージョンと次のバージョンだけの保守で済む
* ソーシャル系サービスと違い、会社などの組織単位でリレーションを分離できるので、 OrgID のハッシュでテーブルを partition

とくに興味があったのはユーザー定義のメタデータをどうやって保持しているかで、
* オーバーヘッドが大きいので DDLを使わない(動的に CREATE/ALTER/DROP TABLE しない)
* 自由度の高いピボットテーブル? でメタデータを定義、保持
* 数値や日付などのデータも文字列カラムで保持

具体的には、プレゼンテーションの 15:00 前後のスライドで解説していますが、Fields, Objects, Data の3つのテーブルを使っています。

ちゃんと理解してるか自信ないんですけど、たとえば、

Person:
Name: Hiroshi Saito
BirthDate: 1973-09-17

という構造をつくる場合、


Objeject:
ObjID: 1
ObjName: Person

Field:
FieldID: 1
ObjID: 1
FieldName: Name
DataType: String
FieldNum: 0

Field:
FieldID: 1
ObjID: 1
FieldName: BirthDate
DataType: Date
FieldNum: 1

Data:
GUID: 1619c672-71d2-11de-8643-e784bb274b72
ObjID: 1
Name: ???
Value0: Hiroshi Saito
Value1: 1973-09-17


Person は ObjID=1 とわかっていれば、 Person は以下のクエリで検索できますね。

SELECT Value0 AS Name, Value1 AS BirthDate FROM Data WHERE ObjID = 1;


Index のあたりの話などは理解してませんが、 SalesForce が実際に運用しているデータ構造ならば自分で思いついたのよりまともなハズなので、次回、ユーザー定義データを保存する必要がある場合はこの方法でやってみようかと思います。

Friday, July 10, 2009

pony += attachment files + TLS

2010-07-30: My fork of pony is merged into benprew's pony - GitHub. Try it instead.
$ sudo gem install pony



I don't have any other servers, I mean real hardwares, apart from the server my web applications reside. However, I need to keep backup files of database dump or something precious safe from destructions. So I decide to send backup files to a gmail account.

pony makes easy to write a script sending mails, but it can't attach files nor use TLS transport.

Using Tmail, it's easy attaching some files to a mail. And Net::SMTP, included in ruby 1.8.7 or latter, can use TLS/SSL transport without hustle (for ruby 1.8.6 or earlier, there is the smtp_tls gem). So I forked and patched pony.

I sent a pull request to the author of pony, but for now, you can use my fork:

Web アプリケーションの DB のバックアップをとりたいけど、サーバーが1台しかないのでバックアップファイルをメールに添付して gmail のアカウントに送ることにしました。

pony を使うと簡単に送信することができます。 Pony はSMTP 経由で送信もできるんですけど、今回必要なファイル添付と gmail の SMTP サーバーが要求する TLS/SSL 通信も対応してません。

ファイル添付は TMail で簡単にできるし、TLS/SSL も ruby 1.8.7 以降の Net::SMTP なら実装され、 1.8.6 以前でも smtp_tls gem をインストールすることにより利用できるので、それらに対応できるよう Pony を fork して変更してみました。

Pull リクエストを pony の作者に送ったんですが、マージしてくれるかわからないのでこれを使って下さい。



$ gem sources -a http://gems.github.com
$ sudo gem install hiroshi-pony



Here is a sample:

メールを送るスクリプトはこんな感じ




require "rubygems"
require "pony"
Pony.mail(
:to => "example@gmail.com",
:subject => "DB backup",
:via => :smtp,
:smtp => {
:host => "smtp.gmail.com",
:port => "587",
:auth => :plain,
:user => "example",
:password => "********",
:tls => true
},
:attachments => {"database_name.sql.gz" => `pg_dump database_name | gzip`}
)

Monday, June 15, 2009

annotates where partial code come from

Rails アプリケーションの view で partial を多用しているときに、どこからどこまでがどの partial でレンダリングされているのか知りたいことがあるのでプラグイン partial_annotation というものを作ってみました。


<%= render :partial => "/foo" %>


がレンダリングされるとこうなります。


<!-- begin partial "_foo.html.erb" -->
content of the partial....
<!-- end partial "_foo.html.erb" -->


ちなみに、development 以外では無効になるようにしてます

Friday, June 5, 2009

Safari hanging up due to Dropbox contextual menu plugin

最近、気がついたら、 Safari の Contextual Menu を開こうとするとしばらくハングするようになったので犯人探しをしてみました。
Dropbox にバグ報告をしようと思って英語で書いたものです。

Recently I got Safari hanging up when I try to pop up contextual menu in Safari.
So I sampled with Activity monitor.app when Safari got hang.

...
1724 TContextualMenuPlugin::LoadCMPluginsFromCFPlugin(FSRef const&, __CFArray*)
1724 DropboxPluginFactory
1724 AllocDropboxPluginType
1724 reconnect
1724 connect$NOCANCEL$UNIX2003
1724 connect$NOCANCEL$UNIX2003

I found a suspect.

~/Library/Contextual Menu Items/DropboxPlugin.plugin


After removing DropboxPlugin.plugin, Safari's contextual menu is popped up as smoothly as ever.
However, every time Dropbox.app is started, it places the plugin. As I'm a programmer I can't bear torment of removing the plugin every boot time of Mac by hand. So I renamed the plugin:

$ mv /Applications/Dropbox.app/Contents/Resources/DropboxPlugin.plugin \
/Applications/Dropbox.app/Contents/Resources/DropboxPlugin.disabled.plugin


I'v used Dropbox for most half a year. Until this problem happened, it works great. I couldn't remind when I upgraded Dropbox app recently, so I suppose other changes of mac caused this problem.

Mac OS X 10.5.7
Safari 3.2.3 (5525.28.3)
Dropbox.app 0.6.402 or 0.6.507

Monday, May 4, 2009

Rechargeable Batteries

Lifehacker の記事のリンクから、 Coding Horror: Adventures in Rechargeable Batteries を読んで、乾電池型充電池について勉強になりました。というか、おすすめの充電器が欲しくなった。

箇条書きに要約すると、

  • アンペア時(mAh) の大きさに踊らされるな、エネループ(または同等品)を買え。ニッカド(Ni-Cd)電池の10-20%、(従来の)ニッケル水素(Ni-MH)電池の20-30%の容量が一ヶ月で自己放電する。(eneloop - wikipedia によると15%/年なのでおよそ1.4%/月の自己放電)

  • 低電流で充電すると充電に時間はかかるが、電池を痛めない。高電流で急速充電すると、電池の寿命が縮まる。

  • 安い充電器(とくに急速充電タイプ)は電流や充電済みかどうかのチェックをしないので電池を痛める。(ほとんどの電池とセット売りのものはゴミ)

  • La Crosse Technology BC-900 AlphaPower battery chargerを買え。充電電流を設定できたり、現在の容量(mAh)を確認できる。


まあ、もっと奥が深いのでしょうが、そんなに深追いはしたくないので。

ちなみに、 BC-900 の安価版 BC-700 は充電電流を高く設定できないだけで他の機能は同じ、余計なケースや充電池が付いていなので、それを amazon.com で注文しようとしたら、米国内のみ出荷可能でした。

元記事にあるように米国より日本のほうが乾電池型充電池は出回っているようなのですが、日本では電池メーカーの専用充電器でないものはほとんどみあたりませんね(ミニ四駆向けの高価な特殊なやつは除外)。TECHNO CORE という会社が作っていたみたいですが、今は販売していないようですし、液晶で容量などを表示できるやつが欲しい。

ほとんど、受け売りなので間違いなどの指摘は大歓迎です。

Saturday, April 18, 2009

9 life lessons

ちょっと普通のブログみたいなこと書いてみます。

よく知らないんですけど、有名なクライマーの9つの教訓は他の分野でも当てはまるいい話のようでした(ちゃんと聴き取れてない)。
Matthew Childs: Hang in there! 9 life lessons from rock climbing

1. Don't let go - 手を離すな
2. Hesitation is bad - ためらいは良くない
3. Have a plan - 無計画ではだめだ
4. The move is the end - 進む限り辿り着く
5. Know how to rest - 休む方法を知る
6. Fear sucks - 恐れは人を無能にする
7. Opposites is good - 対称的な力は良い
8. Strength ≠ success - 力だけでは成功しない (バランンスが重要)
9. Know how to let go - 撤退(失敗)する方法を知る

適当に意訳してみましたが、わかりにくいのは 7 の対称性についてで、岩壁の割れ目に体が入る場合は突っ張るようにして登り、逆に指先しか入らない割れ目では自動ドアをこじ開けるようにして体を支えるので、その左右対称な力のことを言っているようです。

1, 9 は矛盾するように見えますが、状況によってはって感じですよね。変な例ですけど、満員電車の車内に自力で立とうとしない奴っていますよね。ドアが閉まったら、完全脱力で他人に寄りかかるのではなく人として自力で立とうとする努力が欲しいと思います。逆にドアが空いたら、無理に社内に留まろうとせずに流れに身を任せる感じで一旦ホームに出る潔さ。

6 もアレですね、電車がホームに到着したときに降りる人がまだいるのに乗ろうとする奴。利己的に座りたいからという人が大半かとは思うのですが、乗り遅れてしまうのではないかという恐怖を克服できない人もいるんじゃないかなと思います。

ルールにより制約が生じる大半のスポーツと違い、環境と肉体が制約となるフリークライミングならではの原理に近い教訓だと思いました。

Sunday, April 12, 2009

using SyntaxHighlighter

SyntaxHighlighterを試してみました。


class FooController < ApplicationController
before_filter :set_foo

# 詳細
def show
end
end

EMOBILE H11LC with Mac - a review

イーモバイルの小型通話+データ通信端末 H11LC を買ってしまいました。
Mac につないで実際に利用した場合のレビュー記事が見つからなかったのでちょっと書いてみます。

まだ一週間も経っていませんが、いまのところは、まあ、いいんじゃないですかね。

使う前は、一度何かをインストールすればあとは、USBで接続したらもうネットに接続されると勝手に思い込んでいましたが、実際は、
1. USBで接続すると、"Modem" という名のボリュームがマウントされる
2. そのボリュームに含まれる "H11LC_utility_mac_V1_00.app" または /Application にインストールされる "EMOBILE H11LC Utility.app" を起動する
3. その Utility で接続をクリックするとモデムで発信してネットに接続する
最低でも3アクション必要で、(自分の環境では) utility の起動に数秒かかります。

勝手に接続すると、接続料金が知らずに加算されていたりしそうなので、考えてみればあり得ないですね。
でも、USBに挿したらメニューバーの常駐アプリケーションの表示が変わり、メニューから「接続」を選択できたりするといいのに。

あとは文章にするのが面倒なので箇条書きに列挙します。

他に気づいた点を列挙すると、
* microSD のボリュームも utility 起動にちょっと遅れてマウントされるので USBメモリと同じ感覚では使えない
* 有機ELだからなのか?ディスプレイは日中の太陽光の下では非常に見にくい
* なぜか試供品扱いのストラップになる USBケーブル2 はかっこ悪いが便利なので外せない

音楽プレイヤーに関しては、(音質を気にするなら使わない前提で)
* utf-8 の日本語ファイル名は表示できている
* スペック通り mp3 以外は再生できないので m4a などは変換する必要あり
* mp3 の(ID3などの)タグ情報は参照されないのでファイル名でのみ識別
* mac 接続してユーティリティーを起動すると音楽再生は停止する
* イヤホンを接続するためには黒くダサイ専用イヤホンマイクを利用するか、ありえないデザインと大きさの黒いアダプタを利用する必要がある (pdfマニュアル p21 参照) => 他の携帯向けの変換アダプタが使えるか?
* 背面スピーカーからの音量は以外と大きいのでポケットに入れて、フロ掃除したりするときのBGMには使えるかも
* プレイリストの編集はメモリカードでなく本体のメモリ?に保存され、本体からでしか操作できない
現実的にはmp3を厳選するか、たくさん入れて全曲プレイリストのランダム再生?

Mac と他のシステムとファイル共有したりするときのいつもの問題だが、
* Finder を利用してコピーするとリソースフォークが ._ファイル名 として保存されるてしまい、音楽再生時に ._ファイル名.mp3 を無視してくれないので、いちいち「ファイルが壊れています」と表示されウザイ
* Spotlight 環境設定で除外しないと Spotlight の index が作成されて容量がムダになる (._ ファイルと同様、 Mac OS X 側の問題)

プログラマの視点からのどうでもいいこととしては、
* Utility はいちおう Cocoa アプリケーションのため、連絡先編集などのテキスト入力で emacs binding は使えるが、コスト削減のためか Windows 版と同じ設計(デザイン)で非常に格好悪い(スプラッシュ画面が出るようなアプリケーションに共通の格好悪さがある)。

あとは、参考資料
* イーモバイルのダウンロードページに H11LC の マニュアル(pdf)があります。
* ASCII.jp でのレビュー
* 小暮祐一という方のブログ記事
* みんぽす (先のリンクに複数のレビューあり)
などを参考にしてください。

Thursday, April 2, 2009

Pulling forked changes with git - an example

うれしいことに、拙作 script/refactor を改善する変更の pull request のメッセージが届いていたので早速、 pull しようと思ったけど手間取ってしまったのでそのメモです。

GitHub のガイド wiki には Pull Requestsがあるんですけど、手元の git (v 1.6.2.1) では、そのまんまだとリモートブランチとローカルブランチの名前が同じになってしまって、何かすると
warning: refname 'tjsheehy/master' is ambiguous.

のような warning が出て気持ちわるい。

試行錯誤の結果、シンプルにローカルブランチは作らずに master ブランチで pull して GitHub に push しました。
$ git remote add -f tjsheehy git://github.com/tjsheehy/script-refactor.git
$ git pull tjsheehy master
$ git commit


また、CHANGELOG をつくるのには、
$ git log --pretty=format:"* %s [%an] %h" | cat
こんな感じでログをフォーマット指定の pager なしで吐いて、切り貼りしました。


でも、あれですね。メジャーなプロジェクトをホストしている人は pull request 来まくって、ウザいでしょうね。

あと思うのは、 ssl_required など、とりあえず GitHub に引っ越しただけのプロジェクトとか fork されまくってるけど全然本家にマージされてないやつとかどれ使っていいのかわからなくて困りますね。Network グラフをみてどのリポジトリの本気度が高いか見極める必要があるし。

Tuesday, March 31, 2009

Disassembling Microsoft Bluetooth Notebook Mouse 5000

2009-11-8: See this instructable photos instead of my post.
2009-11-8: この記事を見るより、写真による説明を見た方がいいです。百聞は一見にしかず...。


(English version of instruction at the bottom of the post...)

Microsoft Wireless Notebook Optical Mouse 4000 を気に入っていたのですが、
* Macbook で使うには USBレシーバーが邪魔
* 光学式なので僕の机だとマウスパッドがないと動かない
* ホイールを左右に傾けられるやつなのでホイールが溝にひっかかる感じになることがある
というところが気に入らなかった。

Microsoft Bluetooth Notebook Mouse 5000ですべて解消すると思って買ってみました。
しかし、
1. 4000 と比べると形状が違うのでホールド感に違和感がある
2. 4000 のホイールはヌルヌルだったけど 5000 はゴリゴリでうるさいし、ちゃんとホールドしないと回しにくい

1 の問題は、まあ慣れればいいかなと思いましたが、2のゴリゴリ言うホイールは我慢できなかったので、分解して調整してみました。
分解の仕方がわからなかったけど、試行錯誤の結果分解できたのでそれを共有しようというのが本題です。

ポイントは
1. 最初にまわすべきネジの位置 -> 上部後方の三角のレーザーマーク?の下
2. そのネジがトルクスネジ(T6)なのでふつうの+/-のドライバーでは外せない
3. 2/3番目のねじはマウスボタンの下だけど、マウスボタンが固定されている後方のツメをうまくはずさないと回せない
という感じですね。



分解できたら、ホイールの軸受けみたいなところのデコボコと金属のヤマがゴリゴリいうのでそのヤマをマイナスドライバーとかで少し潰す。(画像ピンボケですいません)


はい終わり。

以下は英語で助けを求められたので説明を英語で書いてみました。(2009-5-13)

Instruction
1. Remove the emblem (image of laser?) on the hip? of the mouse. Because of it is glued you can remove it with tip of pin or needle.
2. After removing the emblem, you can see a torx screw (See the first photo). Remove it (I suppose required size of driver is T6).
3. I can't recall precisely, but without the screw you can slid mouse buttons, then unscrew pair of screws under the mouse buttons. Be careful to slid the mouse buttons, they are fixed with claws on the body.
4. Sorry, I can't recall anymore, I hope you get the point from my instruction.

Monday, February 2, 2009

search with named scopes

複数条件の AND 検索機能は Web アプリケーションを実装すると必ずといっていいほど実装するかと思います。
例えば、フォームからの入力で
params  # => {:city => "tokyo", :age => 30}
のようなパラメータが与えられるとすると、 fat controller を気にしなければ rails のアクションの実装は以下のようにやってました。
def index
conds, args = [], {}
unless (city = params[:city]).blank?
conds << "city = :city"
args[:city] = city
end
unless (age = params[:age]).blank?
conds << "age = :age"
args[:age] = age
end

if conds.blank?
@users = User.find(:all)
else
@users = User.find(:all, :conditions => [conds.map{|c|"(#{c})"}.join(" AND "), args])
end
end


named scope を使うと
class User
named_scope :city, lambda{|city| {:conditions => ["city = ?", city]}}
named_scope :age, lambda{|age| {:conditions => ["age = ?", age]}}
end

def index
@users = [:city, :age].inject(User) do |ret, scope|
params[scope].blank? ? ret : ret.send(scope, params[scope])
end.all
end

すばらしいじゃないですか。

検索してみるとすでに同じ事を思いついている人はたくさんいるようですね。

(上記、実際に動かしたコードをブログ用に書き換えたのでどっか間違っていたらごめんなさい。)

Tuesday, January 27, 2009

script/refactor

script/refactor という rails アプリケーションのリファクタリングを支援するスクリプトを書いてみました。

$ script/plugin install git://github.com/hiroshi/script-refactor.git

インストールすると、 script/refactor が生成されます。

例: user を person に変える。
$ script/refactor resource user person
Renamming files and directories:
git mv app/views/users app/views/people
git mv app/helpers/users_helper.rb app/helpers/people_helper.rb
git mv app/models/user.rb app/models/person.rb
git mv test/unit/user_test.rb test/unit/person_test.rb
git mv test/functional/users_controller_test.rb test/functional/people_controller_test.rb
git mv app/controllers/users_controller.rb app/controllers/people_controller.rb
git mv test/fixtures/users.yml test/fixtures/people.yml

Replacing class and variables:
user -> person
Users -> People
User -> Person
users -> people
pettern: /(\b|_)(user|Users|User|users)(\b|[_A-Z])/

./test/unit/person_test.rb:3: class UserTest < ActiveSupport::TestCase
./test/unit/person_test.rb:7: fixtures :users
./test/unit/person_test.rb:9: def test_should_create_user
./test/unit/person_test.rb:10: assert_difference 'User.count' do
...
./app/controllers/application.rb:18: current_user.group

NOTE: If you want to revert them:
git reset --hard


こんな感じにモデル、コントローラ、ヘルパー、テストのファイル名を変更して、コード中のクラス名、変数名もルールに従っているものは変更します。

適当に書いたスクリプトなので、特に置換する部分が思うような挙動にならない場合もあるかと思います。改善案やパッチをください。

Friday, January 23, 2009

My philosophy about testing

テストを含む開発の哲学については Rails 開発者の中でも様々あります。僕の場合、現状ではこんな感じなんですけど、みなさんどうですか?

テストの目的は2つあると考えます。
開発する最中に自分の書いているコードが正しいか確認するためのものと、コードを変更したときにその影響により過去に書いたコードが壊れないか確認するもの。

Rails アプリケーション開発の場合、前者は、基本的には、見た目の確認も行うため development mode でブラウザ確認で行います。
例外的に、レコードの作成、更新などで複雑な処理をする場合など、ブラウザでフォームに入力して、レコード作成、表示をするのに手間がかかったり、画面には現れないカラムの内容を確認したいときに、簡単な unit test を書いたりもします。

後者は一般的に回帰テスト(regression test)と呼ばれるもので、 Rails では functional test を中心に書いてゆきます。記述する精度は余裕やモチベーションによっても違うと思いますが、controller の各 action を実行して結果を簡単に確認して、 rcov による coverage 率が 100% に近づくようにします。

実装と平行、またはテスト駆動が望ましいとは思いますが、そうは言ってもね、たいていの場合は仕様がガッチリ決まっているわけではなく実験しながら実装することになるので、大きく変更する可能性があったり場合によっては捨ててしまうコードのテストに時間をかけるのはもったいないしモチベーションも上がらないので、実装がほぼ完了して次のタスクにとりかかる前にテストを書きます。
仕様決定権限がある人に確認してもらうこともある意味テストなので、極論ですけど、実装したものが仕様として望ましいかどうかのテストに合格してから実装の品質をテストしないと、「テストも全部書いてしまったので変更はできません」なんて本末転倒なことになるかと思います。

あとは、リリース後に不具合が見つかった場合、テストが甘かったわけなので、理想的には、その不具合を再現するテストを書いて、コードの修正でテストが通ることを確認して解決とします。