l'essentiel est invisible pour les yeux

Wednesday, December 03, 2008

[C++] Library for serialization of boost::subgraph

Oops, long time no post.

Boost has powerful Graph library named BGL(Boost Graph Library), and serialization libraries, however the library for serialization of boost::subgraph doesn't exist, so i implement simple library to do that.

boost_subgraph_serialize was commited on Github, so you can check out them with git.


% git clone git://github.com/rakuto/boost_subgraph_serialize.git


subgraph_serialize_test.cpp
Demo that serialize boost::subgraph.

/**
* Serialization of boost::subgraph
*
* Created by Rakuto Furutani <xri://rakuto/> (rakuto+nospam@gmail.com)
*
* output:
* original:
* 0 <--> 1 2
* 1 <--> 0 4
* 2 <--> 0
* 3 <-->
* 4 <--> 5 5 1
* 5 <--> 4 4
* children num: 1
*
* from file:
* 0 <--> 1 2
* 1 <--> 0 4
* 2 <--> 0
* 3 <-->
* 4 <--> 5 5 1
* 5 <--> 4 4
* children num: 1
*/
#include <fstream>
#include <string>
#include <boost/graph/subgraph.hpp>
#include <boost/graph/graph_utility.hpp>
// arhivers
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>

#include "subgraph_serialize.h"

using namespace boost;

typedef property<vertex_name_t, char> VertexProperty;
typedef property<edge_index_t, uint32_t,
property<edge_weight_t, uint32_t> > EdgeProperty;
typedef subgraph<adjacency_list<listS, vecS, undirectedS, VertexProperty, EdgeProperty> > Graph;

static const char* DAT_FILE_NAME = "subgraph.dat";

int main()
{
enum {A, B, C, D, E, F, N};
const char* node_names = "ABCDEF";

// create root graph
Graph root(N);
property_map<Graph, vertex_name_t>::type vertex_names = get(vertex_name_t(), root);
for(uint32_t i = 0; i < N; ++i) vertex_names[i] = node_names[i];
add_edge(A, B, EdgeProperty(1), root);
add_edge(A, C, EdgeProperty(2), root);
add_edge(E, F, EdgeProperty(3), root);

// create sub graph
enum {B1, E1, F1}; // refering to vertices in sub_g1
Graph& sub_g1 = root.create_subgraph();
add_vertex(B, sub_g1);
add_vertex(E, sub_g1);
add_vertex(F, sub_g1);
add_edge(E1, F1, sub_g1);
add_edge(B1, E1, sub_g1);

std::cout << "original:" << std::endl;
print_graph(root);
std::cout << "children num: " << root.num_children() << std::endl;

// serialize and save graph
std::ofstream ofs(DAT_FILE_NAME, std::ios::out | std::ios::binary);
if(!ofs.is_open()) {
std::cerr << "Can't open " << DAT_FILE_NAME << " file." << std::endl;
return EXIT_FAILURE;
}
archive::binary_oarchive oa(ofs);
oa << root;
ofs.close();

// Try to restore saved graph
Graph g;
std::ifstream ifs(DAT_FILE_NAME, std::ios::in | std::ios::binary);
if(!ifs.is_open()) {
std::cerr << "Can't open " << DAT_FILE_NAME << " file." << std::endl;
return EXIT_FAILURE;
}
archive::binary_iarchive ia(ifs);
ia >> g;

std::cout << "\nfrom file:" << std::endl;
print_graph(g);
std::cout << "children num: " << g.num_children() << std::endl;

return EXIT_SUCCESS;
}


subgraph_serialize.h
Implementation of serialazation of boost::subgraph.

/**
* Serialization of boost::subgraph
*
* Created by Rakuto Furutani <xri://rakuto/> (rakuto+nospam@gmail.com)
*/
#ifndef SUBGRAPH_SELIALIZE_H
#define SUBGRAPH_SELIALIZE_H

#include <boost/graph/adj_list_serialize.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/subgraph.hpp>

namespace boost {
namespace serialization {

template<class Archive, class Graph>
inline void save(Archive& ar,
const subgraph<Graph> graph,
const unsigned int /* file_version*/)
{
typedef typename subgraph<Graph>::vertex_descriptor Vertex;
typedef typename subgraph<Graph>::const_children_iterator ChildrenIter;

// serialize global verticies and edges
size_t num_children = graph.num_children();
bool root = graph.is_root();
ar << BOOST_SERIALIZATION_NVP(root);
ar << BOOST_SERIALIZATION_NVP(num_children);
ar << BOOST_SERIALIZATION_NVP(graph.m_graph);
ChildrenIter ci, ci_end;
tie(ci, ci_end) = graph.children();
for(; ci != ci_end; ++ci) {
ar << *ci;
}
}

template<class Archive, class Graph>
inline void load(
Archive& ar,
subgraph<Graph>& graph,
const unsigned int /* file_version */)
{
typedef typename subgraph<Graph>::vertex_descriptor Vertex;
typedef typename Graph::vertex_iterator VertexIter;
Graph g;
bool root;
size_t num_children;
ar >> BOOST_SERIALIZATION_NVP(root);
ar >> BOOST_SERIALIZATION_NVP(num_children);
ar >> BOOST_SERIALIZATION_NVP(g);

if(root) {
graph.m_graph = g;
} else {
VertexIter vi, vi_end;
tie(vi, vi_end) = vertices(g);
graph.create_subgraph(vi, vi_end);
}
for(size_t i = 0; i < num_children; ++i) {
ar >> BOOST_SERIALIZATION_NVP(graph);
}
}

template<class Archive, class Graph>
inline void serialize(
Archive& ar,
boost::subgraph<Graph>& graph,
const unsigned int file_version)
{
boost::serialization::split_free(ar, graph, file_version);
}

} // namespace serialization
} // namespace boost

#endif



Theses codes aren't tested enough, if you find bugs please email me(rakuto+nospam@gmail.com).

Monday, October 13, 2008

SFX VM 命令コード作成とバイトコードのプリティプリントのメモ

Revision 37555時点で、106の命令コードが実装されていて、103の命令コードについてドキュメントがコメント形式で与えられている。

命令コードドキュメントの生成

% cd /path/to/WebKit/JavaScriptCore
% perl docs/make-bytecode-docs.pl VM/Machine.cpp docs/bytecode.html


バイトコードプリティプリント
DEBUGモードでビルドした時のみ、バイトコードを表示するための-dオプションが有効です。

date_test.js

var d = new Date();
print(d.getFullYear(), 1 + d.getMonth(), d.getDate());



% ./JavaScriptCore/build/Debug/jsc -d date_test.js
18 instructions; 388 bytes at 0x905b50; 1 parameter(s); 18 callee register(s)

[ 0] enter
[ 1] mov r-14, r0
[ 4] mov r2, r0
[ 7] resolve_global r3, [object global], Date(@id0)
[ 13] get_by_id r4, r3, prototype(@id1)
[ 21] construct r-14, r3, r4, 5, 1, 14
[ 28] construct_verify r-14, r5
[ 31] resolve_func r2, r3, print(@id2)
[ 35] get_by_id r6, r-14, getFullYear(@id3)
[ 43] call r5, r6, r-14, 7, 1, 16
[ 50] mov r7, r1
[ 53] get_by_id r8, r-14, getMonth(@id4)
[ 61] call r9, r8, r-14, 9, 1, 18
[ 68] add r6, r7, r9
[ 73] get_by_id r8, r-14, getDate(@id5)
[ 81] call r7, r8, r-14, 9, 1, 18
[ 88] call r2, r3, r2, 4, 4, 16
[ 95] end r2

Identifiers:
id0 = Date
id1 = prototype
id2 = print
id3 = getFullYear
id4 = getMonth
id5 = getDate

Constants:
r0 = undefined
r1 = 1

StructureIDs:
[ 7] resolve_global: 0x0
[ 13] get_by_id: 0x0
[ 35] get_by_id: 0x0
[ 53] get_by_id: 0x0
[ 73] get_by_id: 0x0

2008 10 13
End: undefined
LEAK: 135 StructureID
%

Thursday, October 09, 2008

5倍速いSquirrelFish Extremeの正規表現エンジンWREC

「recursive callを得意とするV8が、recursive callに比重をおいた、V8 Benchmark Suiteで速い!速い!と語られるのはフェアではない」

今回、正規表現のみに焦点を当ててJavaScriptエンジンを比較してみた。

環境

  • SpiderMonkey - 1.7.0 2007-10-03
  • SFX - Revision: 37445
  • v8 - Revision: 389

SFX(SquirrerlFish Extreme)に新しく搭載されたWREC("the WebKit Regular Expression Compiler")、Safari 3に搭載されているJavaScript Coreに比べて、なんと5倍も速い。正規表現の実行が占める実行時間が、Webアプリケーション全体の実行時間の3%ほどだとすれば、WRECは、2.4%ほどの高速化に貢献している。

V8, SFX, SpiderMonkey, Safari 3でregexp-dna.htmlをベースに作成したベンチマークスクリプトでベンチマークを計測した。スループット(1分間の実行回数)を算出しているので、グラフが大きい方が高性能。(5回測定した結果の中央値を利用)



SFXが、Safari 3の6.44倍も速いという結果がでた!!公式に発表されている結果では、5倍だからそれよりも速い!が、String.prototype.replaceメソッドの実装に差があるため、この結果はフェアではない。regex-dna.jsを修正し、実行した結果は次の通り。

実行結果


公式の発表に近い、Safari 3の5.19倍速いという結果がでたので、概ね正しそうだ。

regexp-dna.jsの修正内容は、次のとおり。

< dnaInput = dnaInput.replace(k, subs[k], "g")
---
> dnaInput = dnaInput.replace(new RegExp(k, 'g'), subs[k]);


String.prototype.replaceの実装の差
ECMAScript262によるString.prototype.replace(searchValue, replaceValue)の定義では、第三引数は受付けないが、MozillaのSpiderMonkeyでは、第一引数に文字列が渡された場合に、第三引数に正規表現フラグを指定できるように拡張している。

もうひとつ。SpiderMonkey(js), SFX(jsc), v8(v8-shell)でString.prototype.replace関数の比較をすると、SFXの実装だけ明らかに他の2つとは異なることがわかる。


% js
js> 'aaaaa'.replace('a', '_$&_', 'g') # SpiderMonkeyでは、gフラグが有効
_a__a__a__a__a_

% v8-shell
V8 version 0.2.5
> 'aaaaa'.replace('a', '_$&_', 'g') # v8では、gフラグは無効
_a_aaaa

% jsc
> 'aaaaa'.replace('a', '_$&_', 'g') # SFXでも、gフラグは無効
_$&_aaaa
>'aaaaa'.replace(/a/, '_$&_', 'g')
_a_aaaa


WRECでは、第一引数が通常の文字列の場合は、通常の文字列置換が行われ、第二引数の置換テキスト($&)が展開されない。SFX中では、"WebKit/JavaScriptCore/kjs/StringPrototype.cpp"にString.prototype.replaceの実装があるが、文字列を探索して、マッチした以前の部分、置換する文字列、マッチした後の文字列を連結して返している。

WebKit/JavaScriptCore/kjs/StringPrototype.cpp

JSValue* stringProtoFuncReplace(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
{
// 引数の処理
if (pattern->isObject(&RegExpObject::info)) {
// 第一引数がRegExpオブジェクトのケースの処理
}
// 第一引数が文字列の場合
// First arg is a string
UString patternString = pattern->toString(exec);
int matchPos = source.find(patternString);
int matchLen = patternString.size();
// Do the replacement
if (matchPos == -1)
return sourceVal;

if (callType != CallTypeNone) {
ArgList args;
args.append(jsSubstring(exec, source, matchPos, matchLen));
args.append(jsNumber(exec, matchPos));
args.append(sourceVal);

replacementString = call(exec, replacement, callType, callData, exec->globalThisValue(), args)->toString(exec);
}

return jsString(exec, source.substr(0, matchPos) + replacementString + source.substr(matchPos + matchLen));
}


String.prototype.replaceの第一引数が文字列の場合に、単純な文字列置換をおこないパフォーマンスを向上する最適化は、SpiderMonkeyでもとりこまれる予定だ。(See Bug 432525)

WRECでは、グルーピングは未実装
シンプル!軽量!速い!と3拍子そろったWRECだけど、グルーピングの機能は実装しておらず、グルーピング付きのパターンが指定された時は、PCREに処理を任せることになるため、実行速度が低下する。


bool WRECParser::parseParentheses(JmpSrcVector&)
{
// FIXME: We don't currently backtrack correctly within parentheses in cases such as
// "c".match(/(.*)c/) so we fall back to PCRE for any regexp containing parentheses.

m_err = TempError_unsupportedParentheses;
return false;
}


regepx-dna.htmlのベンチマークでグルーピングありとなしを比べると実行速度の差が明らかになる。実行時間が変更前の140%になったSpiderMonkeyに比べて、SFXは、680%もの増加となった。

変更前

> dnaInput = dnaInput.replace(/g*t/g, subs[k]);



% jsc regexp-dna.js
285 (msec)

% js regepx-dna.js
1789 (msec)


変更後 (SFXでは、680%の速度低下)

> dnaInput = dnaInput.replace(/(g*)t/g, subs[k]);


% jsc regexp-dna.js
1942 (msec)

% js regexp-dna.js
2501 (msec)

Thursday, September 11, 2008

Pythonでデコ•メソッドキャッシュ (memcached)

おっPythonハカーを多数抱える、煩悩駆動開発で有名なglucose.jpのお手伝いをする機会があり、4年ぶりにPythonを書いた。2.3以来だったので、2.5を眺めているとデコレーターと呼ばれる機能が導入されていた。

デコレーターとクロージャーを組み合わせれば、メソッドの挙動を自由にカスタマイズすることができる。この機能を使用して、関数の結果をmemcachedでキャッシュする機能を付与するデコレーターを作ってみた。


あらかじめ、CACHE変数をmemcachedクライアントで初期化しておく必要がある。

挙動
ソースは、少々ややこしいけど、実行の仕組みは単純。

Step 1:
@cached構文実行時に、ack関数に対して、cached関数が実行され、ack関数がdecorated_funcを呼び出した結果でack関数が置換される。(返り値は、callableなオブジェクトでないといけない。)

Step 2:
decorated_func関数の呼び出し時の引数は、元のack関数。decorated_func関数の内部では、func_with_cacheが定義されており、ack関数に渡した引数を渡して実行される。この関数が、関数呼び出しの結果のキャッシュをチェックする本体となる。


# Decorate methods with capability for caching result
#
# @author Rakuto Furutani <http://raku.to/>
# @version 0.1.0
#
import cPickle
import memcache
import time
import md5

__all__ = ['cached', 'init']

# TODO: CACHE variable and function for initialize move to scope in Devkit.cache.*
# You must define global variable named 'CACHE' with instance of memcache client.
CACHE = None

def init(cache_client):
""" We should initialize this library with this method
examples:
CACHE = memcache.Client(['127.0.0.1:11211'], debug=0)
methods_cache.init(CACHE)
"""
global CACHE
CACHE = cache_client

def cached(d_args):
""" Decorate method with caching capability for caching
All result call the function are cached with cache key generated by function name and parameters.

examples:
@cached({'ttl': 3600})
def havy_complex_func(args):
# do something

# Return whether result call real function or cached result
havy_complex_func()

# You can specify cache key name explicitly
@cached({'ttl': 3600, 'key': 'foo_bar'})
def foo_bar():
# doo something

# You can also decorate one without ttl parameter
@cached
def havy_complex_func(args):
# do something
"""
def cache_key(func, args):
"""Generate unique cache key with funcion name and arguments"""
return "%s_%s" % (func.__name__, md5.new(str(args)).hexdigest())

def call_and_cache(func, args, key):
ret = func(*args)
data = {'ttl': (time.time() + d_args['ttl'] if 'ttl' in d_args else None), 'd': ret}
CACHE.set(key, cPickle.dumps(data))
return ret

def decorated_func(func):
def func_with_cache(*args):
key = d_args['key'] if ('key' in d_args) else cache_key(func, args)
cached_val = CACHE.get(key)
if cached_val is not None:
cached_val = cPickle.loads(cached_val)
if (cached_val['ttl'] is not None) and (cached_val['ttl'] >= time.time()):
return cached_val['d']
return call_and_cache(func, args, key)
return func_with_cache
return decorated_func

if __name__ == '__main__':
import sys
import time

sys.setrecursionlimit(10000)

# Define memcache client
CACHE = memcache.Client(['127.0.0.1:11211'], debug=0)

def _internal_ack(m, n):
if m == 0:
result = n + 1
elif n == 0:
result = ack(m - 1, 1)
else:
result = ack(m - 1, ack(m, n -1))
return result

def ack(m, n):
return _internal_ack(m, n)

@cached({'ttl': 3600})
def ack_with_cache(m, n):
return _internal_ack(m, n)

t = time.time()
ret = ack(3, 4)
print("ack(3, 4) returned %d - %s sec" % (ret, str(time.time() - t)))

ack_with_cache(3, 4) # cached once
t = time.time()
ret = ack_with_cache(3, 4)
print("ack(3, 4) returned %d with cached - %s sec" % (ret, str(time.time() - t)))


実行結果

ack(3, 4) returned 125 - 0.00920796394348 sec
ack(3, 4) returned 125 with cached - 0.000248908996582 sec


まとめ
来月から、shn@glucose.jpによるおっPython連載がオライリーで始まるらしい。代表取締役としての世間体と、煩悩の狭間で、どこまで書いていいのか悩んでいるようだ。結論をそれに帰着するという路線と合わせて、”ゆるかわPython”なるコンセプトを提案し、20代後半女性Pythonianを増やす革命者になるという路線も考えているようだ。

記事の影響により、glucose発の女性Pythonハカー誕生なるか。

Friday, August 29, 2008

iPhoneのセキュリティ向上のために設定しておくべき事


脆弱性。

将来において改善されそうなiPhoneの仕様 or バグの一つが話題になっている。パスコードロックがかかっている画面から緊急電話をクリックした画面でホームボタンをダブルクリックすると「よく使う項目」にアクセスできてしまう。(表示された画面のキャンセルボタンも機能しないし、おそらくバグ)

脆弱性回避のために、
設定 -> 一般 -> ホームボタンで、「よく使う項目にチェックされているフィールドを、「ホーム」にしておく。

P.S.
パスコードロックの画面では、スクリーンショット機能は起動できないが、緊急電話をかけるための画面では、スクリーンショット機能が利用できた。(ただし、実際は、壁紙しか映らなかった。)

関連記事

Tuesday, August 26, 2008

ワイヤレス共振エネルギー・リンク(WREL)と物体プログラミング

「机に座り、起動時間が3分程かかる窓のアイコンを眺めつつ、ただ待つ。モデムのスイッチを入れて、PPP接続アシスタントを立ち上げ、青いeのアイコンをクリックする。さぁ、インターネットを始めるぞ!」13年程前か。そんな時代が、随分と懐かしく感じる。

iPhoneの登場が、私達のオフラインでいる時間を無情にも奪う。Firmware 2.0.2でも、電波状況は(まだ)悪いけど、場所を選ばすにSafariが立ち上がり、Google Readerを読めるのはとても魅力的だ。オンラインでいる時間が増えるから、ライフストリーミング系のアプリケーションが盛り上がるわけだ。パーベイシブコンピューティング、インターネットは場所を選ばず利用できるようになりつつある。原丈人氏の言葉で言えば、PUC(パーベイシブユビキタスコミュニケーション)だろうか。GPS, WiFiをiPhone上で使っていて、電池の減りがいつも気になる。iPhoneは、バッテリーの交換が出来ないのに。

瀧内氏と飲んでいる時にも、よく盛り上がる話題の一つが、ワイヤレス給電だ。
WiFi同様に、電力が場所を選ばずに利用できる時代、町中に"パワースポット"が普及するのはいつ頃だろうか?といった内容の話をする。人体に影響を与えず、利用料に応じて課金される従量制。そんな電力スポットの登場が待ち遠しい。

インテル・デベロッパー・フォーラム(IDF)Fall 2008で、MITで研究されているWREL(Resonant Energy Link)のデモが公開された。

via 2050 年までに人間と機械はより一層近づくと講演

ノートブック PC を持って空港や部屋に入るだけで、バッテリーが消耗するどころか充電されるとしたら…。MIT の物理学者の理論をもとに、インテルではワイヤレス共振エネルギー・リンク(Wireless Resonant Energy Link:WREL)の研究を行っています。ラトナーは、電源プラグも電線も使わずに、60 ワットの電球を点灯してみせました。60 ワットは、標準的なノートブック PC の消費電力を上回る電力です。

WREL の素晴らしい点は、電力をワイヤレスで安全かつ効率的に供給できることです。この技術は強結合共振器を使用します。訓練された歌手が声でガラスを割ることができるのとよく似た原理です。これはガラスの固有振動数で音響エネルギーが吸収されることと同じ様に、受信側の共振器の固有振動数と共振することで、エネルギーは効率よく吸収されます。このテクノロジーをノートブック PC などに搭載すれば、送信側の共振器から数十センチの距離に近づけることでバッテリーを充電することが可能になります。




WRELは、MITの物理学者Marin Soljacic氏らの研究をベースにしている。関連記事は次の通り。


このプレスリリースには、ポイポイカプセルを思い起こさせるような一節がある。「物体もプログラム可能に:形を変えるコンピューター」と題して、次のように記載されている。

インテルではまた、何百万個もの「catom」と呼ばれる微小なマイクロロボットによって、自在に形状を変えることができる素材の研究を進めています。この素材をコンピューティング機器の筐体やディスプレイ、キーボードの製造に使うことにより、ユーザー固有の形状にすることができます。例えばノートブック PC ならば、ポケットに入れるときは小さくなり、携帯電話として使用するときは受話器の形になり、インターネットを閲覧したり映画を見るときは、大きく薄くなってキーボードも現れる、といったことが可能になります。

インテル面白いなぁ...

Friday, August 08, 2008

robots.txt 2.0の書き方

海の向こうで話題になっていた時は、その圧倒的な力に感心する程度であったが、実際に日本でもGoogle Street Viewが、リアルクローラーを走らせているとなるとプライバシーが気になる。公共の道路で撮影された映像には、著作権は存在しなく、まずい画像については、モザイクやユーザからの投稿で対応していくとの事だが、土地所有者や人にもrobot.txtを書く権利を与えてくれてもいいだろう。



「ベッドルームの撮影はお断り」との事だ。
クローラーがVanでなくて、小型偵察機や昆虫のような大きさまで小さくなった時には、どうなるのだろうか。拡張現実社会の到来にむけて、実世界におけるrobots.txtの書き方を真剣に考えるべき時である。

撮影された画像に著作権が無いとすれば、Google Street View上に広告を配信することは可能なんだろうか?ネタ画像を探そうと、みんながどこを探しまわっているかは、だいたい想像がつく。何よりGoogleには、Google Street View上での膨大なユーザのアクティビティログが残っている。ユーザが良く訪れる場所に広告を出して、「一部、拡張現実です」と明記している事はいけないのだろうか?

ザッツ監視社会はどのような世界なのか?
覗いてみたい方は、大統領暗殺の濡れ衣を着せられた一人の男の物語、ゴールデンスランバーを一読してみると良い。街中に設置されたセキュリティポットは、犯罪をおかさない善良な市民にとってはいいかもしれない。しかし、この男は、"見えない力"によりオズワルドに仕立てられた男なのだ。



Google.govなんてくそくらえ。

Friday, July 18, 2008

OpenID動向 - Trusted Data Exchangeがユーザ属性ポータビリティの切り札になるか?

第三回 Liberty Alliance 技術セミナーで=natさんの基調講演を公聴してきて、OpenID関連の動向を仕入れたのでメモ。

OPとRP間で属性情報を交換するための拡張として、SREGやAXがあるが、AXも今ひとつ普及するに至っていない。(myopenid.comとVeriSignだけ?)また、プライバシポリシーや利用規約の問題もあり、日本企業では、ユーザ属性をサードパーティに公開出来ない事も多い。

基本的に、AXとSREGの違いは、

  • 交換可能な属性をコミュニティベースで提案&決定する
  • 属性を識別するために、プリミティブな値でなく、ネームスペースURIを使う
  • OPに要求する属性の個数が指定可能
  • RPがOPに対して属性の保存をする事が可能。(ただし、使われているプロバイダは知らない。)


が挙げられるが、根本的な問題は、OpenIDのユーザ属性として、クレジットカード番号や電話番号などプライバシー性の高い情報を使う事など、気が狂っていると思われている事だ。AXへの本格的な以降が進まないのは、結局OpenIDで扱うユーザ属性は、ニックネームやメールアドレスのみで、SREGで十分に事が足りているからではないだろうか。

さて、単純なユーザ属性の交換と、OP側でのユーザの許可の仕組みしか提供していないAXに代わる仕様として、Trusted Data Exchangeが=natさん、=masakiさん (NRI)から提出されている。

TXのコンセプトには次のような物が含まれる。
  • 契約ベースの属性提供
  • XML Encryption/XML Signatureによる暗号化•書名
  • 非同期な属性提供 (非否認性を持った契約ベース)
  • RPの信憑性を判断するReputation Platform (現状のホワイトリストに代わる)
仕様は既に、提案済みで、仕様が取り込まれる方向で話が進んでいる様子。OpenIDによるログインフォームは、会員登録の敷居を下げる。結果的に、サービスを利用する敷居が下がり、クレジットカートや住所などの個人情報が信頼できないRPに渡る可能性が高くなる。ユーザ属性ポータビリティには、Reputation Platformの構築は、急務であると言える。

年内に取り込まれるだろうか?

もう一つの最新動向は、PAPEの仕様拡張。PAPEと言えば、OpenIDの認証強度を明示するためのOpenID拡張だが、採用するセキュリティモデルを明示的に指定するための仕様を提案しているとの事。現状のPAPEでは、NISTの定めるセキュリティモデルを指定できるだけであるが、日本のFISCの基準を採用する際には、次のように指定できるとの事だ。


openid.pape.auth_level.fisc:2
openid.pape.auth_level.ns.fisc: http://www.fisc.or.jp/ex/authlevel


See also: まちゅダイアリー - SAML と OpenID と CardSpace

Tuesday, July 15, 2008

[Rails] Gears on Rails helps developers to write fully offline functionnal web applications

Google anounced about Gears on Rails, see Take your Rails application offline with the Gears on Rails project. We can listen to audio interview. This is Rails plugin to manipulate offline data from RoR.We can install GoR as Rails plugin is as follows:


% sudo gem install json_pure
% rails gor_demo && cd gor_demo
% ruby script /plugin install http://gearsonrails.googlecode.com/svn/trunk/acts_as_local


It need to add acts_as_local method in your controller in order to use it.

acts_as_local :except => [:hello]

def create_local
'
post = Post.build(params("post"));
Post.create_local(post);
window.location.reload( false );
'
end


Sorry, I never use GoR yet, but It seems interesting, so i may use it. See Gears on Rails in order to see how to write view and controller for more details.

Monday, July 14, 2008

[Erlang tips] Sometimes to call mnesia:wait_for_tables is required

Hmm..,
I spent three hours for a Mnesia's strange error message, so write tips about error I'm confused. The tables on Mnesia often need a time to prepare their tables, and if tables aren't available, then we'll see storange error message.

% db_test.erl


write_db_test() ->
start(), % Start the server, mnesia and create required tables.
?assertMatch({ok, _}, mnesia:transaction(fun() -> #person{name="rakuto"})).

You may see the error is as follows:

{badmatch,{aborted,{no_exists,ready_queue}}}


It seems it need to call mnesia:wait_for_tables.

% db_test.erl

write_db_test() ->
start(), % Start the server, mnesia and create required tables.
mnesia:wait_for_tables([person], 3000),
?assertMatch({ok, _}, mnesia:transaction(fun() -> #person{name="rakuto"})).

I think that error message "{no_exists, table_name}" is not human friendly.

Friday, July 04, 2008

[Erlang] How to package an application with erlware(faxien and sinan commands)

We usually need to package system and repositories in order to create a big application. Erlware is a repository for Erlang programs and it provides softaware to create a package and release it to the world. There are pretty cool, it is just thing I want to. This entry introduces that how to create an application as package and install to system.

I create a HAVAL bindings for Erlang in order to learn how to create linked-in driver.
See Tutorial for how to create Erlang linked-in driver.

In this entry, I introduce how to create an application provides API for HAVAL bindings for Erlang. We need to install Faxien and Sinan previously.

0. Dicied a names of application and start to development a pakcage.
Create required directories for the application.

% mkdir haval && cd haval && mkdir -p cmds doc bin lib
% ls .
bin/ cmds/ doc/ lib/ releases/
%
Create directories for HAVAL bindings.
% mkdir -p lib/haval && cd lib/hava && mkdir src ebin include priv/lib
Configuration file named "_build.cfg" for this application.
% cat > _build.cfg
project : {
name : haval
vsn : "1.0.0"
},

repositories : ["http://repo.erlware.org/pub", "http://repo.martinjlogan.com/pub"]
1. Create an application
Create a HAVAL bindings for Erlang in this entry. This includes following source codes:
HAVAL bindings is provides as linked-in driver, these source are in lib/haval/c_src directory.
  • Makefile
  • config.h
  • haval.c
  • haval.h
  • haval_drv.o
2. Build the shared library
HAVAL bindings requires shared library named "erl_drv.so", we may think want to integrate building task for linked-in driver to the package manager(Faxien). But unfortunately I don't know that, so I need to research for handling shared library.

All sources are here.

Do make task manually here.
% cd lib/haval/c_src
% make # Copy haval_drv.so haval/priv/lib
3. Build the application.
It 'sinan' command is used for building the application. We need to run background server with 'sinserv' command before compile them.
% sinserv # Placed in "/usr/local/erlware/release_packages/sinan-0.10.0.12/bin/sinserv" in my enviroment
Build the application with 'sinan' command. We can see help when '+help' command is passed.
% sinan +help
sinan [args] [task]
local args (+) and server args. local args may be any of the following
+url : The url to connect to and control
+help : This help message

Server args are much more complex. There are always sane defaults so
you shouldn't need them, but you may. To get information about server
args read the sinan documentation.
%
% sinan # Default task is build
starting run
[check_depends] start
[check_depends] stop
[build] start
[build] Building ~/haval-1.0.0/lib/haval/src/haval_server.erl
[build] Building ~/haval-1.0.0/lib/haval/src/haval_sup.erl
[build] Building ~/haval-1.0.0/lib/haval/src/haval_app.erl
[build] Building ~/haval-1.0.0/lib/haval/src/haval.erl
[build] stop
run complete
% ls _build/development/apps/haval-1.0.0 # Generated following sources
c_src/ ebin/ include/ priv/ src/
%
Create a package for release. This package is generated underneath "_build/development/apps/" directory.
% sinan release
starting run
[check_depends] start
[check_depends] stop
[build] start
[build] stop
[release] start
[release] stop
run complete
%
4. Install the application locally.
Some of tasks are required in order to install the application. At first, we need to prepare the directory for released package, copy "_build/development/release" to "releases/haval-1.0.0/" and copy "_build/development/haval-1.0.0" to "releases/haval-1.0.0".
% mkdir releases/haval-1.0.0/ && mkdir lib
% cp -r _build/development/release releases/haval-1.0.0/
% cp -r _build/development/apps/haval-1.0.0 releases/haval-1.0.0/lib

Install the application locally, there will be deployed on "/usr/local/erlware/release_packages/haval-1.0.0/". We can use 'faxien' command in order to handle the packages (local and remote). Please execute "faxien help commands" for more details.

% faxien install-release releases/haval-1.0.0
ok
% ls /usr/local/erlware/release_packages/haval-1.0.0/
LICENCE README lib/ release/
Run and test.
% erl
Erlang (BEAM) emulator version 5.6.2 [source] [smp:2] [async-threads:0] [kernel-poll:false]

Eshell V5.6.2 (abort with ^G)
1> haval:start().
ok
2> haval:haval_string("test").
"593C9AED973BB51A3C852FB4E051D7C26686B9468B4E405350CB6805DC1B99E6"
3> haval:haval_file("_build.cfg").
"5A114E356FBB0CCCED8C7574B7A71780C8F33D3A9B37B8642126B78429B2988F"
4>
5. Test the application
We can use EUnit for testing the application, and do test with following command:
% sinan test

Tuesday, July 01, 2008

Manipulate Erlang binary term format in C/C++ with ei library

Erlang includes ei library for handling Erlang binary term format. This entry introduces how to use this library.

1. Pass the one string to C driver from Erlang.
It's pretty simple case, and pass one string argument to C driver from Erlang. It should be passed port_control/3 or erlang:port_control/3 after all arguments should be encoded as binary. The "index" variable are used for pointing position in the buffer.

% echo.erl


-define(DRV_ECHO, 1).

echo(Str) ->
control(?DRV_ECHO, Str).

control(Cmd, Data) ->
[{port, Port}| _] = ets:lookup(echo_table, port),
Bin = term_to_binary(Data), % XXX: All arguments will be encoded as binary term format.
Res = port_control(Port, Cmd, Bin),
binary_to_term(Res).

% echo_drv.c

#define DRV_ECHO 1

static int control(ErlDrvData drv_data, unsigned int command, char *buf,
int len, char **buf, int rlen) {
int index, type, size, arity ,ver;
char *arg1;

switch(command) {
case DRV_ECHO:
// It must call ei_decode_version at the beginning when argument is Erlang binary term format.

// All ei_xxx functions return 0 if it will be success, else return -1
ei_decode_version(buf, &index, &ver); // Value of 'index' will become 1.

// Get size of string in order to allocate buffer for argument
ei_get_type(buf, &index, &type, &size); // value of 'type' equal ERL_STRING_EXT

// Allocate memory for buffer
arg1 = new char[size + 1]; // Extra bite is required for NULL string.
/* do something */
}
}


Type of Erlang term
It can obtain type of Erlang term with result of ei_get_type function. All value of types are defined in ei.h.

#define ERL_SMALL_INTEGER_EXT 'a'
#define ERL_INTEGER_EXT 'b'
#define ERL_FLOAT_EXT 'c'
#define ERL_ATOM_EXT 'd'
#define ERL_REFERENCE_EXT 'e'
#define ERL_NEW_REFERENCE_EXT 'r'
#define ERL_PORT_EXT 'f'
#define ERL_PID_EXT 'g'
#define ERL_SMALL_TUPLE_EXT 'h'
#define ERL_LARGE_TUPLE_EXT 'i'
#define ERL_NIL_EXT 'j'
#define ERL_STRING_EXT 'k'
#define ERL_LIST_EXT 'l'
#define ERL_BINARY_EXT 'm'
#define ERL_SMALL_BIG_EXT 'n'
#define ERL_LARGE_BIG_EXT 'o'
#define ERL_NEW_FUN_EXT 'p'
#define ERL_FUN_EXT 'u'

#define ERL_NEW_CACHE 'N' /* c nodes don't know these two */
#define ERL_CACHED_ATOM 'C'


2. Pass the List
It should call ei_decode_list_header function when parse the list term. It must be called when parse the list term.

% echo_list.erl

-define(DRV_ECHO_LIST, 1).

echo(List) when is_list(List) ->
control(?DRV_ECHO_LIST, List).

control(Cmd, Data) ->
[{port, Port}| _] = ets:lookup(echo_list_table, port),
Bin = term_to_binary(Data), % XXX: All arguments will be encoded as binary term format.
Res = port_control(Port, Cmd, Str),
binary_to_term(Res).


% echo_drv.c

#define DRV_ECHO 1

static int control(ErlDrvData drv_data, unsigned int command, char *buf,
int len, char **buf, int rlen) {
int index, type, size, arity ,ver;
char *arg1;

switch(command) {
case DRV_ECHO_LIST:
// It must call ei_decode_version at the beginning when argument is Erlang binary term format.

// All ei_xxx functions return 0 if it will be success, else return -1
ei_decode_version(buf, &index, &ver); // Value of 'index' will become 1.

// Get size of string in order to allocate buffer for argument
ei_get_type(buf, &index, &type, &size);

// Check the type
if(type == ERL_LIST_EXT) {
// It must be called at the begginning when hanle the list term.
ei_decode_list_header(buf, &index, &arity);

printf("number of elements: %d\n", arity);

// Check the type of first element in the list
ei_get_type(buf, &index, &type, &size);

swithc(type) {
case ERL_SMALL_INTEGER_EXT:
case ERL_INTEGER_EXT:
// do something
break;
case ERL_STRING_EXT:
// do something
break;
}
}
}
}

Monday, June 30, 2008

Tutorial for how to create Erlang linked-in driver.

Erlang provides mechanism to communicate between Erlang and other programs written by C/C++ or other. This entry introduce how to create simple linked-in driver. Create shared library and Erlang interface to use Erlang's linked-in driver.

Goal: To create HAVAL bindings for Erlang.
HAVAL is fast cryptographic hash algorithm is invented by Yuliang Zheng, Josef Pieprzyk, and Jennifer Seberry in 1992. This library is pretty simple, so this is good choice for this tutorial.

Step 0: Files


config.h (Generated by configure script in HAVAL package)
haval.h
haval.c
haval.erl
haval_drv.cc
Makefile


haval.c and haval.h are included haval-1.1.tar.gz (C source code).

You can checkout these sample sources with Git. see haval_erlang.

% git clone git://github.com/rakuto/erlang_haval.git erlang_haval


Step 1: Create Erlang's interface
Erlang provides port mechanism in order to communicate between Erlang and other loaded shared object. See also Writing an Erlang Port using OTP Principles


-module(haval).
-author('Rakuto Furutani <xri://=rakuto>').

-define(DRV_INFO, 1).
-define(DRV_HAVAL_STRING, 2).
-define(DRV_HAVAL_FILE, 3).

-export([start/0, stop/0]).
-export([info/0, haval_string/1, haval_file/1]).
-ifdef(debug).
-export([test/0, test/1]).
-endif.

%%
%% Public interface
%%
start() ->
start("haval_drv"),
ok.

start(SharedLib) ->
case erl_ddll:load_driver(".", SharedLib) of
ok -> ok;
{error, already_loaded} -> ok;
_ -> exit({error, could_not_load_driver})
end,
register_lib(SharedLib).

stop() ->
[{port, Port}| _] = ets:lookup(haval_table, port),
Port ! {close, self()},
ok.

%% TODO: Implement this function return the information for module
info() -> ok.

%% Caluculate a value of HAVAL from string
haval_string(Str) ->
binary_to_term(control(?DRV_HAVAL_STRING, Str)).

%% Caluculate a value of HAVAL from file
haval_file(FileName) ->
binary_to_term(control(?DRV_HAVAL_FILE, FileName)).

-ifdef(debug).
test() ->
haval:start(),
Str = "I love Erlang.",
FileName = "haval.erl",
Hash1 = haval:haval_string(Str),
Hash2 = haval:haval_file(FileName),
io:format("HAVAL(~p) = ~p ~n", [Str, Hash1]),
io:format("HAVAL(~p) = ~p ~n", [FileName, Hash2]),
haval:stop(),
halt().

test([Str|_]) ->
haval:start(),
Hash = haval:haval_string(Str),
io:format("HAVAL(~p) = ~p ~n", [Str, Hash]),
haval:stop(),
halt().
-endif.

%%
%% Internal functions
%%
register_lib(SharedLib) ->
Port = open_port({spawn, SharedLib}, []),
Tab = ets:new(haval_table, [set, protected, named_table]),
ets:insert(Tab, {port, Port}).

control(Cmd, Data) ->
[{port, Port}| _] = ets:lookup(haval_table, port),
erlang:port_control(Port, Cmd, Data).



Step 2: Create C/C++ shared library
Shared library writted by C++ is loaded by Erlang interface when call erl_ddll::load_driver/2. This driver uses ei library in order to manipulate Erlang binary term.


/**
* HAVAL (cryptographic hash function) bindings for Erlang
*
* @author Rakuto Furutani <xri://=rakuto>
* @date 2008/06/28
*/
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <new>
#include "ei.h"
#include "erl_driver.h"
#include "erl_interface.h"
extern "C" {
// Define constant for haval.h
#define PASS 3
#define NUMBER_OF_BLOCKS 5000
#define FPTLEN 256
#ifndef LITTLE_ENDIAN
#define LITTLE_ENDIAN 1
#endif

#include "haval.h"
}

// Functions are provided by this driver
#define DRV_INFO 1
#define DRV_HAVAL_STRING 2
#define DRV_HAVAL_FILE 3

/* Driver Interface Declarations */
static ErlDrvData start_haval_driver(ErlDrvPort port, char *command);
static void stop_haval_driver(ErlDrvData drv_data);
static int control(ErlDrvData drv_data, unsigned int command, char *buf,
int len, char **rbuf, int rlen);
static void haval_to_hex(unsigned char*, char*);
static ErlDrvBinary* ei_x_to_new_binary(const ei_x_buff*);

/* Driver Entry */
static ErlDrvEntry haval_driver_entry = {
NULL,
start_haval_driver,
stop_haval_driver,
NULL,
NULL,
NULL,
"haval_drv",
NULL,
NULL,
control,
NULL,
NULL
};

typedef struct _drv_data {
ErlDrvPort port;
} drv_data_t;

/* DRIVER INTERFACE */

static ErlDrvData start_haval_driver(ErlDrvPort port, char *command)
{
drv_data_t *data;

data = (drv_data_t*) driver_alloc(sizeof(drv_data_t));
data->port = port;
set_port_control_flags(port, PORT_CONTROL_FLAG_BINARY);
return (ErlDrvData) data;
}

static void stop_haval_driver(ErlDrvData drv_data)
{
driver_free((char*) drv_data);
}

static int control(ErlDrvData drv_data, unsigned int command, char *buf, int len, char **rbuf, int rlen)
{
int ret = -1;
char hex[(FPTLEN >> 3) << 1];
unsigned char fingerprint[FPTLEN >> 3];
char *arg1;
ei_x_buff x_buff;

try {
// argument
arg1 = new char[len + 1];
strncpy(arg1, buf, len);
strcat(arg1, "�0");

ei_x_new_with_version(&x_buff);
switch(command) {
case DRV_INFO:
ei_x_encode_string(&x_buff, "info");
ret = sizeof("info") * sizeof(char);
break;
case DRV_HAVAL_STRING:
haval_string(arg1, fingerprint);
haval_to_hex(&fingerprint[0], &hex[0]);
ret = sizeof(hex);
ei_x_encode_string(&x_buff, hex);
break;
case DRV_HAVAL_FILE:
if(!haval_file(arg1, fingerprint)) {
haval_to_hex(&fingerprint[0], &hex[0]);
ret = sizeof(hex);
ei_x_encode_string(&x_buff, hex);
} else {
erl_err_sys("haval_file");
}
break;
}
if(ret > 0) *rbuf = reinterpret_cast<char*>(ei_x_to_new_binary(&x_buff));
ei_x_free(&x_buff);
} catch(std::bad_alloc) {
erl_err_sys("can not allocate memory");
}

return ret;
}

static void haval_to_hex(unsigned char *fingerprint, char *hex)
{
for(int i=0; i < FPTLEN >> 3; ++i) {
sprintf(&hex[i << 1], "%02X", fingerprint[i]);
}
}

// Init the driver
extern "C" DRIVER_INIT(haval_drv)
{
return &haval_driver_entry;
}

// Utilities
static ErlDrvBinary* ei_x_to_new_binary(const ei_x_buff *x_buff)
{
ErlDrvBinary *bin = driver_alloc_binary(x_buff->index);
if(bin != NULL) {
memcpy(bin->orig_bytes, x_buff->buff, x_buff->index);
}
return bin;
}


Step 3: Compile all sources
Create Makefile for build.
FYI: If you want to build linked-in driveron Mac OS, see Compile Erlang linked-in driver on Mac OSX (Darwin)


.PHONY: clean
.SUFFIXES: .o .c .cc .erl .beam

OS= ${shell uname}
CC=gcc
CXX=g++
CXXFLAGS=-Wall -g

# Erlang
ERL_INCLUDE = -I/usr/local/lib/erlang/usr/include
ERL_LIBS = -L/usr/local/lib/erlang/usr/lib \
-lerts
EI_INCLUDE = -I/usr/local/lib/erlang/lib/erl_interface-3.5.6/include
EI_LIBS = -L/usr/local/lib/erlang/lib/erl_interface-3.5.6/lib \
-lei \
-lerl_interface

TARGET_LIB = haval_drv.so
ifeq ($(OS), Darwin)
EXTRA_OPTIONS = -fno-common -bundle -undefined suppress -flat_namespace
endif
ALL: $(TARGET_LIB) haval.beam

.erl.beam:
erlc -W -Ddebug $<

.c.o:
$(CC) $(CFLAGS) -c $<

.cc.o:
$(CXX) $(CXXFLAGS) $(ERL_INCLUDE) $(EI_INCLUDE) -c $<

haval_drv.so: haval.o haval_drv.o
$(CXX) -o $@ $^ $(ERL_LIBS) $(EI_LIBS) $(EXTRA_OPTIONS) -fpic -O2

clean:
rm -f *.beam *.o *.so



Step 4: Run and test

% erl -noshell -run haval test
HAVAL("I love Erlang.") = "3AECEDF5133ED147C704A25C2CCA9A994FBB984FBCB22C1A523F31963E418498"
HAVAL("haval.erl") = "E006098555DFF788E73C7A263615DF60CC82396B1BCE7AEB5FB7050C376F2B03"

Saturday, June 28, 2008

Compile Erlang linked-in driver on Mac OSX (Darwin)

In order to compile the Erlang linked-in driver on Darwin, we must specify some options when it will be linked. If you don't specify these options, you might see errors is as follows:

% gcc -o my_drv.dymlib my_drv.c -dynamiclib -fpic

/usr/bin/ld: Undefined symbols:
_driver_alloc
_driver_free
_driver_output

That's invalid, so it must specify some options below in order to create the shared object.

% gcc -o my_drv.so my_drv.c -bundle -flat_namespace -udefined suppress


see README in source code of Erlang/OTP for more details.

Friday, June 27, 2008

Asynchronous driver in Erlang using driver_async

Erlang provides some mechanism is to communicate other language, this can be used for to reuse module, speed things up (Erlang is ten times as slow as slow than C), to access OS resource and so on. The below mechanism are provided.

Pipe Drivers
The "pipe drivers" enables bi-directional communication. The external process can be implemented in C or any language, and it can use erl_interface and ei library in order to manipulate data of Erlang as ETERM.

Benefit:

  • Frexible, it can use some types data.
  • Any language

Demerit:
  • Communication overhead

Linked-in Drivers
A driver in Erlang is a library written in C/C++, that is linked to the Erlang emulator and called from erlang. A driver can be dynamically loaded, as a shared library (known as a DLL on windows), or statically loaded, linked with the emulator when it is compiled and linked.

Benefit:
* Faster than "Pipe Drivers"

Demerit:
* Not frexible, to pass the complex data between C/C++ and Erlang is difficult. (see also ei)


Asynchonous Linked-in Driver
The "Linked-in Drivers" is faster than "Pipe Drivers", but it can not scale with a lot of process, since it run synchronously. So If you'd like to take advantage of platforms with multiple CPUs, then you must run some Erlang virtual machine since it run on single thread.

It sounds like great!, but we should care the some problems, multi-thread problem and so on.

Resources:

Next, I'll write an entry about how to create asynchronous driver.

Wednesday, June 18, 2008

[EC2] mount /dev/sdc device since /dev/sdb is not available

AWS team announced about persistent storage, see below the link.

http://www.allthingsdistributed.com/2008/04/persistent_storage_for_amazon.html

That's looks like pretty cool, but it's closed beta now, so we should use S3 or EC2 ephemeral storage (aka. Instance Storage). The 160GB storage is available on m1.large AMI, and some below devices are available.

/dev/sda1 Formatted and mounted as root (/) on all instance types
/dev/sda2 Formatted and mounted as /mnt on small instances
/dev/sda3 Formatted and mounted as /swap on small instances
/dev/sdb Formatted and mounted as /mnt on large and extra large instances
/dev/sdc Available on large and extra large instances; not mounted
/dev/sdd Available on extra large instances; not mounted
/dev/sde Available on extra large instances; not mounted


ATTENTION: The /dev/sdb isn't mounted to /mnt on m1.large AMI, see below a link for more details.
But the /dev/sdb device looks like that isn't mounted to /mnt.


% df -h
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 9.9G 8.6G 801M 92% /
tmpfs 3.8G 0 3.8G 0% /lib/init/rw
udev 10M 10M 0 100% /dev
tmpfs 3.8G 4.0K 3.8G 1% /dev/shm
%


/dev/sdb is recognized in /etc/fstab, but it isn't mounted.

# Default /etc/fstab
# Supplied by: ec2-ami-tools-1.3-20041
/dev/sda1 / ext3 defaults 1 1
/dev/sdb /mnt ext3 defaults 0 0
none /dev/pts devpts gid=5,mode=620 0 0
none /proc proc defaults 0 0
none /sys sysfs defaults 0 0



% sudo mount /mnt
mount: /dev/sdb is not a valid block device


So we should initialize device to use as file system.
At first, optimize virtual devices before use them in production.

dd if=/dev/zero of=/dev/sdb bs=1M
dd if=/dev/zero of=/dev/sdc bs=1M
dd if=/dev/zero of=/dev/sdd bs=1M (m1.xlarge only)
dd if=/dev/zero of=/dev/sde bs=1M (m1.xlarge only)


Create a file system and mount it, and mounted /dev/sdc device is available now.

mkfs -t ext3 /dev/sdc
mount -t ext3 /dev/sdc /www



Filesystem Size Used Avail Use% Mounted on
/dev/sda1 9.9G 8.2G 1.2G 88% /
tmpfs 3.8G 0 3.8G 0% /lib/init/rw
udev 10M 10M 0 100% /dev
tmpfs 3.8G 4.0K 3.8G 1% /dev/shm
/dev/sdc 414G 6.7G 386G 2% /www

Tuesday, June 17, 2008

グラデーションブックスで本を探そう。amazonのおすすめ本ばかり読んでいたら世界が広がらない。


Photo via Flickr

グラデーションブックス

amazonの本ランキングや、楽天ブックスの本ランキングは、読者に新しい発見や本をブラウズする楽しみをもたらしているだろうか?実は、深いつながりがある、経済学の本と、最近話題のKYについて書いた本を一緒にリコメンドするだろうか?島嶼http://www.blogger.com/img/gl.link.gif生物学と企業の経営について、二つの本を結びつける事ができるだろうか?

先日、クローズアップ現代「ランキンhttp://www.blogger.com/img/gl.link.gifグ依存が止まらない」で、出版業界が抱える問題にスポットを当てた特集が放送された。とても素晴らしいまとめ記事が2008-06-04 今日の「クローズアップ現代」にある。
出版ニュース社の清田代表は、「ランキングで売れているからそれでいいというわけではない。出版の世界は奥が深いし、多様なものがあって、いろんな面白い本がある。むしろ、売れない本、売りにくい本こそ、いい本があって、埋もれてしまっている状況だ」


そのような状況の中、本を扱うサイト「グラデーションブックス」がオープンした。サイトの運営元である、澁川直子氏の言葉を引用する。

「従来の目的型検索やリコメンデーションサービスでは出会うことができな
かった、思いもよらない本を見つけ出せる喜びを提供できればと思います。」


amazonのリコメンドでは、思いもよらなかった発見が無い。極端な言い方をしてしまえば、amazonのオススメ本ばかり読んでいては、世界観が広がらない。だからこそ、人は、本屋に足を運び、本を買う。本好きの知人から、面白い本について教えてもらう。憧れている人が読んでいる本を、自分も読む。

上記に引用したブログ中にも書かれている通り、ランキングを見て本を購入する読者は、年に本を数冊しか読まないユーザである。たくさんの本を読んでいる人は、複数のジャンルを超えて、面白い本を発見し、つながりを見つけ出す英知を持っている。年間数冊しか読まない読者も、年間200冊読む読者と同じように、面白い本に出会えるサイトが、グラデーションブックスであるような気がしている。

技術本やビジネス本などの実用書しか読まなかった私も、このサービスをきっかけに小説やミステリーを読み出してみた。そんな、きっかけを与えてくれた面白い本を集めてくれている本棚をいくつかリンク。

chibinaoさん
Junさん
yukoさん
Saitoさん

Monday, May 19, 2008

[rails] RSpec matchers for render(:nothing => true)

This is matchers for render(:nothing => true).

Add some code into spec/spec_helper.rb is as follows:


# Matchers for render(:nothing => true)
class RenderNothing
def initialize
end

def matches?(controller)
@actual = controller.rendered_file
@actual == nil
end

def failure_message
return "render_nothing expected (render :nothing => true), got #{@actual.inspect}"
end

def negative_failure_message
return "render_nothing expected (render :nothing => true) not to equal #{@actual.inspect}"
end
end

def render_nothing
RenderNothing.new
end


Use render_nothing.

it "should not render anything" do
post :destroy, :id => 1
response.should render_nothing
end

Sunday, May 18, 2008

[rails] RSpec render_layout expects render specified layout file

Original idea via http://rubyforge.org/pipermail/rspec-users/2007-October/004026.html

Add some code into your spec/spec_helper.rb is as follows:


class RenderLayout
def initialize(expected)
@expected = 'layouts/' + expected
end

def matches?(controller)
@actual = controller.layout
@actual == @expected
end

def failure_message
return "render_layout expected #{@expected.inspect}, got #{@actual.inspect}", @expected, @acutual
end

def negative_failure_message
return "render_layout expected #{@expected.inspect} not to equal #{@actual.inspect}", @expected, @actual
end
end

def render_layout(expected)
RenderLayout.new(expected)
end

your_controller_spec.rb

it "should render 'application' layout file" do
get :index
response.should render_layout('application')
end

Tuesday, May 06, 2008

[rails] Running Erubis on Edge Rails

ActionView class was refactoring on Edge Rails, see Ticket #10437 for more details. The template engines are integrated into new ActionView::Template class, but we have to modify some scripts in order to run Erubis on Edge Rails.

0. Install Erubis and Edge Rails

% sudo gem install erubis
% cd /path/to/rails_app/ && rake rails::freeze:edge

1. Create a template handler for Erubis.

Copy and paste below code at #{RAILS_ROOT}/lib/erubis_rails_helper.rb.
require 'erubis'
require 'erubis/preprocessing'

module Erubis
class Eruby
include ErboutEnhancer
end

class FastEruby
include ErboutEnhancer
end
end

module ActionView
module TemplateHandlers
class Erubis < TemplateHandler
include Compilable

# Erubis engine class
cattr_accessor :engine_class
@@engine_class = ::Erubis::Eruby

# Properties
cattr_accessor :init_properties
@@init_properties = {}

# Enable preprocessing if true
cattr_accessor :preprocessing
@@preprocessing = false

def compile(template)
if preprocessing
preprocessor = ::Erubis::PreprocessingEruby.new(template, init_properties)
template = preprocessor.evaluate(@view)
end
engine_class.new(template, init_properties).src
end
end
end
end
ActionView::Template.register_default_template_handler :erb, ActionView::TemplateHandlers::Erubis
ActionView::Template.register_template_handler :rhtml, ActionView::TemplateHandlers::Erubis

2. Configure settings of Erubis in enviroment.rb.

Append below scripts in config/enviroment.rb
require 'erubis_rails_helper'
ActionView::TemplateHandlers::Erubis.engine_class = Erubis::FastEruby
ActionView::TemplateHandlers::Erubis.preprocessing = true
Restart the web server.

Saturday, May 03, 2008

[rails] released jrails_in_place_editing

The jrails_in_place_editing is implementation of inplace editor with jQuery, so this plugin is dependent on jRails. This uses David Hauenstein's jQuery inplace editor plugin. Thank you.

INSTALL (Note: Edge Rails)


./script/plugin install git://github.com/rakuto/jrails_in_place_editing.git

USAGE

# Controller
class BlogController < ApplicationController
in_place_edit_for :post, :title
end

# Customize the action that update the value
class BlogController < ApplicationController
# set_#{object}_#{title}
def set_post_title
post = Post.find(params[:id])
post.title = params[:value]
post.save

# It should render a text
render :text => post.title
end
end

# View
<%= in_place_editor_field :post, :title %>

# Pass some options
<%= in_place_editor_field :post, :title, {}, {:field_type => 'textarea', :textarea_cols => 25, :textarea_rows => 10}%>
<%= in_place_editor_field :post, :title, {}, {:field_type => 'textarea', :textarea_rows => 10}%>

For more details, see jrails_inplace_editing/javascripts/jquery.inplace.js

Tuesday, April 29, 2008

Edge Rails: Describes Gem Dependencies

So far today, Gem dependencies might be written with Capistrano, but we can write Gem dependencies in config/environemt.rb with Edge Rails, and it will be installed with Rake task.

# in config/enviroment.rb


config.gem 'hpricot'
config.gem 'aws/s3', '>= 0.4.0'
config.gem 'aws-s3', :lib => 'aws/s3', :version => '>= 0.4.0', :source => "http://code.whytheluckystiff.net"


Install all required Gems.
rake gems:install

Cool

Saturday, April 26, 2008

OpenID再利用問題

ドメインの更新忘れもOpenIDにおける脆弱性の一つ。

URLやXRIを入力するだけで、Yadisプロトコルに基づきOpenIDプロバイダーやi-Brokerを発見し、認証が行えるシステムは、とてもシンプルでありながら、WWWの分散アーキテクチャの上に構築された強力なエコシステムだ。しかし、問題は、私達自身の識別子として利用可能なURLやXRIは、永遠ではないことだ。

もしも、私達が利用しているOpenIDプロバイダがドメインの更新を忘れて、第三者にドメインが取得された場合、私達のアカウントがこの第三者により不正に使用される可能性が出てくる。myOpenIDや、多くのプロバイダでは、単純なルールに基づいた、Human FriendlyなOP-Local Identifierを提供してくれているが、ユーザは、セキュリティ的、高可用性の両方の側面からRelying Partyでのユーザ登録に、OP-Local Identifierを使用すべきではない。

もう少し、現実的に起こりえそうな問題は、OpenIDプロバイダにより特定のアカウントの持ち主が変更されたケースである。初めは、Aというユーザが、a.example.comというOP-Local Identifierを保持していたが、Aが退会して同じOP-Local IdentifierがBというユーザに渡った場合、Bは、AがOP-Local Identifierを用いて会員登録したRPにサインインして登録された情報に自由にアクセスすることができる。

もう一つの問題は、自分のHPのURLを識別子として利用した場合のリスクである。この場合、自分がドメインの更新を忘れて(または意図的に)、ドメインが第三者の手に渡ると、Relying Party上に残した私達の情報が、第三者に再利用される可能性が生まれる。

どちらの問題も、OPでのアカウントのExpireや移行がRPと同期できないために発生する問題である。
既存のOpenIDライブラリ(といっても、ruby-openidしか見ていない)では、OpenID URLの変更とアクティベーションのサンプルはついていないが、RPはこの機能を用意すべきだろう。

OpenID再利用問題一つとっても認証をOpenIDのみに踏み切るには、まだまだリスクが高い。

P.S.
念のため補足すると、XRIでは再利用の問題が起きない。これは、XRIが取得される度にi-Numberと呼ばれる全世界で一意な値を割り当てるからである。XRIでは、このi-NumberがClaimed Identifier(aka XRDS::XRD::CanonicalEquivID)になるからである。

myOpenIDなどユーザのセキュリティに対して十分な対応をしているプロバイダでは、一度取得されたアカウントは、退会した後も再利用される事は無いのでここに書いた問題は発生しない。ただし、退会後のアカウントについて明記していないプロバイダは要注意である。