var addListener = (function() {
    if ( window.addEventListener ) {
        // DOM Events 実装ブラウザ用
        return function(target, type, func) {
            target.addEventListener(type, func, false);
            return true;
        };
    } else if( window.attachEvent ) {
        // IE 用
        return function(target, type, func) {
            // ----- 局所変数の宣言 -----
            var i = 0;
            var hasBeenAdded = false;
            // ----- 処理 -----
            // target のプロパティに管理用配列を追加
            if( ! target._vividcode_el ) {
                target._vividcode_el = new Array(0);
                // unload 時に解体
                window.attachEvent("onunload", function myself(evt) {
                    // 配列の中身を null に
                    for( i = 0; i < target._vividcode_el.length; i++ ) {
                        target._vividcode_el[i][0] = null;
                        target._vividcode_el[i][1] = null;
                        target._vividcode_el[i] = null;
                    }
                    // 配列への参照をなくす
                    target._vividcode_el = null;
                    // 自分自身を detachEvent
                    window.detachEvent("onunload", myself);
                });
            }
            // 既に登録済みかどうかチェックする
            hasBeenAdded = false;
            for( i = 0; i < target._vividcode_el.length; i++ ) {
                if( target._vividcode_el[i][0] === func ) {
                    hasBeenAdded = true;
                    break;
                }
            }
            // 未登録の場合, 登録する
            if( ! hasBeenAdded ) {
                i = target._vividcode_el.length;
                target._vividcode_el[i] = new Array(func, function(evt) {
                        // evt.currentTarget を指定
                        evt.currentTarget = target;
                        // EventListener 起動
                        func(evt);
                    });
            }
            // addEventListener の方では, 同じ関数を二重に登録しようとすると 2 個目は破棄される. 
            // attachEvent の方だと 2 個目は破棄されない. 同一の動作になるよう, まず detachEvent する. 
            target.detachEvent("on"+type, target._vividcode_el[i][1]);
            target.attachEvent("on"+type, target._vividcode_el[i][1]);
            // unload 時に detachEvent しなければメモリリークを起こすとどこかで読んだので念のため. 
            // 必要以上に detachEvent する場合もあるが実害はないと思う 
            // (さすがに動作時間はそんなに変わらないでしょう) ので気にしないことにする.
            window.attachEvent("onunload", (function () {
                // target._vividcode_el も onunload イベントで解体するので, 
                // 下手すると参照前に解体されている可能性もある. 
                // よって, あらかじめ局所変数に読み込んでおく.
                var func = target._vividcode_el[i][1];
                return function myself(evt) {
                    target.detachEvent("on"+type, func);
                    window.detachEvent("onunload", myself);
                };
            })() );
            return true;
        };
    } else {
        // addEventListener も attachEvent も持ってないブラウザ用
        return function(target, type, func) {
            return false;
        };
    }
})();
