どうも、こんにちは。hirokiです。前回は、HTML::Template::ProのJavaScript実装を紹介させていただきました。今回はその実装部においてのちょっとした工夫についてと、Webフロントエンドのパフォーマンスチューニングについて簡単にまとめさせていただきます。

正規表現の話

通常、テキストベースのDSL評価系を作成する際にはyacc/lexなどで文法記述を行うのが定石なんですが、

  • シンプルな文法であること
  • 構文木の評価からコードジェネレートに方向性を転換した
  • テキストマッチングの回数や高速化のための制御がしやすい

などの理由から、HTML Template(JavaScript)では正規表現ベースの文法解釈を行っています。( HTML::Template::Proのyacc文法ファイルをそのまま使えば記述は楽だったのですが…)以下に実際に利用している正規表現を示します。

/<(\/)?TMPL_(VAR|LOOP|IF|ELSE|ELSIF|UNLESS|INCLUDE)\s*(?:(?:DEFAULT)=(?:'([^'>]*)'|"([^">]*)"|([^\s=>]*)))?\s*(?:(?:ESCAPE)=(?:(JS|URL|HTML|0|1|NONE)))?\s*(?:(?:DEFAULT)=(?:'([^'>]*)'|"([^">]*)"|([^\s=>]*)))?\s*(?:(NAME|EXPR)=(?:'([^'>]*)'|"([^">]*)"|([^\s=>]*)))?\s*(?:(?:DEFAULT)=(?:'([^'>]*)'|"([^">]*)"|([^\s=>]*)))?\s*(?:(?:ESCAPE)=(?:(JS|URL|HTML|0|1|NONE)))?\s*(?:(?:DEFAULT)=(?:'([^'>]*)'|"([^">]*)"|([^\s=>]*)))?\s*>/

正規表現に慣れている方でしたら、ふむふむなるほどね。となるところでしょうが、私自身はそんなに正規表現が得意でないので、これ自体をちょっと記述しようとかメンテナンスしようという気にはなりませんでした。

Perl/Rubyなどには改行可能な正規表現リテラルが存在しますが、JavaScriptにはこういったものは存在しません。存在しなければ作ればいいということで、正規表現を構築する関数を作成し、以下のような記述を可能にしました。


HTML.Template.createMatcher('%',[
    "<",
    "(%/)?",{map:'close'},
    "TMPL_",
    "(VAR|LOOP|IF|ELSE|ELSIF|UNLESS|INCLUDE)",{map:'tag_name'},
    "%s*",
    "(?:",
        "(?:DEFAULT)=",
        "(?:",
            "'([^'>]*)'|",{map:'default'},
            '"([^">]*)"|',{map:'default'},
            "([^%s=>]*)" ,{map:'default'},
        ")",
    ")?",
    "%s*",
    "(?:",
        "(?:ESCAPE)=",
        "(?:",
            "(JS|URL|HTML|0|1|NONE)",{map:'escape'},
        ")",
    ")?",
    "%s*",
    "(?:",
        "(?:DEFAULT)=",
        "(?:",
            "'([^'>]*)'|",{map:'default'},
            '"([^">]*)"|',{map:'default'},
            "([^%s=>]*)" ,{map:'default'},
        ")",
    ")?",
    "%s*",
    /*
        NAME or EXPR
    */
    "(?:",
        "(NAME|EXPR)=",{map:'attribute_name'},
        "(?:",
            "'([^'>]*)'|",{map:'attribute_value'},
            '"([^">]*)"|',{map:'attribute_value'},
            "([^%s=>]*)" ,{map:'attribute_value'},
        ")",
    ")?",
    /*
        DEFAULT or ESCAPE
    */
    '%s*',
    "(?:",
        "(?:DEFAULT)=",
        "(?:",
            "'([^'>]*)'|",{map:'default'},
            '"([^">]*)"|',{map:'default'},
            "([^%s=>]*)" ,{map:'default'},
        ")",
    ")?",
    "%s*",
    "(?:",
        "(?:ESCAPE)=",
        "(?:",
            "(JS|URL|HTML|0|1|NONE)",{map:'escape'},
        ")",
    ")?",
    "%s*",
    "(?:",
        "(?:DEFAULT)=",
        "(?:",
            "'([^'>]*)'|",{map:'default'},
            '"([^">]*)"|',{map:'default'},
            "([^%s=>]*)" ,{map:'default'},
        ")",
    ")?",
    "%s*",
    ">"
]);

第一引数にescape charを示して、配列として正規表現を記述します。captureの次の要素(正確には次でなくても良いが)にはキャプチャされた値のプロパティ名を指定できるようにしています。実現方法はぜひ実装をご覧ください。

コメント可能で可読性の良い正規表現を記述したいという際には、このような方法も頭のすみにおいておくと良いかもしれません。

※ちなみにこの正規表現は「完全な」HTML::Templateのシンタックスを表現していませんが、マナーのよいほとんどすべてのテンプレートをパースすることができます。

パフォーマンスチューニングの話

HTML Template(JavaScript)の実装に際しては、順次リファクタリングする必要がありそうだという点と、インタフェースがある程度決まっているということから、TDD(テスト駆動開発)を心がけました。また、JavaScriptライブラリでのUnitTestにはscript.aculo.usのunittest.jsを採用しました。unittest.jsはベンチマーク用関数も同梱されており、あらかじめ必要と思われるベンチマークとテストを記述した上で、パフォーマンスチューニングを行いました。

unittest.jsを用いると以下のようにベンチマークを記述することができます。

benchmark(function(){
    new HTML.Template({type:'text',source:COMPLEX_TMPL+Math.random()});
},100);

しかし、ベンチマークだけではパフォーマンスに悪影響を与えている箇所の特定は難しいので他の言語と同様プロファイリングをすることで、ボトルネックを発見します。

プロファイリングの話

JavaScriptのプロファイリングは特別な環境はほとんど必要なくなりましたが、あまり利用されていないのでここで簡単に紹介させていただきます。

現在、Safari4(Webkit Nightly Build)かFirefox3.x+Firebugで簡単にプロファイリングすることができます。今回はFirefox&Firebugでのプロファイリング方法を示します。

document.getElementById('test').addEventListener('click',function(){
	// DO SOME ACTION
},false);

まず、上記のように任意の操作可能なエレメントに対して、イベントを付与しプロファイルをとりたいアクションを記述してください。

この際に本質的動作でないalertやconsole.log、同期ネットワーク処理、DOMのリードライト繰り返しなどの副作用のある操作は控えたほうがより正確にコード自体のボトルネックを発見することができます。

準備ができたら、FirefoxおよびFirebugを起動し、該当HTMLを開きます。そして、

  1. プロファイルボタンを押す
  2. プロファイル対象の操作を行う
  3. プロファイルボタンで終了

profile

今回は例として、以前、小山先生のエントリにて公開されましたJavaScriptによるCamellia実装を用いました。

プロファイルを行うと(?)()という関数名がたくさん表示されるのがお分かりになるかと思います。これは無名関数をあらわすプロファイル上の表現なのですが、これではどの関数がボトルネックであるのか分かりにくいですね。

これは、

PACKAGE.prototype._xor_block = function (x, y, l) {(略)}

のように関数が実装されており、PACKAGE.prototype._xor_block関数がプロファイラ上には無名関数の代入として表現されているため、関数に「処理系上の公式な名称」が付与されないために、このような状態になっています。

Firebugプロファイラの場合、以下のような方法で「処理系上の公式な名称」を付与することができます。

// function文
function test(){
	return true;
}

// 名前付function式
var vtest = function test(){
	return true;
}

// オブジェクトリテラル中
var Test = {
	test:function(){return true;}
}

プロファイリングを行う場合にはこのような条件にも注目して実装することで、問題の発見を容易にすることができます。

これらを踏まえて、実装に手を加えプロファイルを取り直すと以下のようになります。
profile2
このようにすればボトルネックとなる関数がどれなのか、判別することができます。

時間感覚の話

Templateモジュールのようなコードを書く際に注意しなければならないのが、サーバサイドのページとの時間感覚の違いです。以下に感覚的なレベルでのサーバサイド、クライアントサイドのボトルネックに関して表にまとめたものを示します。
table1
サーバサイドの平均的なプログラムにおいて、もっともボトルネックとなるのはデータベースサーバ等への処理です。クライアントサイドも同じように外部環境ネットワークとの通信処理がもっともネックになります。注目するべきは、クライアントサイドプログラミングにおいて、DOMの描画リフレッシュ操作もボトルネックになるということです。

一方、サーバサイドにおいては処理の内容に応じてスケールアウトするための技術が盛んに議論されていますが、クライアントサイドにおいては1ユーザのために、ユーザのCPU時間を消費しますのでスケールアウトという観念はありません。しかし、GUIプログラムにおいては採用するアーキテクチャから、異なったアプローチでのレスポンス改善策があります。以下にプログラミングパラダイムから考えたクライアントサイドプログラミングとサーバサイドプログラミングの違いを示します。

table2
ほとんどの場合、サーバサイドプログラミングでは1リクエストあたりの処理は1OSレベルスレッドが割り当てられ、体感時間と実際にプログラミングが処理を行っている実働時間はイコールとなります。最近では、こういった状況に対応するためにJob Queue Serverなどを用いることで、プログラムの実行タイミングを遅延&平滑化することが注目されていますが、基本的にはこういったモデルが採用されています。一方で、クライアントサイドのGUIプログラミングにおいては、ユーザアクションに対して、レスポンスを返すまでの時間が体感時間となりますので、ユーザアクション以前に実行しておける処理が多くあります。このような状況では、如何にユーザアクションが発生する前にできうるかぎりの処理をしておくか、といったことが重要になります。

このようなベースを踏まえたうえで、HTML.Template(JavaScript)の各フェーズでの処理時間に注目してプロファイルをとってみると以下のようになります。
time1
evalと文字列処理という重い処理を実行するTemplate ParseとCompileに6割近い時間が消費されていることがわかるかと思います。そしてこれらの処理は多くの場合、ユーザアクションの前に実行可能です。

そこで、以下の図のような戦略をとります。
time2
もっとも時間のあるブラウザのアイドル時間にParseとCompileを実行し、その後にユーザアクションが予見可能なプリアクションが存在すれば、そのタイミングでデータのアサインとテンプレートテキストの出力を行います。

そしてもっともユーザが即時の応答を期待するユーザアクション時にはDOMのリフレッシュ処理のみを動作させるようにするというものです。

実際のコードでは以下のようになります。

// ブラウザのアイドル時間にtemplatesクラスの付いているテンプレートを
// コンパイルする。
HTML.Template.precompileBySelector.defer('.templates');
/*
   .HTML_TEMPLATE
   .HTML_TEMPLATE_DEFERRED
  は予約され、それぞれDOM構築時、DOM構築後最初のアイドル時間
   にコンパイルされる
*/

// クリック時にテンプレートを呼び出す
// コンパイルされていれば、キャッシュが効いていて動作
// コンパイルされていなければ、コンパイルして実行
$('button').observe('click',function(){
    var template = new HTML.Template('dom:hoge_tmpl');
    template.param({
        test:1
    });
    $('hoge').update(template);
});

HTML.Template(JavaScript)では自動的にDOM構築時や最初のブラウザアイドル時間にテンプレートをコンパイルするように指示できるclassNameを定義しています。マークアップによる記述のみでこれらの非同期で煩雑な処理を隠蔽することができるため、テンプレートの処理自体にかかる動作はほとんど意識することなく、プログラミングを行うことが出来ます。

また、これは実験的な内容なのですが、DOMの更新処理時間そのものをより、高速にすることはできないのだろうかと勘案した内容を紹介します。DOM更新処理は内部的には、DOMエレメントを構築し、それを描画するという二つの処理に分解されます。
図に示すと以下のようになります。
time3
ということは、この内部的に行われている処理のDOMエレメント構築をプリアクション時に実行できれば、より高速なUXを実現することができます。
time4

$('button').observe('click',function(){
    var template = new HTML.Template('dom:hoge_tmpl');
    template.param({
        test:1
    });
    // renderを呼び出すとtoElementメソッドが自動生成され、
  // documentFragmentを構成する。
    template.render();
    $('hoge').update(template);
});
//内部処理
if(document.createDocumentFragment){
    var dfrag   = document.createDocumentFragment();
  // 事前にエレメントを構成して、DocumentFragmentとしておく
    Element._getContentFromAnonymousElement(
         tagName,this.output()
    ).each(
    function(e){
        dfrag.appendChild(e);
    });
    // DocumentFragmentのコピーを引き渡す
    this.toElement = function(){
        var tmp = dfrag.cloneNode(true);
        return tmp;
    }
}

テキストのElement化としては、実験的内容であったためにPrototype.jsのプライベートメソッドを利用しています。そのうち、実用レベルになった際には、別途実装するようにします。このようにすることで、update性能にこそ差はほとんど見られませんでしたが、insert時(DOM追加時)の性能は約3倍になりました。まだ、透過的に実用できる状態にはなっていないのですが、パラメータが定義されてから、アイドル時間が発生すると自動的にrenderしておくこともできます。

まとめ

今回はTemplateエンジンの実装にかかわるちょっとしたノウハウとパフォーマンスチューニングについて、簡単に紹介させていただきました。Webフロントエンドのアーキテクチャは、バックエンドのモデルと異なるアーキテクチャを採用しているためそれぞれのアーキテクチャに適合したパフォーマンスチューニングの方法論があり、適切に状況を見ることでより快適なアプリケーションを構築することができるようになります。これからも、トピックがあればWebフロントエンドについての話題を本ブログで紹介できればと思います。

はじめましてhirokiです。こんにちは。新卒で弊社に入って一年が経過しようとしているので、そろそろエンジニアブロガーの仲間入りをしてみようかと思っています。

今回はJavaScriptのお話です。ハードボイルドなバックエンド側技術のご紹介が多い当ブログですが、スイーツ(笑)なフロントエンド技術もおもしろいんだよ!ということをアピってやろうという魂胆です><。

HTML.Template(JavaScript)

弊社では、サーバサイドによるHTMLの出力テンプレートエンジンにCPANモジュールであるHTML::Template::Proを使用しています。今回はそのJavaScript実装をオープンソースとして開発しましたので、紹介をさせていただきます。

HTML::Templateは貧弱で、冗長で、洗練されていないシンタックスでお馴染みのテンプレートエンジンですが、高速で必要以上のロジックを積み込まないようにできるという点で優れたView Templateモジュールです。

長年、このモジュールを使用してきたという経緯もあり、社内ではこのテンプレート言語に対するノウハウも蓄積されています。そんな中、昨今ではJavaScriptを利用したDHTML+XHRなアプリケーション開発要件も増加傾向にあり、案件ごとに必要なJavaScriptのテンプレートモジュールを探してみるという状況でした。

そこで、ノウハウの継承をしつつ高速でサーバサイドとの統一利用可能なJavaScript Template EngineとしてHTML.Template(JavaScript)を作成しました。

能書きはいいからドキュメントを見せろ!という方はこちらからどうぞ。Prototype1.6xxを必須としているのでご注意ください。

あとは能書きをだらだらと書かせていただきます。

テンプレートエンジンとは

JavaScriptでは、画面の書き換えに主に2つの方法を使用します。1つはinnerHTMLによる方法、もう一つがDOM操作による方法です。

それぞれコードで見てみましょう。

// innerHTMLによる置き換え
document
   .getElementById('bodyMainArea')
       .innerHTML = "Hello!World";
// DOM操作による追記
document
   .getElementById('bodyMainArea')
        .appendChild(
            document.createTextNode('helloWorld!')
	);

それぞれに一長一短があるのですが、大規模な書き換えの場合にはStringとしてHTMLを構築してinnerHTMLを行うという方法がもっとも単純です。

DOM構築の複雑さを補うscript.aculo.usのbuilder.jsのようなライブラリも存在しますが、若干のロジックが入ってくるとどちらの方法も記述が難しくなってきます。

// innerHTMLによる書き換え(変数)
document.getElementById('bodyMainArea').innerHTML=[
    '<div class="testBox">',
    '    <ol>',
    '        <li>'+hoge+'</li>',
    '    </ol>',
    '</div>'
].join('');

// 分岐
document.getElementById('bodyMainArea').innerHTML=[
    '<div class="testBox">',
    '    <ol>',
    (someCondition == true)?'<li>hello!</li>':'',
    '    </ol>',
    '</div>'
].join('');

//繰り返し
document.getElementById('bodyMainArea').innerHTML=[
    '<div class="testBox">',
    '    <ol>',
    (function(){
        var ret = [];
      for(
              var i    = 0,
                elem   = arguments[i],
                length = arguments.length;

             i < length;

             i++,elem = array[i]
        ){
             if(elem.num % 2 == 0 ) ret.push('<li>'+elem.text+'</li>');
         }

        return ret.join('');
    })(
        {num:1,text:'hoge'},
        {num:2,text:'fuga'},
        {num:3,text:'piyo'},
        {num:4,text:'moga'}
     ),
    '    </ol>',
    '</div>'
].join('');

このような文字列処理や関数処理を毎度行うのは面倒ですし、コーダーによるメンテナンスも難しくなります。場合によっては誰も手をつけることのできない残念なコードになりがちです。

もしもHTML.Template(JavaScript)があれば

先ほどの煩雑になったロジックの入った文字列操作をテンプレートを用いて記述すると次のように書くことができます。

var tmpl = new HTML.Template([
    '<div class="testBox">',
    '    <ol>',
    '    <TMPL_LOOP NAME=loop>',
    '    <TMPL_UNLESS NAME=__odd__>',
    '        <li><TMPL_VAR NAME=text></li>',
    '    </TMPL_UNLESS>',
    '    </TMPL_LOOP>',
    '    </ol>',
    '</div>'
].join(''));

tmpl.param({
    loop:[{text:'hoge'},{text:'fuga'},{text:'piyo'},{text:'moga'}]
});

$('bodyMainArea').update(tmpl);

また、テンプレートをコード中からHTMLコメントやXHRからの取得によって隠蔽することもできます。


// test.tmplとして保存
<div class="testBox">
    <ol>
    <TMPL_LOOP NAME=loop>
    <TMPL_UNLESS NAME=__odd__>
        <li><TMPL_VAR NAME=text></li>
    </TMPL_UNLESS>
    </TMPL_LOOP>
    </ol>
</div>
// テンプレートをXHRで取得
var tmpl = new HTML.Template('url:/test.tmpl');
  :
  :
tmpl.param({
    loop:[{text:'hoge'},{text:'fuga'},{text:'piyo'},{text:'moga'}]
});

$('bodyMainArea').update(tmpl);

あるいは、HTML中にコメントとして記述してネットワークリソースの節約や非同期性に伴う煩雑な処理を軽減して利用することもできます。

// html中に記述
<div class="HTML_TEMPLATE" id='test'><!--

<div class="testBox">
    <ol>
    <TMPL_LOOP NAME=loop>
    <TMPL_UNLESS NAME=__odd__>
        <li><TMPL_VAR NAME=text></li>
    </TMPL_UNLESS>
    </TMPL_LOOP>
    </ol>
</div>

--></div>
// テンプレートをHTMLコメントから取得
var tmpl = new HTML.Template('dom:test');

tmpl.param({
    loop:[{text:'hoge'},{text:'fuga'},{text:'piyo'},{text:'moga'}]
});

$('bodyMainArea').update(tmpl);

これは何をしてるの?

LLによるテンプレートエンジンといえば関数の生成と相場が決まっているのですが、HTML.Template(JavaScript)も多分にもれず関数の生成です。先ほどのテンプレートも内部では以下のような関数に変換されています。

function anonymous() {
    var $_R = [];
    var $_C = [this._param];
    var $_GF = HTML.Template.GLOBAL_FUNC;
    var $_T = this._param;
    var $_S = HTML.Template.Cache.STRING_FRAGMENT;
    var $_SELF = this;
    $_R.push($_S[43]);
    var $_L_40 = $A(($_T.loop ? $_T.loop: undefined)) || [];
    var $_LL_40 = $_L_40.length;
    $_C.push($_T);
    for (var i_40 = 0; i_40 < $_LL_40; i_40++) {
        $_T = (typeof $_L_40[i_40] == "object") ? $_L_40[i_40] : {};
        $_T.__first__ = (i_40 == 0) ? true: false;
        $_T.__counter__ = i_40 + 1;
        $_T.__odd__ = ((i_40 + 1) % 2) ? true: false;
        $_T.__last__ = (i_40 == $_LL_40 - 1) ? true: false;
        $_T.__inner__ = ($_T.__first__ || $_T.__last__) ? false: true;
        $_R.push($_S[44]);
        if (! ($_T.__odd__ ? $_T.__odd__: undefined)) {
            $_R.push($_S[45]);
            $_R.push(($_T.__counter__ ? $_T.__counter__: undefined));
            $_R.push($_S[46]);
        }
        $_R.push($_S[47]);
    }
    $_T = $_C.pop();
    $_R.push($_S[48]);
    return $_R.join("");
}

比較的可読性の高いコードジェネレートになっているかと思いますが、それでもやはり手で書く気のうせるイイ感じのコードに仕上がっています。

これらのコードはCopy and Pasteで再利用可能な形として出力可能ですので、関数生成のコストが気になる方はプロダクションコードとしてはダンプ結果を利用することもできます。ただ、オススメはしません。”evalは遅い、evilだ”と教え込まれた方にとっては受け入れがたいかもしれませんが、ほとんどのWebアプリケーションにとってブラウザのアイドル時間は膨大に存在しており、適切なタイミングでコンパイルされれば、UXに影響を与えることはないからです。

C/S同一のシンプルなテンプレートエンジンを使うということ

なぜ、フロントエンドのテンプレートとサーバサイドのテンプレートを同一にする必要があるんだ?という疑問もあるかと思います。たとえば、EJS(embeded javascript)のようなJavaScriptプログラマにとって分かりやすく、何でもできるテンプレートのほうが便利じゃないか、と。

確かに一面的にはそのとおりで、小規模開発や単発案件であればこういったモジュールのほうが便利だという局面もあるでしょう。たとえばPHP/erubyなどはそういった局面で非常に優れた言語です。

これらの回答としては、「HTMLコーディングのメンテナンス性」と「ViewとLogicの分離」という2点に尽きます。

次のようなケースを考えて見ましょう。
同一のテンプレート構成をPHPとEJSで記述しているケースです。

<!-- PHP -->
<div class="testBox">
    <ol>
    <?php
    $a = array("hoge","fuga","more","piyo");
    for($i=0; $i<count($a); $i++){
        if(($i%2) == 0){?>
	    <li><?= $a[$i] ?></li>
        <?}
    }
    ?>
    </ol>
</div>
<!-- EJS -->
<div class="testBox">
    <ol>
    <% var a = ["hoge","fuga","more","piyo"];
     for(var i=0; i<a.length; i++){
     if((i%2) == 0){ %>
         <li>
         <%= a[i] %>
         </li>
    <% }
    }%>
    </ol>
</div>

これらは、HTML中のUIパーツとしてユーザからは同じものとして見えています。どちらも同一のロジックで記述されています。このような状況下でデザイン変更が入ったとします。HTMLコーダは、PHP版のテンプレートとJS版のテンプレートを書き換えなければなりません。また、どちらもロジック部分の記述が生の言語環境を利用しているため、双方の言語についての基本的な知識が無ければ、うかつに変更することができません。

HTML.Template(JavaScript)とHTML::Templateを利用している環境であれば、単一のファイルの修正のみで対応できます。

同じく、JavaScriptの関数生成をして、PerlとJavaScript/ClientとServerで同一のテンプレートを利用可能にしているモジュールにJemplateがあります。TT(Tokyo TyrantじゃなくてTemplate Toolkit)のシンタクスで記述できます。Perl実装で、コマンドラインによるjsファイル生成を基本機能として提供していますが、そのままではメンテナンスには向いていないので、フレームワーク取り込みなど何らかの形で透過的に取り扱えるようにすれば非常に快適なテンプレートライフをエンジョイできます。

HTML.Template(JavaScript)は、Jemplateから一部設計思想をインスパイヤしつつ、Pure JavaScriptによる実装で、EJSのような取り扱いの容易さも実現しています。

まとめ

HTML::Templateのシンタックスを備えたテンプレートエンジンをJavaScriptで実装しました。個人ないし少人数でプロダクトを作っているとなかなか気づかないことですが、大規模なシステムを開発していくということはさまざまな分業で成り立っていて、学習コストが低く、適切なTemplateモジュールを採用することで、ますます複雑化するWebアプリケーション開発をスマートに記述できるようになったりします。

次回はもう一歩踏み込んで、JavaScriptテンプレートエンジンの開発と設計についてのちょっとしたノウハウをお話できたらと思います。

まだまだ、つたない実装ですがツッコミいれながら読んでいただければ幸いです。そんなわけで、この次も、ワッフルワッフル!

NTTと三菱電機が共同開発した共通鍵ブロック暗号 “Camellia” の実装について以前調査していた時、ついカッとなってJavaScriptで実装してしまいました。類似の実装も既にあるようですし今は反省しているのですが、死蔵しておくのもナンなので晒しておきます。

ソースコードと使い方

小ネタなので、このソースコードはpublic domainということにしますね。

Public domain CryptoCipherCamellia-js-1.0.2

CryptoCipherCamellia.jsは128-bitブロック暗号Camelliaのプリミティブの実装と、暗号利用モードとしてCBCモードの実装を含んでいます。例を簡単に示すと次のような感じです:

var SECRET_KEY = CryptoUtil.arrayFromHex(
    "00112233445566778899AABBCCDDEEFF");
var INITIAL_VECTOR = CryptoUtil.arrayFromHex(
    "000102030405060708090A0B0C0D0E0F");
var PLAIN_TEXT = CryptoUtil.arrayFromString("Hello World!"); 

var engine = new CryptoCipherCamellia();
/* 暗号化 */
var cbc = new CryptoModeCBC(engine, SECRET_KEY, INITIAL_VECTOR);
var cipherText = cbc.encrypt(PLAIN_TEXT);
alert("Cipher Text(HEX): " + CryptoUtil.hexFromArray(cipherText)); 

/* 復号 */
cbc = new CryptoModeCBC(engine, SECRET_KEY, INITIAL_VECTOR);
var plainText = cbc.decrypt(cipherText);
alert("Plain Text: " + CryptoUtil.stringFromArray(plainText));

パッケージにはデモと単体テストとして

を含んでいます。

ちなみに。(すごくおおざっぱな説明になりますが)Feistel構造をもつ暗号アルゴリズムであるCamelliaは、入力された128ビットのデータを前後半分64ビットずつに2分割して、

  1. 副鍵と置換表で片側のデータブロックを撹拌する
  2. 撹拌結果をもう片側のデータブロックとXORする

といった処理を64ビットのデータブロックを交互に入れ替えながらくり返して暗号化しています。これらの処理を一般的な計算機で実行する場合、普通はCPUに都合のよい32ビットや64ビット幅の整数を使って撹拌処理を実装します。しかしながらCryptoCipherCamellia.jsは、これまた私の気の迷いでわざわざ8ビット幅の整数で実装しています。さらに僕自身JavaScriptは遊びかそれ以前のレベルでしか書いていないので、作法やチューニングしどころがよくわかっていません故、モノスゴク遅いのでそこんとこよろしくです。

CamelliaそのものについてはNTT 情報流通プラットフォーム研究所のCamellia紹介仕様書 (PDF)などを参照してください。

カッとなったついでにPerl版

これまたついカッとなって書いてしまったのですが、同様にPerlだけで書いたCamelliaの実装 Crypt::Camellia_PPもこっそりCPANに上げていたりしますので、ネタとして遊んでみて頂けると幸いです。
Perl向けCamelliaの他の実装としては、XSで記述したCrypt::Camelliaがあります。こちらは当初Dan Kogaiさん書かれたモジュールですが、一年ほど前に小山がメンテナンスを引き継ぎました。実行速度はPure Perl版と比べて段違いに速いので、PerlでCamelliaを使いたい用件では普通にこちらを選んで頂けると幸いです。

はじめまして、mixi開発部Find Job !開発グループの fukumura です。

 米Googleが7月11日にマップレットを正式版としてリリースしました。ということで『Find Job !版マップレット』を作成しました!就職活動やライバル会社調査?にとても便利です!

マップレットをご存知ない方のために簡単な説明をしますとマップレットとはGoogleマップに組み込むアプリケーションのことで、これらアプリケーションを好みで追加してもらうことによりオリジナルのマップを作り上げていくことができるというもので、面白い&有用なので是非皆さん試してみて下さい。

 登録&利用方法は下記の通りです。(※利用するにはGoogleアカウントが必要です)

まず、GoogleMapの画面のマイマップを選択し、コンテンツの追加をクリックします。

次の画面で、『URLを指定して追加』で

『 http://www.find-job.net/xml/google_mapplet.xml 』を指定して追加します。

あとは、『Googleマップに戻る』で地図に戻り『他人が作成した地図』の『Find Job !求人情報(β)』をクリックして利用できます。地図を動かしたり左に出力された企業一覧の赤枠をクリックしたりして動かして見てください。

 作成してみての感想ですが、GoogleマップレットはGoogleマップ・Googleガジェットを作成したことのある方なら簡単に実装できると思います。(もちろん、してなくても簡単にいける人は沢山いると思います。)

Google Mapplet 開発ツールとして

・Mapplet Scratch Pad  『 http://www.google.com/ig/modules/geoscratchpad.xml 』

 URLを指定すればテキストエリアにソースが丸ごと呼ばれてそれを変えて再読み込みできるツールです。

・Developer Mapplet 『 http://www.google.com/ig/modules/geodeveloper.xml 』

 登録したxmlを再読み込みできます。修正後などに便利です。

・API Reference 『 http://www.google.com/ig/modules/mapplets-api-reference.xml 』

Googleマップレット上で実際に動かせるAPI集です。

上記の開発ツール用のアプリケーションも公開されています。大変便利なので、Find Job !マップレットを登録したのと同様に登録してアプリケーション作成をされてみてはいかがでしょうか?

 当グループでは、『Find Job ! Maps(β)』 (Google Maps API利用)や最近ではWikipediaを利用した『Find Job !キーワード(β)』なども開発しています。どうぞ皆さんご利用ください。