« 2008年05月 | メイン | 2008年07月 »



2008年06月 アーカイブ

2008年06月01日

マーラー丼作ってみた

DSCF2357.jpg 花椒(ホアジャオ)と呼ばれる中国の香辛料が生協で25円で売ってたので買って使ってみました。作ってみた写真の料理は麻辣丼(マーラー丼)と呼ばれる台湾の屋台料理です(だと思います)
マーラー丼は、以前の出向先の近くで初めて食べたのですが、豚バラをボロボロになるまで煮込んでご飯に乗っけたものだったと思います。その乗っかってる豚バラの90パーセントは脂身で、しかもものすごい辛くて、そのときお世話になっていた部長が「コレ食べると血圧気になってしょうがない」みたいな事を言ってました。作り方も想像で作ってます。
・脂身がものすごかったのでたぶん豚バラだと思います。
・ホアジャオはマーラー麺に使うらしいのでマーラー丼にも使うだろうと。
そんな感じで作ってみました。「ほとんど脂身だけの豚バラくださーい」とか言える精肉店は知らないので普通に豚バラ500gを使っています。
作り方はトンポーロー作って細かく切って最後に辛く味付けるだけです。簡単。

・豚バラが浸るくらいの水(2リットル~)をなべに用意する。 ・ネギ1本と、ニンニク1かけ、しょうが2かけと豚バラを1時間煮込む。煮汁はすてちゃだめ。
・豚バラを取り出して賽の目になるまで細かく切る。勿体無いと思うけど切る。
・しょうゆ大匙2と紹興酒大匙1で味付け。しばらく浸しておく。
・豚バラをフライパンで焼く。コンガリ行く。
・先ほどの煮汁に味付け。しょうゆ大匙3、砂糖大匙3、紹興酒大匙2、豚バラを投入。
・ホアジャオ、みじん切りにした唐辛子を適宜投入。味見しながら投入。
・2時間ほどとろ火で煮込む。
写真のマーラー丼はあまり煮込んでないです。1時間くらい。香辛料がエグくなるかなーと思ったけど、ぜんぜん大丈夫でした。
辛そうに見えないのはあまりにも辛いのは苦手だからです。ピリッとするくらいです。ホアジャオはピリッと言うか、バチッという辛味です。そういえばとろみをつけるの忘れてました。つけたい人は片栗粉でどうぞ。

大きな地図で見る
まだあれば、ここらへんでマーラー丼が食べられる。お店の名前忘れちゃった。

[ 最近のエントリーとその関連エントリー ]


[ スポンサードリンク ]

2008年06月26日

Ext.DomQueryの基本的な使い方#1

domQuery.PNG ExtJSのエントリはこちらにまとめてあります

ExtJSのDOMセレクタはExt.query()というメソッドで使えるようになっています。Ext.query()メソッドは2つのパラメータを持ち、第1パラメータに取得したい場所を書式に基づいた文字列で与えて、第2パラメータにエレメントのidを渡します。第2パラメータは省略可能ですのでこれを使わずとも、第1パラメータだけでかなり柔軟な取得ができます。また、Ext.query()メソッドはExt.DomQuery.select()のエイリアス(shorthand)ですので、どちらを使ってもいいようです。
動作サンプル

DomQueryで探索するサンプルHTML

<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
  <div id="fuga" class="piyo">
   ここはdiv#fuga.piyoです。
   <span class="fuga">
    ここはspan.fugaです。div#fuga.piyoの中に配置されています。
   </span>
   <a href="#" class="piyo">
    ここはa.piyoです。span.fugaと同じ高さで、その直後に配置されています
   </a>
  </div>
  <div id="piyo" class="fuga">
   ここはdiv#piyo.fugaです。
   <a href="#">
    ここはaです。div#piyo.fuga直下に配置されています。
   </a>
   <p>
    ここはpです。div#piyo.fugaの中に配置されています。
    <a href="#">
     ここはaです。div#piyo.fuga内ですがその直下にはありません。
    </a>
    <a href="#">
     ここはaです。div#piyo.fuga内ですがその直下にはありません。
    </a>
   </p>
   <span class="fuga">
    ここはspan.fugaです。div#piyo.fugaの中に配置されています。
   </span>
   <p class="piyo">
    ここはp.piyoです。span.fugaと同じ高さでその直後に配置されています
   </p>
  </div>
  <p class="piyo">
   ここはp.piyoです。div#piyo.fugaと同じ高さでその直後に配置されています
  </p>
</body>
</html>

Elementセレクタ

Element(要素)とは?を先に説明しておきますと
<a href="#" >リンク</a>
このタグ開始~タグ終了セットをElementと呼んでいます。よくタグとエレメントがごっちゃになったりしますが、タグは開始タグも終了タグもタグですので、エレメントより分解された言い方ですね。『タグと要素(エレメント)の違いを説明して』がわかりやすいです。

で、ちょっと余談ですが、じゃあエレメントとノードの違いって何よ?って疑問があって、C#でパタパタ実装しているとXmlElementとXmlNodeなんてのを使うことになるんですが、XmlElementとXmlNodeというクラスの扱いだけで言うと、「りんご:XmlElement」と「フルーツ:XmlNode」くらいに覚えておけばいいみたいです。XmlNodeのほうが抽象化されてるってか一般化されてるって言うかそういう風に腹に落としました。ふーん。
で、javascriptのgetElementByIdだとエレメントが返るぞと言われてる気がするのですが、selectSingleNodeっていわれるとノードだと言われる。後者はXPathで指定するので手続きは違うとして、返って来たモノはなんだろね。呼び方の違い?まぁタイプセーフではないのでごちゃごちゃいわないことにします。(余談なげー)

ということでElementセレクタの説明です。
    Ext.query( "span" ); // [ span.fuga, span.fuga ]
このクエリは[ span.fuga, span.fuga ]という2つの要素からなる配列を返します。全ドキュメントからspanエレメントに合致するものを拾ってきます。
    Ext.query( "span", "fuga" ); // [ span.fuga ]
このクエリは[ span.fuga ]という1つの要素からなる配列を返します。サンプルHTMLにはspanエレメントが2つありますが、idが"fuga"からなるdiv内のspanを指定していますので、前者のほうが返ります。

次は書式付の第1パラメータで取得する方法です。

id指定:"#"

idを指定してエレメントを拾いたい場合は、"#"をプレフィックスとして与えてあげます。
    Ext.query( "#piyo" ); // [ div#piyo.fuga ]
このクエリは、idが"piyo"でclassが"fuga"のdivが返ります。2つあるdivのうち後者のほうが返ります。

class指定:"."

classを指定してエレメントを拾いたい場合は、"."をプレフィックスとして与えてあげます。
    Ext.query( ".piyo" ); // [ div#fuga.piyo, a.piyo, p.piyo, p.piyo ]
このクエリは、classが"piyo"のエレメントを返します。

全指定:"*"

全ての要素を拾いたい場合は"*"を指定することで拾えます。
    Ext.query( "*" ); // [ html, head, meta, body, div#fuga.piyo, span.fuga, a.piyo, div#piyo.fuga, a, p, a, a, span.fuga, p.piyo, p.piyo ]

子エレメント指定:" "(スペース)

あるエレメント内で指定した全ての子エレメントを拾う場合は、" "(スペース)を間にはさんで与えてあげます。
    Ext.query( "div p" ); // [ p, p.piyo ]
このクエリは親にdivエレメントを持つ p を返します。
    Ext.query( "div span" ); // [ span.fuga, span.fuga ]
このクエリは親にdivエレメントを持つspanエレメントを返すので、2つのspanが返ります。

直下の子エレメント指定:">"または"/"

あるエレメント内の直下の子エレメントを指定して拾う場合は">"または"/"を間にはさんで与えてあげます。
    Ext.query( "div/a" ); // [ a.piyo, a ]
div#fuga.piyo直下のa.piyoエレメントとdiv#piyo.fuga直下のaエレメントを返します。pエレメント内の2つのaエレメントは直下にないので返しません。

直後の同じ高さ(兄弟要素)のエレメント指定:"+"

あるエレメントと同じ高さにいるエレメントで、その直後にいるエレメントを拾う場合は"+"を間にはさんで与えてあげます。一応挙動も確認したのですが(あまり使いそうにないなーと思いながら)、ちょっと自信ないです。
    Ext.query( ".fuga+.piyo" ); // [ a.piyo, p.piyo, p.piyo ]
ちょっとわかりにくいですが、class="fuga"のエレメントと同じ高さにいて、その直後でclass="piyo"のエレメントを返しています。

後方の同じ高さ(兄弟要素)のエレメント指定:"+"

あるエレメントと同じ高さにいるエレメントで、その後方にいるエレメントを拾う場合は"~"を間にはさんで与えてあげます。
    Ext.query( "a~span" ); // [ span.fuga ]
これもちょっとわかりにくいですが、aと同じ高さにいるspan.fugaを拾っています。"+"と違い、拾ってきたspan.fugaはaの直後にいません。これも一応挙動も確認したのですが、かなり自信ないです。

ほかにもアトリビュートから指定してエレメントを取得したり出来るのですがまた次回に紹介します。

via : DomQueryのチュートリアル
via : APIDoc

[ 最近のエントリーとその関連エントリー ]


2008年06月24日

ExtJSの質問を見つけたので横から回答してみます。

modgridStylepic.PNG ExtJSの使い方で、ちょっと徘徊してましたらmojalogのエントリを参照していただいた方がおりましたので、ちょっとその回答を横から入らせていただこうかと思います。
内容はコチラで、girdのヘッダの隠し方と、gridのボーダーの消し方を質問されていました。ワタシはそのサービスのアカウントを持っておりませんので回答も何も出来なかったのでちょっとこちらから。


    var grid = new Ext.grid.EditorGridPanel({
        store:store,
        hideHeaders:true,    //<- gridのヘッダを隠します。
        colModel:clmnModel,
        renderTo:'renderTarget',
        title:'simple-editorgrid',
        stripeRows:false,
        height:200,
        width:320,
        frame:true,
        clicksToEdit:1
    });

    // cssセレクタでx-grid3-rowを検出して、メソッドに渡します。
    rmvGridBorder( Ext.query("*[class=x-grid3-row]") );

    function rmvGridBorder( els ){
        for( var x = 0 ; x < els.length; x++ ){
            var el = Ext.get( els[ x ] );
            if( el ) {
                if( el.hasClass( "x-grid3-row" ) ){
                    el.dom.style.border='0px';
                }
            }
        }
    };
本筋の使い方ではないかと思いますが、CSSにアクセスしてエレメントからdomのスタイルを直接いじっています。ちなみにEditorGridはレコードがコミットされるとスタイルも初期化されるようですので注意する必要があります。
反射的に書いたエントリですのでそのうちDOM/CSSセレクタあたりをまとめてみたいと思います。

[ 最近のエントリーとその関連エントリー ]


2008年06月23日

Ext.grid.EditorGridPanelの使い方

editorgridsumple.PNG ExtJSのエントリはこちらにまとめてあります

ダウンロードページより、アーカイブ(Ext JS 2.1 SDK)をダウンロードして解凍してください。20080623時点のバージョンは ext-2.1 です。
今日は、ExtJSのEditor Grid Exampleを解説してみたいと思います。
ワタシが作ってみたEditorGridは、上記リンクのサンプルのようにプルダウンやチェックボックスは装備しておりません。EditorGridそのものは非常にシンプルに作った代わりに、編集されたセルを検出するボタンを追加してみました。Gridをフォームとしてどこかへポストしたいといった時に、有効かもしれません。あと、いきなりEditorGridPanelとか言われても・・と言う方にはここにExtJSのチュートリアルを簡単にまとめてみました。
まず、以下に今回解説するEditorGridPanelのソースを全て載せてみましたので、この実装方法とコンフィグを解説します。
動作サンプルとサンプルソース
Ext.onReady( function(){
    var id = 0;
    var reader = new Ext.data.ArrayReader( { id: 0 }, [
          { name: 'str', mapping: 1 },
       { name: 'num', mapping: 2 }
    ]);
    var store = new Ext.data.Store({
        reader: reader,
        data:[ 
            [ id++, 'hoge', 1 ],
            [ id++, 'moge', 2 ],
            [ id++, 'fuga', 3 ]
        ]
    });
    
    var clmnModel = new Ext.grid.ColumnModel([
        { header: "Title", width: 200, sortable: true, dataIndex: 'str', editor: new Ext.form.TextField() },
        { header: "Number", width: 100, sortable: true, dataIndex: 'num', editor: new Ext.form.NumberField() }
    ]);

    var grid = new Ext.grid.EditorGridPanel({
        store:store,
        colModel:clmnModel,
        renderTo:'renderTarget',
        title:'simple-editorgrid',
        stripeRows:true,
        height:200,
        width:320,
        frame:true,
        clicksToEdit:1,
        tbar:[
        { text: 'touch', handler:function(){
            grid.getStore().each( function( targetObj ){
                var touchField = targetObj.getChanges();
                for( name in touchField ){
                    alert(
                        "index : [ " + targetObj.id + " ]\n" + 
                        "fieldName : [ " + name + " ]\n" +
                        "value : [ " + touchField[ name ] +" ]\n" 
                    );
                }
                targetObj.commit();
            });
        }}]
    });
});

【Ext.grid.EditorGridPanelの解説】

それではEditorGridPanelを見ていきたいと思います。普通のGridPanelの使い方はこちらを参照ください。

EditorGridPanel

    var grid = new Ext.grid.EditorGridPanel({
という箇所がエディターグリッドパネルそのものになります。GridPanelと違うところはコンフィグオプションの
     clicksToEdit:1,
という個所と、カラムモデルにeditorというコンフィグオプションを適用しているところだけです。
clicksToEditのAPIDocをみると
The number of clicks on a cell required to display the cell's editor (defaults to 2)
とありまして、セルが編集可能になるクリック数みたいなことが書いてありますが、なんかあんまり関係ないような気がします。(値がいくつでもダブルクリックで編集可能になった)このコンフィグオプションがなくても編集可能になりました。
で、実際に編集可能にするためにはカラムモデルにeditorという設定をしなければならないようです。
    var clmnModel = new Ext.grid.ColumnModel([{ 
        header: "title", 
        width: 200, 
        dataIndex: 'str', 
        editor: new Ext.form.TextField()  // <-コレ
    },
ここのeditorにformパッケージのクラスでnewしてあげると、編集時にそのクラスで動くようになります。例えばComboBoxでnewしてあげるとプルダウンできるようになります。(適宜ComboBoxのコンフィグは必要になります)
これでEditorGridPanelが完成しました。

編集セルの特定

冒頭で記述しましたようにEditorGridの編集個所が特定できないと、どこかのページに値をポストしようにも出来ませんので、この解説をしたいと思います。ポストの前にとりあえず、gridのデータをどこかに渡すためには、
  1. どのレコードの、
  2. どのフィールドで
  3. どんな値に
変更されたのか?という情報は必要になってきます。今回はその情報を取り出すだけで、データをポストするところまで組んでいません。
tbar:[
{ text: 'touch', handler:function(){
    grid.getStore().each( function( targetObj ){
        var touchField = targetObj.getChanges();
        for( name in touchField ){
            alert(
                "index : [ " + targetObj.id + " ]\n" + 
                "fieldName : [ " + name + " ]\n" +
                "value : [ " + touchField[ name ] +" ]\n" 
            );
        }
        targetObj.commit();
    });
}}]
というわけで、実装の解説を進めていきますが、tbarというコンフィグオプションは前回のTreePanelのときに解説しましたツールバーです。今回はツールバーにtouchというボタンを与えてあげて、そこにハンドラとして編集セルを見るメソッドを用意しました。
まず、gridが用意しているgetStore()メソッドを呼び出して、データストアを取得します。次に返ってきたstoreで持っているeachメソッドを使って、レコード単位に全てのオブジェクトを拾いあげます。
grid.getStore().each( function( targetObj ){
パラメータのtargetObjはExt.data.Recordのオブジェクトが入ってきますので、このオブジェクトに変更があったかどうかを聞きます。
var touchField = targetObj.getChanges();
getChanges()メソッドはAPIDocに以下のような説明がありました。
Gets a hash of only the fields that have been modified since this Record was created or commited.
「レコードが作られたか、あるいは、コミットされた後に編集されたフィールドをハッシュ(オブジェクト)で返すよー」と言っているみたいです。なるほど。便利。編集されてなければ返されたオブジェクトはプロパティを持たないようです。ですので、for~inで調べてみました。これで、編集されたフィールドと値を取得することが出来ます。
ちなみに、targetObjの実態はExt.data.Recordですので、idを持っていて自分がどのレコードかを知っているのですが、今回の実装はストアを作るときに明示的にidを振っています。
    var id = 0;
    var reader = new Ext.data.ArrayReader( { id: 0 }, [
          { name: 'str', mapping: 1 },
       { name: 'num', mapping: 2 }
    ]);
    var store = new Ext.data.Store({
        reader: reader,
        data:[ 
            [ id++, 'hoge', 1 ],
            [ id++, 'moge', 2 ],
            [ id++, 'fuga', 3 ]
        ]
    });
前回作ったGridはSimpleStoreを使って簡単にデータストアを構築しましたが、今回はレコードのidも見たかったのでちょっと構築方法が違います。
ArrayReaderのコンストラクタの第1パラメータで、「レコードのidは扱うデータ(配列)の0番目ですよ」と明示的に指定しています。さらに第2引数でレコードのnameと扱うデータ(配列)の何番目かをmappingで指定しています。マッピングをずらすと、grid内にidを表示することも出来ます。idの生成やその一意性は実装依存ですが、自ら生成しなくとも勝手に割り当てられるようです。ただ、一意に割り当ててあげないとバインド出来ませんね。
これでソートしてレコードの位置が変わってもidでバインドできるようになりました。ちなみにレコードが上から何番目か?ってのを知りたい場合は、
grid.getStore().indexOf( targetObj )
というstoreのindexOfでそのレコードが上から何番目に位置するのか聞けます。
で、最後にtargetObj.commit();で編集をコミットしてあげています。

というわけで、EditorGridPanelの解説をしてみました。ワタシの理解を多分に含めておりますので、誤った情報である可能性がありますのでご注意ください。

[ 最近のエントリーとその関連エントリー ]


2008年06月22日

throwableラビットをデザインしてみました!

DSCF2370.jpg シルクスクリーンなるものをハンズで購入しまして、Tシャツのデザインをしてみました。
このもっさりしたウサギは、「throwable ラビット」という名前をつけてあげました。愛情がないときに(ぶん)投げられます。愛情があっても証明書を要求されます。
Tシャツには、
throw ( !love )
    ? new ThrowableLoveit()
    : new CertificateException();
というジョークコードも載せたいと思います。始めはこのコードだけ描こうかと思っていたのですが、んなもんプログラムをやってない方にはさっぱり分からん内容ですので写真の白目をむいたウサギもデザインしてみました。実にかわいいです(貧相な発想が)。
このTシャツはPOW-WOWTシャツ展に出品いたしますので、万が一欲しい方がいらっしゃいましたら訪れていただけるとうれしいです。
販促で付けようとしているケータイストラップも、やる夫という2chキャラクターだとちょっとあれなので、耳を付けてthrowableラビットケータイストラップにしようかと思います。はい。耳を付けるだけです。はい。耳はとらないでください。

[ 最近のエントリーとその関連エントリー ]


2008年06月21日

キッチンドランカーが赤尾アジのタタキと茄子のお吸い物作った

DSCF2364.jpg
DSCF2366.jpg
DSCF2368.jpg
DSCF2369.jpg
休みの日は大抵キッチンドランカーです。なんか作りながら飲むのって結構おいしく飲めますよね。で、いつもブログにポストしている料理がイタリアンとか中華とかばっかりでしたので今日は和風に行ってみました。

Tシャツのデザインの用具を買いにちょっとハンズまで買い物に出かけておりまして、帰宅する頃には結構おなかが減っていたのですが、財布の中にほとんどお金が入ってません。100円マックか?とかいうレベルで入っていない。で、スーパーに寄ると200円で赤尾アジなるものが売ってました。おお。でかい。尾っぽが確かに赤い。へー。しかも鯵?こんだけでかけりゃ鯵のたたきが出来る!と言うわけで購入。よって素寒貧。うまいのかコレ?
で、とりあえずアジは3枚におろします。おろしてみるとやはりアラがでかいので、出汁になるんじゃないかと2枚目の写真は「昆布から出汁をとってみる」の写真。汁物はお吸い物に決定。

で、ご飯を炊いて、赤尾アジのタタキに昆布ポン酢をかけて、茄子のお吸い物の出来上がり。おいおいおいうまいんじゃねーか。質素にうまい。200円が化けたよー!\(^o^)/

作り方もくそも無いのですが、
・アジの皮をはぐときはキッチンペーパーとかで押さえて上げないと身が持ってかれます。
・ナスは焼いて皮をはいでから使います。お吸い物のなかで茹で上げると色が悪くなります。
おいしかった。Tシャツどうしよ。

[ 最近のエントリーとその関連エントリー ]


オリジナルTシャツそろそろやる。

DSCF2363.jpg POW-WOWクリエーターによるTシャツ展に参加しますと前に書いたのですが、もうやばい。そろそろTシャツデザインしないとやばい。なんにもやってないんです。いっそのこと、写真のTシャツを着てフレンチとかイタリアンとか中華とか食べ歩いて、食べこぼしデザインにしてしまおうかと思います。ません。積極的に後ろ向きな発想が浮かんできております。友人の赤ちゃんをあやしたときについたヨダレデザインとかそういうことばかり浮かんできております。赤ちゃん「あばー」とか言って。言わない。

と言うわけでして、Tシャツをそろえてみました。どう考えても守りに入っている枚数。4枚。藍色、ちょっと深い赤、桜っぽいピンクと、くすんだ水色。普通に「赤紺水色ピンク」って書かないところがいやらしいです。無駄に商品価値をあげてるユルフワくしゃモテ巻き髪と変わらないです。うそ。ごめんなさい。先に謝っておきます。(ブフー)
で、ユニクロにすこーし厚手の生地のシャツを探しに行ったのですが無かったのでg.u.というところで購入。ぐいぐい引っ張ったり、ほつれがないか見ましたが大丈夫。(生地は大丈夫だと必死に主張しています)

色々考えた結果、背面、オシリの少し右上あたりにちょこっとデザインすることにしました。あとは無地です。主張しすぎないところが慎ましやかで慈しみ深いジャパニーズスタイル仕上げとなっております。自分で何言ってるのか分かってないです。

ということでこれからハンズに行ってTシャツ君とかいう便利セット買ってくるよー。

[ 最近のエントリーとその関連エントリー ]


2008年06月17日

クラスター分析をjavascriptでやってみた。

ちょっと勉強のためにクラスター分析をjavascriptで書いてみました。
いろいろと調査していると、距離の演算にはウォード法がいいんじゃないかというポストがたくさんあったのでウォード法を使っています。今回はクラスター分析結果で何かをしたいわけじゃないのでこれでいいとします。
で、使ってみるとデータの数×変数の数を抑えてあげないとブラウザが固まります(ノ∀`)ダハー。実装の仕方が悪いというのもありますが、サーバサイドでやったほうがいい処理なのかもしれません。実際、そんなにデータ量が多くてもピンとこないと思いますので初期値を勝手に設定してあります。

・データの数を20~30個くらいで
・変数1にして
・グループ数を10くらいから1に向かってぐりぐり変えてあげると、

なんとなく上手くグルーピングされていってるんじゃねーか?ってのがわかります。本当はクリック位置とかを分析して視覚的に見せようかと思ったのですが途中で投げてしまいました。
inputoutput
グループの数:
変数の数:
データの数:
乱数を初期化する:

サンプルソース

function ClusterAnalysis(){
    this.init.apply( this, arguments );
}

ClusterAnalysis.prototype = {

    dataStore : {
        grpCnt  : 0,
        dataCnt : 0,
        rngCnt  : 0,
        grpRng  : null,
        data    : null
    },

    init : function(){
            var store = this.dataStore;
            store.grpCnt  = parseInt( $( "grpcnt" ).value );
            store.dataCnt = parseInt( $( "datacnt" ).value );
            store.rngCnt  = parseInt( $( "rngcnt" ).value );
            if( $( "retain" ).checked ){
                store.grpRng = new Array( store.dataCnt );
                store.data = new Array( store.dataCnt );
                for( var idx = 0; idx < store.dataCnt; idx++ ){
                    store.data[ idx ] = new Array( store.rngCnt );
                }

                for( var idx = 0; idx < store.dataCnt; idx++ ){
                    for( var ndx = 0; ndx < store.rngCnt; ndx++ )
                        store.data[ idx ][ ndx ] = Math.round( Math.random() * 100 );
                }
            }
            $( "retain" ).checked = false;
    },

    analysis : function(){
        var store = this.dataStore;
        var dataCntBuf = new Array( store.dataCnt );
        var rangeBuf = new Array( store.dataCnt )
        for( var idx = 0; idx < store.dataCnt; idx++ ){
            rangeBuf[ idx ] = new Array( store.dataCnt );
        }

        for( var idx = 0; idx < store.dataCnt; idx++ ){
            store.grpRng[ idx ] = idx;
            dataCntBuf[ idx ] = 1;
            for( var ndx = idx + 1; ndx < store.dataCnt; ndx++ )
                rangeBuf[ idx ][ ndx ] = this.getRange( idx, ndx );
        }

        for( var idx = 0; idx < store.dataCnt; idx++ ) {
            for ( var ndx = idx + 1; ndx < store.dataCnt; ndx++ )
                rangeBuf[ ndx ][ idx ] = rangeBuf[ idx ][ ndx ];
        }

        var loopCnt = store.dataCnt;
        while ( loopCnt > store.grpCnt ) {
            var range = this.getMinimumRange( rangeBuf );
            for( var idx = 0; idx < store.dataCnt; idx++ ){
                if( store.grpRng[ idx ] == idx ) {
                    for ( var ndx = idx + 1; ndx < store.dataCnt; ndx++ ) {
                        if( store.grpRng[ ndx ] == ndx ) {
                            if( idx != range.to && ndx != range.to ) {
                                if ( idx == range.from ) {
                                    rangeBuf[ idx ][ ndx ] = this.analyticRange({
                                        dest1 : rangeBuf[ range.from ][ ndx ],
                                        dest2 : rangeBuf[ range.to ][ ndx ],
                                        dest3 : rangeBuf[ range.from ][ range.to ],
                                        size1 : dataCntBuf[ range.from ],
                                        size2 : dataCntBuf[ range.to ],
                                        size3 : dataCntBuf[ ndx ]
                                    });
                                    rangeBuf[ ndx ][ idx ] = rangeBuf[ idx ][ ndx ];
                                }
                                else if ( ndx == range.to ) {
                                    rangeBuf[ idx ][ ndx ] = this.analyticRange({
                                        dest1 : rangeBuf[ idx ][ range.from ], 
                                        dest2 : rangeBuf[ idx ][ range.to ],
                                        dest3 : rangeBuf[range.from][ range.to ], 
                                        size1 : dataCntBuf[ range.from ], 
                                        size2 : dataCntBuf[ range.to ], 
                                        size3 : dataCntBuf[ ndx ]
                                    });
                                    rangeBuf[ ndx ][ idx ] = rangeBuf[ idx ][ ndx ];
                                }
                            }
                        }
                    }
                }
            }

            dataCntBuf[ range.from ] += dataCntBuf[ range.to ];
            for( var idx = 0; idx < store.dataCnt; idx++ ) {
                if( store.grpRng[ idx ] == range.to )
                    store.grpRng[ idx ] = range.from;
            }
            loopCnt--;
        }
    },
    
    getRange: function( from, to ){
        var store = this.dataStore;
        var buf = 0 ;
        var range = 0;
        for( var idx = 0; idx < store.rngCnt; idx++ ){
            buf = store.data[ from ][ idx ] - store.data[ to ][ idx ];
            range = range + ( buf * buf );
        }
        return range;
    },

    getMinimumRange : function( rangeBuf ){
        var store = this.dataStore;
        var range = { from:0, to:0 };
        var min = -1.0;
        for ( var idx = 0; idx < store.dataCnt; idx++ ) {
            if ( store.grpRng[ idx ] == idx ) {
                for ( var ndx = idx + 1; ndx < store.dataCnt; ndx++ ) {
                    if ( store.grpRng[ ndx ] == ndx ) {
                        if( min < 0.0 || rangeBuf[ idx ][ ndx ] < min ) {
                            min  = rangeBuf[ idx ][ ndx ];
                            range.from = idx;
                            range.to   = ndx;
                        }
                    }
                }
            }
        }
        return range;
    },
    
    analyticRange : function( relation )
    {
        var range = (
            ( relation.size1 + relation.size3 ) * relation.dest1 + 
            ( relation.size2 + relation.size3 ) * relation.dest2 - 
            relation.size3 * relation.dest3 
        ) / ( relation.size1 + relation.size2 + relation.size3 );
        return range;
    },

    dataStore : {
        grpCnt  : 0,
        dataCnt : 0,
        rngCnt  : 0,
        grpRng  : null,
        data    : null
    },

    renderOutput : function(){
        var store = this.dataStore;

        var grpidx = 1;
        var grpndx;
        var renderText = '';
        while( grpidx <= store.grpCnt ) {
            grpndx = -1;
            renderText += '\nグループ ' + grpidx + "\n";
            for ( var idx = 0; idx < store.dataCnt && grpndx < 0; idx++ ) {
                if( store.grpRng[ idx ] >= 0 )
                    grpndx = store.grpRng[ idx ];
            }
            for ( var idx = 0; idx < store.dataCnt; idx++ ) {
                if( store.grpRng[ idx ] == grpndx ) {
                    var head = 'データ No.' + idx + '\t[ ';
                    for ( var ndx = 0; ndx < store.rngCnt; ndx++ ){
                        renderText += head + store.data[ idx ][ ndx ] + 
                            ( ( ndx == store.rngCnt -1 ) ? "" : ", ");
                        head = '';
                    }
                    renderText += ' ]\n';
                    store.grpRng[ idx ] = -1;
                }
            }
            grpidx++;
        }
        $( 'outarea' ).value = renderText;
     },
     
    renderInput : function(){
        var store = this.dataStore;
        var renderText = '';
        for ( var idx = 0; idx < store.dataCnt; idx++ ) {
            var head = 'データ No.' + idx + '\t[ ';
            for ( var ndx = 0; ndx < store.rngCnt; ndx++ ){
                renderText += head + store.data[ idx ][ ndx ] + 
                    ( ( ndx == store.rngCnt -1 ) ? "" : ", ");
                head = '';
            }
            renderText += ' ]\n';
        }
        $( 'inarea').value = renderText;
     }

}

function exec(){
    $( "inarea" ).value = '';
    $( "outarea" ).value = '';
    try {
        execInst = new ClusterAnalysis();
        execInst.renderInput();
        execInst.analysis();
        execInst.renderOutput();
    }
    catch( e ){ alert( e.description )}
}

function $( id ){
    return document.getElementById( id );
}

[ 最近のエントリーとその関連エントリー ]


2008年06月12日

予告.inと聞いて飛んでった

yokokuin.PNG 予告.inが話題になってるので早速飛んでって見てきました。
始めは犯行予告ジェネレータかと思いましたが、そうではなく、「インターネット上の犯行予告を集積・共有し、犯罪を未然に防ぐサービス」というもの。
2chやはてなやブログなどでポストされる犯行予告を刈り取って表示すると言うサービスです。
(開発した)矢野さんは11日夜、「増田寛也総務相が来年度予算の概算要求に、ネット上の犯行予告を検知できるソフトの開発費を盛り込む。費用は数億円かかる」という内容の報道を見て、「インターネットの仕組みを使えば、0億円で数時間でできる」と考え、実際に1人で2時間で作ったという。
ちなみに、冒頭の画像は、twitterのyokoku_inというアカウントをフォローしたときのものです。ワタシがフォローしているアカウントが少ないためか、すぐにいっぱいになってしまいました。みんな予告しすぎ。わーいオレも混ぜろ(←ゲス野郎)

[ 最近のエントリーとその関連エントリー ]


Google Dynamic Feed Control

GoogleDynamicFeedControl使ってみました。昔、ダイナミックドライブからティッカー探してきてフィード食わして見たいな事をやってみましたが、コレは便利です。ウィザードで作ることも出来るのでとても簡単。

フィードを複数指定することももちろん出来るのですが、先ほど10個くらいフィードを与えて表示したらブラウザが固まってしまいましたので、はてなの人気エントリのみを表示させています。
function LoadDynamicFeedControl()
{
    var feeds = [
        { url: 'http://b.hatena.ne.jp/hotentry?mode=rss' }
    ];
    var options = {
        numResults : 10,
        displayTime : 3000,
        fadeOutTime : 1000,
        scrollOnFadeOut : true,
        horizontal : true
    }
    new GFdynamicFeedControl( feeds, 'feed-control', options );
}
var obj = new Array();
google.load( 'feeds', '1' );
google.setOnLoadCallback( LoadDynamicFeedControl );
Loading...

[ 最近のエントリーとその関連エントリー ]


2008年06月10日

やる夫がデザインパターンをやるようです 第19回

≪第18回第20回≫

やる夫で学ぶデザインパターンとは何の関係もありませんが、このポストで300エントリになりました。結構書いてるなー。mojalogは始めてから丁度1年くらいになるのでおよそ1日に1回くらいはポストしている割合になります。読み返すとほんっとにくだらないポストばかりしていますが、見に来ていただいてる方には心より感謝申し上げます。ありがとうございます。(うれしいですと言いたいだけです。)

と言うわけで、今回はイテレータパターンで解決に向かいたいと思います。
public void listAbilityCollection(){

    // 潜在能力コレクションの取得・・・
    // 魔法コレクションの取得・・・

    ArrayList ptntItems = potentialCollection.getAbiiltyItems();
    AbilityItem[] mgcItems = magicCollection.getAbiiltyItems();

    // 潜在能力コレクションはArrayListを返すのでキャストしてリスト
    for( int idx = 0; idx < ptntItems.size(); idx++ ){
        AbilityItem abiItem = (AbilityItem)ptntItems.get( idx );
        System.out.println( abiItem.getName() );
        // ・・・
    }

    // 魔法コレクションは配列をそのまま返すので直接参照してリスト
    for( int idx = 0; idx < mgcItems.length; idx++ ){
        AbilityItem abiItem = mgcItems[ idx ];
        System.out.println( abiItem.getName() );
        // ・・・
    }

コードを見ると
PotentialCollectionのgetAbiiltyItems()も
MagicCollectionのgetAbiiltyItems()も
返す型さえ違わなければ、後はほとんど同じ動きをするクラスだお。。。
     ____
   /      \
  /  ─    ─\
/    (●)  (●) \
|       (__人__)    |
/     ∩ノ ⊃  /
(  \ / _ノ |  |
.\ “  /__|  |
  \ /___ / 





         |
     \  __  /
     _ (m) _
        |ミ|
      /  `´  \
   てことはとりあえずMagicCollectionのほうを
   ArrayListにして合わせちゃえば問題は解決するお。
       ____
     /⌒  ⌒\
   /( ●)  (●)\
  /::::::⌒(__人__)⌒::::: \
  |     |r┬-|     |
  \      `ー'´     / 











   / ̄ ̄\
 /  _ノ   \   おいおい。ちょっとまて。
 |   ( ●)(●)l 今は返す型が配列とArrayListだけだから
. |    (__人__) |どっちかに倒せばいいと思ってるようだが、
  |    ` ⌒´ | 今後、Vectorでコレクションを実装してる
.  |         } なんてのが見つかったらどうすんだ?
.  ヽ        }
   ヽ     ノ
   /    く
   /     ヽ





// 忍術は魔法と違う扱い
public class NinpoCollection implements Collection {
    Vector abilityItems;
    // Vectorでアビリティを扱う。
    public Vector getAbiiltyItems(){
        return abilityItems;
    }
}
         ___
       / ⌒  ⌒\
      / (○)  (○) \  え。いけなかったのかお。。。
    /   ///(__人__)/// \
     |   u.   `Y⌒y'´    |
      \       ゙ー ′  ,/
      /⌒ヽ   ー‐    ィヽ
      / rー'ゝ       〆ヽ
    /,ノヾ ,>      ヾ_ノ,|
    | ヽ〆        |´ | 





 ・・・オマエ、その日の気分で好き勝手に実装してるだろ。
 今は忍術を潜在能力や魔法と全く違う扱いで動かしてるが
 どうせそのうち企画がブースト機能とか言い出すんだから
 とっとと手を打っとけ。
   / ̄ ̄\
 /   _ノ  \
 |    ( ●)(●)
. |     (__人__)
  |     ` ⌒´ノ
.  |         }
.  ヽ        }
   ヽ     ノ
   /    く
   |     \
    |    |ヽ、二⌒)





    for( int idx = 0; idx < ptntItems.size(); idx++ ){
        AbilityItem abiItem = (AbilityItem)ptntItems.get( idx );

    for( int idx = 0; idx < mgcItems.length; idx++ ){
        AbilityItem abiItem = mgcItems[ idx ];

うーん。違うのは
1.走査の判定にsizeを返すかlengthを返すかと
2.要素の取得にget( idx )メソッドを使うか配列の添え字[ idx ]を使うかだけだお。。
         ____
       /      \
      /  ─    ─\
    /    (●)  (●) \
    |       (__人__)    | ________
     \      ` ⌒´   ,/ .| |          |
    ノ           \ | |          |
  /´                 | |          |
 |    l                | |          |
 ヽ    -一ー_~、⌒)^),-、   | |_________|
  ヽ ____,ノγ⌒ヽ)ニニ- ̄   | |  | 






   つまり、カプセル化したいのは
   1.「走査の判定」と
   2.「要素を返す」だお。
        / ̄ ̄ ̄\
        /        \
     /   ─   ─  ヽ
      |   (●)  (●)  | 
     \   (__人__) __,/
      /_______\   



要は、
    while( 走査の判定 ){
        要素を返す
    }

ができればいいんだお。インターフェイスは確定だお!!
public interface Iterator {
    boolean hasNext();  // 次はあるのか
    Object next();      // 次の要素を返す
}
          ____
       / \  /\  キリッ
.     / (ー)  (ー)\
    /   ⌒(__人__)⌒ \
    |      |r┬-|    |
     \     `ー'´   /
    ノ            \
  /´               ヽ
 |    l              \
 ヽ    -一''''''"~~``'ー--、   -一'''''''ー-、.
  ヽ ____(⌒)(⌒)⌒) )  (⌒_(⌒)⌒)⌒))







   / ̄ ̄\
 /   _ノ  \  よくわかってんじゃねーか。そのとおりだ。
 |    ( ●)(●)
. |     (__人__)
  |     ` ⌒´ノ
.  |         }
.  ヽ        }
   ヽ     ノ
   /    く
   |     \
    |    |ヽ、二⌒)






ぎゃひひ!おいらに任せとけば全てがうまくいくお!
          ____
        /_ノ  ヽ、_\
 ミ ミ ミ  o゚((●)) ((●))゚o      ミ ミ ミ
/⌒)⌒)⌒. ::::::⌒(__人__)⌒:::\   /⌒)⌒)⌒)
| / / /     |r┬-|    | (⌒)/ / / //
| :::::::::::(⌒)    | |  |   /  ゝ  :::::::::::/
|     ノ     | |  |   \  /  )  /
ヽ    /     `ー'´      ヽ /    /
 |    |   l||l 从人 l||l      l||l 从人 l||l
 ヽ    -一''''''"~~``'ー--、   -一'''''''ー-、
  ヽ ____(⌒)(⌒)⌒) )  (⌒_(⌒)⌒)⌒)) 







           ____ 
        /⌒  ⌒\ 
.      /( ―)  (―)\   ふん、ふーん。
     / ::::::⌒(__人__)⌒::::: \ ふ、んー。
    |      |r┬-|     |  
     \       `ー'´     / 
    ノ            \ 
  /´               ヽ                 カ 
 |    l   l||l 从人 l||l      l||l 从人 l||l   カ    タ 
 ヽ    -一''''''"~~``'ー--、   -一'''''''ー-、.     タ 
  ヽ ____(⌒)(⌒)⌒) )  (⌒_(⌒)⌒)⌒)) 
     ┌┬┬┐┌┬┬┬┐┌┬┬┬┐┌┬┬┬┐ 
  ,. - ''"| ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ρ ̄`l 
   ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ノ ̄ 






       ____
     /⌒  ー、\
   /( ―)  (―)\
  /::::::⌒(__人__)⌒:::::\  んー?
  |     |r┬-/ '    |
  \      `ー'´     / 





         ____
      /::::::─三三─\  ん・ん・んー?
    /:::::::: ( ○)三(○)\
    |::::::::::::::::::::(__人__)::::  | ________
     \:::::::::   |r┬-|  / | |          |
    ノ::::::::::::  `ー'´   \ | |          | 





           ___
     ____,./      \   すみません。
    ノ   /         \  既存のコードにインプリメントしたら
  /   /            \ドカドカ変更が入ってしまいましたお。
 |     |::..           ...::::| 
 ヽ    `一ー――――-、;;;;::/`一ー―-、
  ヽ____(⌒)(⌒)⌒) )  (⌒_(⌒)⌒)⌒))

public class MagicCollection implements Collection, Iterator {
    static final int MAX_ITEMS = 6;
    int numberOfItems = 0;
    AbilityItem[] abilityItems;

    // mod yaruo 何も返さない。使うな
    public AbilityItem[] getAbiiltyItems(){
//      mod yaruo
//        return abilityItems;
        return null;
    }

    // add yaruo
    boolean hasNext(){
        // 配列の走査判定
    }

    // add yaruo
    Object next(){
        // 次の要素を返す
    }
}





いやいやいや。ちょっとまて。どこに手を入れてやがる。
冒頭のソースでMagicCollectionそのものを走査に使ったか?
クライアントはカプセル化された走査がしたいだけだ。
Iteratorって言うインターフェイスを返すメソッドを追加してやりゃ
既存のコードの修正は数ステップだろが。
   / ̄ ̄\
 /  _ノ   \
 |   ( ○)(○)l
. |    (__人__) |
  |    ` ⌒´ |
.  |         }
.  ヽ        }
   ヽ     ノ
   /    く
   /     ヽ 
public class MagicCollection implements Collection {
    static final int MAX_ITEMS = 6;
    int numberOfItems = 0;
    AbilityItem[] abilityItems;

//  remove method. sucks
//    public AbilityItem[] getAbiiltyItems(){
//        return abilityItems;
//    }

    // イテレータを返す。
    public Iterator createIterator(){
        return new MagicCollectionItr( abilityItems );
    }
}

MagicCollection用のイテレータはこうだ
配列をパラメータにしたコンストラクタにしてある。
イテレータをimplementsしたクラスに走査処理を委譲してやればいい。
   / ̄ ̄\
 /   _ノ  \
 |    ( ●)(●)
. |     (__人__)
  |     ` ⌒´ノ
.  |         }
.  ヽ        }
   ヽ     ノ
   /    く
   |     \
    |    |ヽ、二⌒)
public class MagicCollectionItr implements Iterator {
    int curPos = 0;
    AbilityItem[] abilityItems;
    public MagicCollectionItr( AbilityItem[] abilityItems ){
        this.abilityItems = abilityItems;
    }

    // 配列の走査判定を行う。
    boolean hasNext(){
        return ( curPos >= abilityItems.length || abilityItems[ curPos ] == null ) ? false : true;
    }

    // 次の要素を返す
    Object next(){
        AbilityItem curAbi = abilityItems[ curPos ];
        curPos++;
        return curAbi;
    }
}



いいかやる夫。既存のコードに対する修正はできるだけ最小限に抑えろ。
仕様変更における既存のコードというものは、
「バグのない適切なコードにするために、多くの時間を費やしたモノ」
と考えるんだ。事実そうじゃなくてもそう思うんだ。

だから既存のコードで振る舞いを変更するみたいなことは極力するな。
今回で言えば、コレクションの走査はもともと
MagicCollectionやPotentialCollectionになかっただろう。
ココに走査するコードを突っ込んだのはオマエの勘違いだとして、
「変更」は最小限にして「拡張」を自由に行うように癖をつけろ。

俺が書いたMagicCollectionItrは、
MagicCollectionからコレクションを取り出して
捜査できるように拡張したコードだ。
今度はこのコードに時間をかけてバグのない適切なコードにするように
デバッグしてコードの品質を積み上げていけ。
   / ̄ ̄\
 /  _ノ   \
 |   ( ●)(●)l
. |    (__人__) |
  |    ` ⌒´ |
.  |         }
.  ヽ        }
   ヽ     ノ
   /    く
   /     ヽ 






いいかやる夫。
・・・・・・・・
今度はこのコードに時間をかけてバグのない適切なコードにするように
デバッグしてコードの品質を積み上げていけ・・・・?
`――――――――――――○―――――――――――――――’
              O
                o
         ____
       /_ノ   ヽ_\
      /( ●) ( ●)\
    / ::::::⌒(__人__)⌒:::::\
    |        ̄      |
    \              / 






     / ̄ ̄\  えー。単体テストくらいは自分でやってほしいお。
   /       \       ___
   |::::::   U    |    /     \
  . |::::::::::: U   |   /⌒   ⌒  \
    |::::::::::::::    | / (●) (●)   \
  .  |::::::::::::::    }  |    (__人__)     | 
  .  ヽ::::::::::::::  U }  \   ` ⌒´     _/
     ヽ::::::::::  ノ    |           \
     /:::::::::::: く     | |         |  |
 ―――|:::::::::::::::: \――┴┴―――――┴┴―― 

[ 最近のエントリーとその関連エントリー ]