スタッフブログ
以前にもARToolKitの紹介をしましたが、最近はARを簡単に実現するためのライブラリも増えてきたようです。
まず、ARToolKitはマーカーが必要ですが、これがマーカーレスになったPTAMというものがあります。
この動画を見てもらうとわかりますが、カメラの入力情報だけでリアルタイムに平面を作成し、そこに対し3Dオブジェクトを配置できるようになります。
マーカーが不要なので、より自然に見えますね。
また別のアプローチとして、人間の手をマーカーにするHandyARというライブラリもあります。
こちらはこれしか動画が見あたらなかったのですが(ニコニコ動画にもう少しあるようなので興味のある方は調べてみてください)、手の上で3Dモデルがぴったり連動しているのがわかります。
手から何かを出すような演出とかだと手軽に作れるかもしれません。
最近ではセカイカメラなどで実用化も見えてきたAR技術ですが、ライブラリもこれだけ揃ってくると簡単に作れるので何か試せそうですね。
iPhoneやAndroid対応のものが増えると、いろいろ遊べそうなので期待しています。(その前にどちらの端末も持っていませんが…)
今日は、ケータイサイトを作る上での対応機種などについて簡単にですが書こうと思います。
今までにケータイサイトを開発したことのある方でしたら、こちらやこちらの記事をご覧になった方も多いかと思います。
どちらも3GC(第三世代携帯電話)に関する記事で、非常に参考になる内容が書いてあります。
ケータイサイトを開発する場合、対応機種をどこまでに設定するかによって、難易度が変わると思うのですが、現在のケータイサイト開発であれば、殆どの場合3GC以上限定で問題がないと私は思います。
少し調べて見た限りは、
- 3G端末の契約率は、対携帯電話契約数で90%を超えている
- ケータイサイトへのアクセスは、3GC以上で98%を超えている
もちろん3GCであっても初期の端末や、海外製の一部の端末などでは正常に表示されないこともありますし、端末特有の現象が発生することがあったりもしますが、これから開発するのであれば、殆どのユーザが利用可能なサイトに出来ると思います。
※参考:社団法人電気通信協会(TCA)
社団法人モバイル・コンテンツフォーラム(MCF)
株式会社インプレスR&D発行『ケータイ白書2009』
今日は、DNSキャッシュサーバのUnboundについて書こうと思います。
上述のとおり、自宅のサーバが壊れてしまったこともあり、こちらの記事で書いたCitrix XenServerを利用して、サーバの分散と仮想化に着手し始めました。
今までは、さほど必要としなかったこともあり、内向きDNSを構築せずにバーチャルホストを利用することで、複数のドメインを扱っていたのですが、勉強も兼ねて内向きDNSを構築してみることにしました。
最初は、BINDを利用することも考えたのですが、設定が面倒なことや、トップシェアを誇ることにより攻撃対象となりやすいことなどから、別のソリューションを探し、最終的にUnboundを利用してみることにしました。
Unboundを選んだ主な理由は、
- 昨年あたりから、かなり注目されている
- 設定がシンプルである
- 内向きDNSの構築に向いている
- デフォルトでも、そこそこセキュアである(らしい)
設定は非常に簡単で、サーバにunboundをインストールしてから、unbound.confに最低限の設定を記述して、サーバ自身が参照するネームサーバの一番最初にサーバ自身を指定するだけです。
テストと言えばユニットテストとかはだいぶ充実してきましたが、機械的なコードになりがちなので、プログラマ以外のテストケースの検証が難しいという問題があり、別途説明用にテストケースを書き直したりする必要がありました。
Ruby on Railsの話になりますが、Cucumberというツールがあるようです。
これは、YAMLで受け入れテストを書くことによって、Railsアプリのテストを行えるようにするものです。
ちなみにこれは正確にはBDD(Behavior Driven Development/ビヘイビア駆動開発)のためのツールらしいです。
Cucumberのページを開くと、以下のようなものが記述されています。
Feature: Search courses
In order to ensure better utilization of courses
Potential students should be able to search for courses
Scenario: Search by topic
Given there are 240 courses which do not have the topic "biology"
And there are 3 courses A,B,C that each have "biology" as one of the topics
When I search for "biology"
Then I should see the following courses:
| title |
| A |
| B |
| C |
■インストール
CucumberはRails2.1以降で動作します。
gem install rspec rspec-rails cucumber webrat
また、別途
gem install term-ansicolor treetop diff-lcs nokogiri builder
■テスト用プロジェクト作成
とりあえずブログアプリケーションのようなものを作る想定で作ります。
rails blog
cd blog
script/generate scaffold entry name:string title:string body:text
rake db:migrate
■Cucumber初期化
script/generate cucumber
script/generate feature Entry
features/manage_entries.feature
features/step_definitions/entry_steps.rb
このうち、manage_entries.featureが、実際のテストコードになります。このファイルを開くと以下のように書かれています。
Feature: Manage entries
In order to [goal]
[stakeholder]
wants [behaviour]
Scenario: Register new entry
Given I am on the new entry page
And I press "Create"
Scenario: Delete entry
Given the following entries:
||
||
||
||
||
When I delete the 3rd entry
Then I should see the following entries:
||
||
||
||
実際の動作は、各Scenarioに記述していきます。
とりあえずScenarioを書いてみます。
Feature: Manage entries
In order to [goal]
[stakeholder]
wants [behaviour]
Scenario: Register new entry
Given I am on the new entry page
When I fill in "Name" with "user"
And I fill in "Title" with "blog title"
And I fill in "Body" with "blog content"
And I press "Create"
Then I should see "user"
And I should see "blog title"
And I should see "blog content"
Scenario: Delete entry
Given the following entries:
| name | title | body |
| name1 | title1 | body1 |
| name2 | title2 | body2 |
| name3 | title3 | body3 |
| name4 | title4 | body4 |
| name5 | title5 | body5 |
When I delete the 3rd entry
Then I should see the following entries:
| name | title | body |
| name1 | title1 | body1 |
| name2 | title2 | body2 |
| name4 | title4 | body4 |
| name5 | title5 | body5 |
rake features
すると、以下のようにテストが実行されます。
/usr/bin/ruby1.8 -I "/usr/lib/ruby/gems/1.8/gems/cucumber-0.3.11/lib:lib" "/usr/lib/ruby/gems/1.8/gems/cucumber-0.3.11/bin/cucumber" --format pretty features/manage_entries.feature
Feature: Manage entries
In order to [goal]
[stakeholder]
wants [behaviour]
Scenario: Register new entry # features/manage_entries.feature:6
Given I am on the new entry page # features/step_definitions/webrat_steps.rb:6
When I fill in "Name" with "user" # features/step_definitions/webrat_steps.rb:22
And I fill in "Title" with "blog title" # features/step_definitions/webrat_steps.rb:22
And I fill in "Body" with "blog content" # features/step_definitions/webrat_steps.rb:22
And I press "Create" # features/step_definitions/webrat_steps.rb:14
Then I should see "user" # features/step_definitions/webrat_steps.rb:93
And I should see "blog title" # features/step_definitions/webrat_steps.rb:93
And I should see "blog content" # features/step_definitions/webrat_steps.rb:93
Scenario: Delete entry # features/manage_entries.feature:16
Given the following entries: # features/step_definitions/entry_steps.rb:1
| name | title | body |
| name1 | title1 | body1 |
| name2 | title2 | body2 |
| name3 | title3 | body3 |
| name4 | title4 | body4 |
| name5 | title5 | body5 |
When I delete the 3rd entry # features/step_definitions/entry_steps.rb:5
Then I should see the following entries: # features/step_definitions/entry_steps.rb:12
| name | title | body |
| name1 | title1 | body1 |
| name2 | title2 | body2 |
| name4 | title4 | body4 |
| name5 | title5 | body5 |
2 scenarios (2 passed)
11 steps (11 passed)
0m1.040s
passedとなっているので、正常終了しているようです。
試しに失敗させてみます。
app/controllers/entries_controller.rb
def destroy
@entry = Entry.find(params[:id])
# @entry.destroy # ここをコメントアウト
respond_to do |format|
format.html { redirect_to(entries_url) }
format.xml { head :ok }
end
end
rake features
すると以下のようになると思います。
/usr/bin/ruby1.8 -I "/usr/lib/ruby/gems/1.8/gems/cucumber-0.3.11/lib:lib" "/usr/lib/ruby/gems/1.8/gems/cucumber-0.3.11/b
in/cucumber" --format pretty features/manage_entries.feature
Feature: Manage entries
In order to [goal]
[stakeholder]
wants [behaviour]
Scenario: Register new entry # features/manage_entries.feature:6
Given I am on the new entry page # features/step_definitions/webrat_steps.rb:6
When I fill in "Name" with "user" # features/step_definitions/webrat_steps.rb:22
And I fill in "Title" with "blog title" # features/step_definitions/webrat_steps.rb:22
And I fill in "Body" with "blog content" # features/step_definitions/webrat_steps.rb:22
And I press "Create" # features/step_definitions/webrat_steps.rb:14
Then I should see "user" # features/step_definitions/webrat_steps.rb:93
And I should see "blog title" # features/step_definitions/webrat_steps.rb:93
And I should see "blog content" # features/step_definitions/webrat_steps.rb:93
Scenario: Delete entry # features/manage_entries.feature:16
Given the following entries: # features/step_definitions/entry_steps.rb:1
| name | title | body |
| name1 | title1 | body1 |
| name2 | title2 | body2 |
| name3 | title3 | body3 |
| name4 | title4 | body4 |
| name5 | title5 | body5 |
When I delete the 3rd entry # features/step_definitions/entry_steps.rb:5
Then I should see the following entries: # features/step_definitions/entry_steps.rb:12
| name | title | body |
| name1 | title1 | body1 |
| name2 | title2 | body2 |
| name4 | title4 | body4 |
| name5 | title5 | body5 |
expected: "name4",
got: "name3" (using ==)
Diff:
@@ -1,2 +1,2 @@
-name4
+name3
(Spec::Expectations::ExpectationNotMetError)
./features/step_definitions/entry_steps.rb:16
./features/step_definitions/entry_steps.rb:15
(eval):3:in `each_with_index'
./features/step_definitions/entry_steps.rb:14:in `each'
./features/step_definitions/entry_steps.rb:14:in `each_with_index'
./features/step_definitions/entry_steps.rb:14
(eval):3:in `each_with_index'
./features/step_definitions/entry_steps.rb:13:in `each'
./features/step_definitions/entry_steps.rb:13:in `/^I should see the following entries:$/'
features/manage_entries.feature:25:in `Then I should see the following entries:'
2 scenarios (1 failed, 1 passed)
11 steps (1 failed, 10 passed)
0m0.884s
rake aborted!
Command failed with status (1): [/usr/bin/ruby1.8 -I "/usr/lib/ruby/gems/1....]
(See full trace by running task with --trace)
削除をコメントアウトしたので、削除の部分が失敗しているのがわかると思います。
このような感じでテストを書くことができるようになります。
英語だと若干わかりづらいのですが、有志の手によって一部を日本語で書けるようにしたものもあるようです(今回は省略します)。また、同時に生成されたstepファイル(今回だとentry_steps.rb)で、細かい実行内容の定義を書くことができます。これらを組み合わせることにより、自然な日本語でテストを書くことができるようにもなります。
従来のテストコードに比べて視認性が格段に良くなりますので、Railsで開発をしている方は是非試してみてください。
HatenaSyntaxは、はてなダイアリーで使われている、はてな記法 ( http://hatenadiary.g.hatena.ne.jp/keyword/%e3%81%af%e3%81%a6%e3%81%aa%e8%a8%98%e6%b3%95%e4%b8%80%e8%a6%a7 ) を解釈します。
はてな記法を利用する事で、ユーザは、簡単な記号を書くだけで、HTMLの知識がなくても複雑な表現する事ができ、
サービス提供者側は、HTMLタグを直接使わなくても多様な表現ができる分、脆弱性発生のリスクを抑える事ができます。
(もちろんはてな記法の解釈に問題があって脆弱性が発生する可能性は受け入れる必要がありますが)
HatenaSyntaxの特徴は、「少ない行数で使える事」です。最低限の変換ができるだけでよければ、以下のコードで動きます。
require_once 'HatenaSyntax.php';
$str = '
* header
';
echo HatenaSyntax::render($str);
HatenaSyntax.phpをrequireした後にHatenaSyntax::render()を実行するだけです。
ただし、HatenaSyntaxはPEGライブラリに依存しているので、こちらも同時にインストールしておく必要があります。
私は過去にPukiWiki記法をパースするライブラリを書いた事があるのですが、すべての構文をカバーする気力がなく、途中で力尽きました。
有名な記法ならなんでもよかったので、その時にHatenaSyntaxがあれば大幅に工数を減らせたのになーと昔の事を思いだしました。
Emacsで使う日本語入力メソッドを、Prime(prime.el)に変えました。 いままでは、Anthy(anthy.el)を使っていました。 (過去記事:Emacs修行中)
Anthyでは英数字やカナを入力する前に、モードを切り替えないといけないのですが、できるようになりませんでした。
身に染みついた変換の癖はかなり強くて、「入力してからファンクション・キーで変換」という方法が使えないか模索していたのですが、そこで見つけたPrimeに乗り換えることにしました。
これはこれで(予測変換という)今まで体験していなかったような動きがあって、その部分は慣れていこうと思っているのですが、今まで感じていた入力のストレスが大幅に軽くなったと思います。
Ubuntu 8.04 でのインストールは、APTでインストールできるのでお手軽です。 必要なライブラリも含めて、load-pathには勝手に入るのですが、有効化するには設定ファイル(.emacs)を自分で書き換える必要がありました(私の環境の場合)。 その書き方をノウハウとしてメモ書きしておきます。
以下、.emacsに追加する部分
;;; PRIME for Emacs (require '55prime-el) (global-set-key "\C-\\" 'prime-mode) (setq default-input-method "japanese-prime")
今週末に札幌でオープンソースカンファレンス2009 Hokkaidoがあります。
私もRedmineについて話す予定ですので、北海道の方は是非お越し下さい。
さて、Redmineを普通に使うには、Redmine.jpという、日本語でRedmineの情報を集めたサイトがありますので、こちらをご覧頂けると大体問題なく使えるのですが、実運用になると何かと問題が発生します。
Redmine.jpではPassengerを使用した方法が書かれていますが、Passengerは動作が安定しないことがあり、個人的にはまだ実用するには不安が残ります。
そこで、Railsアプリ運用では一般的だと思われる、mod_proxy_balancerとThinを組み合わせた運用方法について説明します。
WEBrick(素の状態でruby script/serverで起動するサーバ)のRedmineの起動ができていることを前提とします。
■Thin
Thinは、RubyのWebサーバで、Mongrelを内部でパーサとして使用しており、かつMongrelより高速なのが特徴です。
まずインストールをします(以下ほとんどsudo等の管理者権限で実行することになります)
gem install rack
gem install thin
なお、Ubuntuで
extconf.rb:1:in `require': no such file to load -- mkmf (LoadError)
sudo aptitude install ruby1.8-dev
これだけでもいいのですが、このままでは起動が面倒です。また、1プロセスしか存在しないため、1プロセスが死ぬと繋がらない状態になります。
Thinには、両方とも解決する機能が搭載されており、起動スクリプトの自動生成と、クラスタ化ができるようになっております。
thin install
ですが、このままだと起動できないので、起動用の設定ファイルを別途出力します。
thin config -C /etc/thin/redmine.yml -c /path/to/redmine/ --servers 3 -e production
Thinの起動スクリプトは、/etc/thin/*.ymlを読み込みます。そのため、そこに設定ファイルを出力します。
/path/to/redmine/はRedmineのパス、--servers 3はプロセスを3つ立ち上げる、-e productionはproduction環境で実行する、ということになります。
出力される/etc/thin/redmine.ymlは名前の通りYAMLですので、簡単に修正することができます。使用するポート番号の範囲とかも書かれているので確認しておいてください。
ここまでできたら、
/etc/init.d/thin start
■mod_proxy_balancer
mod_proxy_balancerは、Apache2.2から導入されたソフトウェアのロードバランサモジュールです。
今回はThinを複数プロセス起動しているので、これを使用して1つのURLでアクセスできるようにします。
<VirtualHost *:80>
ServerAdmin admin@example.com
ServerName redmine.example.com
ProxyPass / balancer://redmine_cluster/
ProxyPassReverse / balancer://redmine_cluster/
<Proxy balancer://redmine_cluster/>
BalancerMember http://127.0.0.1:3000 loadfactor=20
BalancerMember http://127.0.0.1:3001 loadfactor=20
BalancerMember http://127.0.0.1:3002 loadfactor=20
</Proxy>
</VirtualHost>
大体こんな感じです。
BalancerMemberで、立ち上げたThinのURLをプロセス分記入します。
ロードバランサだけならPoundやNginxとかでもいいのですが、通常Redmineだけでサーバ1つ占有することはないと思いますので、大体入っていると思われるApacheを使って設定するのが便利だと思います。
■余談
リポジトリ画面は、そのままだと毎回取得して遅いので、本番環境では必ずcronで取得するようにしましょう。
詳細はRedmine.jpの記事をご覧下さい。
この週末にVirtualBoxを試してみたので、今日はそれについて書こうと思います。
VirtualBoxとは、正式にはSun xVM VirtualBoxといい、サン・マイクロシステムズが公開している仮想化アプリケーションで、個人・教育・評価目的であれば無償で使用出来ます。
特徴としては、スナップショットなどの機能を備えつつ無償で利用出来ること、対応ゲストOSが多く存在すること、起動などの速度が他の仮想化アプリケーションに比べて速いことなどがあるようです。
また、機能面での大きな特徴としては、「シームレスモード」が存在することが挙げられます。
私はプライベートのメイン環境をVMWare上に構築しているのですが、最近起動の際にかかる重さが気になっていたところに、金曜日の社内発表会でVirtualBoxに関するhaltのプレゼンを聞いて、試して見る気になりました
ということで、この週末にVirtualBoxをインストールして、メイン環境として利用出来るか試してみました。
ベンチマークなどについては、多くの方が既にブログなどで書かれているので、今回は「メイン環境として利用できるか」を中心に、体感速度などを重視してみました。
ついさっき知ったのですが,「既存」という漢字の読みは「きそん」が正しいのですね.知らずに「きぞん」と読んでいました.(現在では「きぞん」と読む人が増えている為,「きぞん」でも間違いではありません)
ところでYahoo! Japanのサービスに「ルビ振りAPI ( http://developer.yahoo.co.jp/webapi/jlp/furigana/v1/furigana.html ) 」があります.
ルブ振りAPIは既存をどう読むか調べてみましょう.
ルビ振りAPIを使うにはYahoo! デベロッパーズネットワークでアプリケーションIDを取得する必要があります. ( http://developer.yahoo.co.jp/ )
アプリケーションAPIを取得したら,pearコマンドでServices_Yahoo_JP_Furiganaをインストールします.このライブラリはServices_Yahooに依存しているので,-aオプションで一括インストールするか,別途インストールしておいてください.
pear install -a Services_Yahoo_JP_Furigana-alpha
インストールが完了したら,以下のコードを入力します.$app_idの部分には取得したヤフーのアプリケーションIDを入力してください.
<?php
require_once 'Services/Yahoo/JP/Furigana.php';
$app_id = '';
try {
$yahoo = Services_Yahoo_JP_Furigana::factory('furigana');
$yahoo->withAppID($app_id);
$yahoo->setSentence('既存の設定で極小になっている');
$yahoo->setGrade(1);
$result = $yahoo->submit();
$str = null;
foreach ($result as $word) {
$str .= isset($word['Furigana']) ? $word['Furigana'] : $word['Surface'];
}
echo $str . PHP_EOL;
} catch (Services_Yahoo_Exception $e) {
die($e->getMessage());
}
これを実行すると「きそんのせっていできょくしょうになっている」と表示されます.やっぱり既存は「きそん」と読むんですね!
今まで間違えていた自分がはずかしいです
既存って
http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1010669095
極小の読み方は (きょくしょう) (ごくしょう) どっちですか?
http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1312031488?fr=rcmd_chie_detail
なおとです。
今日の帰り道、もしくは次の出勤日の朝に起こるかもしれないこと。
- 乗った電車に電車が衝突
- いつも最後尾車両に乗っています
- 夜道で暴漢に襲われて動作不能になる
- 夜道を歩きまわる習慣があります
- 会社の開発用PCがどうしてもブートしない
- VMのイメージを定期的にバックアップしたいけれど、前回いつ行ったかすぐに思い出せない
ちょと大げさな例を挙げましたが、リリース前に限って体調を崩すなどはあり得そうです。 こういったときに、プロジェクトに与える影響を低くする方法、それが、「いつも、コミットしてから帰る」です。
言い換えると「作業中のものでも、手元に抱え込まない」ということです。
既に以前、私はこのブログで「開発でのバージョン管理の秘訣」という記事を書いています。
実は今日、社内の発表会で上記のようなことを話しました。 どうやらうまく伝えることができたようです。 こういった考えをチームの中で共有できるということは、とても大事なことだと思っています。