!function(context, undefined) {

    var Cache, Events, E, Template, XHR,
        noop = function() {};

    Cache = function Cache() {
        this._data = {};
    };
    
    Cache.prototype = {

        get: function(key) {
            return this._data[key] || undefined;
        },
        
        set: function(key, value) {
            this._data[key] = value;
            return this._data[key];
        }

    };
    
    Events = function(key) {
        if(!Events._listeners.get(key)) {
            Events._listeners.set(key, new E());
        }
        
        return Events._listeners.get(key);
    };
    
    Events._listeners = new Cache();
    
    E = function() {
        this._methods = [];
    };
    
    E.prototype.fire = function() {
        var i = 0, len = this._methods.length;
        
        for( ; i<len; i++) {
            this._methods[i].apply(null, arguments);
        }
    };
    
    E.prototype.bind = function(fn) {
        this._methods[this._methods.length] = fn;
    };
    
    E.prototype.unbind = function() {
        this._methods = [];
    };
    
    Template = {
        
        DEBUG: false,
        
        _loaded: new Cache(),
        _cache: new Cache(),
    
        load: function(url, fn) {
            var xhr     = new XMLHttpRequest(),
                fn      = fn || noop,
                that    = this;
            
            if(this.DEBUG) {
                url += '?' + (new Date()).getTime();
            }
            
            if(!this._loaded.get(url)) {
                
                xhr.open('GET', url);
                xhr.onreadystatechange = function() {

                    if(this.readyState === 4 && this.status === 200) {
                        that._loaded.set(url, this.responseText);
                        fn(this.responseText);
                    }

                };
                xhr.send(null);
                
            } else {
            
                fn(this._loaded.get(url));
            
            }
        },
        
        render: function(str, data) {
            var data = data || {};
            
            if(!this._cache.get(str)) {
                this._cache.set(str, _.template(str));
            }
            
            return this._cache.get(str)(data);
        }
    
    };
    
    context.Cache       = Cache;
    context.Evt         = Events;
    context.Template    = Template;

}(this);

