Show:
                            /**
                             * The Cache utility provides a common configurable interface for components to
                             * cache and retrieve data from a local JavaScript struct.
                             *
                             * @module cache
                             * @main
                             */
                            
                            /**
                             * Provides the base class for the YUI Cache utility.
                             *
                             * @submodule cache-base
                             */
                            var LANG = Y.Lang,
                                isDate = Y.Lang.isDate,
                            
                            /**
                             * Base class for the YUI Cache utility.
                             * @class Cache
                             * @extends Base
                             * @constructor
                             */
                            Cache = function() {
                                Cache.superclass.constructor.apply(this, arguments);
                            };
                            
                                /////////////////////////////////////////////////////////////////////////////
                                //
                                // Cache static properties
                                //
                                /////////////////////////////////////////////////////////////////////////////
                            Y.mix(Cache, {
                                /**
                                 * Class name.
                                 *
                                 * @property NAME
                                 * @type String
                                 * @static
                                 * @final
                                 * @value "cache"
                                 */
                                NAME: "cache",
                            
                            
                                ATTRS: {
                                    /////////////////////////////////////////////////////////////////////////////
                                    //
                                    // Cache Attributes
                                    //
                                    /////////////////////////////////////////////////////////////////////////////
                            
                                    /**
                                    * @attribute max
                                    * @description Maximum number of entries the Cache can hold.
                                    * Set to 0 to turn off caching.
                                    * @type Number
                                    * @default 0
                                    */
                                    max: {
                                        value: 0,
                                        setter: "_setMax"
                                    },
                            
                                    /**
                                    * @attribute size
                                    * @description Number of entries currently cached.
                                    * @type Number
                                    */
                                    size: {
                                        readOnly: true,
                                        getter: "_getSize"
                                    },
                            
                                    /**
                                    * @attribute uniqueKeys
                                    * @description Validate uniqueness of stored keys. Default is false and
                                    * is more performant.
                                    * @type Boolean
                                    */
                                    uniqueKeys: {
                                        value: false
                                    },
                            
                                    /**
                                    * @attribute expires
                                    * @description Absolute Date when data expires or
                                    * relative number of milliseconds. Zero disables expiration.
                                    * @type Date | Number
                                    * @default 0
                                    */
                                    expires: {
                                        value: 0,
                                        validator: function(v) {
                                            return Y.Lang.isDate(v) || (Y.Lang.isNumber(v) && v >= 0);
                                        }
                                    },
                            
                                    /**
                                     * @attribute entries
                                     * @description Cached entries.
                                     * @type Array
                                     */
                                    entries: {
                                        readOnly: true,
                                        getter: "_getEntries"
                                    }
                                }
                            });
                            
                            Y.extend(Cache, Y.Base, {
                                /////////////////////////////////////////////////////////////////////////////
                                //
                                // Cache private properties
                                //
                                /////////////////////////////////////////////////////////////////////////////
                            
                                /**
                                 * Array of request/response objects indexed chronologically.
                                 *
                                 * @property _entries
                                 * @type Object[]
                                 * @private
                                 */
                                _entries: null,
                            
                                /////////////////////////////////////////////////////////////////////////////
                                //
                                // Cache private methods
                                //
                                /////////////////////////////////////////////////////////////////////////////
                            
                                /**
                                * @method initializer
                                * @description Internal init() handler.
                                * @param config {Object} Config object.
                                * @private
                                */
                                initializer: function(config) {
                            
                                    /**
                                    * @event add
                                    * @description Fired when an entry is added.
                                    * @param e {EventFacade} Event Facade with the following properties:
                                     * <dl>
                                     * <dt>entry (Object)</dt> <dd>The cached entry.</dd>
                                     * </dl>
                                    * @preventable _defAddFn
                                    */
                                    this.publish("add", {defaultFn: this._defAddFn});
                            
                                    /**
                                    * @event flush
                                    * @description Fired when the cache is flushed.
                                    * @param e {EventFacade} Event Facade object.
                                    * @preventable _defFlushFn
                                    */
                                    this.publish("flush", {defaultFn: this._defFlushFn});
                            
                                    /**
                                    * @event request
                                    * @description Fired when an entry is requested from the cache.
                                    * @param e {EventFacade} Event Facade with the following properties:
                                    * <dl>
                                    * <dt>request (Object)</dt> <dd>The request object.</dd>
                                    * </dl>
                                    */
                            
                                    /**
                                    * @event retrieve
                                    * @description Fired when an entry is retrieved from the cache.
                                    * @param e {EventFacade} Event Facade with the following properties:
                                    * <dl>
                                    * <dt>entry (Object)</dt> <dd>The retrieved entry.</dd>
                                    * </dl>
                                    */
                            
                                    // Initialize internal values
                                    this._entries = [];
                                    Y.log("Cache initialized", "info", "cache");
                                },
                            
                                /**
                                * @method destructor
                                * @description Internal destroy() handler.
                                * @private
                                */
                                destructor: function() {
                                    this._entries = [];
                                    Y.log("Cache destroyed", "info", "cache");
                                },
                            
                                /////////////////////////////////////////////////////////////////////////////
                                //
                                // Cache protected methods
                                //
                                /////////////////////////////////////////////////////////////////////////////
                            
                                /**
                                 * Sets max.
                                 *
                                 * @method _setMax
                                 * @protected
                                 */
                                _setMax: function(value) {
                                    // If the cache is full, make room by removing stalest element (index=0)
                                    var entries = this._entries;
                                    if(value > 0) {
                                        if(entries) {
                                            while(entries.length > value) {
                                                entries.shift();
                                            }
                                        }
                                    }
                                    else {
                                        value = 0;
                                        this._entries = [];
                                    }
                                    return value;
                                },
                            
                                /**
                                 * Gets size.
                                 *
                                 * @method _getSize
                                 * @protected
                                 */
                                _getSize: function() {
                                    return this._entries.length;
                                },
                            
                                /**
                                 * Gets all entries.
                                 *
                                 * @method _getEntries
                                 * @protected
                                 */
                                _getEntries: function() {
                                    return this._entries;
                                },
                            
                            
                                /**
                                 * Adds entry to cache.
                                 *
                                 * @method _defAddFn
                                 * @param e {EventFacade} Event Facade with the following properties:
                                 * <dl>
                                 * <dt>entry (Object)</dt> <dd>The cached entry.</dd>
                                 * </dl>
                                 * @protected
                                 */
                                _defAddFn: function(e) {
                                    var entries = this._entries,
                                        entry   = e.entry,
                                        max     = this.get("max"),
                                        pos;
                            
                                    // If uniqueKeys is true and item exists with this key, then remove it.
                                    if (this.get("uniqueKeys")) {
                                        pos = this._position(e.entry.request);
                                        if (LANG.isValue(pos)) {
                                            entries.splice(pos, 1);
                                        }
                                    }
                            
                                    // If the cache at or over capacity, make room by removing stalest
                                    // element(s) starting at index-0.
                                    while (max && entries.length >= max) {
                                        entries.shift();
                                    }
                            
                                    // Add entry to cache in the newest position, at the end of the array
                                    entries[entries.length] = entry;
                                    Y.log("Cached entry: " + Y.dump(entry), "info", "cache");
                                },
                            
                                /**
                                 * Flushes cache.
                                 *
                                 * @method _defFlushFn
                                 * @param e {EventFacade} Event Facade object.
                                 * @protected
                                 */
                                _defFlushFn: function(e) {
                                    var entries = this._entries,
                                        details = e.details[0],
                                        pos;
                            
                                    //passed an item, flush only that
                                    if(details && LANG.isValue(details.request)) {
                                        pos = this._position(details.request);
                            
                                        if(LANG.isValue(pos)) {
                                            entries.splice(pos,1);
                            
                                            Y.log("Flushed cache item " + Y.dump(details.request), "info", "cache");
                                        }
                                    }
                                    //no item, flush everything
                                    else {
                                        this._entries = [];
                                        Y.log("Cache flushed", "info", "cache");
                                    }
                                },
                            
                                /**
                                 * Default overridable method compares current request with given cache entry.
                                 * Returns true if current request matches the cached request, otherwise
                                 * false. Implementers should override this method to customize the
                                 * cache-matching algorithm.
                                 *
                                 * @method _isMatch
                                 * @param request {Object} Request object.
                                 * @param entry {Object} Cached entry.
                                 * @return {Boolean} True if current request matches given cached request, false otherwise.
                                 * @protected
                                 */
                                _isMatch: function(request, entry) {
                                    if(!entry.expires || new Date() < entry.expires) {
                                        return (request === entry.request);
                                    }
                                    return false;
                                },
                            
                                /**
                                 * Returns position of a request in the entries array, otherwise null.
                                 *
                                 * @method _position
                                 * @param request {Object} Request object.
                                 * @return {Number} Array position if found, null otherwise.
                                 * @protected
                                 */
                                _position: function(request) {
                                    // If cache is enabled...
                                    var entries = this._entries,
                                        length = entries.length,
                                        i = length-1;
                            
                                    if((this.get("max") === null) || this.get("max") > 0) {
                                        // Loop through each cached entry starting from the newest
                                        for(; i >= 0; i--) {
                                            // Execute matching function
                                            if(this._isMatch(request, entries[i])) {
                                                return i;
                                            }
                                        }
                                    }
                            
                                    return null;
                                },
                            
                                /////////////////////////////////////////////////////////////////////////////
                                //
                                // Cache public methods
                                //
                                /////////////////////////////////////////////////////////////////////////////
                            
                                /**
                                 * Adds a new entry to the cache of the format
                                 * {request:request, response:response, cached:cached, expires:expires}.
                                 * If cache is full, evicts the stalest entry before adding the new one.
                                 *
                                 * @method add
                                 * @param request {Object} Request value.
                                 * @param response {Object} Response value.
                                 */
                                add: function(request, response) {
                                    var expires = this.get("expires");
                                    if(this.get("initialized") && ((this.get("max") === null) || this.get("max") > 0) &&
                                            (LANG.isValue(request) || LANG.isNull(request) || LANG.isUndefined(request))) {
                                        this.fire("add", {entry: {
                                            request:request,
                                            response:response,
                                            cached: new Date(),
                                            expires: isDate(expires) ? expires :
                                        (expires ? new Date(new Date().getTime() + this.get("expires")) : null)
                                        }});
                                    }
                                    else {
                                        Y.log("Could not add " + Y.dump(response) + " to cache for " + Y.dump(request), "info", "cache");
                                    }
                                },
                            
                                /**
                                 * Flushes cache.
                                 *
                                 * @method flush
                                 */
                                flush: function(request) {
                                    this.fire("flush", { request: (LANG.isValue(request) ? request : null) });
                                },
                            
                                /**
                                 * Retrieves cached object for given request, if available, and refreshes
                                 * entry in the cache. Returns null if there is no cache match.
                                 *
                                 * @method retrieve
                                 * @param request {Object} Request object.
                                 * @return {Object} Cached object with the properties request and response, or null.
                                 */
                                retrieve: function(request) {
                                    // If cache is enabled...
                                    var entries = this._entries,
                                        length = entries.length,
                                        entry = null,
                                        pos;
                            
                                    if((length > 0) && ((this.get("max") === null) || (this.get("max") > 0))) {
                                        this.fire("request", {request: request});
                            
                                        pos = this._position(request);
                            
                                        if(LANG.isValue(pos)) {
                                            entry = entries[pos];
                            
                                            this.fire("retrieve", {entry: entry});
                            
                                            // Refresh the position of the cache hit
                                            if(pos < length-1) {
                                                // Remove element from its original location
                                                entries.splice(pos,1);
                                                // Add as newest
                                                entries[entries.length] = entry;
                                                Y.log("Refreshed cache entry: " + Y.dump(entry) +
                                                        " for request: " +  Y.dump(request), "info", "cache");
                                            }
                            
                                            Y.log("Retrieved cached response: " + Y.dump(entry) +
                                                    " for request: " + Y.dump(request), "info", "cache");
                                            return entry;
                                        }
                                    }
                                    return null;
                                }
                            });
                            
                            Y.Cache = Cache;