;(function($) { "use strict"; $.memoize = function(factory, ctx) { var cache = {}; return function(key) { if (!(key in cache)) { cache[key] = factory.call(ctx, key); } return cache[key]; }; }; $.indexedDB = function(dbname, store, keyPath) { var def = $.Deferred(); var version; (function retry() { var request; if (typeof version === 'undefined') { request = indexedDB.open(dbname); } else { request = indexedDB.open(dbname, version); } request.onupgradeneeded = function(ev) { var db = ev.target.result; if (!db.objectStoreNames.contains(store)) { db.createObjectStore(store, {keyPath: keyPath}); } }; request.onsuccess = function(ev) { var db = ev.target.result; if (!db.objectStoreNames.contains(store)) { version = db.version + 1; db.close(); retry(); } else { def.resolve(db); } }; request.onerror = function() { throw "help!"; }; })(); return def.promise(); }; $.memoizeForever = function(factory, store, keyPath, ctx) { var idb = $.indexedDB("indexed", store, keyPath); return function(key) { var def = $.Deferred(); idb.done(function(db) { db.transaction(store).objectStore(store).get(key).onsuccess = function(ev) { if (typeof ev.target.result === 'undefined') { $.when(factory.call(ctx, key)).done(function(data) { db.transaction(store, 'readwrite').objectStore(store) .add(data).onsuccess = function() { def.resolve(data); }; }).fail(def.reject); } else { def.resolve(ev.target.result); } }; }); return def.promise(); }; }; })(jQuery);