tag:blogger.com,1999:blog-68681758098926234102024-03-14T04:05:36.987+09:00kumatch's blogspotUnknownnoreply@blogger.comBlogger114125tag:blogger.com,1999:blog-6868175809892623410.post-182213562868282192013-12-08T23:16:00.002+09:002013-12-09T09:46:18.841+09:00browserify を使い始めるためのファーストステップ 2013 冬<a href="https://github.com/substack/node-browserify">browserify</a> は、ブラウザ JavaScript のためのコードを、Node スタイルのコード(Node 向けの JavaScript コードを書いているかのような形)で記述しておいて、ブラウザ上で利用できるような Javascript コードとして出力してくれるツール。<br />
require() で利用しているモジュール群をすべてアナライズして、それらモジュールコードまですべて都合よい形で同梱してくれる。<br />
<br />
リリース当初(3年くらい前)は Node で HTTP サーバを建ててブラウザ用 Javascript コードを返すような仕掛けから始まったはずで、そこから静的ファイルを出力する仕組みが追加されて、現在ではむしろ後者の方がメイン扱いになっている感じになっている。<br />
そうなった背景として、<a href="http://gruntjs.com/">Grunt</a> の登場でその辺りの機能が有効的に参照利用できるようになったり、実際に Grunt を使ってのビルド環境がカジュアルに行われるような土壌が出来上がったからというのが大きいのかもしれない。<br />
<br />
今から browserify の利用を始めるべく browserify 側の情報をみても、低レベルなところが中心で戸惑ってしまい躊躇してしまうかもしれない。どんなものかを知るために動かすならば、簡単に利用できる Grunt 経由側のものを知ってしまったほうがよいと思う。<br />
ということで、簡単なサンプルを紹介。<br />
<br />
今回利用するファイルとツリーの状態は以下の通り。<br />
<br />
<script src="https://gist.github.com/kumatch/7857227.js?file=tree"></script><br />
<br />
------------<br />
<br />
まずは環境作りのための package.json。<br />
モジュールは grunt と、grunt で browserify するための grunt-browserify。<br />
あとはサンプル用スクリプトで使うモジュール例として async.js を指定している。<br />
<br />
<script src="https://gist.github.com/kumatch/7857227.js?file=package.json"></script><br />
<br />
記述後、npm install を実行する。<br />
<br />
続いて、ブラウザ上で動作させるための JavaScript コードを Node スタイルで記述。<br />
以下のサンプルでは、core モジュールと npm で入れたモジュールを require() で利用しつつ、エントリポイントとなるスクリプトから自前のファイルを require() して読み込んでいる。<br />
<br />
<script src="https://gist.github.com/kumatch/7857227.js?file=main.js"></script><br />
<script src="https://gist.github.com/kumatch/7857227.js?file=foo.js"></script><br />
<script src="https://gist.github.com/kumatch/7857227.js?file=baz.js"></script><br />
<div>
<br /></div>
browserify を実行する Gruntfile.js を用意。<br />
<br />
<script src="https://gist.github.com/kumatch/7857227.js?file=Gruntfile.js"></script><br />
<br />
grunt を実行すると、build.js が出力される。<br />
中身を覗いてみると、browserify が頑張って構築してくれたブラウザ用 JavaScript コードとして、先ほど自分で記述したコードやアナライズした結果同梱する必要ありと判断された util.fomat や async.js などが含まれている。<br />
<br />
適当な HTML ファイルを用意して、この build.js を script タグで読み込むようにする。<br />
<br />
<script src="https://gist.github.com/kumatch/7857227.js?file=index.html"></script><br />
<br />
<a href="http://hatotech.org/samples/20131208_browserify/">実行デモ</a><br />
<br />
<br />
先ほど <a href="http://substack.net/browserify_v3_0_changelog">browserify v3 がリリースされた</a>ばかりで、記念的な感じで。<br />
<br />
上記例は v2 系を動かした結果 (grunt-browserify がまだ v2 を使うため) なものの、恐らくただ単純に使う分には v3 以降も違いなくいけるんじゃないかと(個人的な期待)。<br />
<br />Unknownnoreply@blogger.comtag:blogger.com,1999:blog-6868175809892623410.post-16578200046392287872013-02-19T20:04:00.003+09:002013-02-19T20:04:48.477+09:00MongoDB イン・アクションを頂きました<br />
2012年末、勉強会後の懇親会で玉川竜司さん (<a href="https://twitter.com/tamagawa_ryuji">@tamagawa_ryuji</a>) と初めてお会い/お話することがあり、その際に話の流れで<br />
<br />
「NodeでのストレージにはMongoDBを使う事が多くて触ってるんですけども、小規模なら簡単でも、中大規模になると途端に難しくて…」<br />
<br />
みたいなことを言っていたら、<br />
<br />
「今度 MongoDB の翻訳本が出るから、これもなにかの縁だし送ってあげるよ」<br />
<br />
と言われ、そんなこと初めてだし、わーそうなったらいいなあなどと思っていたら、本当に郵送で送っていただきました。やたー!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-aYBClxEUHWc/USNZ-Ppec5I/AAAAAAAAAXs/OpIXktZXVSo/s1600/A-9W0RBCQAEi74b.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-aYBClxEUHWc/USNZ-Ppec5I/AAAAAAAAAXs/OpIXktZXVSo/s1600/A-9W0RBCQAEi74b.jpg" height="320" width="240" /></a></div>
<br />
<br />
……などと、年末の話だったにも関わらず、年明け早々いろんなことがあったせいで今頃のエントリで大変申し訳ございません…。<br />
<br />
<br />
<br />
<br />
ということで、MongoDB イン・アクション (<a href="http://www.oreilly.co.jp/books/9784873115900/">http://www.oreilly.co.jp/books/9784873115900/</a>) の紹介です。<br />
海外ではいくつか出ている MongoDB の書籍ですが日本では単独でのものがなく、これまで MongoDB の日本語情報といえば利用者によるブログ、勉強会、および公式ドキュメントでの翻訳を頼りに進めてきていた感じでした。(でもそれらが比較的充実していたり、はまりやすいポイントをいち早く紹介されていたりと、比較的恵まれた環境だったと思う)<br />
<br />
MongoDB イン・アクションでは、MongoDB の基本的なお話、特徴、および利用法について1から紹介していきます。<br />
中身は大きく3つの部に分かれていて、「1. はじめての方のための MongoDB」「2. ショッピングサイトシステムを実例にした利用方法の紹介」「3. 本格運用する際に抑えておくべき要素」となっています。<br />
<br />
1, 2 では所々 RDB と比較して「RDB ならばこうだっただろう、MongoDB ではこうするんだ」といった具合に解説が入るので、既に RDB を利用している人であれば、MongoDB におけるアプローチ方法や差異などを把握しながら読んでいく感じになります。リレーショナルなデータであったものについて、RDB で正規化していた事に対して MongoDB での対非正規化であったりそれに伴う設計の流儀などが、2 のショッピングサイトシステムを例として紹介されるので、2 までを読み終えた時点で、簡単な CRUD アプリケーションならば作れてしまう程度に知識はついているんじゃないでしょうか。<br />
<br />
3 では、データベースを扱っている人ならば気になるであろう、クエリ最適化(インデックスの話)、レプリカ、シャーディング、バックアップとリストアなどを扱っています。<br />
冒頭に書いているとおり、MongoDB は簡単なデータ構造で規模も小さいアプリケーションならば本当にシンプルに扱えるものの、取り扱うデータが大きくなったり構造が複雑になったりすると知っておかなければならない話が色々あったりします。特にクエリ最適化とシャーディングあたりが重要(そしてはまりやすい)だと思うんですが、きちんとそのあたりが構築例、動作例含めて紹介されているのが良い感じです。<br />
<br />
<br />
<br />
全体的にテンポ良く読み進めていける本です。目的に対するクエリ例を逐一紹介してくれるのが嬉しい。<br />
ちょっとだけ気になった点としては「突然紹介され始める○○」みたいなのが何回かあったような。でも変な感じではないので大丈夫。<br />
<br />
完全に知識がつくまで、これを見ながらシステム構築する感じなりそう。<br />
<div>
<br /></div>
<br />
<br />
以上、MongoDB イン・アクションの紹介でした。<br />
玉川さん、およびオライリージャパンさん本当にありがとうございました。<br />
<br />
Unknownnoreply@blogger.comtag:blogger.com,1999:blog-6868175809892623410.post-17145072603228400332013-02-06T19:36:00.002+09:002013-02-06T19:38:21.985+09:00新しい Windows PC を組んで Win8 環境にした ー 2013春<br />
最近パソコンの普段使いは完全に Mac に移っているものの、Windows マシンはゲームのために一応持ち続けている。<br />
<br />
もうずいぶんと昔に買ったマシンパーツから入れ替えしながらやってはきていたけど、それも 2009年1月 (Warhammer Online のためにビデオとCPUを変えた) を最後に進化は止まっていて、壊れた電源だけは変えたものの、性能的にはもうずいぶんと置いてけぼり状態だった。OS も未だ Windows XP だった。<br />
<br />
で、シムシティの新作がこの春に出ることと、近頃の為替に比例してパーツの値段がモリモリ上がっていっているのを眺めていてもう我慢ならん!ということで久々に一機買いしてみた。<br />
<div>
<ul>
<li>CPU: Intel Core i7 3770</li>
<li>Cooler: ENERMAX ETS-T40-TB</li>
<li>RAM: 8GB x 2</li>
<li>Mother: ASUS P8H77-V</li>
<li>GPU: 玄人志向 GF-GTX660-E2GHD/DF/OC</li>
<li>Storage: Intel SSD 335series 240GB</li>
<li>Case: Corsair Obsidian 550D</li>
</ul>
<div>
<br /></div>
<div>
しめて 89,796 円。電源だけ流用。</div>
<div>
DVDドライブは、必要なときにUSB接続 (IDE/SATA変換) すればよいと思って買ってない、というか最近はマザーに IDE 端子ついてないんだね。おじさんびっくり状態。</div>
</div>
<div>
そのくせにデカいケース買ってどうすんの状態だけども、ケースはメンテナンスしやすいに越したことはない。最近の良いケースは本当によく出来ている。これまでの苦労が嘘のようだ。</div>
<div>
</div>
<div>
<br /></div>
<div>
OS は Windows 8。さすがにこの時期から 7 はないだろうということで。(8 が良いものかどうかは置いといて)</div>
<div>
<br /></div>
<div>
以下、 Windows 8 導入後に行ったときの作業メモの写しを紹介。</div>
<div>
前述のとおり、メインは Mac で Windows はゲーム用途ということなので、実はそこまでやる事はない。</div>
<div>
<br /></div>
<div>
<div class="p1">
<br /></div>
<div class="p1">
<b><u>キーカスタマイズ</u></b></div>
<div class="p2">
<br /></div>
<div class="p1">
利用している Real force にあわせて、レジストリを操作することで低レベルでキーポジションを変更する。</div>
<div class="p2">
<br /></div>
<div class="p1">
参考:</div>
<div class="p1">
<a href="http://exlight.net/devel/windows/keyboard.html">http://exlight.net/devel/windows/keyboard.html</a></div>
<div class="p1">
<a href="http://www.jaist.ac.jp/~fujieda/scancode.html">http://www.jaist.ac.jp/~fujieda/scancode.html</a></div>
<div class="p2">
<br /></div>
<div class="p1">
HKEY_LOCAL_MACHINE/System/CurrentControlSet/Control/Keyboard Layout</div>
<div class="p1">
という領域に、新たに Scancode Map というバイナリ値を新規作成。</div>
<div class="p2">
<br /></div>
<div class="p1">
以下、バイナリ値として次のように設定した。</div>
<div class="p1">
今回は Ctrl を A の左に、および ESC と半角/全角を入れ替えるというシンプルな変更に留めている。</div>
<div class="p2">
<br /></div>
<div class="p1">
0000 0000 # ヘッダ</div>
<div class="p1">
0000 0000 # ヘッダ</div>
<div class="p1">
0400 0000 # 以下に続くエントリー数を定義。終端のNULLのぶんも含める</div>
<div class="p1">
1D00 3A00 # 1. CapsLock を Ctrl に</div>
<div class="p1">
0100 2900 # 2. 半角/全角 を ESC に</div>
<div class="p1">
2900 0100 # 3. ESC を 半角/全角 に</div>
<div class="p1">
0000 0000 # 4. NULLによるターミネータ</div>
<div class="p2">
<br /></div>
<div class="p2">
<br /></div>
<div class="p1">
<u><b>ショートカットキー</b></u></div>
<div class="p2">
<br /></div>
<div class="p1">
Emacs のショートカットが欲しいので xkeymacs をいれた。</div>
<div class="p2">
<br /></div>
<div class="p1">
<a href="http://xkeymacs.sourceforge.jp/">http://xkeymacs.sourceforge.jp/</a></div>
<div class="p2">
<br /></div>
<div class="p3">
<span class="s1">近年ついに</span><span class="s2">64bit版の対応がなされた ( <a href="http://d.hatena.ne.jp/kfujieda/20110428/1303924737"><span class="s3">http://d.hatena.ne.jp/kfujieda/20110428/1303924737</span></a></span><span class="s1"> </span><span class="s2">) とのことで、本当に有り難いお話。</span></div>
<div class="p4">
<br /></div>
<div class="p5">
XP の頃は窓使いの憂鬱を利用してキー入れ替えやショートカット変更をしていたが、設定ファイルをゴリゴリ書くほどのカスタマイズはもうしないだろう(テキストを書くような作業を Windows に求めていない)ので、のどか ( <a href="http://www.appletkan.com/nodoka.htm">http://www.appletkan.com/nodoka.htm</a> ) や yamy ( <a href="http://sourceforge.jp/projects/yamy/">http://sourceforge.jp/projects/yamy/</a> ) の採用は見送った。ブラウザのアドレスバーで C-a や C-h が効いてくれればそれでよい。</div>
<div class="p2">
<br /></div>
<div class="p2">
<br /></div>
<div class="p1">
<b><u>Dropbox</u></b></div>
<div class="p2">
<br /></div>
<div class="p1">
Dropbox のサイトからプログラムをダウンロードしてセットアップ、既存アカウントを設定。気づいたら同期完了していたので出来るやつだ。</div>
<div class="p2">
<br /></div>
<div class="p2">
<br /></div>
<div class="p1">
<b><u>Skype</u></b></div>
<div class="p2">
<br /></div>
<div class="p1">
for Windows8 を Windows Store から落とせと言われたが、レビューを見る限り使い勝手が悪いことばかり書いている。</div>
<div class="p1">
なによりストア利用のためのアカウントを(多分持っているけど)用意するのが面倒だったので、別プログラムとして Skype サイト上で用意されていた Windows Desktop 版というものを入れた。いつもの Skype だった。</div>
<div class="p2">
<br /></div>
<div class="p2">
<br /></div>
<div class="p1">
<b><u>Steam</u></b></div>
<div class="p2">
<br /></div>
<div class="p1">
Steam のサイトからプログラムを落としてセットアップ。新しいマシンでの初ログインではメールによる確認キーを求められる。一手間かかるけども安心できる。</div>
<div class="p1">
早速 Civ5 をいれて DirectX 11 版で起動、その速度をみて満足する。(ちゃんと遊んで、八方美人具合に度が過ぎたのかお隣の大国から喧嘩売られて散る)</div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
<b><u>Diablo3</u></b></div>
<div class="p1">
<br /></div>
<div class="p1">
いれてない。</div>
<div class="p2">
<br /></div>
</div>
Unknownnoreply@blogger.comtag:blogger.com,1999:blog-6868175809892623410.post-36585098891343382402012-10-19T09:00:00.001+09:002012-10-19T09:08:50.533+09:00依存するモジュールも解決できる Node/AMD (サーバ/クライアント) 共通化モジュールを書く<br />
<br />
このエントリは、 <a href="http://atnd.org/events/33022">東京Node学園祭 2012 アドベントカレンダー</a> 5日目の記事です。<br />
<br />
<br />
<h3>
■ 前置き - AMD とは</h3>
<br />
AMD (Asynchronous Module Definition) は、Javascript のコードをモジュールとして定義して、非同期ないし遅延ロードするための仕組みです。<br />
<br />
<a href="http://wiki.commonjs.org/wiki/Modules/AsynchronousDefinition">http://wiki.commonjs.org/wiki/Modules/AsynchronousDefinition</a> (現在、接続が遅い模様)<br />
<br />
CommonJS により提唱されたものですが、昨年あたりからクライアントサイド (ブラウザ) で JavaScript モジュールを構築する仕組みとして各所で一気に取り上げられ、現在ではクライアントサイドの主要なライブラリでもサポートされてきている(AMD によるモジュールとして利用できる)状態にあります。<br />
<br />
モジュールに依存性を指定する仕組みも用意されています。遅延ロードされますので、依存モジュールの読み込みが完了次第、目的の(依存元の)モジュールの定義処理が実行されます。<br />
比較的カオスになりがちなクライアントサイド Javascript が、このモジュール化によりすっきりしたものになります。<br />
<br />
また処理は非同期で行われるため、ブラウザ上での読み込みの速度向上が見込まれます。実際に、Twitter の Web ページの高速化にも一役買ったとの話があります。<br />
<br />
Twitter Engineering Blog: <a href="http://engineering.twitter.com/2012/05/improving-performance-on-twittercom.html">http://engineering.twitter.com/2012/05/improving-performance-on-twittercom.html</a><br />
Publickey による日本語紹介: <a href="http://www.publickey1.jp/blog/12/twitter51.html">http://www.publickey1.jp/blog/12/twitter51.html</a><br />
<br />
クライアントサイドで AMD を利用するには、AMD 機能を提供してくれるライブラリを用います。たとえば、 RequireJS があります。<br />
<br />
<a href="http://requirejs.org/">http://requirejs.org/</a><br />
<br />
<br />
<br />
<h3>
■ サーバサイド/クライアントサイド Javascript のモジュール共通化</h3>
<br />
もし仮に Web アプリケーションのサーバ実装を Node.js で行っていて、かつある処理をサーバ/クライアントのどちらでも行いたいとするならば、その処理を行うコードを改変することなくサーバ/クライアントどちらでも実行できればという考えが出てきます。<br />
<br />
そこで、その処理のコードを Node モジュールかつ AMD モジュールとして実装しておき、環境にあわせて適切にモジュールとして読み込まれるようにします。<br />
<br />
<br />
今回は例として、「その年の 1/1 から今日までの日数の回数 hello world を出力する」というつまらない機能を、Node/AMD 共通モジュールとして作ります。<br />
<br />
この問題に対して、Lo-Dash (<a href="http://lodash.com/">http://lodash.com/</a>) と Moment.js (<a href="http://momentjs.com/">http://momentjs.com/</a>) の2種類のライブラリを使おうと考えました。<br />
Lo-Dash, moment ともに Node モジュールとして npm で導入できると共に、AMD モジュールとしても利用できるもので提供されています。<br />
<br />
実際に実装したコードが次のものです。<br />
<br />
<pre><code>(function(define) {
define('hellodays', ['lodash', 'moment'], function (_, moment) {
function hellodays() {
var days = Number( moment().utc().format('DDD') );
_.times(days, function (d) {
console.log('Hello, world ! (' + (d + 1) + ' days)');
});
}
return hellodays;
});
})(
// 1: AMD
typeof define === 'function' ? define :
// 2: Node
typeof module !== 'undefined' ? function(id, deps, factory) {
module.exports = factory.apply(this, deps.map(require));
} :
// 3: Plain (window object)
function(id, deps, factory) {
var dependencies = [ this._, this.moment ];
this[id] = factory.apply(this, dependencies);
});
</code></pre>
<br />
<br />
2行目で実行している define は、AMD API の仕様に基づき Javascript モジュールを定義するための関数です。引数として AMD 内モジュール名 (以後、id と呼びます)、依存モジュールのリスト (以後、deps と呼びます)、およびモジュールの構築を行う関数 (以後、factory と呼びます) を指定します。<br />
モジュール構築関数 factory 内でオブジェクトあるいは関数を返すと、それがモジュールとして利用できるようになります。ここでは、実際に 1/1 から現在日までの日数を算出し、その回数分 hello, world を出力する処理を記述しています。<br />
<br />
実際に Node/AMD モジュールのためのコントロールを行っているのは、1行目から定義している即時関数の引数として与えている、13 行目からのコードです。若干分かりやすくなるよう、コメントを明記しています。<br />
<br />
もしグローバル空間に define 関数が定義されているのであれば、AMD によるモジュール機構を備えているため、そのまま define を即時関数に与えて実行させるようにします。これで、AMD モジュールとして hellodays が利用できるようになります。<br />
<br />
AMD define 関数はないものの、module が定義されているのであれば Node のモジュール機構と見なし、define のような振る舞いをする関数を与えます。<br />
define への引数はモジュール名 id、依存するモジュール名のリスト deps と、モジュール構築のための関数 factory が与えられるわけなので、Node の require を使って deps で指定されている依存モジュールを読み込み、得られたインスタンスを factory の引数として与えます。factory を実行すると構築された関数が返されるので、それを module.exports にセットします。これで、Node でこの hellodays モジュールを require すると、factory で作られた関数が得られます。<br />
<br />
最後は、AMD でも Node でもないパターンです。これまでのブラウザ用 Javascript ライブラリであれば、window オブジェクトへ割り当てるくらいはしていることと思います。lodash, moment もそれぞれ _, moment という名称で参照可能になっていることでしょうから、それらを factory の引数に与えてモジュール構築を行います。名称として id が define の引数で渡ってくるので、その値で window オブジェクトの要素の1つとして定義しています。<br />
<br />
<br />
以上、AMD > Node > plain という優先度でモジュール定義を行うことができるようになりました。<br />
状況にあわせて依存モジュールの実体であるインスタンスが適切に factory に渡っている、factory の結果が利用されている、あたりがポイントになります。<br />
<br />
<br />
<br />
<br />
<h3>
■ 共通モジュールを利用する</h3>
<br />
サーバサイドである Node ならば次のように利用します。<br />
普通の Node モジュールの利用となんら違いはありません。(require で読み込めるようモジュールパスが解決されている場合)<br />
<pre><code>var hellodays = require('hellodays');
hellodays();
</code></pre>
<br />
一方クライアントサイドの場合は、AMD が利用できるよう RequireJS を使います。<br />
上記で作成したモジュールが読み込まれ、hellodays 変数として参照可能になってやってきます。<br />
<pre><code><script src="./scripts/require.js"></script>
<script>
requirejs.config({
paths: {
"lodash": "./scripts/lodash.min",
"moment": "./scripts/moment.min",
"hellodays": "./scripts/hellodays"
}
});
requirejs(['hellodays'], function (hellodays) {
hellodays();
});
</script>
</code></pre>
<br />
Jam (<a href="http://jamjs.org/">http://jamjs.org/</a>) などのクライアントサイドパッケージマネージャを使うと、依存先となるモジュールの導入や、AMD (RequireJS) で読み込むパスの管理などを一手に引き受けてくれるので、もう少し楽に利用できるようになります。<br />
<pre><code>$ jam install lodash
$ jam install moment
</code></pre>
<pre><code><script src="./jam/require.js"></script>
<script>
requirejs.config({
paths: {
"hellodays": "./scripts/hellodays"
}
});
requirejs(['hellodays'], function (hellodays) {
hellodays();
});
</script>
</code></pre>
<br />
最後に、クライアントサイドで AMD を利用しない場合です。必要なファイルをすべて読み込んだ後、直接 hellodays 変数の関数を実行します。利用の機会はほとんどないと思いますが、利用すること自体は問題はありません。<br />
<pre><code><script src="./scripts/lodash.min.js"></script>
<script src="./scripts/moment.min.js"></script>
<script src="./scripts/hellodays.js"></script>
<script>
hellodays();
</script>
</code></pre>
<br />
<br />
<br />
<h3>
■ 共通モジュールとして用意する対象について</h3>
<br />
今回依存モジュールとして利用した Lo-Dash や Moment.js のような、サーバ/クライアント関係なく汎用的に利用できるライブラリなどは、共通するモジュールとして利用できると大きな価値がありそうです。他にもフローコントロールやイベント管理などは同じように共通モジュール化の価値があると考えられます。<br />
<br />
一方、自前で提供するサービスのためのコードではと考えると、データの正規化 / 妥当性確認 (Filter / Validator) ルールの共通モジュール化に一定の価値がありそうです。<br />
例えばユーザ情報の更新処理において、あるルールに基づいた妥当性確認をサーバサイドだけでなくクライアントサイドでも行って確認結果をいち早く掲示したい、といった要件がある場合。これまでなら同一ルールながらも異なるコードで実装したり、妥当性確認処理を非同期で逐一サーバと通信して行ったりしていたところです。<br />
共通モジュール化されているならば、妥当性確認処理をクライアントで行い、サーバへ POST されてきた情報も同じモジュールで再度確認する、といったことができます。<br />
<br />
<br />
<br />
<br />
<h3>
■ 備考. テストについて</h3>
<br />
共通モジュールとして実装されたコードのテストをどうするか?<br />
<br />
現在の私の場合はですが、まずは使い慣れた環境による、提供されうる機能のテストを書きます。<br />
すなわち、Node モジュールとして提供されて、Node 上でなんら問題なく利用できるである確信のためのテストを用意します。<br />
その上で、AMD モジュールとして読み込んで利用可能な状態になるかのテストを用意しています。<br />
<br />
Node モジュールの amdefine (<a href="https://github.com/jrburke/amdefine">https://github.com/jrburke/amdefine</a>) を使うことで、Node 上で define を使ったコードが一時的に利用可能になります。<br />
これを用いてモジュールをロードし、読み込んだモジュールが不自由なく(そこまでの機能テストは省略しつつ。機能の妥当性は前述のテストコードで満たされているはずなので。)利用できれば、良しとしています。<br />
<br />
<br />
<br />
<br />
<h3>
■ 備考2. Node の RequireJS モジュールと AMD 採用の是非</h3>
<br />
実は Node 上でも RequireJS モジュールが用意され、利用することができます。<br />
<br />
<a href="http://requirejs.org/docs/node.html">http://requirejs.org/docs/node.html</a><br />
<br />
非同期にモジュールを読み込む AMD のための RequireJS ですが、Node の場合は立ち上がったサーバインスタンスが基本的に永続した上でモジュールインスタンスの永続化がコードの書き方次第で容易だったり、Node 本体の require 時におけるインスタンスの再利用性が悪くなかったりといった理由から、その Node モジュールが RequireJS に依存する、というのは必要ないのではないかと個人的には思っています。<br />
<br />
<br />Unknownnoreply@blogger.comtag:blogger.com,1999:blog-6868175809892623410.post-57367218149798217302012-10-13T17:46:00.002+09:002012-10-13T17:46:43.817+09:00ランダム文字列生成 gachar<br />
<a href="https://github.com/kumatch/gachar">https://github.com/kumatch/gachar</a><br />
<br />
ただのランダム文字列生成です。<br />
最近の個人的なブームに沿って、一応フロントエンドでも使えるようにしときました。使うかどうかは別にして。<br />
<br />
<pre><code>var gachar = require('gachar');
var string1 = gachar.run(128);
gacha.run(256, function (string2) {
....
});
</code></pre>
<br />
<br />
実は最初 crypt なにがし系を使って適当な文字列を作る処理で書いてたんですが、C モジュールを持ってしてもただの Math.random() に速度で勝てなかったという。やっぱ暗号化処理って重いんですねー(当たり前)。<br />
<br />
ランダム性能的にはそこまで良くなさそうですが、使い捨てなトークン値などではこれで十分かなと思ってます。<br />
あと、名前は結構気に入ってます。<br />
<div>
<br /></div>
Unknownnoreply@blogger.comtag:blogger.com,1999:blog-6868175809892623410.post-41039019890742878712012-10-03T22:18:00.000+09:002012-10-03T22:21:11.397+09:00runie.js<a href="https://github.com/kumatch/runie">https://github.com/kumatch/runie</a><br />
<br />
Node で用意された任意変数を、フロント javascript で参照、利用するためのライブラリです。<br />
変数を一旦 DOM 要素として埋め込んで(描写して)、フロントスクリプトで改めて読み込みます。<br />
<div>
<br /></div>
<div>
<div>
Jade template</div>
</div>
<pre><code>div
p= title
!{ runie.tag('items', items) }
</code></pre>
<div>
<br /></div>
<div>
<div>
Front javascript</div>
</div>
<pre><code class="js">runie.read('items', function (items) {
if (items.length) {
....
}
});</code></pre>
<div>
<br /></div>
<div>
これ以前はフロントスクリプト上から ajax で JSON を受け取って読み込んでいたりしてたので遅かったんですが、これを使うようになってから処理が圧倒的に早くなりました(当たり前)。</div>
Unknownnoreply@blogger.comtag:blogger.com,1999:blog-6868175809892623410.post-25572929805428682472012-09-19T01:08:00.000+09:002012-09-19T01:23:49.823+09:00フロントエンドパッケージマネージャ bower のメモ<br />
Twitter が先日リリースした、Javascript や CSSなどのフロントエンド向けパッケージマネージャ Bower (<a href="http://twitter.github.com/bower/">http://twitter.github.com/bower/</a>) についての簡単な下調べを行ったときのメモ。<br />
<div>
<br /></div>
<div>
<br /></div>
<div>
<h3>
■ Git リポジトリを指定しての導入</h3>
<div>
<br /></div>
<div>
bower install コマンドで指定できるのは名前だけじゃなくて、git リポジトリの URL を指定することができる。</div>
<div>
<br /></div>
<div>
$ bower install git://github.com/kumatch/asyncall.git</div>
<div>
<br /></div>
<div>
末尾にシャープ付きでバージョンを指定すると、ちゃんと git タグのバージョンが使われる(シェルによっては # をバックスラッシュでエスケープすること)。みんなでちゃんとバージョン付けをしよう。</div>
<div>
<br /></div>
<div>
$ bower install git://github.com/kumatch/asyncall.git#0.1.1</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
これら方法で導入したパッケージも、bower update で最新のものに更新されることを確認した。</div>
</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<h3>
■ component.jsonを使ってのパッケージ管理</h3>
<div>
<br /></div>
<div>
component.json ファイルを自身のプロジェクトリポジトリに置いて、そのプロジェクト内で利用しているパッケージ群を定義することができる。</div>
<div>
<br /></div>
<pre><code class="json">{
"dependencies": {
"jquery": "~1.7.2",
"asyncall": "git://github.com/kumatch/asyncall.git"
}
}</code></pre>
<div>
<br /></div>
<div>
component.json のあるディレクトリ(あるいは bower 側で辿ることができる場所。マニュアル参照。)で bower install を実行すれば、定義しているパッケージ群を一気に導入できる。</div>
</div>
<div>
<br />
<br />
<div>
先ほどのように、git リポジトリ URL でのバージョン指定も OK。</div>
<div>
注意点としては、dependencies に定義するキーの値は、導入パッケージ側の "name" 要素で指定されている名前とあわせること。そうでないと、導入後の list コマンドでおかしなことになった。<br />
<br /></div>
<br />
<br />
<h3>
■ bower で導入されることを想定しているコンポーネントの依存性定義</h3>
</div>
<div>
<div>
<br />
例として、次のような component.json を含んだ git リポジトリがあるとする。</div>
<div>
(ここでは git://github.com/kumatch/bower-samples-nop.git とする)</div>
<div>
<br /></div>
<pre><code class="json">{
"name": "sampels-nop",
"version": "0.1.0",
"main": "./lib/index.js",
"dependencies": {
"asyncall": "git://github.com/kumatch/asyncall.git"
}
}</code></pre>
<div>
<br /></div>
<div>
<br /></div>
<div>
一方、自身のプロジェクト側の component.json で、このパッケージを利用するよう定義。</div>
<div>
<br /></div>
<pre><code class="json">{
"dependencies": {
"sampels-nop": "git://github.com/kumatch/bower-samples-nop.git"
}
}</code></pre>
<div>
<br /></div>
<div>
<br /></div>
<div>
bower install を実行すると、samples-nop パッケージと一緒に、依存している asyncall が導入される。</div>
<div>
<br /></div>
<div>
$ bower list</div>
<pre><code>/path/to/bower-test
├── asyncall#0.1.2
└─┬ sampels-nop#0.1.0
└── asyncall#0.1.2</code></pre>
<div>
<br /></div>
<div>
<br /></div>
<div>
$ bower list --paths</div>
<pre><code class="json">{
"asyncall": "components/asyncall/asyncall-0.1.2.min.js",
"sampels-nop": "components/sampels-nop/lib/index.js"
}</code></pre>
<div>
<br /></div>
<div>
<br /></div>
<div>
bower-samples-nop.git リポジトリの component.json を package.json としていても、問題なく(依存性を解決して)導入することができた。従って、npm パッケージとして用意されていて、かつブラウザでも利用可能なもの (Underscore.js とか) は普通に依存パッケージとして指定することができて、導入時にも問題なく解決される。</div>
</div>
<div>
<br />
<br />
<br />
<h3>
■ 導入パッケージのエントリポイントをスクリプトで得る</h3>
<br />
次のようなコードで paths にオブジェクトで受け取ることができた。まだ何も試していないけども、色々と自動化したいならば必要になってくると思う。<br />
<br />
<pre><code class="js">var bower = require('bower');
bower.commands.list({ paths: true }).on('data', function (paths) {
// console.log(paths);
// …
});</code></pre>
</div>
Unknownnoreply@blogger.comtag:blogger.com,1999:blog-6868175809892623410.post-7617990856572681542012-09-11T19:23:00.000+09:002012-09-11T19:23:41.341+09:00asyncall.js<a href="https://github.com/kumatch/asyncall">https://github.com/kumatch/asyncall</a><br />
<br />
<br />
ブラウザ、および Node.js 上で javascript 関数の非同期実行を行うライブラリです。<br />
いろんな環境下でも変わらず使えるものが欲しかったので、簡単ながら書きました。<br />
<br />
引数に関数を与えると、たた単純に非同期で実行されます。<br />
<br />
<pre class="brush:js">asyncall(function () {
console.log(1 + 2);
});
</pre>
<br />
次にあげる順の方法を使って実行します。<br />
<br />
<ol>
<li>setImmediate (IE 10, および Node v0.9 以上)</li>
<li>process.nextTick (Node v0.8 以下)</li>
<li>MessageChannel (WebKit 系)</li>
<li>setTimeout (それ以外)</li>
</ol>
<br />
<div>
<br /></div>
<div>
網羅できるテストが思いつかないので、テストが書けてないです。</div>
Unknownnoreply@blogger.comtag:blogger.com,1999:blog-6868175809892623410.post-56561336373072206892012-03-04T12:41:00.000+09:002012-03-06T11:04:46.767+09:00いかにしておっぱい画像をダウンロードするか〜2012 for Node.js<br />
<a href="http://yusukebe.com/archives/20120229/072808.html" target="_blank">いかにしておっぱい画像をダウンロードするか〜2012</a> の Node.js 実装です。<br />
こういう動機で頑張るっていうのはいつまでも少年時代であろうとしていていいよね!うちの場合もそれをゲームへ向けたわけだし。<br />
<br />
動作には npm で request と async を導入する必要あり。<br />
Node.js の場合、何も考えずに書いてしまうと逆に並列処理が走り過ぎて落ちて終わってしまうという。<br />
ということで async を使って並列処理数の制限を行っている。<br />
<br />
<u>2012-03-06 追記</u><br />
ファイルが既に存在している際に callback が呼ばれずに次のタスクへ進まないという不具合があった。コード修正。<br />
<br />
<br />
<pre class="brush:js">var request = require('request');
var querystring = require('querystring');
var async = require('async');
var crypto = require('crypto');
var fs = require('fs');
var path = require('path');
var appid = '';
var uri = 'http://api.bing.net/json.aspx?';
var dir = './data';
var page_count = 0;
var download_count = 0;
var md5hex = function (str) {
var md5 = crypto.createHash('md5');
md5.update(str, 'utf8');
return md5.digest('hex');
};
(function Oppai() {
var offset = page_count * 50;
var params = querystring.stringify({
Appid : appid,
Version : '2.2',
Markert : 'ja-JP',
Sources : 'Image',
'Image.Count' : 50,
'Image.Offset' : offset,
Adult : 'off',
Query : 'おっぱい'
});
request(uri + params, function (err, res, body) {
if (err) throw err;
var ref = JSON.parse(body);
if (ref.SearchResponse.Image) {
var results = ref.SearchResponse.Image.Results;
async.forEachLimit(results, 10, function (result, callback) {
var url = result.MediaUrl;
if (url.match(/\.jpg$/)) {
var filename = md5hex(url) + '.jpg';
var filepath = dir + '/' + filename;
path.exists(filepath, function (exists) {
if (!exists) {
var output = fs.createWriteStream(filepath);
output.on('close', function () {
callback();
});
download_count += 1;
request(url).pipe(output);
console.log(download_count + ' : Download... ' + url);
} else {
callback();
}
});
}
});
page_count += 1;
process.nextTick(Oppai);
}
});
})();
</pre>Unknownnoreply@blogger.comtag:blogger.com,1999:blog-6868175809892623410.post-24161665420354917742012-03-03T16:18:00.001+09:002012-03-03T16:19:34.713+09:00[おわび] Node.js 用モジュール event-transceiver は event-sign へ名称変更して再リリースします<br />
先日公開した、Node.js でイベント駆動の支援モジュールである <a href="http://kumatchs.blogspot.com/2012/03/event-transceiver.html">event-transceiver</a> を、<b>event-sign</b> という名称へ変更して再リリースすることにします。<br />
<br />
<a href="https://github.com/kumatch/node-event-sign">https://github.com/kumatch/node-event-sign</a><br />
<div>
<br /></div>
<div>
このモジュールが提供する機能として、以下の特徴が根本にあり、全てでした。</div>
<div>
<ul>
<li>ある関数によって取り扱われるイベント名を事前に定義する</li>
<li>定義イベントをメソッドベースで扱うと共に、非定義イベントは利用できない</li>
</ul>
<div>
こういった特徴を考慮した場合、transceiver という「送受信」をイメージするような名称は本モジュールには適切ではなく、むしろイベント定義を行った上で仕様に基づく振る舞いを厳密化するという特徴をイメージできるものへ改名するほうが良いと判断しました。</div>
</div>
<div>
<br /></div>
<div>
npm 提供パッケージは名称がかなり重要なものですので、その名称を変更するのならば、一般利用されている可能性が最も低いであろう今のほうがよい、早いに越したことはないと判断し、この再リリースに至りました。</div>
<div>
実際のところこのモジュールがこれ以上機能拡張されることは考えにくいので、別に前の名称のままフリーズでも良い気もしましたが、前述の通り時間が経てば経つほど変更できない状況になりますので。</div>
<div>
<br /></div>
<div>
既に旧モジュールをチェックされていた方にはご迷惑をおかけします。</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
なお、本当に旧モジュールが既に組み込まれてリリースされたような箇所は自分以外のものではないと思いますが、再リリースにあたっての仕様変更はありません。念のため。</div>
<div>
<br /></div>Unknownnoreply@blogger.comtag:blogger.com,1999:blog-6868175809892623410.post-908026374333168632012-03-01T11:06:00.000+09:002012-03-03T16:39:30.163+09:00Node.jsでメソッドベースイベント駆動のためのモジュール event-transceiver<b><u>2012-03-03 追記</u></b><br />
<br />
<a href="http://kumatchs.blogspot.com/2012/03/nodejs-event-transceiver-event-sign.html">本モジュール (event-transceiver) は、仕様をそのままに <b>event-sign</b> へと名称変更して再リリースしました。</a><br />
本モジュールが提供する機能内容を考慮すると、旧名称では適切ではないと判断しての変更です。参考にされた方々へはご迷惑をお掛けします。<br />
<br />
<b><u>追記ここまで</u></b><br />
<br />
<div>
<br /></div>
<br />
最近書く node.js コードは、EventEmitter を使ってのイベント駆動でやるようしている。<br />
それに伴って、イベント発生やリスナー設定を行う際のイベント名の指定を、文字列ではなくてメソッドで行うことができるモジュールを作った。<br />
<br />
すなわち、<br />
<br />
<pre>emitter.emit('done', value);
emitter.on('done', function (value) {
console.log(value)
});
</pre>
<br />
を、次のように実行できるように。<br />
<br />
<pre>transmitter.done(value);
receiver.done(function (value) {
console.log(value)
});
</pre>
<br />
世間でもメソッドでイベントリスナーを登録するモジュールがあったりするが、それ自体を実現するためのモジュールというのは見つけることができなかったので、書いてみてリリースした次第。<br />
<br />
<br />
イベントをメソッドベースで書きたい理由は単純で、「文字列で指定していると本当にペアになっているかいまいち分かりづらいから」。<br />
<br />
イベント駆動でよくあるのが、起きるつもりだったイベントが起きなくて実行に失敗するという状況。もちろんテストでカバーしているつもりなものの、もしイベントがメソッドならば、実行時のイベント名ミスマッチが undefined function などで簡単に検出できるようになる。<br />
<br />
通常の on('event') や emit('event') ならばコードを一目見ただけでイベント駆動だと分かるというメリットがあるので好みは分かれると思うが、個人的にはそれよりも「予想外の実行結果時に何が起きているのか分からない」シチュエーションを出来る限り回避できる方法を優先したい。<br />
<br />
<br />
利用法としては、モジュールの define メソッドでイベントを定義して、イベント仕様を決定。コンストラクタ関数が返される。<br />
それを使ってイベントのインスタンスを作成。インスタンスは transmitter と receiver という2つのオブジェクトのプロパティを持っていて、それぞれがイベント発生、リスナー登録の役割を持つ。そして、その2つのオブジェクトは先ほど定義したイベント名のメソッドを持つという仕組み。<br />
<br />
<pre>var EventTransceiver = require('event-transceiver');
var MyEvent = EventTransceiver.define(['done', 'error']);
var event = new MyEvent();
event.transmitter.error(Error('このようにつかうのだ'));
</pre>
<br />
<br />
より具体的なサンプルなどは上記 github の readme をどうぞ。Unknownnoreply@blogger.comtag:blogger.com,1999:blog-6868175809892623410.post-27214918529534058632011-12-09T00:26:00.001+09:002011-12-09T11:29:15.113+09:00Node Ninja に挑戦 2<br />
<div class="p1">
前回初めて利用してみた <a href="http://kumatchs.blogspot.com/2011/11/node-ninja.html">Node Ninja に挑戦</a>の第2弾でござる。</div>
<div class="p2">
<br /></div>
<div class="p1">
今回はオリジナルの Node プログラムを Git リポジトリに準備してそれをデプロイすると共に、リポジトリ更新によるサーバ自動更新までの動きを確認してみる。</div>
<div class="p2">
<br /></div>
<div class="p1">
Node Ninja の特徴の1つとして WebSocket に対応している……とは公式サイトには全く書いていないが、Twitter で <a href="https://twitter.com/node_ninja">@node_ninja</a> のニンジャがそう言っているので問題はないだろう。そこで今回は Socket.IO を使って、WebSocket を利用するシンプルなサーバプログラムを準備してデプロイすることにする。</div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
</div>
<div class="p1">
<b><u>Socket.IO サンプルプログラム</u></b></div>
<div class="p2">
<br /></div>
<div class="p3">
<span class="s1"><a href="https://github.com/kumatch/sample-socketiopulse">https://github.com/kumatch/sample-socketiopulse</a></span></div>
<div class="p1">
今回の挑戦のために、上記リポジトリのようなつまらないサーバプログラムを準備した。<br />
Socket.IO を使って断続的に通信が発生するため、そのままサーバを更新した際にどの程度ダウンするのかを確認することができる。</div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
</div>
<div class="p1">
<u><b>Node Ninja Machine へデプロイされるプログラムのルール</b></u></div>
<div class="p2">
<br /></div>
<div class="p1">
Machine 上で動作する Node サーバプログラムとして、現在のところいくつかのルールが設けられている。</div>
<div class="p1">
</div>
<ul>
<li>(おそらくトップレベルに) server.js というファイル名でエントリポイントを準備する</li>
<li>config.json というファイル名で実行する Node バージョンを指定できる</li>
<li>package.json が機能するので、デプロイ時にモジュールを指定してインストールできる</li>
</ul>
<br />
<div class="p1">
個人的には、package.json が機能するのだから、それに従って (モジュールとして) サーバが動作するようにできるのではないかと思う。</div>
<div class="p1">
<br /></div>
<div class="p1">
<br /></div>
<div class="p1">
</div>
<div class="p1">
<u><b>Git リポジトリを指定してのデプロイ</b></u></div>
<div class="p2">
<br /></div>
<div class="p1">
さて、実際の Machine へのデプロイは以下の簡単なステップで完了する。</div>
<div class="p1">
以下の例は、前述の Github 上のリポジトリを対象に行ったもの。Git リポジトリ URLは git://github.com/kumatch/sample-socketiopulse.git (読み込み専用) になる。</div>
<div class="p1">
</div>
<ol>
<li>Git Setup の Private タブで Add を押して、Git リポジトリURLを登録する</li>
<li>登録したアプリケーションが Private アプリケーション一覧に表示されるので、Install を押す</li>
<li>Machine にデプロイが開始されて稼働開始</li>
</ol>
<br />
<div class="p2">
その上で、Git の Post-Receive Hooks を利用して、リポジトリが更新された (push された) 際にサーバを自動的を更新する仕組みが備わっている。</div>
<div class="p1">
</div>
<ol>
<li>Git Setup の AutoSync タブで、Git リポジトリの URL を入力して Create</li>
<li>Post-Receive 用の専用 URL が発行される</li>
<li>(例えば Github 上で) Post-Receive Hooks の設定として、先ほど発行された URL を指定する</li>
</ol>
<br />
<div class="p2">
これでデプロイ元となるリポジトリへ push すれば、Node サーバアプリケーションは自動更新される。</div>
<div class="p1">
Git リポジトリ側の Post-Receive Hook がどのタイミングで行われるかにもよるが、push 直後に再デプロイが始まり、ほんのわずかなダウンタイムの後に新しいプログラムで稼働したことを確認できた。</div>
<div class="p2">
<br /></div>
<div class="p1">
デプロイした Machine の URL はこちら。</div>
<div class="p3">
<span class="s1"><a href="http://kumapulse.node-ninja.com/">http://kumapulse.node-ninja.com/</a></span></div>
<div class="p2">
<br /></div>
<div class="p1">
アクセス後、Chrome/Safari の開発ツール、ないし Firefox の Firebug のコンソール上で断続的に通信されているのが確認できる。IE は知らないが F12 を押そう。</div>
<div class="p2">
<br /></div>
<div class="p2">
<br /></div>
<div class="p2">
どうやら現在のところ立ち上げることができる Machine は1つのアカウントで1つまでのようで、上記 URL を機能させ続けるならば、もう別の Node アプリケーションをデプロイすることができない。恐らく、後ほど上記 URL の Machine は停止させて頂くことになるだろう。</div>
<br />
<br />
<br />Unknownnoreply@blogger.comtag:blogger.com,1999:blog-6868175809892623410.post-27838068106599568462011-11-30T23:11:00.002+09:002011-11-30T23:24:43.384+09:00Node Ninja に挑戦<div class="p1">この前の Node 勉強会で Node PaaS である Node Ninja (<a href="https://node-ninja.com/">https://node-ninja.com/</a>) のアカウントを頂いたにも関わらずさっぱり利用していなかったものの、それはさすがに勿体ないし、可能であればレポートを書いてねとも言われていたので、このたび挑戦してみることに。</div><div class="p1"><br />
</div><div class="p1">実は PaaS 自体はこの Node Ninja が初体験。</div><div class="p2">稼働までの準備等は Web ブラウザによる設定コンソールにて行っていく。</div><div class="p2"><br />
</div><div class="p2"><br />
</div><div class="p1"><b><u>Machine の作成</u></b></div><div class="p2"><br />
</div><div class="p1">アプリケーションを稼働させるために、最初は Machine を準備する。正式サービスが展開されればおそらく性能を選択するようなことになるだろうけども、現在は固定になっている。今は指定項目としては Machine につける名前のみ。ここでは「kumasrv」とつけた。これで Machine の準備は完了。</div><div class="p2"><br />
</div><div class="p2"><br />
</div><div class="p1"><b><u>アプリケーションのデプロイ</u></b></div><div class="p2"><br />
</div><div class="p1">この作成した Machine に Node アプリケーションを設定する。現在のところ以下の4つの方法がある。</div><div class="p2"><br />
</div><div class="p1">1. オフィシャルに提供されるアプリケーションから選択してインストールする。</div><div class="p1">現在はサンプルアプリケーションが準備されているが、今後は Node の有益なアプリケーションがボタン1つでデプロイできて Ready になるのだろうと予想できる。</div><div class="p2"><br />
</div><div class="p1">2. 利用者による Shared アプリケーションから選択してインストールする。</div><div class="p1">オフィシャルではないものの、他のユーザによって提供されるアプリケーションパッケージの位置づけ。</div><div class="p2"><br />
</div><div class="p1">3. プライベートアプリケーション。選択ではなく、自身で Git リポジトリを指定してでデプロイする。また、ここで追加したアプリケーションを Shared 化することができる(最初はちょっとわからなかった)</div><div class="p2"><br />
</div><div class="p1">4. AutoSync。Git リポジトリから展開した上で、そのリポジトリが更新されると自動的に git pull してくれる。逆にいえば、これまでの3つの方法ではデプロイ後は基本的に「そのまま」となる。ただし、先に設定した SSH key で Machine に接続して、コンソール上でコードを変更したりサーバの起動をしなおしたりといったことは可能。</div><div class="p2"><br />
</div><div class="p2"><br />
</div><div class="p1"><b><u>オフィシャルアプリケーションをデプロイ</u></b></div><div class="p2"><br />
</div><div class="p1">今回は、オフィシャルなアプリケーションを展開してみる。hello-http という、おそらく hello world なアプリケーションがあったので、それを選択。Logs 画面に遷移した後、Machine が準備される様子(ログ)が追加されていく!</div><div class="p2"><br />
</div><div class="p1">完了後、kumasrv.node-ninja.com へブラウザで繋いでみる。あれ、繋がらない。どういうことなの、ってことで Machine に SSH で接続する。プロセスを確認すると、Nodeプロセスは存在するものの httpd のようなものは存在していない。</div><div class="p1">そういうものなのかなー<span class="s1">ニンともカンともとか言いつつ</span>、実行プログラムの中身を覗いてコードを確認。8080 番で動いていることがわかったので、 kumasrv.node-ninja.com:8080 で接続。無事「Hello World」が表示される。</div><div class="p2"><br />
</div><div class="p1">その後アプリケーション選択ページを見てみると、説明文に「ポート 8080 でHTTPのリクエストを待ち受け」ってちゃんと書いていた。てめえが<span class="s1">ニンともカンともだった。</span></div><div class="p2"><br />
</div><div class="p2"><br />
</div><div class="p1">別のオフィシャルアプリケーション (express + giraffi) も試す。こちらは普通に80でアクセスすることができた。こちらもコンソールからソースコードを覗くと、たしかにそのまま 80 番で待ち受けるよう記述されていた。ユーザにはそういう権限がある模様。</div><div class="p1"><br />
</div><div class="p1">Machine Logs ページ上ではこのアプリケーションのデモとして、アプリログの様子が記録されているのが分かる。どうやらこれがカラクリの中身らしい。</div><div class="p1"><br />
</div><div class="p3"><a href="https://github.com/node-ninja/ninja-giraffi">https://github.com/node-ninja/ninja-giraffi</a></div><div class="p2"><br />
</div><div class="p2"><br />
</div><div class="p1"><b><u>その他雑多なところ</u></b></div><div class="p2"><br />
</div><div class="p1"></div><ul><li>Machine 上には mongodb が動いている。情報はないがデモでは普通に使っているし CLI でも接続可能。</li>
</ul><ul><li>作成した Machine を削除して再度別名で作成した際、同じ IP が割当てられたにも関わらず名前割当ては古いままだった。切り替わるのに結構な時間を要したのでこの辺はまだまだ調整が必要そう。</li>
</ul><br />
<div class="p2"><br />
</div><div class="p2">今度は自前アプリケーションのデプロイに挑戦する予定。</div>Unknownnoreply@blogger.comtag:blogger.com,1999:blog-6868175809892623410.post-17696059107092641262011-10-03T23:30:00.003+09:002011-10-04T09:25:56.427+09:00node.js のモジュール配置について 2011 秋今のところこれでいこうという形ができたので、現時点のものを一旦まとめるというお話。<br />
<br />
<br />
<b><u>モジュールの読み込み優先度</u></b><br />
<br />
<a href="http://nodejs.jp/nodejs.org_ja/docs/v0.4/api/modules.html#loading_from_node_modules_Folders">http://nodejs.jp/nodejs.org_ja/docs/v0.4/api/modules.html#loading_from_node_modules_Folders</a><br />
<br />
この項に書いている話ですべてではあるものの改めて書くと、<br />
ある js ファイル上で require() を使ってモジュールを読み込もうとする際、指定した path が「/」「./」「../」といった指定の仕方ではないならば、その js ファイルからルートまでのすべてのパス上に存在する *node_modules* というディレクトリ内がモジュール読み込み対象となる。もちろん、深いレベル (読み込み元 js ファイルに近い) ほど優先度が高い。<br />
<br />
/path/to/app/app.jp で require() したならば、次に示す順のディレクトリ内モジュールが検索される。<br />
<br />
<ol><li>/path/to/app/node_modules</li>
<li>/path/to/node_modules</li>
<li>/path/node_modules</li>
<li>/node_modules</li>
</ol><br />
もちろん、require() で指定する path が階層構造でも問題なし。上の例で、require('my/app/foo_module.js') という指定をしたならば、モジュールとしてのファイルは以下のように検索される。<br />
<br />
<ol><li>/path/to/app/node_modules/my/app/foo_module.js</li>
<li>/path/to/node_modules/my/app/foo_module.js</li>
<li>/path/node_modules/my/app/foo_module.js</li>
<li>/node_modules/my/app/foo_module.js</li>
</ol><br />
基本的にはこれさえ分かっていれば、容易に共有/固有のモジュール領域が作れる。<br />
<br />
<br />
<b><u>ソフトウェアごとのモジュール配置</u></b><br />
<br />
私は現在のところ、Nodeで開発しているソフトウェア (ex: foo_project) のモジュール配置は次のように行っている。<br />
<br />
<pre>- foo_project
- app
- app.js
- node_modules
- (ソフトウェア固有ドメインのモジュール)
- node_modules
- (npm 等で導入される共有モジュール)
- (node_modules)
</pre><br />
foo_project として実装されたソースは app ディレクトリ以下に配置、実行するようにし、直下にそのソフトウェア固有ドメイン向けのモジュール領域を作成する。開発したドメインモデル等はすべてこの app/node_modules 以下に設置する。<br />
一方、npm 等で配布されているパッケージや会社資産などのライブラリモジュール (これも package として社内配布するとよい) は、先ほどの固有ドメイン向けの領域より一段上に配置する。本質的には読み込み優先順位を下げる必要はないが、ツリー自体の可読性と固有ドメインとの分別説明のために明確な分離を行う。<br />
なおこれ以上分離が必要な場合は、さらにその上位にモジュールディレクトリを準備する。分離したい数だけ、上位ディレクトリに node_modules ディレクトリを作成すればよい。制限はただ一つ、ルートディレクトリにたどり着くまで。<br />
<br />
<br />
<br />
<b><u>npm による任意モジュールディレクトへのパッケージ導入</u></b><br />
<br />
目的の node_modules ディレクトリへ移動した後に npm install を行えば、そのディレクトリへパッケージを導入できる。<br />
npm は現在のところ対象となる node_modules 内パッケージディレクトリの内容のみで管理しているように思われるため、目的のディレクトリ内におけるパッケージの追加や削除も容易に行うことができる。<br />
<br />
<br />
<u><b>「require.paths」の削除</b></u><br />
<br />
以前は require.paths という組み込み配列に任意のパスを push することで、モジュールの読み込み対象ディレクトリを増やすことができた。しかし、現在ベータバージョンである v0.5 系では削除されている。元々 v0.4 系リリース時点のドキュメントで「いつか消すから止めとけ」という明記がされていて、いつ完全削除されるものかと思っていたものの、案外早く対処されたという印象。<br />
<br />
コード上から容赦なくパスを操作できてしまうのはトラブルの元だし不安定な挙動を引き起こす可能性が高いということで、なくなって正解だったと思われる。何より、現在の仕組みはシンプルながらも強力で融通も利く。Unknownnoreply@blogger.comtag:blogger.com,1999:blog-6868175809892623410.post-20000012213995645632011-02-08T23:58:00.001+09:002011-02-08T23:58:39.673+09:00Windows 版 Safari の file drop event がヘン以下のような、ブラウザ外からファイルを Drop することを想定しているページがあるとする。<br />
ここでは、ファイルを Drop すると drop イベントとして「dropped.」と、利用したファイル名を表示。<br />
<br />
<pre><code><html>
<head>
<title>Drag & Drop test.</title>
<script type="text/javascript">
window.addEventListener('dragover', function(event) {
event.preventDefault();
}, false);
window.addEventListener('dragenter', function(event) {
event.preventDefault();
}, false);
window.addEventListener('drop', function(event) {
event.preventDefault();
alert('dropped.');
var file = event.dataTransfer.files[0];
if (file) {
alert('file = ' + file.name);
}
}, false);
</script>
</head>
<body>
<div>Drop a file.</div>
<br />
<div>If you use safari on windows, drop a unders dummy link first, and drop a file next.</div>
<div>
<a href="#">a dummy link.</a>
</div>
</body>
</html>
</code></pre><br />
Firefox, Chrome, Safari で動作することを想定しているけども、Windows 版 Safari ではファイルを Drop することができない。<br />
<br />
しかし、同じページ内にあるリンク (もしくは画像があればそれでも OK) を掴んでページ内へ Drop すると Drop イベントが発生し、さらに何故か以降のファイル Drop が成功するようになる。<br />
<br />
実際にその動きが確認できるページはこちら。<br />
<a href="http://hatotech.org/labo/drop.html">http://hatotech.org/labo/drop.html</a><br />
<br />
<br />
ちなみにこの現象は他の「ファイル Drop 機能を提供しているページ」でも見ることができる。例えば Google Docs。<br />
<br />
何が起きてるんですかね。ブラウザと Javascript に詳しい人教えてください。Unknownnoreply@blogger.comtag:blogger.com,1999:blog-6868175809892623410.post-19497240693112278042010-09-07T06:47:00.009+09:002010-12-03T23:16:22.409+09:00Mac における円とバックスラッシュ非 Mac 環境から Mac 環境へ移ると、いろんな差異が発生しますね。<br />
Emacs で正規表現を書いていたところ、なぜかエスケープシーケンスがちっとも効かない。<br />
<br />
<pre><code>/(.+)[¥s]+(.+)/ # 実際はすべて半角</code></pre><br />
こんなシンプルな抽出なのにちっとも機能しない。どういうことだと色々悩んでいたところに、1つの疑惑が。<br />
<br />
「ひょっとすると円とバックスラッシュは別コードで示される文字なのでは。」<br />
<br />
別所(ターミナル)ではそのまま表示されているバックスラッシュをコピーして Emacs に持ってきたところ、しっかりと画面上にはバックスラッシュが掲載される。そのまま正規表現に利用すると見事マッチ。<br />
<br />
で、改めて調べたところ、Mac の日本語キーボードでは以下のような入力になるとのこと。<br />
<br />
<ul><li>円は「¥」キー</li>
<li>バックスラッシュは Option +「¥」</li>
</ul><br />
Windows, Linux で今まで当たり前のように使っていた「エスケープ等に利用するためのバックスラッシュ」は円とイコールの扱いだったし、キー入力も¥キー1つでOKだった。それが Mac ではこの違い。そして何が驚いたって、これが Mac ユーザには「バックスラッシュは Option +¥ で入力すべき文字」ということが当然のことだったという。<br />
<br />
「じゃあ円(¥)は何に使うの?」と聞くと、「少なくともコードには必要ない」ということだったので、既に導入済みのキーボードカスタマイズソフト <a href="http://pqrs.org/macosx/keyremap4macbook/index.html.ja">KeyRemap4MacBook</a> で¥キーでバックスラッシュが入力されるように変更したのでした。Windows の窓使いの憂鬱並に、既にマストソフトウェアです。Unknownnoreply@blogger.comtag:blogger.com,1999:blog-6868175809892623410.post-74499073432564620932010-09-03T08:10:00.001+09:002010-12-03T23:17:41.769+09:00株式会社フィードテイラーに入社しましたご無沙汰しておりました。<br />
以前から表立っての活動やアウトプットがめっきりなくなってしまっていましたが、このたび記事を書くべき報告がありまして帰ってきました。<br />
<br />
9月1日から<a href="http://feedtailor.jp/">株式会社フィードテイラー</a>で働くことになりました。<br />
<br />
同社は iPhone/iPad アプリケーションの開発を主力事業としてやっておりますが、私は主にサーバサイドのシステム構築、実装に携わることになります。これまで行ってきたWebアプリ開発の経験を活かしつつ、これからも日々邁進していくことで成長し、それが会社自身の成長に繋がればと想う次第です。<br />
<br />
<br />
本当に近頃どうしているのかさっぱり分からない状況ではありましたが、これからは少しは何かしら表立っての活動があるかもしれません(?)<br />
<br />
振り返れば色々あった時期もありましたが、もう少し気楽に、楽しいことが続けられれば、仕事もプライベートも充実した日々が送れるかなと。きっと。それに先駆けて自宅の開発マシン用にと MacBook Pro を買いました。はじめての Mac です。知らないソフトは多いですが結局 Unix マシンなので楽しく使っております。<br />
<br />
それでは、今後ともよろしくお願いします。Unknownnoreply@blogger.comtag:blogger.com,1999:blog-6868175809892623410.post-69156111508990534772010-03-05T02:11:00.005+09:002010-12-04T10:59:08.537+09:00ubuntu に kumofs を導入して動かしてみた先日えとらぼより公開された、<a href="http://github.com/etolabo/kumofs" target="_blank">kumofs</a> を自宅マシンの ubuntu に導入して、動くところまでを確認してみた。Key-Valueストアを利用する機会を作ろうと考えている手前、実際のところちゃんと利用したことがなかったので、まずは基本部分から。ドキュメント通りの導入ステップと、簡単なアクセスによる利用テストのみ。<br />
<br />
なお kumofs のアーキテクチャについては<a href="http://d.hatena.ne.jp/viver/20100118/p1">こちらで紹介されている。</a><br />
<br />
今回導入した環境は以下のとおり。<br />
<br />
<ul><li>OS: Ubuntu 9.10 (KVM)</li>
</ul><br />
<br />
<b>必要パッケージの導入</b><br />
<br />
コンパイルや動作のために必要となるパッケージを導入。<br />
<br />
<pre class="brush:bash">$ sudo apt-get install libtokyocabinet-dev
$ sudo apt-get install ruby rubygems
$ sudo apt-get install g++
</pre><br />
<b>MessagePack for C/C++ の導入</b><br />
<br />
<a href="http://msgpack.sourceforge.jp/">MessagePack</a> の C/C++ はパッケージがないので自前でソースから導入する。この時点でのバージョンは 0.4.2。<br />
<br />
<pre class="brush:bash">$ wget "http://dl.sourceforge.jp/msgpack/46155/msgpack-0.4.2.tar.gz"
$ tar xzf msgpack-0.4.2.tar.gz
$ cd msgpack-0.4.2/
$ ./configure
$ make
$ sudo make install
</pre><br />
<b>MessagePack for Ruby の導入</b><br />
<br />
一方 MessagePack for Ruby は gem で導入。<br />
<br />
<pre class="brush:bash">$ sudo gem install msgpack
</pre><br />
<b>kumofs のコンパイル</b><br />
<br />
いよいよ kumofs のコンパイル。この時点でのバージョンは 0.3.1。特別やることはなかった。<br />
<br />
<pre class="brush:bash">$ http://github.com/downloads/etolabo/kumofs/kumofs-0.3.1.tar.gz
$ tar xzf kumofs-0.3.1.tar.gz
$ cd kumofs-0.3.1/
$ ./configure
$ make
$ sudo make install
</pre><br />
<b>kumofs を動かす</b><br />
<br />
アーキテクチャの紹介でもともかく分散構成が基本であることを前面に出しているし、それを実現するための方法もとても簡単なのがすばらしい。でも単一のサーバ上で構築してもなんら問題なく動く。<br />
<br />
まずはマネージャを起動。<br />
<br />
<pre class="brush:bash">$ sudo kumo-manager -v -l localhost &
</pre><br />
続いてサーバを起動。<br />
<br />
<pre class="brush:bash">$ sudo kumo-server -v -l localhost -m localhost -s /var/kumodb.tch &
</pre><br />
管理ツールで状態を確認してみる。VM 稼働かどうかは定かではないけども、なんか時間がおかしい。<br />
<br />
<pre class="brush:bash">$ kumoctl localhost status
hash space timestamp:
Thu Jan 01 09:00:00 +0900 1970 clock 0
attached node:
not attached node:
127.0.0.1:19800
</pre><br />
マネージャにサーバを登録。<br />
<br />
<pre class="brush:bash">$ kumoctl localhost attach
$ kumoctl localhost status
hash space timestamp:
Tue Mar 02 23:38:08 +0900 2010 clock 124
attached node:
127.0.0.1:19800 (active)
not attached node:
</pre><br />
なぜか時間も正常に表示されるようになったぞ。<br />
<br />
最後に、ゲートウェイを起動。アプリケーションはこのゲートウェイに対して通信する。<br />
<br />
<pre class="brush:bash">$ sudo kumo-gateway -v -m localhost -t 11211 &
</pre><br />
使ってみる。直接つっついてみるケースと、プログラムからのアクセスの両方をやってみた。<br />
<br />
<pre class="brush:bash">$ telnet localhost 11211
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
set foo 0 0 5
12345
STORED
get foo
VALUE foo 0 5
12345
END
</pre><br />
<pre class="brush:bash">$ sudo gem install memcache-client
$ sudo gem install system_timer
$ irb
require 'rubygems'
require 'memcache'
kumofs = MemCache::new 'localhost:11211'
kumofs.set 'foo', 123
kumofs.get 'foo'
=> 123
</pre>Unknownnoreply@blogger.comtag:blogger.com,1999:blog-6868175809892623410.post-59937729697152643912008-07-14T08:10:00.001+09:002010-12-03T23:24:32.979+09:00さあいこう!<a href="http://coderepos.org/share/browser/events/phpframework/piece_framework/trunk">http://coderepos.org/share/browser/events/phpframework/piece_framework/trunk</a><br />
<br />
機能をすべて実装したものの、まだまだチューニングや見えざる敵(bug)との戦いが控えています。<br />
俺たちの戦いはこれからだ!<br />
<br />
<br />
<br />
r15761 号をもってコミットメントは終了です。<br />
ご愛読ありがとうございました。Unknownnoreply@blogger.comtag:blogger.com,1999:blog-6868175809892623410.post-16068147556094194142008-03-26T23:28:00.003+09:002010-12-04T10:38:14.984+09:00PHP Simple HTML DOM Parser<a href="http://simplehtmldom.sourceforge.net/" target="_blank">PHP Simple HTML DOM Parser</a><br />
<br />
これ面白い。<br />
<br />
<pre class="brush: php">require_once 'html_dom_parser.php';
$dom = file_get_dom('http://www.google.co.jp/search?q=%E3%83%94%E3%82%AB%E3%83%81%E3%83%A5%E3%82%A6&lr=lang_ja&ie=utf-8&oe=utf-8');
foreach ($dom->find('a') as $node) {
$node->innertext = str_replace('ピカチュウ', 'オプーナ', $node->innertext);
$node->href = 'http://www.opoona.com/index.htm';
}
foreach ($dom->find('b') as $node) {
$node->innertext = str_replace('ピカチュウ', 'オプーナ', $node->innertext);
}
print $dom->save();
</pre><br />
<div class="separator" style="clear: both; text-align: center;"><a href="http://4.bp.blogspot.com/_imETUmSn4B8/TPkBBYOlFXI/AAAAAAAAAK0/CkvYlNKPeR8/s1600/20080326.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="206" src="http://4.bp.blogspot.com/_imETUmSn4B8/TPkBBYOlFXI/AAAAAAAAAK0/CkvYlNKPeR8/s320/20080326.png" width="320" /></a></div><br />
なんか色々思いついたので、暫らくの間これで遊びます。Unknownnoreply@blogger.comtag:blogger.com,1999:blog-6868175809892623410.post-87494601996219678512008-03-26T10:28:00.001+09:002010-12-03T23:47:30.929+09:00室内整頓中ごちゃーっとしていることに嫌気が差した2008年、思い立って自宅室内にところ狭しと並べられていた家電、パソコン類を整頓することにしました。<br />
<br />
手始めに、既に使っていないくせに何故か部屋の中に留まり続けていた小型のブラウン管TVや CRT ディスプレイを処分。<br />
驚くべきことに4台にもなっていた自作パソコンも、機能面や用途面を含めてえいやと一台に集約して残りを排除。<br />
うちに遊びにきた人は必ず反応していた3面もの液晶ディスプレイも、ワイド24型を1つだけを残して残りは排除。<br />
テレビに接続されていた各種プレイヤも、HDDレコーダ1つを残して残りは排除。<br />
<br />
<br />
と、ここまで一気に進めて室内スッキリし始めたところで、PC からアナログ線で繋いで利用していた古いステレオアンプ+スピーカーx2が何故か気に入らなくなり、デスクトップPC向けのエレガントな2.1chサラウンドシステムを IYH!(イヤッッホォォォオオォオウ!の意ですなわち衝動買い)。調整も済んでいい音を楽しんでますが、思い切りやってしまった感が。<br />
<br />
家電はこんなところで、後日は本類に着手する予定。Unknownnoreply@blogger.comtag:blogger.com,1999:blog-6868175809892623410.post-88782338600314473582008-03-19T08:09:00.004+09:002010-12-04T10:53:28.986+09:00Piece_ORM で簡単データベース+PHPプログラムPiece_ORM を使えば、だれでも簡単にデータベースを使ったPHPプログラムを書くことができます。(任天堂のCM風に。)<br />
<br />
<strong><u>1. フォルダの作成</u></strong><br />
<br />
Piece_ORM を動作させるには、プログラムのファイルとは別に3つのフォルダを使います。<br />
プログラムファイルを作成するフォルダ内に、次の3つのフォルダを作成します。<br />
<ul><li>config</li>
<li>cache</li>
<li>mappers</li>
</ul><br />
<br />
<strong><u>2. データベース情報を準備する</u></strong><br />
<br />
次に Piece_ORM から接続するデータベースサーバの情報を設定します。<br />
仮にデータベースの情報が<br />
<br />
データベース: PostgreSQL<br />
ホスト名: localhost<br />
<br />
database : example<br />
username : example_user<br />
password : example_password<br />
<br />
以上のようなものなら、先ほど作ったフォルダのうちの1つ、config フォルダの中に「piece-orm-config.yaml」という名前のファイルを作成し、次のように記述します。<br />
<pre class="brush:plain">- name: database1
dsn: pgsql://example_user:example_password@localhost/example
</pre><br />
<br />
<strong><u>3. テーブルを準備する</u></strong><br />
<br />
続いて、実際にプログラムから読み込みや書き込みを行おうとするテーブルを準備します。<br />
<br />
データベース内の実際のテーブルは予め作成しておきます。ここでは「person」という名前のテーブルを作成したとします。<br />
<br />
先ほど作ったフォルダのうちの1つ、mapper フォルダの中に「Person.yaml」という名前のファイルを作成します。中身は何も必要ありません。<br />
<br />
<br />
<strong><u>4. プログラムを書く</u></strong><br />
<br />
最後にプログラムを書きます。書くプログラムは非常に短くて簡単です。<br />
<br />
SELECT 文の SQL は次のようなコードを準備します。SELECT した結果のレコードがオブジェクトとして簡単に参照が可能です。<br />
<br />
<pre class="brush:php"><?php
// Piece_ORM を読み込む
require_once 'Piece/ORM.php';
// Piece_ORM を設定する
Piece_ORM::configure('config', 'cache', 'mappers');
// person テーブルを対象にする
$mapper = Piece_ORM::getMapper('Person');
// select * from peron where id = 1;
$person1 = $mapper->findById(1);
echo $person1->name; // name カラムを表示
// select * from peron where name = 'foo';
$person2 = $mapper->findByName('foo');
echo $person2->name;</pre><br />
<br />
<br />
INSERT, UPDATE, DELETE も簡単です。<br />
<br />
<pre class="brush:php"><?php
// Piece_ORM を読み込みと設定
require_once 'Piece/ORM.php';
Piece_ORM::configure('config', 'cache', 'mappers');
// person テーブルを対象にする
$mapper = Piece_ORM::getMapper('Person');
// 新しいレコードとして INSERT
$person = new stdClass();
$person->name = 'foo';
$mapper->insert($person);
// name カラムを変更して UPDATE
$person->name = 'bar';
$mapper->update($person);
// DELETE
$mapper->delete($person);</pre><br />
<br />
<br />
<br />
詳しくはこちら<br />
<br />
<a href="http://trac.piece-framework.com/piece-doc/wiki/ja/users/piece-orm/UsersManual/Installation" target="_blank">Piece_ORM のインストール</a><br />
<a href="http://trac.piece-framework.com/piece-doc/wiki/ja/users/piece-orm/QuickStart/CrashCourseInPiece_ORM" target="_blank">Piece_ORM のより詳細なチュートリアル</a>Unknownnoreply@blogger.comtag:blogger.com,1999:blog-6868175809892623410.post-89822628169488657732008-03-13T07:24:00.001+09:002010-12-03T23:56:23.377+09:00iTunes ライブラリのデータ共有&バックアップ環境の最も簡潔な方法音楽や動画などのデータを保存しているストレージ用のマシンとHDDがヘタれたので、ひとまず新しいHDDを買ってきたんですよ。この手のPCパーツを買うのは2年ぶりほどですけど、相変わらず暫らく遠ざかっているだけで性能アップと価格ダウンの進展が大きくて驚くばかりですよ。HITACHI の省電力仕様のHDD 500GB が 9000円でした。<br />
<br />
で、タイトルにあるように iTunes ライブラリ(音楽データ、アートワーク、楽曲再生リスト)を新しい HDD に移しつつ、既存の再生環境でも正しく再生されるようにしないといけないなあと思ったんですね。気をつけないと「データが見つかりません」とか言われてデッドリンクが大量発生しちゃうし。<br />
そこで、ふと気づいたんですよ。なんで今までこの方法が思いつかなかったんだろうと。google で調べても同じことやってるケースが一杯ヒットしているくらいだし。<br />
<br />
iTunes ライブラリ用って1つのフォルダにまとめられているんで、そこをシンボリックリンクにすれば、参照先がどこに移動したって再生環境側は気にする必要がないんですよね。仮に再生側で再インストールしたとしても、ストレージ側の iTunes ライブラリをシンボリックリンクしなおせばすぐ元通りだし、今回のようにストレージ側が変わっても、これまた同じようにシンボリックリンクしなおせばすぐ参照できるようになる。<br />
<br />
まずは現行の再生側の iTunes ライブラリフォルダをバックアップなどに移して、iTunes から認識できるライブラリフォルダが存在しないようにしときます。Windows ならば「マイミュージック」内に iTunes がない状態に。一方、実際の iTunes ライブラリフォルダがどこか別のところにある状態にします。ここでは仮に d:\music\iTunes あたりとします。<br />
<br />
Windows 環境では通常シンボリックリンクをはる手段がないものの、MS の TechNet で<a href="http://technet.microsoft.com/ja-jp/sysinternals/bb896768(en-us).aspx" target="_blank">シンボリックリンクを作る junction コマンドのプログラム</a>が配布されているようなのでコレを使うとOK。windows フォルダや system32 フォルダあたりの実行パスが通っているところにコピーしたあと、コマンドプロンプトを立ち上げて以下のように junction コマンドを発行してあげればOK。<br />
<br />
<pre><code>c:\Documnets and Setting\username> cd "My Documnets\My Music"
c:\Documnets and Setting\username\My Documnets\My Music > junction iTunes d:\music\iTunes</code></pre><br />
<br />
ちなみに Cygwin 環境があれば ln コマンドで同じことができます。<br />
<br />
これで、見かけ上はマイミュージックに iTunes フォルダがあるように見えるものの、実際その中身は d:\music\iTunes という状況に。<br />
<br />
再生側は全般的に c:\Documnets and Setting\username\My Documnets\My Music\iTunes として見えているので、これのシンボリックリンク先がネットワーク越しの異なるマシンなんてこともOKでしょう。複数マシンが1つの iTunes ライブラリを参照する状態になるので、どのマシンでもライブラリへの楽曲追加ができるし、共通の再生リストも利用できますね。Unknownnoreply@blogger.comtag:blogger.com,1999:blog-6868175809892623410.post-22517493460113491952008-02-20T03:55:00.002+09:002010-12-04T15:37:52.658+09:00Movable TypeにおいてSQLiteからMySQLへ手動でデータ移行するうちの Blog で利用している Movable Type は SQLite でデータ保存を行っていたのですが、どうもその SQLite データファイルが、利用しているホスティングであるさくらサーバの容量に対して到底無視できない割合(1/4)を利用しているということが判明。事実、容量の空きが非常に苦しいものとなってきていました。<br />
その一方、さくらでは別途 MySQL も用意されており、ユーザは www 用サーバとは別に準備されたいくつかの MySQL サーバのうちの1つを選択し利用できるというサービス体系になっています。<br />
<br />
そんな利用状況なさくらサービス、ひょっとすると使用可能なホスティングデータ量ってば、利用可能なサーバ容量の範囲とは別でないかという甘い考えが思いついたことはさておき、そもそも SQLite よりも MySQL サーバを利用するほうが保持するデータ容量は少なくなるであろうという考えの元、SQLite から MySQL へデータ移行することにしました。<br />
<br />
その際、当方の SQLite におけるデータ構造や SQL 内容の理解がないので、1つ1つ確認しながら出来るよう、大よそを手動で事を進めていきました。今回のケースは Movable Type におけるお話ですが、他のものにもある程度流用できるのではないでしょうか。なおデータベース、および SQL についての若干ながらの知識が必要になるかもしれません。(SQL エラーが発生した場合に対応できるとか。)<br />
<br />
<br />
<u><strong>0. 環境</strong></u><br />
<br />
参考までに、今回の環境は以下のとおり。<br />
なお作業はオーソドックスにすべて CLI ベースのクライアントで進めました。<br />
<ul><li>MySQL 4.0.27</li>
<li>SQLite 3.3.17</li>
<li>Movable Type 4.0</li>
</ul><br />
<br />
<u><strong>1. Movable Typeのデータスキーマを MySQL 側に作成</strong></u><br />
<br />
まず MySQL 上に Movable Type のデータが格納できるよう、スキーマを作成します。<br />
MT の設定ファイル(mt-config.cgi)内に記述されたデータベース接続設定を SQLite から MySQL のものへ変更し保存します。MT はかつて SQLite 環境で動いていたもので問題ありません。むしろこのまま MySQL へ移行しようとするので、へたに新しい MT の管理ページを作成する必要はありません。<br />
<br />
続けて MT の管理ページへアクセスします。すると MT は MySQL 上に MT 用データが存在しないため、新規作成を行おうとしますので、これを進めていきます。MTユーザ登録などもあわせて行う流れとなりますが、内容を覚えておく必要はありません。<br />
<br />
作成が完了した後、MySQL クライアントを使って、MT 用テーブルのデータを全て消去します。MT 用テーブルは、テーブル名の先頭すべてに「mt_」という接頭辞がついているものです。<br />
テーブルの削除ではなく、データの削除であることに注意しましょう。データ削除コマンドは「truncate テーブル名」です。またその他のテーブルデータも消えぬことのないように…。<br />
<br />
これで MySQL 側の受け口ができました。<br />
<br />
<br />
<u><strong>2. SQLite のデータダンプ</strong></u><br />
<br />
続いて SQLite データをダンプします。<br />
<br />
SQLite データは1つのファイルにまとめられている状態となっています。sqlite のコマンドツールはこのデータファイルを指定して実行する仕組みとなっています。またデータダンプは、sqlite の「.dump」コマンドで行います。たとえば SQLite データファイル example.db に対してのデータダンプは、CLI より以下のように実行します。<br />
<br />
<pre class="brush:bash">$ echo '.dump' | sqlite example.db > sqlite.dump.sql
</pre><br />
SQLite データファイルの指定、および sqlite コマンドの違いに気をつけましょう。(さくらの場合、「sqlite3」コマンドでした。)<br />
<br />
このコマンドの実行で、sqlite.dump.sql というテキストベースの SQL データが出来ました。<br />
<br />
<br />
<u><strong>3. SQL データを MySQL 向けに編集</strong></u><br />
<br />
SQLite のダンプデータは、SQL 文によるデータベースの情報や操作が記載されています。<br />
SQL は色々なデータベースで利用されているものですが、今回ダンプした直後の内容では一部 MySQL で利用できないものが含まれているので、これを編集します。<br />
<ul><li>一行目の「BEGIN TRANSACTION;」を削除</li>
<li>最終行の「COMMIT;」を削除</li>
<li>その直前の「CREATE INDEX~」行をすべて削除</li>
</ul><br />
まず以上のことを行うことで、データ内は「CREATE TABLE~」と「INSERT INTO~」のみのものとなります。<br />
<br />
本来ならば、ここから「CREATE TABLE~」のSQLもすべて削除し「INSERT INTO~」のみにすることで MySQL への投入準備が整うのですが、私の場合はここから「INSERT INTO~」文を編集する必要がありました。このままデータを INSERT してしまうと、MySQL 上では目的のデータ構造とは異なるものになろうとしていたからです。<br />
<br />
例えば、ダンプデータ内の CREATE TABLE 文が<br />
<pre class="brush:sql">CREATE TABLE mt_placement (
placement_id integer not null primary key,
placement_blog_id integer not null,
placement_category_id integer not null,
placement_entry_id integer not null,
placement_is_primary boolean not null
);</pre><br />
というものに対し、実際のこのテーブルへの INSERT 文は<br />
<br />
<pre class="brush:sql">INSERT INTO "mt_placement" VALUES (4,2,2,4,1);
</pre><br />
となっていたとします。データベースに対して CREATE TABLE を行った後にこの INSERT を実行すると、以下のようなレコードができます。<br />
<br />
<pre><code>mt_placement テーブル
---------------------
placement_id = 4
placement_blog_id = 2
placement_category_id = 2
placement_entry_id = 4
placement_is_primary = 1</code></pre><br />
一方、既に MySQL 上で準備されている mt_placement テーブルは、先ほどの CREATE TABLE のものと同じとは限りません。同じテーブル内容なものの、カラム順が異なるケースが実際にありました。(以下は一例)<br />
<br />
<pre class="brush:sql">CREATE TABLE mt_placement (
placement_id int(11) not null auto_increment,
placement_entry_id int(11) not null,
placement_blog_id int(11) not null,
placement_category_id int(11) not null,
placement_is_primary tinyint(4) not null,
PRIMARY KEY(id)
)
type = MYISAM;</pre><br />
この場合、同じ INSERT 文を行った mt_placement テーブルはこうなります。<br />
<br />
<pre><code>mt_placement テーブル
---------------------
placement_id = 4
placement_entry_id = 2
placement_blog_id = 2
placement_category_id = 4
placement_is_primary = 1</code></pre><br />
カラム名を指定した INSERT 文ではないため、テーブル定義を行った順に INSERT が行われてしまい、結果違うレコードに仕上がってしまいます。<br />
<br />
これを回避すべく、ダンプデータ内に記述されている CREATE TABLE 文のカラム順序どおりに、INSERT 文を編集していくのです。(説明長い!)<br />
<br />
<br />
先ほどの、<br />
<br />
<pre class="brush:sql">INSERT INTO "mt_placement" VALUES (4,2,2,4,1);
</pre><br />
これは、こうします。<br />
<br />
<pre class="brush:sql">INSERT INTO mt_placement
(placement_id, placement_blog_id, placement_category_id, placement_entry_id, placement_is_primary)
VALUES (4,2,2,4,1);
</pre><br />
ついでにテーブル名のダブルクオートも排除。なお複数行でなくても一行でOK。<br />
<br />
全ての INSERT 文において、対応するテーブルの CREATE TABLE 文で示されているカラム順に従った形で INSERT 文を書き換えていきます。<br />
<br />
INSERT 文のすべてを書き換え終わった後に、CREATE TABLE 文をすべて削除します。<br />
<br />
<br />
<br />
<u><strong>4. MySQL へデータを投入</strong></u><br />
<br />
編集後のファイルを MySQL へ投入します。<br />
例えば MySQL のデータベース「my_database」に対して投入する状況において、3. のセクションで sqlite.dump.sql ファイルを編集後 mysql.import.sql として保存したのであれば、以下のようなコマンドを実行します。<br />
<br />
<pre class="brush:bash">$ mysql my_database < mysql.import.sql
</pre>
必要に応じて -u, -p などのオプションをつけて、SQL が正しく実行できるようにしましょう。
またエラーが発生した場合は原因を良く確かめて import ファイルを編集し、truncate でもう一度リセットした上で再投入しましょう。
<u><strong>5. Movable Type 管理へアクセス</strong></u>
<br />
投入後再び Web で MT 管理ページへアクセスします。SQLite 環境で稼動していたものと同じものが参照、利用できるはずです。Unknownnoreply@blogger.comtag:blogger.com,1999:blog-6868175809892623410.post-46686450515341976652008-02-07T23:48:00.001+09:002010-12-03T23:57:49.570+09:00大乱闘スマッシュブラザーズX1/31の発売からおよそ一週間たったWii用ゲーム「大乱闘スマッシュブラザーズX」、スマブラX。恥ずかしながら発売後ずっと遊んでます。<br />
<br />
どんなゲームかというと、かつて「マリオブラザーズ」とか「アイスクライマー」とか「バルーンファイト」の2P協力プレイのモードを使って対戦をしていた人に直撃する、ポコポコと4人まで同時に遊べる大乱闘アクションゲームなのです。<br />
また任天堂ゲームのいろんなキャラクターたちが集まって操作できるというのも1つのポイント。<br />
<br />
ゲームの中で動くキャラクターやフィールドこそ3Dモデルなものの、昔ながらの2Dゲームのように左右キーで移動して上キー(もしくはボタン)でジャンプしてボタンで攻撃というシンプルな操作はもはやお馴染みなものだからすぐ慣れる。<br />
<br />
「面白いよ!」といって初めての人にコントローラを渡してしばらく触っていると、すぐに大よその基本的な操作ができるようになるのは良いですねえ。そのまま4人でワーワープレイできて面白いです。<br />
<br />
<br />
このスマブラXは今回で3作目なんですが、今回は「これまでの任天堂ゲーム」を匂わすギミックがこれでもかというほど多数盛り込まれていて、かつて任天堂のゲームで遊んだ数が多ければ多いほど、より楽しめるという仕組みになってます。なつかしい演出やフィールド、キャラクタそして音楽が、記憶の奥に沈みきっていた子供のころのゲームの思い出を呼び起こしてきます。<br />
<br />
特に音楽は新旧あわせて約250もの曲が準備されているらしく凄いボリューム。任天堂ゲームの名作のなかの名曲がアレンジされて流れてきます。あまりに懐かしすぎ+出来が良すぎて涙腺が危なかったのはいよいよ歳ということかなあ。しかしファミコン、スーパーファミコン、ニンテンドー64くらいまでは分かるんだけども、最近のポケモンとかのゲームがよー分からんのが悔しい。<br />
<br />
<br />
また今回はネットワークを通じて対戦できるというモードもあって、知ってる人とも知らない人とも遊べます。やってみた感じ、発売直後は(恐らくアクセスが殺到しすぎて)全然遊べなかったのですが、今週になってボチボチと乱闘できるようになりました。アクションゲームのネットワーク対戦って大抵の場合キャラクターがワープしたりとかいきなり攻撃を受けたりとかあるんですが、このスマブラはネットワークを介して遊んでいるとは思えないほどの滑らかさで遊べてしまうのがまた凄い。(なぜ今までの通信対戦ゲームと違うのかが知りたい。)<br />
<br />
Wii持ってる知り合いは買ってないのかなあ。フレンド対戦やりたいなあ。集まった結果「じゃあ今日は2グループに分かれて遊ぼうぜ!」とかやりたいなあ。Unknownnoreply@blogger.com