« 2009年01月 | メイン | 2009年03月 »

2009年02月 アーカイブ

2009年02月01日

kanasanというハンドルネームって

「kanasan」って名前はあれだ。「kanasanさん」って違和感があるので「kanasan」になる。かといってkanasanが嫌われても「kanaのばかやろう!!!」とはならない。強制的に相手に敬称を使わせつつも、なんとなく呼び捨て感覚も持たせる事ができる。意外と便利なのかもしれない。

2009年02月05日

やぐら茶屋について

やぐら茶屋とは
店内では、ウコン茶と黒烏龍茶等から選択できる。
関西を中心とし全国展開しており、日々、多くの人が訪れている。
訪れたことのなくてもその存在を知る人は多く、発祥の地である関西においてはその知名度は老若男女問わず高い。
そのテレビCMの映像は実に歴史を感じさせる内容となっている。
「はあ~どんとこい」というかけ声が有名である。
お詫び
誠に申し訳ありません。
上記の文は説明不足でした。
補足説明を括弧書きで追加したものを下に掲示します。
これをもってお詫びと替えさせて頂けますようよろしくお願い申し上げます。
やぐら茶屋とは(補足説明あり)
(居酒屋である)店内では、(どうしてもお茶を飲みたい場合、)ウコン茶と黒烏龍茶等(のソフトドリンクの中)から選択できる。
関西を中心とし全国展開しており、日々、多くの人が(定時後、呑みに)訪れている。
(インパクトのあるテレビCMからか)訪れたことのなくてもその存在を知る人は多く、発祥の地である関西においては(深夜帯に流れる大量のテレビCMの影響のため)その知名度は老若男女問わず高い。
その(バブル時代に作られたと思われる)テレビCMの映像は(登場する女性の服装や化粧から)実に歴史を感じさせる内容となっている。
(CMの最後に流れる)「はあ~どんとこい」という(何とも例えようもない)かけ声が有名である。

市町村変遷パラパラ地図を見やすくするグリモンParaParaMapZoomer

2009/02/08 追記
コメント欄でやりとりされている通り、本家の「市町村変遷パラパラ地図」に拡大縮小機能が導入されそうです。
このUserScriptは不要になりますが、entryはこのまま残しておきます。
追記以上
市町村変遷パラパラ地図凄いですね。
よく膨大な情報をまとめられたと敬意を表します。
ただ、表示される地図が大きすぎて環境によっては一部しか見れません。
そこで、地図を拡大縮小するGreasemonkeyをつくりました。
これで大抵の環境でも快適に表示できます。
2009/02/06 追記
市町村変遷パラパラ地図の更新履歴でこのGreasemonkeyに言及いただきました。
これに伴い少々修正しました。
[http://mujina.sakura.ne.jp/history/]以下で実行していた物に[http://www.mujina.sakura.ne.jp/history/]を追加しました。
作者さんも画像の大きさが気になっていたそうです。
ただ、Greasemonkeyのコード内に一部のブラウザでは動かない処理が入っていますので、そのままではページへの追加ができません。
ですが、ページへの組み込み作業、よろしければお手伝いします。

2009年02月07日

profilerという処理速度計測用ライブラリ

IEでもFirebugについてくる処理時間計測用のProfileという機能が欲しくて作ってみた。
IE8からはFirebug相当のデバッグツールがついてくるのでいいけど、IE6,IE7あたりでは結構使えるかも。
他のBrowserでも使えるはず。
FirebugのProfileのように勝手に計測してくれるのではなく、計測部分にコードを埋め込まないといけないのはしかたがないと思って欲しい。
以下、ソースとその後に使い方。
/*
================================================================================
    Name            :   profiler
    In          :   [none]  
    Out         :   [none]  
    Note            :   処理時間を計測する
--------------------------------------------------------------------------------
    Version     :   Ver1.0.0        |   2009/02/07  |   新規作成
--------------------------------------------------------------------------------
    License     :   MIT license
    URL         :   www.kanasansoft.com
================================================================================
*/

var profiler=(
    function(){
        var timeRun={};
        var resultData={};
        var subResultData={};
        var startForMain=function(name){
            if((name in resultData)&&resultData.hasOwnProperty(name)){
            }else{
                timeRun[name]=[];
                resultData[name]={
                    "count":0,
                    "sum":0,
                    "min":Number.POSITIVE_INFINITY,
                    "max":Number.NEGATIVE_INFINITY
                };
                subResultData[name]={};
            }
            var body={
                "time":new Date().getTime(),
                "index":timeRun[name].length
            };
            timeRun[name].push(body);
            return getForChain(name,body);
        }
        var stopForMain=function(name,subname){
            if(timeRun[name].length==0){
                return false;
            }
            var timeCur=timeRun[name].pop();
            var passed=new Date().getTime()-timeCur.time;
            saveResult(name,subname,passed);
        }
        var stopForChain=function(name,body){
            return function(subname){
                var index=void(0);
                for(var i=Math.min(body.index,timeRun[name].length-1);i>=0;i--){
                    if(body==timeRun[name][i]){
                        index=i;
                        break;
                    }
                }
                if(index==void(0)){
                    return false;
                }
                var timeCur=timeRun[name].slice(index,index+1)[0];
                var passed=new Date().getTime()-timeCur.time;
                saveResult(name,subname,passed);
                timeRun[name]=timeRun[name].slice(0,index).concat(timeRun[name].slice(index+1));
            }
        };
        var getForChain=function(name,body){
            return {
                "stop":stopForChain(name,body),
                "dummy":function(){return this;}
            }
        }
        var saveResult=function(name,subname,passed){
            if(subname){
                if((subname in subResultData[name])&&subResultData[name].hasOwnProperty(subname)){
                }else{
                    subResultData[name][subname]={
                        "count":0,
                        "sum":0,
                        "min":Number.POSITIVE_INFINITY,
                        "max":Number.NEGATIVE_INFINITY
                    };
                }
                subResultData[name][subname].count++;
                subResultData[name][subname].sum+=passed;
                subResultData[name][subname].min=Math.min(subResultData[name][subname].min,passed);
                subResultData[name][subname].max=Math.max(subResultData[name][subname].max,passed);
            }else{
                resultData[name].count++;
                resultData[name].sum+=passed;
                resultData[name].min=Math.min(resultData[name].min,passed);
                resultData[name].max=Math.max(resultData[name].max,passed);
            }
        }
        var result=function(){
            var results=[];
            results.push(
                [
                    "start name",
                    "stop name",
                    "count",
                    "minimal time(ms)",
                    "maximum time(ms)",
                    "total time(ms)",
                    "average time(ms)"
                ].join("\t")
            );
            for(var name in resultData){
                if(resultData.hasOwnProperty(name)){
                    var running=[
                        "["+name+"]",
                        "(running)",
                        timeRun[name].length,
                        "-",
                        "-",
                        "-",
                        "-"
                    ].join("\t");
                    var buf={
                        "count":0,
                        "sum":0,
                        "min":Number.POSITIVE_INFINITY,
                        "max":Number.NEGATIVE_INFINITY
                    };
                    var subResults=[];
                    if(resultData[name].count!=0){
                        buf.count+=resultData[name].count;
                        buf.sum+=resultData[name].sum;
                        buf.min=Math.min(resultData[name].min,buf.min);
                        buf.max=Math.max(resultData[name].max,buf.max);
                        subResults.push(
                            [
                                "-",
                                "(no name)",
                                resultData[name].count,
                                resultData[name].min,
                                resultData[name].max,
                                resultData[name].sum,
                                resultData[name].sum/resultData[name].count
                            ].join("\t")
                        );
                    }
                    for(var subname in subResultData[name]){
                        if(subResultData[name].hasOwnProperty(subname)){
                            buf.count+=subResultData[name][subname].count;
                            buf.sum+=subResultData[name][subname].sum;
                            buf.min=Math.min(subResultData[name][subname].min,buf.min);
                            buf.max=Math.max(subResultData[name][subname].max,buf.max);
                            subResults.push(
                                [
                                    "-",
                                    "["+subname+"]",
                                    subResultData[name][subname].count,
                                    subResultData[name][subname].min,
                                    subResultData[name][subname].max,
                                    subResultData[name][subname].sum,
                                    subResultData[name][subname].sum/subResultData[name][subname].count
                                ].join("\t")
                            );
                        }
                    }
                    results.push(running);
                    if(buf.count!=0){
                        results.push(
                            [
                                "-",
                                "(all)",
                                buf.count,
                                buf.min,
                                buf.max,
                                buf.sum,
                                buf.sum/buf.count
                            ].join("\t")
                        );
                    }
                    results=results.concat(subResults);
                }
            }
            return results.join("\n");
        }
        return {
            "start":startForMain,
            "stop":stopForMain,
            "result":result
        }
    }
)();
一番単純な例
fnc1とfnc2の計測は以下のようにする。
profiler.start("fnc1");//計測開始に名前を指定
fnc1();//100msかかる処理
profiler.stop("fnc1");//名前を指定して計測終了
profiler.start("fnc2");
fnc2();//200msかかる処理
profiler.stop("fnc2");
alert(profiler.result());//tsvで処理結果がかえる。実際にはコピーしてexcelなんかにペーストがお勧め。

//処理結果(説明用に整形)
start name  stop name   count   minimal time(ms)    maximum time(ms)    total time(ms)  average time(ms)
[fnc1]      (running)   0       -                   -                   -               -
-           (all)       1       100                 100                 100             100
-           (no name)   1       100                 100                 100             100
[fnc2]      (running)   0       -                   -                   -               -
-           (all)       1       200                 200                 200             200
-           (no name)   1       200                 200                 200             200
関数内部に記述
関数内に記述する場合は次のような感じで。
function fnc3(){
    profiler.start("fnc3");
    //何らかの処理
    profiler.stop("fnc3");
}
fnc3();
alert(profiler.result());
関数内の分岐にも対応
関数内を書き変えてまで計測計測するのは抵抗があるかもしれないけど、これは終了判定別に記録するため。
例えば、if文内でreturnを実行して関数を終わらせる場合に重宝するかと思う。
function fnc4(){
    profiler.start("fnc4");
    var num=Math.floor(Math.random()*10);//0から9までのランダムな値
    if(num==0){
        profiler.stop("fnc4","num==0");//処理終了に名前を指定
        return;
    }else if(num<5){
        profiler.stop("fnc4","num<5");//処理終了に名前を指定
        return;
    }else{
        profiler.stop("fnc4","other");//処理終了に名前を指定
        return;
    }
}
for(var i=0;i<1000;i++){
fnc4();
}
alert(profiler.result());

//処理結果(説明用に整形)
start name  stop name   count   minimal time(ms)    maximum time(ms)    total time(ms)  average time(ms)
[fnc4]      (running)   0       -                   -   -   -
-           (all)       1000    0                   1                   18              0.018
-           [num<5]     412     0                   1                   6               0.014563106796116505
-           [num==0]    84      0                   1                   2               0.023809523809523808
-           [other]     504     0                   1                   10              0.01984126984126984
profilerを変数に保存して使う
start実行時に戻り値を変数に入れておけば、stopの時に名前を指定しなくても止める事ができる。
これにより停止順を個別に指定できる。
下の例は交互に実行と停止を行なった場合。
変数を使わなければ(1)は(2)の約3倍の時間が測定されるけど、下の例であれば(1)と(2)はほぼ同じ時間になる。
var p5_1=profiler.start("fnc5");//(1)
fnc5();
var p5_2=profiler.start("fnc5");//(2)
fnc5();
p5_1.stop();//先に生成したprofilerを停止
fnc5();
p5_2.stop();//後で生成したprofilerを停止
alert(profiler.result());
マトリックス的に使う
以下のようにすると、マトリックスを生成可能。
これはprofilerを変数に保存できる機能と、変数に保持したprofilerのstop処理の引数に終了時の名前を指定できることを応用した例。
function fnc6(){
    var profiler6;
    var numstart=Math.floor(Math.random()*3)+1;//1から3までのランダムな値
    if(numstart==1){
        profiler6=profiler.start("first");
    }else if(numstart==2){
        profiler6=profiler.start("second");
    }else{
        profiler6=profiler.start("third");
    }
    var numstop=Math.floor(Math.random()*3)+1;//1から3までのランダムな値
    if(numstop==1){
        profiler6.stop("I");
    }else if(numstop==2){
        profiler6.stop("II");
    }else{
        profiler6.stop("III");
    }
}
for(var i=0;i<1000;i++){
    fnc6();
}
alert(profiler.result());

//処理結果(説明用に整形)
start name  stop name   count   minimal time(ms)    maximum time(ms)    total time(ms)  average time(ms)
[second]    (running)   0       -                   -                   -               -
-           (all)       342     0                   1                   9               0.02631578947368421
-           [I]         112     0                   1                   4               0.03571428571428571
-           [II]        109     0                   1                   1               0.009174311926605505
-           [III]       121     0                   1                   4               0.03305785123966942
[first]     (running)   0       -                   -                   -               -
-           (all)       319     0                   1                   4               0.012539184952978056
-           [II]        106     0                   1                   2               0.018867924528301886
-           [III]       117     0                   1                   1               0.008547008547008548
-           [I]         96      0                   1                   1               0.010416666666666666
[third]     (running)   0       -                   -                   -               -
-           (all)       339     0                   1                   7               0.02064896755162242
-           [I]         112     0                   1                   2               0.017857142857142856
-           [II]        109     0                   1                   3               0.027522935779816515
-           [III]       118     0                   1                   2               0.01694915254237288
処理をメソッドチェーンで
ここからはマニアックな機能。
こんな書き方も可能。
中間処理用にdummyというメソッドがある。
特に一時的な処理や後で削除したい処理を書く時に明示的に書く事もできる。
//一般的な書き方その1
profiler.start("fnc7");//後で消す
fnc7();//後で消す
profiler.stop("fnc7");//後で消す

//一般的な書き方その2
profiler.start("fnc7");fnc7();profiler.stop("fnc7");//後で消す

//この方がわかりやすい?
profiler.start("fnc7").dummy(fnc7()).stop();//後で消す
応用例
なんの役に立つかはわからないけど次のような書き方も可能。
var num=3;
function fnc8(){num--;if(num==0){alert(profiler.result());}}
function fnc8_1(){arguments.callee._profiler_.stop();fnc8();}
function fnc8_2(){arguments.callee._profiler_.stop();fnc8();}
function fnc8_3(){arguments.callee._profiler_.stop();fnc8();}
fnc8_1._profiler_=profiler.start("fnc8_1");
fnc8_2._profiler_=profiler.start("fnc8_2");
fnc8_3._profiler_=profiler.start("fnc8_3");
setTimeout(fnc8_1,Math.random()*10000);
setTimeout(fnc8_2,Math.random()*10000);
setTimeout(fnc8_3,Math.random()*10000);

//処理結果(説明用に整形)
start name  stop name   count   minimal time(ms)    maximum time(ms)    total time(ms)  average time(ms)
[fnc8_1]    (running)   0       -                   -                   -               -
-           (all)       1       8626                8626                8626            8626
-           (no name)   1       8626                8626                8626            8626
[fnc8_2]    (running)   0       -                   -                   -               -
-           (all)       1       1384                1384                1384            1384
-           (no name)   1       1384                1384                1384            1384
[fnc8_3]    (running)   0       -                   -                   -               -
-           (all)       1       9703                9703                9703            9703
-           (no name)   1       9703                9703                9703            9703
最後に
開始終了処理に名前が指定できる点、変数に保持できる点、メソッドチェーンが可能な点、この三点の機能があるので、ここにあげた方法だけでなくアイディア次第で色々な計測ができると思う。
しかし、処理結果生成の処理がどうも綺麗になっていなくて気持ち悪い。
functionでまとめたい場所も多々ある。
でも、functionを呼ぶのは処理コストが大きいらしい。
計測そのものに時間がかかると、計測結果に影響してしまうのでデータ収集時にはできるだけ複雑な処理をしないようにしている。
その影響でresultメソッド内が複雑になっている。
それでももうちょっとなんとかなかないかと思ってたり...。

2009年02月09日

コミュニティに参加しはじめてから変わったこと

ブログにネタエントリーが増えた。

2009年02月14日

Emacs移行経過(2009/02/14)

前回から相当時間が経っているけど改めて記録。
経過
色々な場所で色々な人に色々と教えてもらった結果がこれ。それなのに前回とあまり変化していない。ただ意識せずに使っているものもあるので抜けがいくつかあるはず。ここまで覚えたら作業効率は多少落ちる時もあるけどとりあえず一通りのことはできるようになった。置換処理が大量にあるときは他のエディタを併用しているのはなんとかしたい。
完全に覚えた完結キー
C-f forward-char 右に移動
C-b backward-char 左に移動
C-n next-line 下に移動
C-p previous-line 上に移動
C-a move-biginning-on-line 行頭に移動
C-e move-end-of-line 行末
C-d delete-char
C-g keyboard-quit プレフィックスキーを中断する場合は2回
C-SPC   set-mark-command
C-x o   other-window
C-x C-c save-buffers-kill-emacs
C-g C-g プレフィックスキー(完結していないキー列)を中断
M-w kill-ring-save copyの事
C-w kill-region cutの事
C-y yank pasteの事
C-SPC C-SPC transient-mark-mode 範囲選択開始
C-m newline
C-k kill-line
C-x C-f find-file
C-x C-s save-buffer
C-x k   kill-buffer
C-h backward-delete-char    global-set-keyで変更
C-x help    プレフィックスキーで始まるコマンドの一覧(プレフィックスキー入力後)
C-x help RET k  describe-key
C-x help RET f  describe-function
C-x help RET v  describe-variable
M-< beginning-of-buffer(数引数対応)
M-> end-of-buffer
C-v scroll-up
M-v scroll-down
M-/ dabbrev-expand
C-/ undo
C-q quoted-insert   (C-q C-iしか使用せず)
C-s isearch-forward

覚えかけている完結キー
M-f forward-word
M-b backward-word
C-x RET c [char code] RET C-x C-f 文字コードを指定して開く
C-x RET c [char code] RET C-x C-v RET 文字コードを指定して開き直す
C-x C-u upcase-region
C-x C-l downcase-region

覚えたい完結キー
M-d kill-word
M-DEL   backward-kill-word
C-x z   repeat
検索系全般
キーマクロ系

よく間違える完結キー
なし

保留中の完結キー
C-j newline-and-indent
C-x =   what-cursor-position
C-z iconify-or-deiconify-frame
M-r move-to-window-line
C-x C-n set-goal-column
C-u C-x C-n ???

忘れていた完結キー
C-i indent-for-tab-command
C-o open-line

完全に覚えたコマンド
set-variable

覚えかけているコマンド
なし

覚えたいコマンド
goto-char
goto-line

保留中のコマンド
なし

完全に覚えた変数
tab-width

覚えかけている変数
column-number-mode

覚えたい変数
なし

保留中の変数
read-quoted-char-radix
目標
『入門 GNU Emacs』という本を買ったので通読を目指す。2章までは読んだ。3章まではとりあえず読んで後は必要に応じて参照する感じ。

2009年02月22日

GreasemonkeyのGM_setValueで保存できるデータの種類

GreasemonkeyのAPIであるGM_setValueで保存できるデータの種類に制限があるのをご存知ですか?
それを調べるために、次のようなUserScriptを実行してみます。
但し、unsafeWindowを使っているので信用のおけるsiteで実行してください。
GM_xxxValueTest.user.js
// ==UserScript==
// @name        GM_xxxValueTest
// @namespace   http://www.kanasansoft.com/
// @include     *
// ==/UserScript==

(
    function(){
        var data=[
            ["Boolean",true],
            ["Number",12345],
            ["Number",12345.67890],
            ["String","12345"],
            ["Array",[1,2,3,4,5,"a","b","c"]],
            ["Date",new Date()],
            ["Math",Math],
            ["Regexp",/./],
            ["Function",function(){return 12345;}],
            ["Object",{"a":1,"b":2}],
            ["Window",unsafeWindow],
            ["Document",unsafeWindow.document],
            ["body",unsafeWindow.document.body]
        ];
        var test=function(name,value){
            return function(){
                try{
                    GM_setValue(name,value);
                    var result=GM_getValue(name);
                    console.log(name,value,result,result.constructor);
                }catch(e){
                    console.log(name,value,e);
                }
            }
        };
        for(var i=0;i<data.length;i++){
            var name=data[i][0];
            var value=data[i][1];
            setTimeout(test(name,value),0);
        }
    }
)();
結果は次のとおり。
Boolean・Number・Stringしか保存されません。
少数にも対応していません。
エラーメッセージにも「Error: Unsupported type for GM_setValue. Supported types are: string, bool, and 32 bit integers.」と書かれています。
Windowはともかく少数や配列は保存できそうなものですが無理です。それは何故でしょうか。
その理由はデータの保存先にあります。
保存先はFirefox各種動作を制御している設定値の中です。
Windowsにおけるレジストリと同じようなものだと思ってもらえれば、慎重にならないといけないのはわかってもらえると思います。
それでは、これをご理解頂いた上で、アドレスバーで「about:config」を入力し、設定値を表示します。
ここで表示される値は全て真偽値・整数値・文字列のどれかです。
それは、右クリックし「新規作成」のサブメニューを見ても明らかです。
Greasemonkeyで保存した値は本当にここに保存されているのでしょうか。
「フィルタ」テキストボックスに「GM_xxxValueTest」と入力してみましょう。
以下のようなものが表示されると思います。
GM_setValueで保存した値が確認できました。
真偽値・整数値・文字列以外の値を保存したい場合には、JSON等に変換して保存すればいいでしょう。
Firefox3.1からはJSONオブジェクトが標準になるそうなので期待して待っていましょう。
Google

タグ クラウド