diff options
author | Determinant <ted.sybil@gmail.com> | 2019-02-02 22:15:54 -0500 |
---|---|---|
committer | Determinant <ted.sybil@gmail.com> | 2019-02-02 22:15:54 -0500 |
commit | 580990a5eb4a79892c48e3a3fce3386fe80e6cc2 (patch) | |
tree | edc4e19741cf6ff50a45ba7c81cb1cb2f1611c66 | |
parent | 848c4f0e60340e5fc6079a0bff1bf516845576e0 (diff) |
finish cache design
23 files changed, 1547 insertions, 200 deletions
diff --git a/build/asset-manifest.json b/build/asset-manifest.json index 5bd4d82..b35bee1 100644 --- a/build/asset-manifest.json +++ b/build/asset-manifest.json @@ -1,14 +1,14 @@ { - "main.js": "/static/js/main.9e0b7c77.chunk.js", - "main.js.map": "/static/js/main.9e0b7c77.chunk.js.map", - "static/css/1.297ee474.chunk.css": "/static/css/1.297ee474.chunk.css", - "static/js/1.b5cbbf9b.chunk.js": "/static/js/1.b5cbbf9b.chunk.js", - "static/js/1.b5cbbf9b.chunk.js.map": "/static/js/1.b5cbbf9b.chunk.js.map", + "main.js": "/static/js/main.a10a122f.chunk.js", + "main.js.map": "/static/js/main.a10a122f.chunk.js.map", + "static/css/1.01dd4c98.chunk.css": "/static/css/1.01dd4c98.chunk.css", + "static/js/1.e953b754.chunk.js": "/static/js/1.e953b754.chunk.js", + "static/js/1.e953b754.chunk.js.map": "/static/js/1.e953b754.chunk.js.map", "runtime~main.js": "/static/js/runtime~main.229c360f.js", "runtime~main.js.map": "/static/js/runtime~main.229c360f.js.map", "static/media/index.css": "/static/media/roboto-latin-900italic.bc833e72.woff", - "static/css/1.297ee474.chunk.css.map": "/static/css/1.297ee474.chunk.css.map", + "static/css/1.01dd4c98.chunk.css.map": "/static/css/1.01dd4c98.chunk.css.map", "index.html": "/index.html", - "precache-manifest.9f3e92b5e4dff660087cc664d98afa28.js": "/precache-manifest.9f3e92b5e4dff660087cc664d98afa28.js", + "precache-manifest.8e25c79dea0a276deaaeffbd790faff8.js": "/precache-manifest.8e25c79dea0a276deaaeffbd790faff8.js", "service-worker.js": "/service-worker.js" }
\ No newline at end of file diff --git a/build/background.js b/build/background.js index ec5d6af..7804de6 100644 --- a/build/background.js +++ b/build/background.js @@ -1,4 +1,728 @@ (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){ +'use strict' + +// A linked list to keep track of recently-used-ness +const Yallist = require('yallist') + +const MAX = Symbol('max') +const LENGTH = Symbol('length') +const LENGTH_CALCULATOR = Symbol('lengthCalculator') +const ALLOW_STALE = Symbol('allowStale') +const MAX_AGE = Symbol('maxAge') +const DISPOSE = Symbol('dispose') +const NO_DISPOSE_ON_SET = Symbol('noDisposeOnSet') +const LRU_LIST = Symbol('lruList') +const CACHE = Symbol('cache') +const UPDATE_AGE_ON_GET = Symbol('updateAgeOnGet') + +const naiveLength = () => 1 + +// lruList is a yallist where the head is the youngest +// item, and the tail is the oldest. the list contains the Hit +// objects as the entries. +// Each Hit object has a reference to its Yallist.Node. This +// never changes. +// +// cache is a Map (or PseudoMap) that matches the keys to +// the Yallist.Node object. +class LRUCache { + constructor (options) { + if (typeof options === 'number') + options = { max: options } + + if (!options) + options = {} + + if (options.max && (typeof options.max !== 'number' || options.max < 0)) + throw new TypeError('max must be a non-negative number') + // Kind of weird to have a default max of Infinity, but oh well. + const max = this[MAX] = options.max || Infinity + + const lc = options.length || naiveLength + this[LENGTH_CALCULATOR] = (typeof lc !== 'function') ? naiveLength : lc + this[ALLOW_STALE] = options.stale || false + if (options.maxAge && typeof options.maxAge !== 'number') + throw new TypeError('maxAge must be a number') + this[MAX_AGE] = options.maxAge || 0 + this[DISPOSE] = options.dispose + this[NO_DISPOSE_ON_SET] = options.noDisposeOnSet || false + this[UPDATE_AGE_ON_GET] = options.updateAgeOnGet || false + this.reset() + } + + // resize the cache when the max changes. + set max (mL) { + if (typeof mL !== 'number' || mL < 0) + throw new TypeError('max must be a non-negative number') + + this[MAX] = mL || Infinity + trim(this) + } + get max () { + return this[MAX] + } + + set allowStale (allowStale) { + this[ALLOW_STALE] = !!allowStale + } + get allowStale () { + return this[ALLOW_STALE] + } + + set maxAge (mA) { + if (typeof mA !== 'number') + throw new TypeError('maxAge must be a non-negative number') + + this[MAX_AGE] = mA + trim(this) + } + get maxAge () { + return this[MAX_AGE] + } + + // resize the cache when the lengthCalculator changes. + set lengthCalculator (lC) { + if (typeof lC !== 'function') + lC = naiveLength + + if (lC !== this[LENGTH_CALCULATOR]) { + this[LENGTH_CALCULATOR] = lC + this[LENGTH] = 0 + this[LRU_LIST].forEach(hit => { + hit.length = this[LENGTH_CALCULATOR](hit.value, hit.key) + this[LENGTH] += hit.length + }) + } + trim(this) + } + get lengthCalculator () { return this[LENGTH_CALCULATOR] } + + get length () { return this[LENGTH] } + get itemCount () { return this[LRU_LIST].length } + + rforEach (fn, thisp) { + thisp = thisp || this + for (let walker = this[LRU_LIST].tail; walker !== null;) { + const prev = walker.prev + forEachStep(this, fn, walker, thisp) + walker = prev + } + } + + forEach (fn, thisp) { + thisp = thisp || this + for (let walker = this[LRU_LIST].head; walker !== null;) { + const next = walker.next + forEachStep(this, fn, walker, thisp) + walker = next + } + } + + keys () { + return this[LRU_LIST].toArray().map(k => k.key) + } + + values () { + return this[LRU_LIST].toArray().map(k => k.value) + } + + reset () { + if (this[DISPOSE] && + this[LRU_LIST] && + this[LRU_LIST].length) { + this[LRU_LIST].forEach(hit => this[DISPOSE](hit.key, hit.value)) + } + + this[CACHE] = new Map() // hash of items by key + this[LRU_LIST] = new Yallist() // list of items in order of use recency + this[LENGTH] = 0 // length of items in the list + } + + dump () { + return this[LRU_LIST].map(hit => + isStale(this, hit) ? false : { + k: hit.key, + v: hit.value, + e: hit.now + (hit.maxAge || 0) + }).toArray().filter(h => h) + } + + dumpLru () { + return this[LRU_LIST] + } + + set (key, value, maxAge) { + maxAge = maxAge || this[MAX_AGE] + + if (maxAge && typeof maxAge !== 'number') + throw new TypeError('maxAge must be a number') + + const now = maxAge ? Date.now() : 0 + const len = this[LENGTH_CALCULATOR](value, key) + + if (this[CACHE].has(key)) { + if (len > this[MAX]) { + del(this, this[CACHE].get(key)) + return false + } + + const node = this[CACHE].get(key) + const item = node.value + + // dispose of the old one before overwriting + // split out into 2 ifs for better coverage tracking + if (this[DISPOSE]) { + if (!this[NO_DISPOSE_ON_SET]) + this[DISPOSE](key, item.value) + } + + item.now = now + item.maxAge = maxAge + item.value = value + this[LENGTH] += len - item.length + item.length = len + this.get(key) + trim(this) + return true + } + + const hit = new Entry(key, value, len, now, maxAge) + + // oversized objects fall out of cache automatically. + if (hit.length > this[MAX]) { + if (this[DISPOSE]) + this[DISPOSE](key, value) + + return false + } + + this[LENGTH] += hit.length + this[LRU_LIST].unshift(hit) + this[CACHE].set(key, this[LRU_LIST].head) + trim(this) + return true + } + + has (key) { + if (!this[CACHE].has(key)) return false + const hit = this[CACHE].get(key).value + return !isStale(this, hit) + } + + get (key) { + return get(this, key, true) + } + + peek (key) { + return get(this, key, false) + } + + pop () { + const node = this[LRU_LIST].tail + if (!node) + return null + + del(this, node) + return node.value + } + + del (key) { + del(this, this[CACHE].get(key)) + } + + load (arr) { + // reset the cache + this.reset() + + const now = Date.now() + // A previous serialized cache has the most recent items first + for (let l = arr.length - 1; l >= 0; l--) { + const hit = arr[l] + const expiresAt = hit.e || 0 + if (expiresAt === 0) + // the item was created without expiration in a non aged cache + this.set(hit.k, hit.v) + else { + const maxAge = expiresAt - now + // dont add already expired items + if (maxAge > 0) { + this.set(hit.k, hit.v, maxAge) + } + } + } + } + + prune () { + this[CACHE].forEach((value, key) => get(this, key, false)) + } +} + +const get = (self, key, doUse) => { + const node = self[CACHE].get(key) + if (node) { + const hit = node.value + if (isStale(self, hit)) { + del(self, node) + if (!self[ALLOW_STALE]) + return undefined + } else { + if (doUse) { + if (self[UPDATE_AGE_ON_GET]) + node.value.now = Date.now() + self[LRU_LIST].unshiftNode(node) + } + } + return hit.value + } +} + +const isStale = (self, hit) => { + if (!hit || (!hit.maxAge && !self[MAX_AGE])) + return false + + const diff = Date.now() - hit.now + return hit.maxAge ? diff > hit.maxAge + : self[MAX_AGE] && (diff > self[MAX_AGE]) +} + +const trim = self => { + if (self[LENGTH] > self[MAX]) { + for (let walker = self[LRU_LIST].tail; + self[LENGTH] > self[MAX] && walker !== null;) { + // We know that we're about to delete this one, and also + // what the next least recently used key will be, so just + // go ahead and set it now. + const prev = walker.prev + del(self, walker) + walker = prev + } + } +} + +const del = (self, node) => { + if (node) { + const hit = node.value + if (self[DISPOSE]) + self[DISPOSE](hit.key, hit.value) + + self[LENGTH] -= hit.length + self[CACHE].delete(hit.key) + self[LRU_LIST].removeNode(node) + } +} + +class Entry { + constructor (key, value, length, now, maxAge) { + this.key = key + this.value = value + this.length = length + this.now = now + this.maxAge = maxAge || 0 + } +} + +const forEachStep = (self, fn, node, thisp) => { + let hit = node.value + if (isStale(self, hit)) { + del(self, node) + if (!self[ALLOW_STALE]) + hit = undefined + } + if (hit) + fn.call(thisp, hit.value, hit.key, self) +} + +module.exports = LRUCache + +},{"yallist":3}],2:[function(require,module,exports){ +'use strict' +module.exports = function (Yallist) { + Yallist.prototype[Symbol.iterator] = function* () { + for (let walker = this.head; walker; walker = walker.next) { + yield walker.value + } + } +} + +},{}],3:[function(require,module,exports){ +'use strict' +module.exports = Yallist + +Yallist.Node = Node +Yallist.create = Yallist + +function Yallist (list) { + var self = this + if (!(self instanceof Yallist)) { + self = new Yallist() + } + + self.tail = null + self.head = null + self.length = 0 + + if (list && typeof list.forEach === 'function') { + list.forEach(function (item) { + self.push(item) + }) + } else if (arguments.length > 0) { + for (var i = 0, l = arguments.length; i < l; i++) { + self.push(arguments[i]) + } + } + + return self +} + +Yallist.prototype.removeNode = function (node) { + if (node.list !== this) { + throw new Error('removing node which does not belong to this list') + } + + var next = node.next + var prev = node.prev + + if (next) { + next.prev = prev + } + + if (prev) { + prev.next = next + } + + if (node === this.head) { + this.head = next + } + if (node === this.tail) { + this.tail = prev + } + + node.list.length-- + node.next = null + node.prev = null + node.list = null +} + +Yallist.prototype.unshiftNode = function (node) { + if (node === this.head) { + return + } + + if (node.list) { + node.list.removeNode(node) + } + + var head = this.head + node.list = this + node.next = head + if (head) { + head.prev = node + } + + this.head = node + if (!this.tail) { + this.tail = node + } + this.length++ +} + +Yallist.prototype.pushNode = function (node) { + if (node === this.tail) { + return + } + + if (node.list) { + node.list.removeNode(node) + } + + var tail = this.tail + node.list = this + node.prev = tail + if (tail) { + tail.next = node + } + + this.tail = node + if (!this.head) { + this.head = node + } + this.length++ +} + +Yallist.prototype.push = function () { + for (var i = 0, l = arguments.length; i < l; i++) { + push(this, arguments[i]) + } + return this.length +} + +Yallist.prototype.unshift = function () { + for (var i = 0, l = arguments.length; i < l; i++) { + unshift(this, arguments[i]) + } + return this.length +} + +Yallist.prototype.pop = function () { + if (!this.tail) { + return undefined + } + + var res = this.tail.value + this.tail = this.tail.prev + if (this.tail) { + this.tail.next = null + } else { + this.head = null + } + this.length-- + return res +} + +Yallist.prototype.shift = function () { + if (!this.head) { + return undefined + } + + var res = this.head.value + this.head = this.head.next + if (this.head) { + this.head.prev = null + } else { + this.tail = null + } + this.length-- + return res +} + +Yallist.prototype.forEach = function (fn, thisp) { + thisp = thisp || this + for (var walker = this.head, i = 0; walker !== null; i++) { + fn.call(thisp, walker.value, i, this) + walker = walker.next + } +} + +Yallist.prototype.forEachReverse = function (fn, thisp) { + thisp = thisp || this + for (var walker = this.tail, i = this.length - 1; walker !== null; i--) { + fn.call(thisp, walker.value, i, this) + walker = walker.prev + } +} + +Yallist.prototype.get = function (n) { + for (var i = 0, walker = this.head; walker !== null && i < n; i++) { + // abort out of the list early if we hit a cycle + walker = walker.next + } + if (i === n && walker !== null) { + return walker.value + } +} + +Yallist.prototype.getReverse = function (n) { + for (var i = 0, walker = this.tail; walker !== null && i < n; i++) { + // abort out of the list early if we hit a cycle + walker = walker.prev + } + if (i === n && walker !== null) { + return walker.value + } +} + +Yallist.prototype.map = function (fn, thisp) { + thisp = thisp || this + var res = new Yallist() + for (var walker = this.head; walker !== null;) { + res.push(fn.call(thisp, walker.value, this)) + walker = walker.next + } + return res +} + +Yallist.prototype.mapReverse = function (fn, thisp) { + thisp = thisp || this + var res = new Yallist() + for (var walker = this.tail; walker !== null;) { + res.push(fn.call(thisp, walker.value, this)) + walker = walker.prev + } + return res +} + +Yallist.prototype.reduce = function (fn, initial) { + var acc + var walker = this.head + if (arguments.length > 1) { + acc = initial + } else if (this.head) { + walker = this.head.next + acc = this.head.value + } else { + throw new TypeError('Reduce of empty list with no initial value') + } + + for (var i = 0; walker !== null; i++) { + acc = fn(acc, walker.value, i) + walker = walker.next + } + + return acc +} + +Yallist.prototype.reduceReverse = function (fn, initial) { + var acc + var walker = this.tail + if (arguments.length > 1) { + acc = initial + } else if (this.tail) { + walker = this.tail.prev + acc = this.tail.value + } else { + throw new TypeError('Reduce of empty list with no initial value') + } + + for (var i = this.length - 1; walker !== null; i--) { + acc = fn(acc, walker.value, i) + walker = walker.prev + } + + return acc +} + +Yallist.prototype.toArray = function () { + var arr = new Array(this.length) + for (var i = 0, walker = this.head; walker !== null; i++) { + arr[i] = walker.value + walker = walker.next + } + return arr +} + +Yallist.prototype.toArrayReverse = function () { + var arr = new Array(this.length) + for (var i = 0, walker = this.tail; walker !== null; i++) { + arr[i] = walker.value + walker = walker.prev + } + return arr +} + +Yallist.prototype.slice = function (from, to) { + to = to || this.length + if (to < 0) { + to += this.length + } + from = from || 0 + if (from < 0) { + from += this.length + } + var ret = new Yallist() + if (to < from || to < 0) { + return ret + } + if (from < 0) { + from = 0 + } + if (to > this.length) { + to = this.length + } + for (var i = 0, walker = this.head; walker !== null && i < from; i++) { + walker = walker.next + } + for (; walker !== null && i < to; i++, walker = walker.next) { + ret.push(walker.value) + } + return ret +} + +Yallist.prototype.sliceReverse = function (from, to) { + to = to || this.length + if (to < 0) { + to += this.length + } + from = from || 0 + if (from < 0) { + from += this.length + } + var ret = new Yallist() + if (to < from || to < 0) { + return ret + } + if (from < 0) { + from = 0 + } + if (to > this.length) { + to = this.length + } + for (var i = this.length, walker = this.tail; walker !== null && i > to; i--) { + walker = walker.prev + } + for (; walker !== null && i > from; i--, walker = walker.prev) { + ret.push(walker.value) + } + return ret +} + +Yallist.prototype.reverse = function () { + var head = this.head + var tail = this.tail + for (var walker = head; walker !== null; walker = walker.prev) { + var p = walker.prev + walker.prev = walker.next + walker.next = p + } + this.head = tail + this.tail = head + return this +} + +function push (self, item) { + self.tail = new Node(item, self.tail, null, self) + if (!self.head) { + self.head = self.tail + } + self.length++ +} + +function unshift (self, item) { + self.head = new Node(item, null, self.head, self) + if (!self.tail) { + self.tail = self.head + } + self.length++ +} + +function Node (value, prev, next, list) { + if (!(this instanceof Node)) { + return new Node(value, prev, next, list) + } + + this.list = list + this.value = value + + if (prev) { + prev.next = this + this.prev = prev + } else { + this.prev = null + } + + if (next) { + next.prev = this + this.next = next + } else { + this.next = null + } +} + +try { + // add if support for Symbol.iterator is present + require('./iterator.js')(Yallist) +} catch (er) {} + +},{"./iterator.js":2}],4:[function(require,module,exports){ "use strict"; var gapi = _interopRequireWildcard(require("./gapi")); @@ -31,7 +755,7 @@ chrome.runtime.onConnect.addListener(function (port) { }); } else if (msg.type == 4) { calData[msg.data.id].getEvents(new Date(msg.data.start), new Date(msg.data.end)).catch(function (e) { - console.log("cannot load calendar ".concat(msg.data.id)); + console.log("cannot load calendar ".concat(msg.data.id), e); return []; }).then(function (data) { console.log(data); @@ -66,7 +790,7 @@ chrome.browserAction.onClicked.addListener(function () { }); }); -},{"./gapi":2}],2:[function(require,module,exports){ +},{"./gapi":5}],5:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { @@ -77,6 +801,10 @@ exports.getCalendars = getCalendars; exports.getColors = getColors; exports.GCalendar = void 0; +var _lruCache = _interopRequireDefault(require("lru-cache")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } @@ -99,7 +827,6 @@ function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } -/* global chrome */ var gapi_base = 'https://www.googleapis.com/calendar/v3'; var GApiError = { invalidSyncToken: 1, @@ -107,11 +834,17 @@ var GApiError = { }; function to_params(dict) { - return Object.entries(dict).map(function (_ref) { + return Object.entries(dict).filter(function (_ref) { var _ref2 = _slicedToArray(_ref, 2), k = _ref2[0], v = _ref2[1]; + return v; + }).map(function (_ref3) { + var _ref4 = _slicedToArray(_ref3, 2), + k = _ref4[0], + v = _ref4[1]; + return "".concat(encodeURIComponent(k), "=").concat(encodeURIComponent(v)); }).join('&'); } @@ -161,8 +894,11 @@ function getEvent(calId, eventId, token) { }); } -function getEvents(calId, token, syncToken) { - var resultsPerRequest = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 100; +function _getEvents(calId, token) { + var syncToken = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; + var timeMin = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null; + var timeMax = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : null; + var resultsPerRequest = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 100; var results = []; var singleFetch = function singleFetch(pageToken, syncToken) { @@ -170,6 +906,8 @@ function getEvents(calId, token, syncToken) { access_token: token, pageToken: pageToken, syncToken: syncToken, + timeMin: timeMin, + timeMax: timeMax, maxResults: resultsPerRequest })), { method: 'GET', @@ -197,51 +935,116 @@ var GCalendar = /*#__PURE__*/ function () { function GCalendar(calId, name) { + var _this = this; + + var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : { + maxCachedItems: 100, + nDaysPerSlot: 10, + largeQuery: 10 + }; + _classCallCheck(this, GCalendar); this.calId = calId; this.name = name; this.token = getAuthToken(); this.syncToken = ''; - this.cache = {}; + this.cache = new _lruCache.default({ + max: options.maxCachedItems, + dispose: function dispose(k, v) { + return _this.onRemoveSlot(k, v); + } + }); + this.eventMeta = {}; + this.options = options; + this.divider = 8.64e7 * this.options.nDaysPerSlot; } _createClass(GCalendar, [{ + key: "dateToCacheKey", + value: function dateToCacheKey(date) { + return Math.floor(date / this.divider); + } + }, { + key: "dateRangeToCacheKeys", + value: function dateRangeToCacheKeys(range) { + return { + start: this.dateToCacheKey(range.start), + end: this.dateToCacheKey(new Date(range.end.getTime() - 1)) + }; + } + }, { key: "getSlot", value: function getSlot(k) { - if (!this.cache[k]) this.cache[k] = {}; - return this.cache[k]; + if (!this.cache.has(k)) { + var res = {}; + this.cache.set(k, res); + return res; + } else return this.cache.get(k); + } + }, { + key: "onRemoveSlot", + value: function onRemoveSlot(k, v) { + for (var id in v) { + console.assert(this.eventMeta[id]); + var keys = this.eventMeta[id].keys; + keys.delete(k); + if (keys.size === 0) delete this.eventMeta[id]; + } + } + }, { + key: "slotStartDate", + value: function slotStartDate(k) { + return new Date(k * this.divider); + } + }, { + key: "slotEndDate", + value: function slotEndDate(k) { + return new Date((k + 1) * this.divider); } }, { key: "addEvent", value: function addEvent(e) { - var ks = GCalendar.dateToCacheKey(e.start); - var ke = GCalendar.dateToCacheKey(new Date(e.end.getTime() - 1)); + var evict = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + //console.log('adding event', e); + if (this.eventMeta.hasOwnProperty(e.id)) this.removeEvent(e); + var r = this.dateRangeToCacheKeys(e); + var ks = r.start; + var ke = r.end; + var t = this.cache.length; + var keys = new Set(); + + for (var i = ks; i <= ke; i++) { + keys.add(i); + if (!this.cache.has(i)) t++; + } + + this.eventMeta[e.id] = { + keys: keys, + summary: e.summary + }; + if (!evict && t > this.options.maxCachedItems) return; if (ks === ke) this.getSlot(ks)[e.id] = { start: e.start, end: e.end, - id: e.id, - summary: e.summary + id: e.id };else { this.getSlot(ks)[e.id] = { start: e.start, - end: GCalendar.slotEndDate(ks), - id: e.id, - summary: e.summary + end: this.slotEndDate(ks), + id: e.id }; this.getSlot(ke)[e.id] = { - start: GCalendar.slotStartDate(ke), + start: this.slotStartDate(ke), end: e.end, - id: e.id, - summary: e.summary + id: e.id }; for (var k = ks + 1; k < ke; k++) { this.getSlot(k)[e.id] = { - start: GCalendar.slotStartDate(k), - end: GCalendar.slotEndDate(k), - id: e.id, - summary: e.summary + start: this.slotStartDate(k), + end: this.slotEndDate(k), + id: e.id }; } } @@ -249,17 +1052,20 @@ function () { }, { key: "removeEvent", value: function removeEvent(e) { - var ks = GCalendar.dateToCacheKey(e.start); - var ke = GCalendar.dateToCacheKey(new Date(e.end.getTime() - 1)); + var _this2 = |