Show:
                            /**
                             * Provides a Cache subclass which uses HTML5 `localStorage` for persistence.
                             *
                             * @module cache
                             * @submodule cache-offline
                             */
                            
                            /**
                             * Extends Cache utility with offline functionality.
                             * @class CacheOffline
                             * @extends Cache
                             * @constructor
                             */
                            function CacheOffline() {
                                CacheOffline.superclass.constructor.apply(this, arguments);
                            }
                            
                            var localStorage = null,
                                JSON = Y.JSON;
                            
                            // Bug 2529572
                            try {
                                localStorage = Y.config.win.localStorage;
                            }
                            catch(e) {
                                Y.log("Could not access localStorage.", "warn", "cache");
                            }
                            
                            /////////////////////////////////////////////////////////////////////////////
                            //
                            // CacheOffline events
                            //
                            /////////////////////////////////////////////////////////////////////////////
                            
                            /**
                            * @event error
                            * @description Fired when an entry could not be added, most likely due to
                            * exceeded browser quota.
                            * <dl>
                            * <dt>error (Object)</dt> <dd>The error object.</dd>
                            * </dl>
                            */
                            
                            /////////////////////////////////////////////////////////////////////////////
                            //
                            // CacheOffline static
                            //
                            /////////////////////////////////////////////////////////////////////////////
                            Y.mix(CacheOffline, {
                                /**
                                 * Class name.
                                 *
                                 * @property NAME
                                 * @type String
                                 * @static
                                 * @final
                                 * @value "cacheOffline"
                                 */
                                NAME: "cacheOffline",
                            
                                ATTRS: {
                                    /////////////////////////////////////////////////////////////////////////////
                                    //
                                    // CacheOffline Attributes
                                    //
                                    /////////////////////////////////////////////////////////////////////////////
                            
                                    /**
                                    * @attribute sandbox
                                    * @description A string that must be passed in via the constructor.
                                    * This identifier is used to sandbox one cache instance's entries
                                    * from another. Calling the cache instance's flush and length methods
                                    * or get("entries") will apply to only these sandboxed entries.
                                    * @type String
                                    * @default "default"
                                    * @initOnly
                                    */
                                    sandbox: {
                                        value: "default",
                                        writeOnce: "initOnly"
                                    },
                            
                                    /**
                                    * @attribute expires
                                    * @description Absolute Date when data expires or
                                    * relative number of milliseconds. Zero disables expiration.
                                    * @type Date | Number
                                    * @default 86400000 (one day)
                                    */
                                    expires: {
                                        value: 86400000
                                    },
                            
                                    /**
                                    * @attribute max
                                    * @description Disabled.
                                    * @readOnly
                                    * @default null
                                    */
                                    max: {
                                        value: null,
                                        readOnly: true
                                    },
                            
                                    /**
                                    * @attribute uniqueKeys
                                    * @description Always true for CacheOffline.
                                    * @readOnly
                                    * @default true
                                    */
                                    uniqueKeys: {
                                        value: true,
                                        readOnly: true,
                                        setter: function() {
                                            return true;
                                        }
                                    }
                                },
                            
                                /**
                                 * Removes all items from all sandboxes. Useful if localStorage has
                                 * exceeded quota. Only supported on browsers that implement HTML 5
                                 * localStorage.
                                 *
                                 * @method flushAll
                                 * @static
                                 */
                                flushAll: function() {
                                    var store = localStorage, key;
                                    if(store) {
                                        if(store.clear) {
                                            store.clear();
                                        }
                                        // FF2.x and FF3.0.x
                                        else {
                                            for (key in store) {
                                                if (store.hasOwnProperty(key)) {
                                                    store.removeItem(key);
                                                    delete store[key];
                                                }
                                            }
                                        }
                                        Y.log("All sandboxes of OfflineCache flushed", "info", "cache");
                                    }
                                    else {
                                        Y.log("Could not flush all OfflineCache sandboxes.", "warn", "cache");
                                    }
                                }
                            });
                            
                            Y.extend(CacheOffline, Y.Cache, localStorage ? {
                            /////////////////////////////////////////////////////////////////////////////
                            //
                            // Offline is supported
                            //
                            /////////////////////////////////////////////////////////////////////////////
                            
                                /////////////////////////////////////////////////////////////////////////////
                                //
                                // CacheOffline protected methods
                                //
                                /////////////////////////////////////////////////////////////////////////////
                                /**
                                 * Always return null.
                                 *
                                 * @method _setMax
                                 * @protected
                                 */
                                _setMax: function(value) {
                                    return null;
                                },
                            
                                /**
                                 * Gets size.
                                 *
                                 * @method _getSize
                                 * @protected
                                 */
                                _getSize: function() {
                                    var count = 0,
                                        i=0,
                                        l=localStorage.length;
                                    for(; i<l; ++i) {
                                        // Match sandbox id
                                        if(localStorage.key(i).indexOf(this.get("sandbox")) === 0) {
                                            count++;
                                        }
                                    }
                                    return count;
                                },
                            
                                /**
                                 * Gets all entries.
                                 *
                                 * @method _getEntries
                                 * @protected
                                 */
                                _getEntries: function() {
                                    var entries = [],
                                        i=0,
                                        l=localStorage.length,
                                        sandbox = this.get("sandbox");
                                    for(; i<l; ++i) {
                                        // Match sandbox id
                                        if(localStorage.key(i).indexOf(sandbox) === 0) {
                                            entries[i] = JSON.parse(localStorage.key(i).substring(sandbox.length));
                                        }
                                    }
                                    return 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 entry = e.entry,
                                        request = entry.request,
                                        cached = entry.cached,
                                        expires = entry.expires;
                            
                                    // Convert Dates to msecs on the way into localStorage
                                    entry.cached = cached.getTime();
                                    entry.expires = expires ? expires.getTime() : expires;
                            
                                    try {
                                        localStorage.setItem(this.get("sandbox")+JSON.stringify({"request":request}), JSON.stringify(entry));
                                        Y.log("Cached offline entry: " + Y.dump(entry), "info", "cache");
                                    }
                                    catch(error) {
                                        this.fire("error", {error:error});
                                        Y.log("Could not cache offline entry: " + Y.dump(entry) +
                                        " due to error: " + Y.dump(error), "warn", "cache");
                                    }
                                },
                            
                                /**
                                 * Flushes cache.
                                 *
                                 * @method _defFlushFn
                                 * @param e {EventFacade} Event Facade object.
                                 * @protected
                                 */
                                _defFlushFn: function(e) {
                                    var key,
                                        i=localStorage.length-1;
                                    for(; i>-1; --i) {
                                        // Match sandbox id
                                        key = localStorage.key(i);
                                        if(key.indexOf(this.get("sandbox")) === 0) {
                                            localStorage.removeItem(key);
                                        }
                                    }
                                },
                            
                                /////////////////////////////////////////////////////////////////////////////
                                //
                                // CacheOffline public methods
                                //
                                /////////////////////////////////////////////////////////////////////////////
                                /**
                                 * Adds a new entry to the cache of the format
                                 * {request:request, response:response, cached:cached, expires: expires}.
                                 *
                                 * @method add
                                 * @param request {Object} Request value must be a String or JSON.
                                 * @param response {Object} Response value must be a String or JSON.
                                 */
                            
                                /**
                                 * Retrieves cached object for given request, if available.
                                 * Returns null if there is no cache match.
                                 *
                                 * @method retrieve
                                 * @param request {Object} Request object.
                                 * @return {Object} Cached object with the properties request, response,
                                 * and expires, or null.
                                 */
                                retrieve: function(request) {
                                    this.fire("request", {request: request});
                            
                                    var entry, expires, sandboxedrequest;
                            
                                    try {
                                        sandboxedrequest = this.get("sandbox")+JSON.stringify({"request":request});
                                        try {
                                            entry = JSON.parse(localStorage.getItem(sandboxedrequest));
                                        }
                                        catch(e) {
                                        }
                                    }
                                    catch(e2) {
                                    }
                            
                                    if(entry) {
                                        // Convert msecs to Dates on the way out of localStorage
                                        entry.cached = new Date(entry.cached);
                                        expires = entry.expires;
                                        expires = !expires ? null : new Date(expires);
                                        entry.expires = expires;
                            
                                        if(this._isMatch(request, entry)) {
                                            this.fire("retrieve", {entry: entry});
                                            Y.log("Retrieved offlinecached response: " + Y.dump(entry) +
                                                    " for request: " + Y.dump(request), "info", "cache");
                                            return entry;
                                        }
                                    }
                                    return null;
                                }
                            } :
                            /////////////////////////////////////////////////////////////////////////////
                            //
                            // Offline is not supported
                            //
                            /////////////////////////////////////////////////////////////////////////////
                            {
                                /**
                                 * Always return null.
                                 *
                                 * @method _setMax
                                 * @protected
                                 */
                                _setMax: function(value) {
                                    return null;
                                }
                            });
                            
                            
                            Y.CacheOffline = CacheOffline;