;;;void function(window, undefined){
    var $ = {
        now:(new Date()).getTime(),
        type2string:{},
        type:function(s){
            return s == null ? 'empty' : ($.type2string[Array.prototype.toString.call(s)] || 'object');
        },
        switch:function(){
            var args = Array.prototype.slice.call(arguments), fn = this;
            var i = 0, p , ff = fn[$.now], path = '';
            while(p = args[i++]){ path += $.type(p) + ','; }
            if(path){ ff = ff[path] }else{ ff = ff['fn'] }
            if($.type(ff)!='function'){ 
                if(ff=fn[$.now]['fn']){
                    return ff.apply(fn,args);
                }
                throw new Error('function undefined!');
            }
            return ff.apply(fn,args);
        },
        defined:function(type,fn,source){
            var types = fn[$.now];
            if(!types){ types = fn[$.now] = {} }
            if($.type(type)=='function'){
                types['fn'] = type;
                return fn;
            }
            types[type + ','] = source;
            return fn;
        }
    };
    ('Object,Function,String,Number,Boolean,Date,RegExp').replace(/[^,]+/g,function(a){
        $.type2string['[object ' + a + ']'] = a.toLowerCase();
    });
    window.fn = {
        defined:function(type,f){
            var fn = function(){ return $.switch.apply(fn,arguments); };
            $.defined(type,fn,f);
            fn['defined'] = function(type,f1){ return $.defined(type,fn,f1); };
            return fn;
        }
    };
}(this);
var a = fn.defined(function(a,b){
    alert([a,b])
}).defined('string,string',function(s1,s2){
    alert(['string|string',s1,s2]);
}).defined('string,object',function(s,o){
    alert(['string|object',s,o])
});
a('1');
a('1','2');
a('1',{});
a('1',true);