From 8b24b7bf2409549a5714fac32d52efb05d7d6621 Mon Sep 17 00:00:00 2001 From: Determinant Date: Fri, 1 Feb 2019 16:05:33 -0500 Subject: maintain data store in background --- build/asset-manifest.json | 6 +- build/background.js | 356 ++++++++++++++++++++- build/index.html | 2 +- ...he-manifest.4b3348396592c5f2793c6b9bef079d99.js | 118 ------- ...he-manifest.9f3e92b5e4dff660087cc664d98afa28.js | 118 +++++++ build/service-worker.js | 2 +- build/static/js/main.0c8ec738.chunk.js | 2 - build/static/js/main.0c8ec738.chunk.js.map | 1 - build/static/js/main.9e0b7c77.chunk.js | 2 + build/static/js/main.9e0b7c77.chunk.js.map | 1 + 10 files changed, 480 insertions(+), 128 deletions(-) delete mode 100644 build/precache-manifest.4b3348396592c5f2793c6b9bef079d99.js create mode 100644 build/precache-manifest.9f3e92b5e4dff660087cc664d98afa28.js delete mode 100644 build/static/js/main.0c8ec738.chunk.js delete mode 100644 build/static/js/main.0c8ec738.chunk.js.map create mode 100644 build/static/js/main.9e0b7c77.chunk.js create mode 100644 build/static/js/main.9e0b7c77.chunk.js.map (limited to 'build') diff --git a/build/asset-manifest.json b/build/asset-manifest.json index 4761af6..5bd4d82 100644 --- a/build/asset-manifest.json +++ b/build/asset-manifest.json @@ -1,6 +1,6 @@ { - "main.js": "/static/js/main.0c8ec738.chunk.js", - "main.js.map": "/static/js/main.0c8ec738.chunk.js.map", + "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", @@ -9,6 +9,6 @@ "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", "index.html": "/index.html", - "precache-manifest.4b3348396592c5f2793c6b9bef079d99.js": "/precache-manifest.4b3348396592c5f2793c6b9bef079d99.js", + "precache-manifest.9f3e92b5e4dff660087cc664d98afa28.js": "/precache-manifest.9f3e92b5e4dff660087cc664d98afa28.js", "service-worker.js": "/service-worker.js" } \ No newline at end of file diff --git a/build/background.js b/build/background.js index 76043c6..ec5d6af 100644 --- a/build/background.js +++ b/build/background.js @@ -1,3 +1,355 @@ -chrome.browserAction.onClicked.addListener(function() { - chrome.tabs.create({url: 'index.html'}); +(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 3 && arguments[3] !== undefined ? arguments[3] : 100; + var results = []; + + var singleFetch = function singleFetch(pageToken, syncToken) { + return fetch("".concat(gapi_base, "/calendars/").concat(calId, "/events?").concat(to_params({ + access_token: token, + pageToken: pageToken, + syncToken: syncToken, + maxResults: resultsPerRequest + })), { + method: 'GET', + async: true + }).then(function (response) { + if (response.status === 200) return response.json();else if (response.status === 410) throw GApiError.invalidSyncToken;else throw GApiError.otherErrors; + }).then(function (data) { + results.push.apply(results, _toConsumableArray(data.items)); + + if (data.nextPageToken) { + return singleFetch(data.nextPageToken, ''); + } else { + return { + nextSyncToken: data.nextSyncToken, + results: results + }; + } + }); + }; + + return singleFetch('', syncToken); +} + +var GCalendar = +/*#__PURE__*/ +function () { + function GCalendar(calId, name) { + _classCallCheck(this, GCalendar); + + this.calId = calId; + this.name = name; + this.token = getAuthToken(); + this.syncToken = ''; + this.cache = {}; + } + + _createClass(GCalendar, [{ + key: "getSlot", + value: function getSlot(k) { + if (!this.cache[k]) this.cache[k] = {}; + return this.cache[k]; + } + }, { + key: "addEvent", + value: function addEvent(e) { + var ks = GCalendar.dateToCacheKey(e.start); + var ke = GCalendar.dateToCacheKey(new Date(e.end.getTime() - 1)); + if (ks === ke) this.getSlot(ks)[e.id] = { + start: e.start, + end: e.end, + id: e.id, + summary: e.summary + };else { + this.getSlot(ks)[e.id] = { + start: e.start, + end: GCalendar.slotEndDate(ks), + id: e.id, + summary: e.summary + }; + this.getSlot(ke)[e.id] = { + start: GCalendar.slotStartDate(ke), + end: e.end, + id: e.id, + summary: e.summary + }; + + 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 + }; + } + } + } + }, { + key: "removeEvent", + value: function removeEvent(e) { + var ks = GCalendar.dateToCacheKey(e.start); + var ke = GCalendar.dateToCacheKey(new Date(e.end.getTime() - 1)); + + for (var k = ks; k <= ke; k++) { + delete this.getSlot(k)[e.id]; + } + } + }, { + key: "getSlotEvents", + value: function getSlotEvents(k, start, end) { + var s = this.getSlot(k); + var results = []; + + for (var id in s) { + if (!(s[id].start >= end || s[id].end <= start)) { + results.push({ + id: id, + start: s[id].start < start ? start : s[id].start, + end: s[id].end > end ? end : s[id].end, + summary: s[id].summary + }); + } + } + + return results; + } + }, { + key: "getCachedEvents", + value: function getCachedEvents(start, end) { + var ks = GCalendar.dateToCacheKey(start); + var ke = GCalendar.dateToCacheKey(new Date(end.getTime() - 1)); + var results = this.getSlotEvents(ks, start, end); + + for (var k = ks + 1; k < ke; k++) { + var s = this.getSlot(k); + + for (var id in s) { + results.push(s[id]); + } + } + + if (ke > ks) results.push.apply(results, _toConsumableArray(this.getSlotEvents(ke, start, end))); + return results; + } + }, { + key: "sync", + value: function sync() { + var _this = this; + + return this.token.then(function (token) { + return getEvents(_this.calId, token, _this.syncToken).then(function (r) { + _this.syncToken = r.nextSyncToken; + var pm_results = r.results.map(function (e) { + return e.start ? Promise.resolve(e) : getEvent(_this.calId, e.id, token); + }); + return Promise.all(pm_results).then(function (results) { + return results.forEach(function (e) { + e.start = new Date(e.start.dateTime); + e.end = new Date(e.end.dateTime); + if (e.status === 'confirmed') _this.addEvent(e);else if (e.status === 'cancelled') _this.removeEvent(e); + }); + }); + }); + }).catch(function (e) { + if (e === GApiError.invalidSyncToken) { + _this.syncToken = ''; + + _this.sync(); + } else throw e; + }); + } + }, { + key: "getEvents", + value: function getEvents(start, end) { + var _this2 = this; + + return this.sync().then(function () { + return _this2.getCachedEvents(start, end); + }); + } + }], [{ + key: "dateToCacheKey", + value: function dateToCacheKey(date) { + return Math.floor(date / 8.64e7); + } + }, { + key: "slotStartDate", + value: function slotStartDate(k) { + return new Date(k * 8.64e7); + } + }, { + key: "slotEndDate", + value: function slotEndDate(k) { + return new Date((k + 1) * 8.64e7); + } + }]); + + return GCalendar; +}(); + +exports.GCalendar = GCalendar; + +},{}]},{},[1]) +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJzcmMvYmFja2dyb3VuZC5qcyIsInNyYy9nYXBpLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7QUNBQTs7OztBQUVBLElBQUksUUFBUSxHQUFHLEVBQWY7QUFDQSxJQUFJLFNBQVMsR0FBRyxFQUFoQjtBQUNBLElBQUksT0FBTyxHQUFHLEVBQWQ7QUFFQSxNQUFNLENBQUMsT0FBUCxDQUFlLFNBQWYsQ0FBeUIsV0FBekIsQ0FBcUMsVUFBUyxJQUFULEVBQWU7QUFDaEQsRUFBQSxPQUFPLENBQUMsTUFBUixDQUFlLElBQUksQ0FBQyxJQUFMLElBQWEsTUFBNUI7QUFDQSxFQUFBLElBQUksQ0FBQyxTQUFMLENBQWUsV0FBZixDQUEyQixVQUFTLEdBQVQsRUFBYztBQUNyQyxJQUFBLE9BQU8sQ0FBQyxHQUFSLENBQVksR0FBWjs7QUFDQSxRQUFJLEdBQUcsQ0FBQyxJQUFKLElBQVksQ0FBaEIsRUFBbUI7QUFDZixNQUFBLFFBQVEsR0FBRyxHQUFHLENBQUMsSUFBZjtBQUNILEtBRkQsTUFHSyxJQUFJLEdBQUcsQ0FBQyxJQUFKLElBQVksQ0FBaEIsRUFBbUI7QUFDcEIsTUFBQSxJQUFJLENBQUMsV0FBTCxDQUFpQjtBQUFFLFFBQUEsRUFBRSxFQUFFLEdBQUcsQ0FBQyxFQUFWO0FBQWMsUUFBQSxJQUFJLEVBQUUsQ0FBcEI7QUFBdUIsUUFBQSxJQUFJLEVBQUU7QUFBN0IsT0FBakI7QUFDSCxLQUZJLE1BR0EsSUFBSSxHQUFHLENBQUMsSUFBSixJQUFZLENBQWhCLEVBQW1CO0FBQ3BCLE1BQUEsU0FBUyxHQUFHLEdBQUcsQ0FBQyxJQUFoQjtBQUNILEtBRkksTUFHQSxJQUFJLEdBQUcsQ0FBQyxJQUFKLElBQVksQ0FBaEIsRUFBbUI7QUFDcEIsTUFBQSxJQUFJLENBQUMsV0FBTCxDQUFpQjtBQUFFLFFBQUEsRUFBRSxFQUFFLEdBQUcsQ0FBQyxFQUFWO0FBQWMsUUFBQSxJ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QUFDSDs7O2tDQVFvQixDLEVBQUc7QUFBRSxhQUFPLElBQUksSUFBSixDQUFTLENBQUMsR0FBRyxNQUFiLENBQVA7QUFBOEI7OztnQ0FDckMsQyxFQUFHO0FBQUUsYUFBTyxJQUFJLElBQUosQ0FBUyxDQUFDLENBQUMsR0FBRyxDQUFMLElBQVUsTUFBbkIsQ0FBUDtBQUFvQyIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uKCl7ZnVuY3Rpb24gcihlLG4sdCl7ZnVuY3Rpb24gbyhpLGYpe2lmKCFuW2ldKXtpZighZVtpXSl7dmFyIGM9XCJmdW5jdGlvblwiPT10eXBlb2YgcmVxdWlyZSYmcmVxdWlyZTtpZighZiYmYylyZXR1cm4gYyhpLCEwKTtpZih1KXJldHVybiB1KGksITApO3ZhciBhPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIraStcIidcIik7dGhyb3cgYS5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGF9dmFyIHA9bltpXT17ZXhwb3J0czp7fX07ZVtpXVswXS5jYWxsKHAuZXhwb3J0cyxmdW5jdGlvbihyKXt2YXIgbj1lW2ldWzFdW3JdO3JldHVybiBvKG58fHIpfSxwLHAuZXhwb3J0cyxyLGUsbix0KX1yZXR1cm4gbltpXS5leHBvcnRzfWZvcih2YXIgdT1cImZ1bmN0aW9uXCI9PXR5cGVvZiByZXF1aXJlJiZyZXF1aXJlLGk9MDtpPHQubGVuZ3RoO2krKylvKHRbaV0pO3JldHVybiBvfXJldHVybiByfSkoKSIsImltcG9ydCAqIGFzIGdhcGkgZnJvbSAnLi9nYXBpJztcblxubGV0IHBhdHRlcm5zID0gW107XG5sZXQgY2FsZW5kYXJzID0ge307XG5sZXQgY2FsRGF0YSA9IHt9O1xuXG5jaHJvbWUucnVudGltZS5vbkNvbm5lY3QuYWRkTGlzdGVuZXIoZnVuY3Rpb24ocG9ydCkge1xuICAgIGNvbnNvbGUuYXNzZXJ0KHBvcnQubmFtZSA9PSAnbWFpbicpO1xuICAgIHBvcnQub25NZXNzYWdlLmFkZExpc3RlbmVyKGZ1bmN0aW9uKG1zZykge1xuICAgICAgICBjb25zb2xlLmxvZyhtc2cpO1xuICAgICAgICBpZiAobXNnLnR5cGUgPT0gMCkge1xuICAgICAgICAgICAgcGF0dGVybnMgPSBtc2cuZGF0YTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChtc2cudHlwZSA9PSAxKSB7XG4gICAgICAgICAgICBwb3J0LnBvc3RNZXNzYWdlKHsgaWQ6IG1zZy5pZCwgdHlwZTogMSwgZGF0YTogcGF0dGVybnMgfSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAobXNnLnR5cGUgPT0gMikge1xuICAgICAgICAgICAgY2FsZW5kYXJzID0gbXNnLmRhdGE7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAobXNnLnR5cGUgPT0gMykge1xuICAgICAgICAgICAgcG9ydC5wb3N0TWVzc2FnZSh7IGlkOiBtc2cuaWQsIHR5cGU6IDMsIGRhdGE6IGNhbGVuZGFycyB9KTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChtc2cudHlwZSA9PSA0KSB7XG4gICAgICAgICAgICBjYWxEYXRhW21zZy5kYXRhLmlkXS5nZXRFdmVudHMobmV3IERhdGUobXNnLmRhdGEuc3RhcnQpLCBuZXcgRGF0ZShtc2cuZGF0YS5lbmQpKVxuICAgICAgICAgICAgICAgIC5jYXRjaChlID0+IHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coYGNhbm5vdCBsb2FkIGNhbGVuZGFyICR7bXNnLmRhdGEuaWR9YCk7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBbXTtcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgIC50aGVuKGRhdGEgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKGRhdGEpO1xuICAgICAgICAgICAgICAgIGxldCByZXNwID0geyBpZDogbXNnLmlkLCB0eXBlOiA0LCBkYXRhOiBkYXRhLm1hcChlID0+IHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlkOiBlLmlkLFxuICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnQ6IGUuc3RhcnQuZ2V0VGltZSgpLFxuICAgICAgICAgICAgICAgICAgICAgICAgZW5kOiBlLmVuZC5nZXRUaW1lKClcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pfTtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhyZXNwKTtcbiAgICAgICAgICAgICAgICBwb3J0LnBvc3RNZXNzYWdlKHJlc3ApO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAobXNnLnR5cGUgPT0gNSkge1xuICAgICAgICAgICAgY2FsZW5kYXJzID0gbXNnLmRhdGE7XG4gICAgICAgICAgICBmb3IgKGxldCBpZCBpbiBjYWxlbmRhcnMpIHtcbiAgICAgICAgICAgICAgICBpZiAoIWNhbERhdGEuaGFzT3duUHJvcGVydHkoaWQpKVxuICAgICAgICAgICAgICAgICAgICBjYWxEYXRhW2lkXSA9IG5ldyBnYXBpLkdDYWxlbmRhcihpZCwgY2FsZW5kYXJzW2lkXS5zdW1tYXJ5KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJ1bmtub3duIG1zZyB0eXBlXCIpO1xuICAgICAgICB9XG4gICAgfSk7XG59KTtcblxuY2hyb21lLmJyb3dzZXJBY3Rpb24ub25DbGlja2VkLmFkZExpc3RlbmVyKGZ1bmN0aW9uKCkge1xuICAgIGNocm9tZS50YWJzLmNyZWF0ZSh7dXJsOiAnaW5kZXguaHRtbCd9KTtcbn0pO1xuXG4iLCIvKiBnbG9iYWwgY2hyb21lICovXG5jb25zdCBnYXBpX2Jhc2UgPSAnaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vY2FsZW5kYXIvdjMnO1xuXG5jb25zdCBHQXBpRXJyb3IgPSB7XG4gICAgaW52YWxpZFN5bmNUb2tlbjogMSxcbiAgICBvdGhlckVycm9yOiAyLFxufTtcblxuZnVuY3Rpb24gdG9fcGFyYW1zKGRpY3QpIHtcbiAgICByZXR1cm4gT2JqZWN0LmVudHJpZXMoZGljdCkubWFwKChbaywgdl0pID0+IGAke2VuY29kZVVSSUNvbXBvbmVudChrKX09JHtlbmNvZGVVUklDb21wb25lbnQodil9YCkuam9pbignJicpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0QXV0aFRva2VuKCkge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZShyZXNvbHZlciA9PlxuICAgICAgICBjaHJvbWUuaWRlbnRpdHkuZ2V0QXV0aFRva2VuKFxuICAgICAgICAgICAge2ludGVyYWN0aXZlOiB0cnVlfSwgdG9rZW4gPT4gcmVzb2x2ZXIodG9rZW4pKSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRDYWxlbmRhcnModG9rZW4pIHtcbiAgICByZXR1cm4gZmV0Y2goYCR7Z2FwaV9iYXNlfS91c2Vycy9tZS9jYWxlbmRhckxpc3Q/JHt0b19wYXJhbXMoe2FjY2Vzc190b2tlbjogdG9rZW59KX1gLFxuICAgICAgICAgICAgeyBtZXRob2Q6ICdHRVQnLCBhc3luYzogdHJ1ZSB9KVxuICAgICAgICAudGhlbihyZXNwb25zZSA9PiByZXNwb25zZS5qc29uKCkpXG4gICAgICAgIC50aGVuKGRhdGEgPT4gZGF0YS5pdGVtcyk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRDb2xvcnModG9rZW4pIHtcbiAgICByZXR1cm4gZmV0Y2goYCR7Z2FwaV9iYXNlfS9jb2xvcnM/JHt0b19wYXJhbXMoe2FjY2Vzc190b2tlbjogdG9rZW59KX1gLFxuICAgICAgICB7IG1ldGhvZDogJ0dFVCcsIGFzeW5jOiB0cnVlIH0pXG4gICAgICAgIC50aGVuKHJlc3BvbnNlID0+IHJlc3BvbnNlLmpzb24oKSk7XG59XG5cbmZ1bmN0aW9uIGdldEV2ZW50KGNhbElkLCBldmVudElkLCB0b2tlbikge1xuICAgIHJldHVybiBmZXRjaChgJHtnYXBpX2Jhc2V9L2NhbGVuZGFycy8ke2NhbElkfS9ldmVudHMvJHtldmVudElkfT8ke3RvX3BhcmFtcyh7YWNjZXNzX3Rva2VuOiB0b2tlbn0pfWAsXG4gICAgICAgIHsgbWV0aG9kOiAnR0VUJywgYXN5bmM6IHRydWUgfSlcbiAgICAgICAgLnRoZW4ocmVzcG9uc2UgPT4gcmVzcG9uc2UuanNvbigpKTtcbn1cblxuZnVuY3Rpb24gZ2V0RXZlbnRzKGNhbElkLCB0b2tlbiwgc3luY1Rva2VuLCByZXN1bHRzUGVyUmVxdWVzdD0xMDApIHtcbiAgICBsZXQgcmVzdWx0cyA9IFtdO1xuICAgIGNvbnN0IHNpbmdsZUZldGNoID0gKHBhZ2VUb2tlbiwgc3luY1Rva2VuKSA9PiBmZXRjaChgJHtnYXBpX2Jhc2V9L2NhbGVuZGFycy8ke2NhbElkfS9ldmVudHM/JHt0b19wYXJhbXMoe1xuICAgICAgICAgICAgYWNjZXNzX3Rva2VuOiB0b2tlbixcbiAgICAgICAgICAgIHBhZ2VUb2tlbixcbiAgICAgICAgICAgIHN5bmNUb2tlbixcbiAgICAgICAgICAgIG1heFJlc3VsdHM6IHJlc3VsdHNQZXJSZXF1ZXN0XG4gICAgICAgIH0pfWAsIHsgbWV0aG9kOiAnR0VUJywgYXN5bmM6IHRydWUgfSlcbiAgICAgICAgICAgIC50aGVuKHJlc3BvbnNlID0+IHtcbiAgICAgICAgICAgICAgICBpZiAocmVzcG9uc2Uuc3RhdHVzID09PSAyMDApXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiByZXNwb25zZS5qc29uKCk7XG4gICAgICAgICAgICAgICAgZWxzZSBpZiAocmVzcG9uc2Uuc3RhdHVzID09PSA0MTApXG4gICAgICAgICAgICAgICAgICAgIHRocm93IEdBcGlFcnJvci5pbnZhbGlkU3luY1Rva2VuO1xuICAgICAgICAgICAgICAgIGVsc2UgdGhyb3cgR0FwaUVycm9yLm90aGVyRXJyb3JzO1xuICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIC50aGVuKGRhdGEgPT4ge1xuICAgICAgICAgICAgICAgIHJlc3VsdHMucHVzaCguLi5kYXRhLml0ZW1zKTtcbiAgICAgICAgICAgICAgICBpZiAoZGF0YS5uZXh0UGFnZVRva2VuKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBzaW5nbGVGZXRjaChkYXRhLm5leHRQYWdlVG9rZW4sICcnKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gKHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG5leHRTeW5jVG9rZW46IGRhdGEubmV4dFN5bmNUb2tlbixcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdHNcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSlcblxuICAgIHJldHVybiBzaW5nbGVGZXRjaCgnJywgc3luY1Rva2VuKTtcbn1cblxuZXhwb3J0IGNsYXNzIEdDYWxlbmRhciB7XG4gICAgY29uc3RydWN0b3IoY2FsSWQsIG5hbWUpIHtcbiAgICAgICAgdGhpcy5jYWxJZCA9IGNhbElkO1xuICAgICAgICB0aGlzLm5hbWUgPSBuYW1lO1xuICAgICAgICB0aGlzLnRva2VuID0gZ2V0QXV0aFRva2VuKCk7XG4gICAgICAgIHRoaXMuc3luY1Rva2VuID0gJyc7XG4gICAgICAgIHRoaXMuY2FjaGUgPSB7fTtcbiAgICB9XG5cbiAgICBzdGF0aWMgZGF0ZVRvQ2FjaGVLZXkoZGF0ZSkge1xuICAgICAgICByZXR1cm4gTWF0aC5mbG9vcihkYXRlIC8gOC42NGU3KTtcbiAgICB9XG5cbiAgICBnZXRTbG90KGspIHtcbiAgICAgICAgaWYgKCF0aGlzLmNhY2hlW2tdKVxuICAgICAgICAgICAgdGhpcy5jYWNoZVtrXSA9IHt9O1xuICAgICAgICByZXR1cm4gdGhpcy5jYWNoZVtrXTtcbiAgICB9XG5cbiAgICBzdGF0aWMgc2xvdFN0YXJ0RGF0ZShrKSB7IHJldHVybiBuZXcgRGF0ZShrICogOC42NGU3KTsgfVxuICAgIHN0YXRpYyBzbG90RW5kRGF0ZShrKSB7IHJldHVybiBuZXcgRGF0ZSgoayArIDEpICogOC42NGU3KTsgfVxuXG4gICAgYWRkRXZlbnQoZSkge1xuICAgICAgICBsZXQga3MgPSBHQ2FsZW5kYXIuZGF0ZVRvQ2FjaGVLZXkoZS5zdGFydCk7XG4gICAgICAgIGxldCBrZSA9IEdDYWxlbmRhci5kYXRlVG9DYWNoZUtleShuZXcgRGF0ZShlLmVuZC5nZXRUaW1lKCkgLSAxKSk7XG4gICAgICAgIGlmIChrcyA9PT0ga2UpXG4gICAgICAgICAgICB0aGlzLmdldFNsb3Qoa3MpW2UuaWRdID0ge1xuICAgICAgICAgICAgICAgIHN0YXJ0OiBlLnN0YXJ0LFxuICAgICAgICAgICAgICAgIGVuZDogZS5lbmQsXG4gICAgICAgICAgICAgICAgaWQ6IGUuaWQsXG4gICAgICAgICAgICAgICAgc3VtbWFyeTogZS5zdW1tYXJ5fTtcbiAgICAgICAgZWxzZVxuICAgICAgICB7XG4gICAgICAgICAgICB0aGlzLmdldFNsb3Qoa3MpW2UuaWRdID0ge1xuICAgICAgICAgICAgICAgIHN0YXJ0OiBlLnN0YXJ0LFxuICAgICAgICAgICAgICAgIGVuZDogR0NhbGVuZGFyLnNsb3RFbmREYXRlKGtzKSxcbiAgICAgICAgICAgICAgICBpZDogZS5pZCxcbiAgICAgICAgICAgICAgICBzdW1tYXJ5OiBlLnN1bW1hcnl9O1xuICAgICAgICAgICAgdGhpcy5nZXRTbG90KGtlKVtlLmlkXSA9IHtcbiAgICAgICAgICAgICAgICBzdGFydDogR0NhbGVuZGFyLnNsb3RTdGFydERhdGUoa2UpLFxuICAgICAgICAgICAgICAgIGVuZDogZS5lbmQsXG4gICAgICAgICAgICAgICAgaWQ6IGUuaWQsXG4gICAgICAgICAgICAgICAgc3VtbWFyeTogZS5zdW1tYXJ5fTtcbiAgICAgICAgICAgIGZvciAobGV0IGsgPSBrcyArIDE7IGsgPCBrZTsgaysrKVxuICAgICAgICAgICAgICAgIHRoaXMuZ2V0U2xvdChrKVtlLmlkXSA9IHtcbiAgICAgICAgICAgICAgICAgICAgc3RhcnQ6IEdDYWxlbmRhci5zbG90U3RhcnREYXRlKGspLFxuICAgICAgICAgICAgICAgICAgICBlbmQ6IEdDYWxlbmRhci5zbG90RW5kRGF0ZShrKSxcbiAgICAgICAgICAgICAgICAgICAgaWQ6IGUuaWQsXG4gICAgICAgICAgICAgICAgICAgIHN1bW1hcnk6IGUuc3VtbWFyeX07XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZW1vdmVFdmVudChlKSB7XG4gICAgICAgIGxldCBrcyA9IEdDYWxlbmRhci5kYXRlVG9DYWNoZUtleShlLnN0YXJ0KTtcbiAgICAgICAgbGV0IGtlID0gR0NhbGVuZGFyLmRhdGVUb0NhY2hlS2V5KG5ldyBEYXRlKGUuZW5kLmdldFRpbWUoKSAtIDEpKTtcbiAgICAgICAgZm9yIChsZXQgayA9IGtzOyBrIDw9IGtlOyBrKyspXG4gICAgICAgICAgICBkZWxldGUgdGhpcy5nZXRTbG90KGspW2UuaWRdO1xuICAgIH1cblxuICAgIGdldFNsb3RFdmVudHMoaywgc3RhcnQsIGVuZCkge1xuICAgICAgICBsZXQgcyA9IHRoaXMuZ2V0U2xvdChrKTtcbiAgICAgICAgbGV0IHJlc3VsdHMgPSBbXTtcbiAgICAgICAgZm9yIChsZXQgaWQgaW4gcykge1xuICAgICAgICAgICAgaWYgKCEoc1tpZF0uc3RhcnQgPj0gZW5kIHx8IHNbaWRdLmVuZCA8PSBzdGFydCkpXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgcmVzdWx0cy5wdXNoKHtcbiAgICAgICAgICAgICAgICAgICAgaWQsXG4gICAgICAgICAgICAgICAgICAgIHN0YXJ0OiBzW2lkXS5zdGFydCA8IHN0YXJ0ID8gc3RhcnQ6IHNbaWRdLnN0YXJ0LFxuICAgICAgICAgICAgICAgICAgICBlbmQ6IHNbaWRdLmVuZCA+IGVuZCA/IGVuZDogc1tpZF0uZW5kLFxuICAgICAgICAgICAgICAgICAgICBzdW1tYXJ5OiBzW2lkXS5zdW1tYXJ5XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHJlc3VsdHM7XG4gICAgfVxuXG4gICAgZ2V0Q2FjaGVkRXZlbnRzKHN0YXJ0LCBlbmQpIHtcbiAgICAgICAgbGV0IGtzID0gR0NhbGVuZGFyLmRhdGVUb0NhY2hlS2V5KHN0YXJ0KTtcbiAgICAgICAgbGV0IGtlID0gR0NhbGVuZGFyLmRhdGVUb0NhY2hlS2V5KG5ldyBEYXRlKGVuZC5nZXRUaW1lKCkgLSAxKSk7XG4gICAgICAgIGxldCByZXN1bHRzID0gdGhpcy5nZXRTbG90RXZlbnRzKGtzLCBzdGFydCwgZW5kKTtcbiAgICAgICAgZm9yIChsZXQgayA9IGtzICsgMTsgayA8IGtlOyBrKyspXG4gICAgICAgIHtcbiAgICAgICAgICAgIGxldCBzID0gdGhpcy5nZXRTbG90KGspO1xuICAgICAgICAgICAgZm9yIChsZXQgaWQgaW4gcylcbiAgICAgICAgICAgICAgICByZXN1bHRzLnB1c2goc1tpZF0pO1xuICAgICAgICB9XG4gICAgICAgIGlmIChrZSA+IGtzKVxuICAgICAgICAgICAgcmVzdWx0cy5wdXNoKC4uLnRoaXMuZ2V0U2xvdEV2ZW50cyhrZSwgc3RhcnQsIGVuZCkpO1xuICAgICAgICByZXR1cm4gcmVzdWx0cztcbiAgICB9XG5cbiAgICBzeW5jKCkge1xuICAgICAgICByZXR1cm4gdGhpcy50b2tlbi50aGVuKHRva2VuID0+IGdldEV2ZW50cyh0aGlzLmNhbElkLCB0b2tlbiwgdGhpcy5zeW5jVG9rZW4pLnRoZW4ociA9PiB7XG4gICAgICAgICAgICB0aGlzLnN5bmNUb2tlbiA9IHIubmV4dFN5bmNUb2tlbjtcbiAgICAgICAgICAgIGxldCBwbV9yZXN1bHRzID0gci5yZXN1bHRzLm1hcChlID0+IGUuc3RhcnQgPyBQcm9taXNlLnJlc29sdmUoZSkgOiBnZXRFdmVudCh0aGlzLmNhbElkLCBlLmlkLCB0b2tlbikpO1xuICAgICAgICAgICAgcmV0dXJuIFByb21pc2UuYWxsKHBtX3Jlc3VsdHMpLnRoZW4ocmVzdWx0cyA9PiByZXN1bHRzLmZvckVhY2goZSA9PiB7XG4gICAgICAgICAgICAgICAgZS5zdGFydCA9IG5ldyBEYXRlKGUuc3RhcnQuZGF0ZVRpbWUpO1xuICAgICAgICAgICAgICAgIGUuZW5kID0gbmV3IERhdGUoZS5lbmQuZGF0ZVRpbWUpO1xuICAgICAgICAgICAgICAgIGlmIChlLnN0YXR1cyA9PT0gJ2NvbmZpcm1lZCcpXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuYWRkRXZlbnQoZSk7XG4gICAgICAgICAgICAgICAgZWxzZSBpZiAoZS5zdGF0dXMgPT09ICdjYW5jZWxsZWQnKVxuICAgICAgICAgICAgICAgICAgICB0aGlzLnJlbW92ZUV2ZW50KGUpO1xuICAgICAgICAgICAgfSkpO1xuICAgICAgICB9KSkuY2F0Y2goZSA9PiB7XG4gICAgICAgICAgICBpZiAoZSA9PT0gR0FwaUVycm9yLmludmFsaWRTeW5jVG9rZW4pIHtcbiAgICAgICAgICAgICAgICB0aGlzLnN5bmNUb2tlbiA9ICcnO1xuICAgICAgICAgICAgICAgIHRoaXMuc3luYygpO1xuICAgICAgICAgICAgfSBlbHNlIHRocm93IGU7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIGdldEV2ZW50cyhzdGFydCwgZW5kKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnN5bmMoKS50aGVuKCgpID0+IHRoaXMuZ2V0Q2FjaGVkRXZlbnRzKHN0YXJ0LCBlbmQpKTtcbiAgICB9XG59XG4iXX0= diff --git a/build/index.html b/build/index.html index 1880729..2edbc66 100644 --- a/build/index.html +++ b/build/index.html @@ -1 +1 @@ -Chromicle
\ No newline at end of file +Chromicle
\ No newline at end of file diff --git a/build/precache-manifest.4b3348396592c5f2793c6b9bef079d99.js b/build/precache-manifest.4b3348396592c5f2793c6b9bef079d99.js deleted file mode 100644 index 0c285f0..0000000 --- a/build/precache-manifest.4b3348396592c5f2793c6b9bef079d99.js +++ /dev/null @@ -1,118 +0,0 @@ -self.__precacheManifest = [ - { - "revision": "d8bcbe724fd6f4ba44d0ee6a2675890f", - "url": "/static/media/roboto-latin-400italic.d8bcbe72.woff2" - }, - { - "revision": "0c8ec738cbc4afdfc52a", - "url": "/static/js/main.0c8ec738.chunk.js" - }, - { - "revision": "bc833e725c137257c2c42a789845d82f", - "url": "/static/media/roboto-latin-900italic.bc833e72.woff" - }, - { - "revision": "229c360febb4351a89df", - "url": "/static/js/runtime~main.229c360f.js" - }, - { - "revision": "987b84570ea69ee660455b8d5e91f5f1", - "url": "/static/media/roboto-latin-100.987b8457.woff2" - }, - { - "revision": "e9dbbe8a693dd275c16d32feb101f1c1", - "url": "/static/media/roboto-latin-100.e9dbbe8a.woff" - }, - { - "revision": "d704bb3d579b7d5e40880c75705c8a71", - "url": "/static/media/roboto-latin-100italic.d704bb3d.woff" - }, - { - "revision": "55536c8e9e9a532651e3cf374f290ea3", - "url": "/static/media/roboto-latin-300.55536c8e.woff2" - }, - { - "revision": "a1471d1d6431c893582a5f6a250db3f9", - "url": "/static/media/roboto-latin-300.a1471d1d.woff" - }, - { - "revision": "6232f43d15b0e7a0bf0fe82e295bdd06", - "url": "/static/media/roboto-latin-100italic.6232f43d.woff2" - }, - { - "revision": "d69924b98acd849cdeba9fbff3f88ea6", - "url": "/static/media/roboto-latin-300italic.d69924b9.woff2" - }, - { - "revision": "210a7c781f5a354a0e4985656ab456d9", - "url": "/static/media/roboto-latin-300italic.210a7c78.woff" - }, - { - "revision": "bafb105baeb22d965c70fe52ba6b49d9", - "url": "/static/media/roboto-latin-400.bafb105b.woff" - }, - { - "revision": "9680d5a0c32d2fd084e07bbc4c8b2923", - "url": "/static/media/roboto-latin-400italic.9680d5a0.woff" - }, - { - "revision": "8c2ade503b34e31430d6c98aa29a52a3", - "url": "/static/media/roboto-latin-900.8c2ade50.woff" - }, - { - "revision": "285467176f7fe6bb6a9c6873b3dad2cc", - "url": "/static/media/roboto-latin-500.28546717.woff2" - }, - { - "revision": "de8b7431b74642e830af4d4f4b513ec9", - "url": "/static/media/roboto-latin-500.de8b7431.woff" - }, - { - "revision": "510dec37fa69fba39593e01a469ee018", - "url": "/static/media/roboto-latin-500italic.510dec37.woff2" - }, - { - "revision": "ffcc050b2d92d4b14a4fcb527ee0bcc8", - "url": "/static/media/roboto-latin-500italic.ffcc050b.woff" - }, - { - "revision": "037d830416495def72b7881024c14b7b", - "url": "/static/media/roboto-latin-700.037d8304.woff2" - }, - { - "revision": "5d4aeb4e5f5ef754e307d7ffaef688bd", - "url": "/static/media/roboto-latin-400.5d4aeb4e.woff2" - }, - { - "revision": "010c1aeee3c6d1cbb1d5761d80353823", - "url": "/static/media/roboto-latin-700italic.010c1aee.woff2" - }, - { - "revision": "cf6613d1adf490972c557a8e318e0868", - "url": "/static/media/roboto-latin-700.cf6613d1.woff" - }, - { - "revision": "846d1890aee87fde5d8ced8eba360c3a", - "url": "/static/media/roboto-latin-700italic.846d1890.woff" - }, - { - "revision": "19b7a0adfdd4f808b53af7e2ce2ad4e5", - "url": "/static/media/roboto-latin-900.19b7a0ad.woff2" - }, - { - "revision": "7b770d6c53423deb1a8e49d3c9175184", - "url": "/static/media/roboto-latin-900italic.7b770d6c.woff2" - }, - { - "revision": "b5cbbf9bff7bad31bf86", - "url": "/static/js/1.b5cbbf9b.chunk.js" - }, - { - "revision": "b5cbbf9bff7bad31bf86", - "url": "/static/css/1.297ee474.chunk.css" - }, - { - "revision": "ae169eb6e1e22ab620835a8b332f1b63", - "url": "/index.html" - } -]; \ No newline at end of file diff --git a/build/precache-manifest.9f3e92b5e4dff660087cc664d98afa28.js b/build/precache-manifest.9f3e92b5e4dff660087cc664d98afa28.js new file mode 100644 index 0000000..fc13304 --- /dev/null +++ b/build/precache-manifest.9f3e92b5e4dff660087cc664d98afa28.js @@ -0,0 +1,118 @@ +self.__precacheManifest = [ + { + "revision": "9680d5a0c32d2fd084e07bbc4c8b2923", + "url": "/static/media/roboto-latin-400italic.9680d5a0.woff" + }, + { + "revision": "9e0b7c772ae44d9b0a03", + "url": "/static/js/main.9e0b7c77.chunk.js" + }, + { + "revision": "bc833e725c137257c2c42a789845d82f", + "url": "/static/media/roboto-latin-900italic.bc833e72.woff" + }, + { + "revision": "229c360febb4351a89df", + "url": "/static/js/runtime~main.229c360f.js" + }, + { + "revision": "987b84570ea69ee660455b8d5e91f5f1", + "url": "/static/media/roboto-latin-100.987b8457.woff2" + }, + { + "revision": "e9dbbe8a693dd275c16d32feb101f1c1", + "url": "/static/media/roboto-latin-100.e9dbbe8a.woff" + }, + { + "revision": "d704bb3d579b7d5e40880c75705c8a71", + "url": "/static/media/roboto-latin-100italic.d704bb3d.woff" + }, + { + "revision": "6232f43d15b0e7a0bf0fe82e295bdd06", + "url": "/static/media/roboto-latin-100italic.6232f43d.woff2" + }, + { + "revision": "a1471d1d6431c893582a5f6a250db3f9", + "url": "/static/media/roboto-latin-300.a1471d1d.woff" + }, + { + "revision": "55536c8e9e9a532651e3cf374f290ea3", + "url": "/static/media/roboto-latin-300.55536c8e.woff2" + }, + { + "revision": "d69924b98acd849cdeba9fbff3f88ea6", + "url": "/static/media/roboto-latin-300italic.d69924b9.woff2" + }, + { + "revision": "210a7c781f5a354a0e4985656ab456d9", + "url": "/static/media/roboto-latin-300italic.210a7c78.woff" + }, + { + "revision": "5d4aeb4e5f5ef754e307d7ffaef688bd", + "url": "/static/media/roboto-latin-400.5d4aeb4e.woff2" + }, + { + "revision": "bafb105baeb22d965c70fe52ba6b49d9", + "url": "/static/media/roboto-latin-400.bafb105b.woff" + }, + { + "revision": "7b770d6c53423deb1a8e49d3c9175184", + "url": "/static/media/roboto-latin-900italic.7b770d6c.woff2" + }, + { + "revision": "d8bcbe724fd6f4ba44d0ee6a2675890f", + "url": "/static/media/roboto-latin-400italic.d8bcbe72.woff2" + }, + { + "revision": "285467176f7fe6bb6a9c6873b3dad2cc", + "url": "/static/media/roboto-latin-500.28546717.woff2" + }, + { + "revision": "de8b7431b74642e830af4d4f4b513ec9", + "url": "/static/media/roboto-latin-500.de8b7431.woff" + }, + { + "revision": "510dec37fa69fba39593e01a469ee018", + "url": "/static/media/roboto-latin-500italic.510dec37.woff2" + }, + { + "revision": "ffcc050b2d92d4b14a4fcb527ee0bcc8", + "url": "/static/media/roboto-latin-500italic.ffcc050b.woff" + }, + { + "revision": "037d830416495def72b7881024c14b7b", + "url": "/static/media/roboto-latin-700.037d8304.woff2" + }, + { + "revision": "cf6613d1adf490972c557a8e318e0868", + "url": "/static/media/roboto-latin-700.cf6613d1.woff" + }, + { + "revision": "010c1aeee3c6d1cbb1d5761d80353823", + "url": "/static/media/roboto-latin-700italic.010c1aee.woff2" + }, + { + "revision": "846d1890aee87fde5d8ced8eba360c3a", + "url": "/static/media/roboto-latin-700italic.846d1890.woff" + }, + { + "revision": "19b7a0adfdd4f808b53af7e2ce2ad4e5", + "url": "/static/media/roboto-latin-900.19b7a0ad.woff2" + }, + { + "revision": "8c2ade503b34e31430d6c98aa29a52a3", + "url": "/static/media/roboto-latin-900.8c2ade50.woff" + }, + { + "revision": "b5cbbf9bff7bad31bf86", + "url": "/static/js/1.b5cbbf9b.chunk.js" + }, + { + "revision": "b5cbbf9bff7bad31bf86", + "url": "/static/css/1.297ee474.chunk.css" + }, + { + "revision": "aeb657f32a103bb2fa4e6ff7a484612c", + "url": "/index.html" + } +]; \ No newline at end of file diff --git a/build/service-worker.js b/build/service-worker.js index eee1ebb..7623ea8 100644 --- a/build/service-worker.js +++ b/build/service-worker.js @@ -14,7 +14,7 @@ importScripts("https://storage.googleapis.com/workbox-cdn/releases/3.6.3/workbox-sw.js"); importScripts( - "/precache-manifest.4b3348396592c5f2793c6b9bef079d99.js" + "/precache-manifest.9f3e92b5e4dff660087cc664d98afa28.js" ); workbox.clientsClaim(); diff --git a/build/static/js/main.0c8ec738.chunk.js b/build/static/js/main.0c8ec738.chunk.js deleted file mode 100644 index f55a1f0..0000000 --- a/build/static/js/main.0c8ec738.chunk.js +++ /dev/null @@ -1,2 +0,0 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[0],{308:function(e,t,a){e.exports=a(655)},655:function(e,t,a){"use strict";a.r(t);var n=a(1),r=a.n(n),c=a(28),o=a.n(c),i=a(137),l=a(101),s=a(39),u=a(45),h=a(78),d=a(74),m=a(79),p=(a(313),a(315),a(341),a(286)),f=a(31),v=a(99),g=a.n(v),y=a(306),E=a.n(y),w=a(305),b=a.n(w),P=a(173),x=a.n(P),k=a(81),S=a.n(k),T=a(177),C=a.n(T),D=a(93),O=a.n(D),j=a(103),R=a.n(j),N=a(40),B=a.n(N),G=a(307),I=a.n(G),W=a(174),K=a.n(W),A=function(e){return r.a.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 98.905998 93.557997",version:"1.1",style:e.style},r.a.createElement("g",{id:"g13",transform:"translate(-153.533,-203.047)"},r.a.createElement("g",{id:"g29"},r.a.createElement("g",{id:"g27"},r.a.createElement("polygon",{id:"polygon7",points:"252.439,241.924 234.556,288.703 185.103,296.605 153.533,257.728 171.416,210.949 220.869,203.047 ",style:{fill:"#ff8000"}}),r.a.createElement("g",{id:"g11",transform:"translate(167.24355,224.20734)"},r.a.createElement("text",{id:"text9",style:{fontStyle:"normal",fontVariant:"normal",fontWeight:"normal",fontStretch:"normal",fontSize:75,fontFamily:"TypoPRO Fantasque Sans Mono",fill:"#ffeade"},transform:"translate(0.586,49.072)"},"Cr"))))))},_="https://www.googleapis.com/calendar/v3",M={invalidSyncToken:1,otherError:2};function z(e){return Object.entries(e).map(function(e){var t=Object(i.a)(e,2),a=t[0],n=t[1];return"".concat(encodeURIComponent(a),"=").concat(encodeURIComponent(n))}).join("&")}function F(){return new Promise(function(e){return chrome.identity.getAuthToken({interactive:!0},function(t){return e(t)})})}function U(e){return fetch("".concat(_,"/users/me/calendarList?").concat(z({access_token:e})),{method:"GET",async:!0}).then(function(e){return e.json()}).then(function(e){return e.items})}function L(e){return fetch("".concat(_,"/colors?").concat(z({access_token:e})),{method:"GET",async:!0}).then(function(e){return e.json()})}var $=function(){function e(t,a){Object(s.a)(this,e),this.calId=t,this.name=a,this.token=F(),this.syncToken="",this.cache={}}return Object(u.a)(e,[{key:"getSlot",value:function(e){return this.cache[e]||(this.cache[e]={}),this.cache[e]}},{key:"addEvent",value:function(t){var a=e.dateToCacheKey(t.start),n=e.dateToCacheKey(new Date(t.end.getTime()-1));if(a===n)this.getSlot(a)[t.id]={start:t.start,end:t.end,id:t.id};else{this.getSlot(a)[t.id]={start:t.start,end:e.slotEndDate(a),id:t.id},this.getSlot(n)[t.id]={start:e.slotStartDate(n),end:t.end,id:t.id};for(var r=a+1;r=a||n[c].end<=t))(n[c].start(n[c].end>a?a:n[c].end)&&console.log(n[c],t,a),r.push({id:c,start:n[c].starta?a:n[c].end})}return r}},{key:"getCachedEvents",value:function(t,a){for(var n=e.dateToCacheKey(t),r=e.dateToCacheKey(new Date(a.getTime()-1)),c=this.getSlotEvents(n,t,a),o=n+1;on&&c.push.apply(c,Object(l.a)(this.getSlotEvents(r,t,a))),c}},{key:"sync",value:function(){var e=this;return this.token.then(function(t){return function(e,t,a){var n=arguments.length>3&&void 0!==arguments[3]?arguments[3]:100,r=[];return function a(c,o){return fetch("".concat(_,"/calendars/").concat(e,"/events?").concat(z({access_token:t,pageToken:c,syncToken:o,maxResults:n})),{method:"GET",async:!0}).then(function(e){if(200===e.status)return e.json();throw 410==e.status?M.invalidSyncToken:M.otherErrors}).then(function(e){return r.push.apply(r,Object(l.a)(e.items)),e.nextPageToken?a(e.nextPageToken,""):{nextSyncToken:e.nextSyncToken,results:r}})}("",a)}(e.calId,t,e.syncToken).then(function(a){e.syncToken=a.nextSyncToken;var n=a.results.map(function(a){return a.start?Promise.resolve(a):function(e,t,a){return fetch("".concat(_,"/calendars/").concat(e,"/events/").concat(t,"?").concat(z({access_token:a})),{method:"GET",async:!0}).then(function(e){return e.json()})}(e.calId,a.id,t)});return Promise.all(n).then(function(t){return t.forEach(function(t){t.start=new Date(t.start.dateTime),t.end=new Date(t.end.dateTime),"confirmed"===t.status?e.addEvent(t):"cancelled"===t.status&&e.removeEvent(t)})})})}).catch(function(t){if(t!=M.invalidSyncToken)throw t;e.syncToken="",e.sync()})}},{key:"getEvents",value:function(e,t){var a=this;return this.sync().then(function(){return a.getCachedEvents(e,t)})}}],[{key:"dateToCacheKey",value:function(e){return Math.floor(e/864e5)}},{key:"slotStartDate",value:function(e){return new Date(864e5*e)}},{key:"slotEndDate",value:function(e){return new Date(864e5*(e+1))}}]),e}(),H=function(){function e(t,a,n,r){Object(s.a)(this,e),this.id=t,this.isRegex=a,this.value=n,this.label=r}return Object(u.a)(e,[{key:"regex",get:function(){return new RegExp(this.isRegex?this.value:"^".concat(this.value,"$"))}},{key:"isEmpty",get:function(){return null===this.label}}]),e}();H.emptyPattern=function(){return new H(0,!0,"",null)},H.anyPattern=function(){return new H("any",!0,".*","Any")};var J=function e(t,a,n,r){Object(s.a)(this,e),this.name=t,this.idx=a,this.cal=n,this.event=r};J.defaultPatternEntry=function(e){return new J("",e,H.emptyPattern(),H.anyPattern())};var V=a(299),q=a.n(V),X=a(659),Y=a(657),Q=a(656),Z=a(554);function ee(e){var t=e.cx,a=e.cy,n=e.x,c=e.y,o=e.fill,i=e.name,l="middle",s=0,u=0;return nt+2&&(s=5,l="start"),ca+2&&(u=10),r.a.createElement("text",{x:n,y:c,dx:s,dy:u,fill:o,textAnchor:l},"".concat(i))}var te=Object(f.withStyles)(function(e){return{pieChart:{margin:"0 auto"}}})(function(e){return r.a.createElement(B.a,{container:!0,spacing:0},r.a.createElement(B.a,{item:!0,xs:12,lg:6},r.a.createElement("div",{className:e.classes.patternTableWrapper},r.a.createElement(X.a,{width:400,height:250,className:e.classes.pieChart},r.a.createElement(Y.a,{data:e.patternGraphData,dataKey:"value",cx:200,cy:125,outerRadius:60,fill:q.a[300],label:ee}),r.a.createElement(Q.a,{formatter:function(e){return"".concat(e.toFixed(2)," hr")}})))),r.a.createElement(B.a,{item:!0,xs:12,lg:6},r.a.createElement("div",{className:e.classes.patternTableWrapper},r.a.createElement(X.a,{width:400,height:250,className:e.classes.pieChart},r.a.createElement(Y.a,{data:e.calendarGraphData,dataKey:"value",cx:200,cy:125,innerRadius:40,outerRadius:70,fill:g.a[300],label:ee},e.calendarGraphData.map(function(e,t){return r.a.createElement(Z.a,{key:t,fill:e.color})})),r.a.createElement(Q.a,{formatter:function(e){return"".concat(e.toFixed(2)," hr")}})))))}),ae=a(136),ne=a.n(ae),re=a(301),ce=a.n(re),oe=a(303),ie=a.n(oe),le=a(140),se=a.n(le),ue=a(100),he=a.n(ue),de=a(302),me=a.n(de),pe=a(304),fe=a.n(pe),ve=a(300),ge=a.n(ve),ye=a(131),Ee=a.n(ye),we=a(172),be=a.n(we),Pe=function(e){function t(){return Object(s.a)(this,t),Object(h.a)(this,Object(d.a)(t).apply(this,arguments))}return Object(m.a)(t,e),Object(u.a)(t,[{key:"render",value:function(){var e=this,t=this.props.classes,a=[],n=this.props.options,c=new H.emptyPattern;for(var o in n[c.id]=c,n){var i=n[o].isEmpty?r.a.createElement("span",{style:{color:this.props.theme.palette.primary.dark}},"Custom"):n[o].label;a.push(r.a.createElement(be.a,{key:o,value:o},i))}var l=this.props.value.isRegex?t.fieldRegex:t.fieldNoRegex;return r.a.createElement(O.a,null,r.a.createElement("span",null,r.a.createElement(Ee.a,{value:this.props.value.id,onChange:function(t){var a;a=null==n[t.target.value].label?new H(0,!0,e.props.value.isRegex?e.props.value.value:"^".concat(e.props.value.value,"$"),null):n[t.target.value],e.props.onChange({target:{value:a}})},className:l},a),null==this.props.value.label&&r.a.createElement(ne.a,{value:this.props.value.value,onChange:function(t){return e.props.onChange({target:{value:new H(0,!0,t.target.value,null)}})}})))}}]),t}(r.a.Component),xe=Object(f.withStyles)(function(e){return{fieldNoRegex:{width:200},fieldRegex:{marginRight:"0.5em"}}})(Pe);var ke=a(139),Se=a.n(ke),Te=Object(f.createMuiTheme)({palette:{primary:{light:Se.a[300],main:Se.a[500],dark:Se.a[700],contrastText:"#fff"}},typography:{useNextVariants:!0}}),Ce=[{label:"Name",field:"name",elem:ne.a},{label:"Calendar",field:"cal",elem:Object(f.withTheme)(Te)(function(e){var t={};for(var a in e.cached.calendars)t[a]=new H(a,!1,e.cached.calendars[a].name,e.cached.calendars[a].name);return r.a.createElement(xe,{value:e.value,options:t,onChange:e.onChange,theme:e.theme})})},{label:"Event",field:"event",elem:Object(f.withTheme)(Te)(function(e){var t=H.anyPattern(),a={};return a[t.id]=t,r.a.createElement(xe,{value:e.value,options:a,onChange:e.onChange,theme:e.theme})})}],De=function(e){function t(){var e,a;Object(s.a)(this,t);for(var n=arguments.length,r=new Array(n),c=0;c0&&r.a.createElement(se.a,{style:{height:48*s}},r.a.createElement(he.a,{colSpan:Ce.length}))))),r.a.createElement(fe.a,{rowsPerPageOptions:[5,10,25],component:"div",count:c.length,rowsPerPage:i,page:l,backIconButtonProps:{"aria-label":"Previous Page"},nextIconButtonProps:{"aria-label":"Next Page"},onChangePage:this.handleChangePage,onChangeRowsPerPage:this.handleChangeRowsPerPage}))}}]),t}(r.a.Component),Oe=Object(f.withStyles)(function(e){return{deleteButtonShow:{position:"absolute",right:0,height:48},deleteButtonHide:{display:"none"},deleteIcon:{height:"100%",cursor:"pointer"},patternTableWrapper:{overflowX:"auto",overflowY:"hidden"},patternTable:{minWidth:600}}})(De),je=[{name:"Work",value:10,color:g.a[300]},{name:"Wasted",value:10,color:g.a[300]}];var Re=function(e){function t(){var e,a;Object(s.a)(this,t);for(var n=arguments.length,r=new Array(n),c=0;c\n \n \n \n \n \n \n Cr\n \n \n \n \n \n","/* global chrome */\nconst gapi_base = 'https://www.googleapis.com/calendar/v3';\n\nconst GApiError = {\n invalidSyncToken: 1,\n otherError: 2,\n};\n\nfunction to_params(dict) {\n return Object.entries(dict).map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`).join('&');\n}\n\nexport function getAuthToken() {\n return new Promise(resolver =>\n chrome.identity.getAuthToken(\n {interactive: true}, token => resolver(token)));\n}\n\nexport function getCalendars(token) {\n return fetch(`${gapi_base}/users/me/calendarList?${to_params({access_token: token})}`,\n { method: 'GET', async: true })\n .then(response => response.json())\n .then(data => data.items);\n}\n\nexport function getColors(token) {\n return fetch(`${gapi_base}/colors?${to_params({access_token: token})}`,\n { method: 'GET', async: true })\n .then(response => response.json());\n}\n\nfunction getEvent(calId, eventId, token) {\n return fetch(`${gapi_base}/calendars/${calId}/events/${eventId}?${to_params({access_token: token})}`,\n { method: 'GET', async: true })\n .then(response => response.json());\n}\n\nfunction getEvents(calId, token, syncToken, resultsPerRequest=100) {\n let results = [];\n const singleFetch = (pageToken, syncToken) => fetch(`${gapi_base}/calendars/${calId}/events?${to_params({\n access_token: token,\n pageToken,\n syncToken,\n maxResults: resultsPerRequest\n })}`, { method: 'GET', async: true })\n .then(response => {\n if (response.status === 200)\n return response.json();\n else if (response.status == 410)\n throw GApiError.invalidSyncToken;\n else throw GApiError.otherErrors;\n })\n .then(data => {\n results.push(...data.items);\n if (data.nextPageToken) {\n return singleFetch(data.nextPageToken, '');\n } else {\n return ({\n nextSyncToken: data.nextSyncToken,\n results\n });\n }\n })\n\n return singleFetch('', syncToken);\n}\n\nexport class GCalendar {\n constructor(calId, name) {\n this.calId = calId;\n this.name = name;\n this.token = getAuthToken();\n this.syncToken = '';\n this.cache = {};\n }\n\n static dateToCacheKey(date) {\n return Math.floor(date / 8.64e7);\n }\n\n getSlot(k) {\n if (!this.cache[k])\n this.cache[k] = {};\n return this.cache[k];\n }\n\n static slotStartDate(k) { return new Date(k * 8.64e7); }\n static slotEndDate(k) { return new Date((k + 1) * 8.64e7); }\n\n addEvent(e) {\n let ks = GCalendar.dateToCacheKey(e.start);\n let ke = GCalendar.dateToCacheKey(new Date(e.end.getTime() - 1));\n if (ks === ke)\n this.getSlot(ks)[e.id] = {\n start: e.start,\n end: e.end,\n id: e.id };\n else\n {\n this.getSlot(ks)[e.id] = {\n start: e.start,\n end: GCalendar.slotEndDate(ks),\n id: e.id };\n this.getSlot(ke)[e.id] = {\n start: GCalendar.slotStartDate(ke),\n end: e.end,\n id: e.id };\n for (let k = ks + 1; k < ke; k++)\n this.getSlot(k)[e.id] = {\n start: GCalendar.slotStartDate(k),\n end: GCalendar.slotEndDate(k),\n id: e.id };\n }\n }\n\n removeEvent(e) {\n let ks = GCalendar.dateToCacheKey(e.start);\n let ke = GCalendar.dateToCacheKey(new Date(e.end.getTime() - 1));\n for (let k = ks; k <= ke; k++)\n delete this.getSlot(k)[e.id];\n }\n\n getSlotEvents(k, start, end) {\n let s = this.getSlot(k);\n let results = [];\n for (let id in s) {\n if (!(s[id].start >= end || s[id].end <= start))\n {\n let nstart = s[id].start < start ? start: s[id].start;\n let nend = s[id].end > end ? end: s[id].end;\n if (nstart > nend) console.log(s[id], start, end);\n results.push({\n id,\n start: s[id].start < start ? start: s[id].start,\n end: s[id].end > end ? end: s[id].end\n });\n }\n }\n return results;\n }\n\n getCachedEvents(start, end) {\n let ks = GCalendar.dateToCacheKey(start);\n let ke = GCalendar.dateToCacheKey(new Date(end.getTime() - 1));\n let results = this.getSlotEvents(ks, start, end);\n for (let k = ks + 1; k < ke; k++)\n {\n let s = this.getSlot(k);\n for (let id in s)\n results.push(s[id]);\n }\n if (ke > ks)\n results.push(...this.getSlotEvents(ke, start, end));\n return results;\n }\n\n sync() {\n return this.token.then(token => getEvents(this.calId, token, this.syncToken).then(r => {\n this.syncToken = r.nextSyncToken;\n let pm_results = r.results.map(e => e.start ? Promise.resolve(e) : getEvent(this.calId, e.id, token));\n return Promise.all(pm_results).then(results => results.forEach(e => {\n e.start = new Date(e.start.dateTime);\n e.end = new Date(e.end.dateTime);\n if (e.status === 'confirmed')\n this.addEvent(e);\n else if (e.status === 'cancelled')\n this.removeEvent(e);\n }));\n })).catch(e => {\n if (e == GApiError.invalidSyncToken) {\n this.syncToken = '';\n this.sync();\n } else throw e;\n });\n }\n\n getEvents(start, end) {\n return this.sync().then(() => this.getCachedEvents(start, end));\n }\n}\n","export class Pattern {\n constructor(id, isRegex, value, label) {\n this.id = id;\n this.isRegex = isRegex;\n this.value = value;\n this.label = label;\n }\n\n get regex() { return new RegExp(this.isRegex ? this.value : `^${this.value}$`); }\n get isEmpty() { return this.label === null; }\n static emptyPattern = () => new Pattern(0, true, '', null);\n static anyPattern = () => new Pattern('any', true, '.*', 'Any');\n}\n\nexport class PatternEntry {\n constructor(name, idx, calPattern, eventPattern) {\n this.name = name;\n this.idx = idx;\n this.cal = calPattern;\n this.event = eventPattern;\n }\n\n static defaultPatternEntry = (idx) => new PatternEntry('', idx, Pattern.emptyPattern(), Pattern.anyPattern());\n}\n","import React from 'react';\nimport PropTypes from 'prop-types';\nimport { withStyles } from '@material-ui/core/styles';\nimport Grid from '@material-ui/core/Grid';\nimport deepOrange from '@material-ui/core/colors/deepOrange';\nimport cyan from '@material-ui/core/colors/cyan';\nimport { PieChart, Pie, Cell, Tooltip } from 'recharts';\n\nconst styles = theme => ({\n pieChart: {\n margin: '0 auto',\n }\n});\n\nfunction customizedLabel(props) {\n const {cx, cy, x, y, fill, name} = props;\n let anchor = \"middle\";\n const EPS = 2;\n let dx = 0;\n let dy = 0;\n if (x < cx - EPS) {\n dx = -5;\n anchor = \"end\"\n } else if (x > cx + EPS) {\n dx = 5;\n anchor = \"start\";\n }\n\n if (y < cy - EPS) {\n dy = -5;\n } else if (y > cy + EPS) {\n dy = 10;\n }\n\n return ({`${name}`});\n}\n\nfunction ChromiclePieChart(props) {\n return (\n \n \n
\n \n \n `${value.toFixed(2)} hr`}/>\n \n
\n
\n \n
\n \n \n {props.calendarGraphData.map((d, i) => )}\n \n `${value.toFixed(2)} hr`}/>\n \n
\n
\n
);\n}\n\nChromiclePieChart.propTypes = {\n patternGraphData: PropTypes.array.isRequired,\n calendarGraphData: PropTypes.array.isRequired,\n};\n\nexport default withStyles(styles)(ChromiclePieChart);\n","import React from 'react';\nimport PropTypes from 'prop-types';\nimport { withStyles } from '@material-ui/core/styles';\nimport Select from '@material-ui/core/Select';\nimport MenuItem from '@material-ui/core/MenuItem';\nimport TextField from '@material-ui/core/TextField';\nimport FormControl from '@material-ui/core/FormControl';\nimport { Pattern } from './pattern';\n\nconst styles = theme => ({\n fieldNoRegex: {\n width: 200\n },\n fieldRegex: {\n marginRight: '0.5em'\n }\n});\n\nclass RegexField extends React.Component {\n render() {\n const { classes } = this.props;\n let items = [];\n var pitems = this.props.options;\n const p0 = new Pattern.emptyPattern();\n pitems[p0.id] = p0;\n for (let id in pitems)\n {\n const label = !pitems[id].isEmpty ? pitems[id].label :\n Custom;\n items.push({label});\n }\n const selectOnClick = event => {\n let value;\n if (pitems[event.target.value].label == null) {\n value = new Pattern(0, true,\n this.props.value.isRegex ?\n this.props.value.value :\n `^${this.props.value.value}$`, null);\n } else {\n value = pitems[event.target.value];\n }\n this.props.onChange({target: {value}});\n };\n\n const regexTextOnChange = event => this.props.onChange({\n target: { value: new Pattern(0, true, event.target.value, null)}});\n\n const className = this.props.value.isRegex ? classes.fieldRegex: classes.fieldNoRegex;\n return (\n \n \n {items}\n \n {this.props.value.label == null && (\n \n )}\n \n );\n }\n}\n\nRegexField.propTypes = {\n classes: PropTypes.object.isRequired,\n};\n\nconst RegexFieldWithStyles = withStyles(styles)(RegexField);\n\nexport function CalendarField(props) {\n let options = {};\n for (let id in props.cached.calendars) {\n options[id] = new Pattern(id, false,\n props.cached.calendars[id].name,\n props.cached.calendars[id].name);\n }\n return (\n );\n}\n\nexport function EventField(props) {\n let any = Pattern.anyPattern();\n let options = {};\n options[any.id] = any;\n return (\n );\n}\n","import { createMuiTheme } from '@material-ui/core/styles';\nimport orange from '@material-ui/core/colors/orange';\n\nconst theme = createMuiTheme({\n palette: {\n primary: {\n light: orange[300],\n main: orange[500],\n dark: orange[700],\n contrastText: \"#fff\"\n }\n },\n typography: {\n useNextVariants: true,\n }\n});\n\nexport default theme;\n","import React from 'react';\nimport PropTypes from 'prop-types';\nimport { withStyles, withTheme } from '@material-ui/core/styles';\nimport TextField from '@material-ui/core/TextField';\nimport Table from '@material-ui/core/Table';\nimport TableBody from '@material-ui/core/TableBody';\nimport TableRow from '@material-ui/core/TableRow';\nimport TableCell from '@material-ui/core/TableCell';\nimport TableHead from '@material-ui/core/TableHead';\nimport TablePagination from '@material-ui/core/TablePagination';\nimport DeleteOutlinedIcon from '@material-ui/icons/DeleteOutlined';\nimport { CalendarField, EventField } from './RegexField';\nimport theme from './theme';\n\nconst styles = theme => ({\n deleteButtonShow: {\n position: 'absolute',\n right: 0,\n height: 48\n },\n deleteButtonHide: {\n display: 'none'\n },\n deleteIcon: {\n height: '100%',\n cursor: 'pointer'\n },\n patternTableWrapper: {\n overflowX: 'auto',\n overflowY: 'hidden'\n },\n patternTable: {\n minWidth: 600\n }\n});\n\nconst patternHead = [\n {label: \"Name\", field: \"name\", elem: TextField},\n {label: \"Calendar\", field: \"cal\", elem: withTheme(theme)(CalendarField)},\n {label: \"Event\", field: 'event', elem: withTheme(theme)(EventField)}];\n\nclass PatternTable extends React.Component {\n state = {\n page: 0,\n rowsPerPage: 5,\n };\n\n handleChangePage = (event, page) => {\n this.setState({ page });\n }\n\n handleChangeRowsPerPage = event => {\n this.setState({ rowsPerPage: event.target.value });\n }\n\n render() {\n const { classes, cached, patterns } = this.props;\n const { rowsPerPage, page } = this.state;\n const nDummy = rowsPerPage - Math.min(rowsPerPage, patterns.length - page * rowsPerPage);\n let rows = patterns.slice(page * rowsPerPage, (page + 1) * rowsPerPage).map(p => (\n this.setState({ activePattern: p.idx })}\n onMouseOut={() => this.setState({ activePattern: null })}>\n {\n patternHead.map(s => {\n const CustomText = s.elem;\n return (\n \n this.props.onUpdatePattern(s.field, p.idx, event.target.value)}/>\n )})\n }\n \n this.props.onRemovePattern(p.idx)} />\n \n ));\n\n return (\n
\n
\n \n \n {patternHead.map((s, i) => ({s.label}))}\n \n \n {rows}\n {\n nDummy > 0 && (\n \n \n )\n }\n \n
\n
\n \n
);\n }\n}\n\n\nPatternTable.propTypes = {\n classes: PropTypes.object.isRequired,\n patterns: PropTypes.array.isRequired,\n cached: PropTypes.object.isRequired,\n onRemovePattern: PropTypes.func.isRequired,\n onUpdatePattern: PropTypes.func.isRequired,\n};\n\nexport default withStyles(styles)(PatternTable);\n","import React from 'react';\nimport PropTypes from 'prop-types';\nimport 'typeface-roboto';\nimport 'react-dates/initialize';\nimport 'react-dates/lib/css/_datepicker.css';\nimport { DateRangePicker } from 'react-dates';\nimport { withStyles } from '@material-ui/core/styles';\nimport { MuiThemeProvider } from '@material-ui/core/styles';\nimport cyan from '@material-ui/core/colors/cyan';\nimport CssBaseline from '@material-ui/core/CssBaseline';\nimport AppBar from '@material-ui/core/AppBar';\nimport Toolbar from '@material-ui/core/Toolbar';\nimport Typography from '@material-ui/core/Typography';\nimport Button from '@material-ui/core/Button';\nimport FormControl from '@material-ui/core/FormControl';\nimport FormGroup from '@material-ui/core/FormGroup';\nimport Grid from '@material-ui/core/Grid';\nimport AddCircleIcon from '@material-ui/icons/AddCircle';\nimport IconButton from '@material-ui/core/IconButton';\nimport Logo from './Logo';\nimport * as gapi from './gapi';\nimport { Pattern, PatternEntry } from './pattern';\nimport PieChart from './Chart';\nimport PatternTable from './PatternTable';\nimport theme from './theme';\n\nconst default_chart_data = [\n {name: 'Work', value: 10, color: cyan[300]},\n {name: 'Wasted', value: 10, color: cyan[300]}];\n\nfunction filterPatterns(patterns, calName) {\n return patterns.filter(p => {\n return p.cal.regex.test(calName);\n });\n}\n\nconst styles = theme => ({\n root: {\n display: 'flex',\n height: '100vh',\n },\n appBar: {\n zIndex: theme.zIndex.drawer + 1,\n transition: theme.transitions.create(['width', 'margin'], {\n easing: theme.transitions.easing.sharp,\n duration: theme.transitions.duration.leavingScreen,\n }),\n },\n title: {\n flexGrow: 1,\n },\n sectionTitle: {\n flex: '0 0 auto'\n },\n appBarSpacer: theme.mixins.toolbar,\n content: {\n flexGrow: 1,\n padding: theme.spacing.unit * 3,\n overflow: 'auto',\n },\n buttonSpacer: {\n marginBottom: theme.spacing.unit * 4,\n },\n fab: {\n margin: theme.spacing.unit,\n },\n});\n\nclass Dashboard extends React.Component {\n state = {\n patterns: [],\n timeRange: null,\n token: gapi.getAuthToken(),\n patternGraphData: default_chart_data,\n calendarGraphData: default_chart_data,\n activePattern: null\n };\n\n cached = {\n calendars: {}\n };\n\n updatePattern = (field, idx, value) => {\n let patterns = this.state.patterns;\n patterns[idx][field] = value;\n this.setState({ patterns });\n };\n\n removePattern = idx => {\n let patterns = this.state.patterns;\n patterns.splice(idx, 1);\n for (let i = 0; i < patterns.length; i++)\n patterns[i].idx = i;\n this.setState({ patterns });\n };\n\n newPattern = () => {\n let patterns = [PatternEntry.defaultPatternEntry(), ...this.state.patterns];\n for (let i = 1; i < patterns.length; i++)\n patterns[i].idx = i;\n this.setState({ patterns });\n };\n\n analyze = () => {\n if (!(this.state.startDate && this.state.endDate)) {\n alert(\"Please choose a valid time range.\");\n return;\n }\n let start = this.state.startDate.startOf('day').toDate();\n let end = this.state.endDate.startOf('day').toDate();\n console.log(start, end);\n let event_pms = [];\n for (let id in this.cached.calendars)\n event_pms.push(this.cached.calendars[id].cal.getEvents(start, end)\n .then(r => { return { id, events: r }; })\n .catch(e => {\n console.log(`cannot load calendar ${id}`);\n return { id, events: [] };\n }));\n\n Promise.all(event_pms).then(all_events => {\n let events = {};\n let results = {}; // pattern idx => time\n let cal_results = {}; // cal id => time\n all_events.forEach(e => events[e.id] = e.events);\n for (let i = 0; i < this.state.patterns.length; i++)\n results[i] = 0;\n for (let id in this.cached.calendars) {\n if (!events[id]) continue;\n let patterns = filterPatterns(this.state.patterns, this.cached.calendars[id].name);\n events[id].forEach(event => {\n patterns.forEach(p => {\n if (!p.event.regex.test(event.summary)) return;\n if (!cal_results.hasOwnProperty(id)) {\n cal_results[id] = 0;\n }\n let duration = (event.end - event.start) / 60000;\n results[p.idx] += duration;\n cal_results[id] += duration;\n });\n });\n }\n let patternGraphData = [];\n let calendarGraphData = [];\n for (let i = 0; i < this.state.patterns.length; i++) {\n patternGraphData.push({ name: this.state.patterns[i].name, value: results[i] / 60.0 });\n }\n for (let id in cal_results) {\n calendarGraphData.push({\n name: this.cached.calendars[id].name,\n value: (cal_results[id] / 60.0),\n color: this.cached.calendars[id].color.background});\n }\n //console.log(patternGraphData, calendarGraphData);\n this.setState({ patternGraphData, calendarGraphData });\n });\n };\n\n loadPatterns = () => {\n let token = this.state.token;\n let colors = token.then(gapi.getColors).then(color => {\n return color.calendar;\n });\n let cals = token.then(gapi.getCalendars);\n Promise.all([colors, cals]).then(([colors, items]) => {\n items.forEach(item => {\n this.cached.calendars[item.id] = {\n name: item.summary,\n color: colors[item.colorId],\n cal: new gapi.GCalendar(item.id, item.summary)\n };\n });\n this.setState({ patterns: items.map((item, idx) => {\n return new PatternEntry(item.summary, idx,\n new Pattern(item.id, false, item.summary, item.summary),\n Pattern.anyPattern());\n })});\n });\n };\n\n render() {\n const { classes } = this.props;\n\n return (\n \n
\n \n \n \n Chromicle\n \n \n \n
\n
\n \n \n \n \n \n \n Event Patterns\n this.newPattern()}>\n \n \n \n \n \n Time Range\n \n
\n {\n this.setState({ startDate, endDate });\n }} \n focusedInput={this.state.focusedInput}\n onFocusChange={focusedInput => this.setState({ focusedInput })}\n isOutsideRange={() => false}/>\n
\n
\n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n Graph\n \n \n \n \n
\n
\n
);\n }\n}\n\nDashboard.propTypes = {\n classes: PropTypes.object.isRequired,\n};\n\nexport default withStyles(styles)(Dashboard);\n","// This optional code is used to register a service worker.\n// register() is not called by default.\n\n// This lets the app load faster on subsequent visits in production, and gives\n// it offline capabilities. However, it also means that developers (and users)\n// will only see deployed updates on subsequent visits to a page, after all the\n// existing tabs open on the page have been closed, since previously cached\n// resources are updated in the background.\n\n// To learn more about the benefits of this model and instructions on how to\n// opt-in, read http://bit.ly/CRA-PWA\n\nconst isLocalhost = Boolean(\n window.location.hostname === 'localhost' ||\n // [::1] is the IPv6 localhost address.\n window.location.hostname === '[::1]' ||\n // 127.0.0.1/8 is considered localhost for IPv4.\n window.location.hostname.match(\n /^127(?:\\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/\n )\n);\n\nexport function register(config) {\n if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {\n // The URL constructor is available in all browsers that support SW.\n const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);\n if (publicUrl.origin !== window.location.origin) {\n // Our service worker won't work if PUBLIC_URL is on a different origin\n // from what our page is served on. This might happen if a CDN is used to\n // serve assets; see https://github.com/facebook/create-react-app/issues/2374\n return;\n }\n\n window.addEventListener('load', () => {\n const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;\n\n if (isLocalhost) {\n // This is running on localhost. Let's check if a service worker still exists or not.\n checkValidServiceWorker(swUrl, config);\n\n // Add some additional logging to localhost, pointing developers to the\n // service worker/PWA documentation.\n navigator.serviceWorker.ready.then(() => {\n console.log(\n 'This web app is being served cache-first by a service ' +\n 'worker. To learn more, visit http://bit.ly/CRA-PWA'\n );\n });\n } else {\n // Is not localhost. Just register service worker\n registerValidSW(swUrl, config);\n }\n });\n }\n}\n\nfunction registerValidSW(swUrl, config) {\n navigator.serviceWorker\n .register(swUrl)\n .then(registration => {\n registration.onupdatefound = () => {\n const installingWorker = registration.installing;\n if (installingWorker == null) {\n return;\n }\n installingWorker.onstatechange = () => {\n if (installingWorker.state === 'installed') {\n if (navigator.serviceWorker.controller) {\n // At this point, the updated precached content has been fetched,\n // but the previous service worker will still serve the older\n // content until all client tabs are closed.\n console.log(\n 'New content is available and will be used when all ' +\n 'tabs for this page are closed. See http://bit.ly/CRA-PWA.'\n );\n\n // Execute callback\n if (config && config.onUpdate) {\n config.onUpdate(registration);\n }\n } else {\n // At this point, everything has been precached.\n // It's the perfect time to display a\n // \"Content is cached for offline use.\" message.\n console.log('Content is cached for offline use.');\n\n // Execute callback\n if (config && config.onSuccess) {\n config.onSuccess(registration);\n }\n }\n }\n };\n };\n })\n .catch(error => {\n console.error('Error during service worker registration:', error);\n });\n}\n\nfunction checkValidServiceWorker(swUrl, config) {\n // Check if the service worker can be found. If it can't reload the page.\n fetch(swUrl)\n .then(response => {\n // Ensure service worker exists, and that we really are getting a JS file.\n const contentType = response.headers.get('content-type');\n if (\n response.status === 404 ||\n (contentType != null && contentType.indexOf('javascript') === -1)\n ) {\n // No service worker found. Probably a different app. Reload the page.\n navigator.serviceWorker.ready.then(registration => {\n registration.unregister().then(() => {\n window.location.reload();\n });\n });\n } else {\n // Service worker found. Proceed as normal.\n registerValidSW(swUrl, config);\n }\n })\n .catch(() => {\n console.log(\n 'No internet connection found. App is running in offline mode.'\n );\n });\n}\n\nexport function unregister() {\n if ('serviceWorker' in navigator) {\n navigator.serviceWorker.ready.then(registration => {\n registration.unregister();\n });\n }\n}\n","import React from 'react';\nimport ReactDOM from 'react-dom';\nimport App from './App';\nimport * as serviceWorker from './serviceWorker';\n\nReactDOM.render(, document.getElementById('root'));\n\n// If you want your app to work offline and load faster, you can change\n// unregister() to register() below. Note this comes with some pitfalls.\n// Learn more about service workers: http://bit.ly/CRA-PWA\nserviceWorker.unregister();\n"],"sourceRoot":""} \ No newline at end of file diff --git a/build/static/js/main.9e0b7c77.chunk.js b/build/static/js/main.9e0b7c77.chunk.js new file mode 100644 index 0000000..bc640ed --- /dev/null +++ b/build/static/js/main.9e0b7c77.chunk.js @@ -0,0 +1,2 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[0],{308:function(e,t,a){e.exports=a(655)},655:function(e,t,a){"use strict";a.r(t);var n=a(1),r=a.n(n),o=a(28),l=a.n(o),i=a(137),s=a(101),c=a(39),u=a(45),m=a(78),d=a(74),p=a(79),h=(a(313),a(315),a(341),a(286)),f=a(31),g=a(99),v=a.n(g),E=a(306),y=a.n(E),w=a(305),b=a.n(w),P=a(173),x=a.n(P),C=a(81),O=a.n(C),j=a(177),k=a.n(j),D=a(93),S=a.n(D),R=a(103),N=a.n(R),T=a(40),B=a.n(T),I=a(307),M=a.n(I),G=a(174),W=a.n(G),F=function(e){return r.a.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 98.905998 93.557997",version:"1.1",style:e.style},r.a.createElement("g",{id:"g13",transform:"translate(-153.533,-203.047)"},r.a.createElement("g",{id:"g29"},r.a.createElement("g",{id:"g27"},r.a.createElement("polygon",{id:"polygon7",points:"252.439,241.924 234.556,288.703 185.103,296.605 153.533,257.728 171.416,210.949 220.869,203.047 ",style:{fill:"#ff8000"}}),r.a.createElement("g",{id:"g11",transform:"translate(167.24355,224.20734)"},r.a.createElement("text",{id:"text9",style:{fontStyle:"normal",fontVariant:"normal",fontWeight:"normal",fontStretch:"normal",fontSize:75,fontFamily:"TypoPRO Fantasque Sans Mono",fill:"#ffeade"},transform:"translate(0.586,49.072)"},"Cr"))))))},A="https://www.googleapis.com/calendar/v3";function q(e){return Object.entries(e).map(function(e){var t=Object(i.a)(e,2),a=t[0],n=t[1];return"".concat(encodeURIComponent(a),"=").concat(encodeURIComponent(n))}).join("&")}function z(){return new Promise(function(e){return chrome.identity.getAuthToken({interactive:!0},function(t){return e(t)})})}function _(e){return fetch("".concat(A,"/users/me/calendarList?").concat(q({access_token:e})),{method:"GET",async:!0}).then(function(e){return e.json()}).then(function(e){return e.items})}function L(e){return fetch("".concat(A,"/colors?").concat(q({access_token:e})),{method:"GET",async:!0}).then(function(e){return e.json()})}var U=function(){function e(t,a,n,r){Object(c.a)(this,e),this.id=t,this.isRegex=a,this.value=n,this.label=r}return Object(u.a)(e,[{key:"regex",get:function(){return new RegExp(this.isRegex?this.value:"^".concat(this.value,"$"))}},{key:"isEmpty",get:function(){return null===this.label}}]),e}();U.emptyPattern=function(){return new U(0,!0,"",null)},U.anyPattern=function(){return new U("any",!0,".*","Any")},U.revive=function(e){return new U(e.id,e.isRegex,e.value,e.label)};var $=function e(t,a,n,r){Object(c.a)(this,e),this.name=t,this.idx=a,this.cal=n,this.event=r};$.defaultPatternEntry=function(e){return new $("",e,U.emptyPattern(),U.anyPattern())},$.revive=function(e){return new $(e.name,e.idx,U.revive(e.cal),U.revive(e.event))};var H=a(299),J=a.n(H),K=a(659),V=a(657),X=a(656),Y=a(554);function Q(e){var t=e.cx,a=e.cy,n=e.x,o=e.y,l=e.fill,i=e.name,s="middle",c=0,u=0;return nt+2&&(c=5,s="start"),oa+2&&(u=10),r.a.createElement("text",{x:n,y:o,dx:c,dy:u,fill:l,textAnchor:s},"".concat(i))}var Z=Object(f.withStyles)(function(e){return{pieChart:{margin:"0 auto"}}})(function(e){return r.a.createElement(B.a,{container:!0,spacing:0},r.a.createElement(B.a,{item:!0,xs:12,lg:6},r.a.createElement("div",{className:e.classes.patternTableWrapper},r.a.createElement(K.a,{width:400,height:250,className:e.classes.pieChart},r.a.createElement(V.a,{data:e.patternGraphData,dataKey:"value",cx:200,cy:125,outerRadius:60,fill:J.a[300],label:Q}),r.a.createElement(X.a,{formatter:function(e){return"".concat(e.toFixed(2)," hr")}})))),r.a.createElement(B.a,{item:!0,xs:12,lg:6},r.a.createElement("div",{className:e.classes.patternTableWrapper},r.a.createElement(K.a,{width:400,height:250,className:e.classes.pieChart},r.a.createElement(V.a,{data:e.calendarGraphData,dataKey:"value",cx:200,cy:125,innerRadius:40,outerRadius:70,fill:v.a[300],label:Q},e.calendarGraphData.map(function(e,t){return r.a.createElement(Y.a,{key:t,fill:e.color})})),r.a.createElement(X.a,{formatter:function(e){return"".concat(e.toFixed(2)," hr")}})))))}),ee=a(136),te=a.n(ee),ae=a(301),ne=a.n(ae),re=a(303),oe=a.n(re),le=a(140),ie=a.n(le),se=a(100),ce=a.n(se),ue=a(302),me=a.n(ue),de=a(304),pe=a.n(de),he=a(300),fe=a.n(he),ge=a(131),ve=a.n(ge),Ee=a(172),ye=a.n(Ee),we=function(e){function t(){return Object(c.a)(this,t),Object(m.a)(this,Object(d.a)(t).apply(this,arguments))}return Object(p.a)(t,e),Object(u.a)(t,[{key:"render",value:function(){var e=this,t=this.props.classes,a=[],n=this.props.options,o=new U.emptyPattern;for(var l in n[o.id]=o,n){var i=n[l].isEmpty?r.a.createElement("span",{style:{color:this.props.theme.palette.primary.dark}},"Custom"):n[l].label;a.push(r.a.createElement(ye.a,{key:l,value:l},i))}var s=this.props.value.isRegex?t.fieldRegex:t.fieldNoRegex;return r.a.createElement(S.a,null,r.a.createElement("span",null,r.a.createElement(ve.a,{value:this.props.value.id,onChange:function(t){var a;a=null==n[t.target.value].label?new U(0,!0,e.props.value.isRegex?e.props.value.value:"^".concat(e.props.value.value,"$"),null):n[t.target.value],e.props.onChange({target:{value:a}})},className:s},a),null==this.props.value.label&&r.a.createElement(te.a,{value:this.props.value.value,onChange:function(t){return e.props.onChange({target:{value:new U(0,!0,t.target.value,null)}})}})))}}]),t}(r.a.Component),be=Object(f.withStyles)(function(e){return{fieldNoRegex:{width:200},fieldRegex:{marginRight:"0.5em"}}})(we);var Pe=a(139),xe=a.n(Pe),Ce=Object(f.createMuiTheme)({palette:{primary:{light:xe.a[300],main:xe.a[500],dark:xe.a[700],contrastText:"#fff"}},typography:{useNextVariants:!0}}),Oe=[{label:"Name",field:"name",elem:te.a},{label:"Calendar",field:"cal",elem:Object(f.withTheme)(Ce)(function(e){var t={};for(var a in e.calendars)t[a]=new U(a,!1,e.calendars[a].name,e.calendars[a].name);return r.a.createElement(be,{value:e.value,options:t,onChange:e.onChange,theme:e.theme})})},{label:"Event",field:"event",elem:Object(f.withTheme)(Ce)(function(e){var t=U.anyPattern(),a={};return a[t.id]=t,r.a.createElement(be,{value:e.value,options:a,onChange:e.onChange,theme:e.theme})})}],je=function(e){function t(){var e,a;Object(c.a)(this,t);for(var n=arguments.length,r=new Array(n),o=0;o0&&r.a.createElement(ie.a,{style:{height:48*c}},r.a.createElement(ce.a,{colSpan:Oe.length}))))),r.a.createElement(pe.a,{rowsPerPageOptions:[5,10,25],component:"div",count:o.length,rowsPerPage:i,page:s,backIconButtonProps:{"aria-label":"Previous Page"},nextIconButtonProps:{"aria-label":"Next Page"},onChangePage:this.handleChangePage,onChangeRowsPerPage:this.handleChangeRowsPerPage}))}}]),t}(r.a.Component),ke=Object(f.withStyles)(function(e){return{deleteButtonShow:{position:"absolute",right:0,height:48},deleteButtonHide:{display:"none"},deleteIcon:{height:"100%",cursor:"pointer"},patternTableWrapper:{overflowX:"auto",overflowY:"hidden"},patternTable:{minWidth:600}}})(je),De=[{name:"Work",value:10,color:v.a[300]},{name:"Wasted",value:10,color:v.a[300]}];var Se=function(e){function t(e){var a;Object(c.a)(this,t),(a=Object(m.a)(this,Object(d.a)(t).call(this,e))).state={patterns:[],calendars:[],timeRange:null,token:z(),patternGraphData:De,calendarGraphData:De,activePattern:null},a.updatePattern=function(e,t,n){var r=a.state.patterns;r[t][e]=n,a.setState({patterns:r}),a.sendMsg({type:0,data:r})},a.removePattern=function(e){var t=a.state.patterns;t.splice(e,1);for(var n=0;n0?r.ids.pop():r.maxId++,r.inFlight[n]=t,e.id=n,a.port.postMessage(e),o},a.getCalEvents=function(e,t,n){return a.sendMsg({type:4,data:{id:e,start:t.getTime(),end:n.getTime()}}).then(function(e){return e.data.map(function(e){return{id:e.id,start:new Date(e.start),end:new Date(e.end)}})})},a.analyze=function(){if(a.state.startDate&&a.state.endDate){var e=a.state.startDate.startOf("day").toDate(),t=a.state.endDate.startOf("day").toDate(),n=[],r=a.state.calendars,o=function(r){n.push(a.getCalEvents(r,e,t).then(function(e){return{id:r,events:e}}))};for(var l in r)o(l);console.log(r),Promise.all(n).then(function(e){console.log(e);var t={},n={},o={};e.forEach(function(e){return t[e.id]=e.events});for(var l=0;l\n \n \n \n \n \n \n Cr\n \n \n \n \n \n","/* global chrome */\nconst gapi_base = 'https://www.googleapis.com/calendar/v3';\n\nconst GApiError = {\n invalidSyncToken: 1,\n otherError: 2,\n};\n\nfunction to_params(dict) {\n return Object.entries(dict).map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`).join('&');\n}\n\nexport function getAuthToken() {\n return new Promise(resolver =>\n chrome.identity.getAuthToken(\n {interactive: true}, token => resolver(token)));\n}\n\nexport function getCalendars(token) {\n return fetch(`${gapi_base}/users/me/calendarList?${to_params({access_token: token})}`,\n { method: 'GET', async: true })\n .then(response => response.json())\n .then(data => data.items);\n}\n\nexport function getColors(token) {\n return fetch(`${gapi_base}/colors?${to_params({access_token: token})}`,\n { method: 'GET', async: true })\n .then(response => response.json());\n}\n\nfunction getEvent(calId, eventId, token) {\n return fetch(`${gapi_base}/calendars/${calId}/events/${eventId}?${to_params({access_token: token})}`,\n { method: 'GET', async: true })\n .then(response => response.json());\n}\n\nfunction getEvents(calId, token, syncToken, resultsPerRequest=100) {\n let results = [];\n const singleFetch = (pageToken, syncToken) => fetch(`${gapi_base}/calendars/${calId}/events?${to_params({\n access_token: token,\n pageToken,\n syncToken,\n maxResults: resultsPerRequest\n })}`, { method: 'GET', async: true })\n .then(response => {\n if (response.status === 200)\n return response.json();\n else if (response.status === 410)\n throw GApiError.invalidSyncToken;\n else throw GApiError.otherErrors;\n })\n .then(data => {\n results.push(...data.items);\n if (data.nextPageToken) {\n return singleFetch(data.nextPageToken, '');\n } else {\n return ({\n nextSyncToken: data.nextSyncToken,\n results\n });\n }\n })\n\n return singleFetch('', syncToken);\n}\n\nexport class GCalendar {\n constructor(calId, name) {\n this.calId = calId;\n this.name = name;\n this.token = getAuthToken();\n this.syncToken = '';\n this.cache = {};\n }\n\n static dateToCacheKey(date) {\n return Math.floor(date / 8.64e7);\n }\n\n getSlot(k) {\n if (!this.cache[k])\n this.cache[k] = {};\n return this.cache[k];\n }\n\n static slotStartDate(k) { return new Date(k * 8.64e7); }\n static slotEndDate(k) { return new Date((k + 1) * 8.64e7); }\n\n addEvent(e) {\n let ks = GCalendar.dateToCacheKey(e.start);\n let ke = GCalendar.dateToCacheKey(new Date(e.end.getTime() - 1));\n if (ks === ke)\n this.getSlot(ks)[e.id] = {\n start: e.start,\n end: e.end,\n id: e.id,\n summary: e.summary};\n else\n {\n this.getSlot(ks)[e.id] = {\n start: e.start,\n end: GCalendar.slotEndDate(ks),\n id: e.id,\n summary: e.summary};\n this.getSlot(ke)[e.id] = {\n start: GCalendar.slotStartDate(ke),\n end: e.end,\n id: e.id,\n summary: e.summary};\n for (let k = ks + 1; k < ke; k++)\n this.getSlot(k)[e.id] = {\n start: GCalendar.slotStartDate(k),\n end: GCalendar.slotEndDate(k),\n id: e.id,\n summary: e.summary};\n }\n }\n\n removeEvent(e) {\n let ks = GCalendar.dateToCacheKey(e.start);\n let ke = GCalendar.dateToCacheKey(new Date(e.end.getTime() - 1));\n for (let k = ks; k <= ke; k++)\n delete this.getSlot(k)[e.id];\n }\n\n getSlotEvents(k, start, end) {\n let s = this.getSlot(k);\n let results = [];\n for (let id in s) {\n if (!(s[id].start >= end || s[id].end <= start))\n {\n results.push({\n id,\n start: s[id].start < start ? start: s[id].start,\n end: s[id].end > end ? end: s[id].end,\n summary: s[id].summary\n });\n }\n }\n return results;\n }\n\n getCachedEvents(start, end) {\n let ks = GCalendar.dateToCacheKey(start);\n let ke = GCalendar.dateToCacheKey(new Date(end.getTime() - 1));\n let results = this.getSlotEvents(ks, start, end);\n for (let k = ks + 1; k < ke; k++)\n {\n let s = this.getSlot(k);\n for (let id in s)\n results.push(s[id]);\n }\n if (ke > ks)\n results.push(...this.getSlotEvents(ke, start, end));\n return results;\n }\n\n sync() {\n return this.token.then(token => getEvents(this.calId, token, this.syncToken).then(r => {\n this.syncToken = r.nextSyncToken;\n let pm_results = r.results.map(e => e.start ? Promise.resolve(e) : getEvent(this.calId, e.id, token));\n return Promise.all(pm_results).then(results => results.forEach(e => {\n e.start = new Date(e.start.dateTime);\n e.end = new Date(e.end.dateTime);\n if (e.status === 'confirmed')\n this.addEvent(e);\n else if (e.status === 'cancelled')\n this.removeEvent(e);\n }));\n })).catch(e => {\n if (e === GApiError.invalidSyncToken) {\n this.syncToken = '';\n this.sync();\n } else throw e;\n });\n }\n\n getEvents(start, end) {\n return this.sync().then(() => this.getCachedEvents(start, end));\n }\n}\n","export class Pattern {\n constructor(id, isRegex, value, label) {\n this.id = id;\n this.isRegex = isRegex;\n this.value = value;\n this.label = label;\n }\n\n get regex() { return new RegExp(this.isRegex ? this.value : `^${this.value}$`); }\n get isEmpty() { return this.label === null; }\n static emptyPattern = () => new Pattern(0, true, '', null);\n static anyPattern = () => new Pattern('any', true, '.*', 'Any');\n static revive = obj => new Pattern(obj.id, obj.isRegex, obj.value, obj.label);\n}\n\nexport class PatternEntry {\n constructor(name, idx, calPattern, eventPattern) {\n this.name = name;\n this.idx = idx;\n this.cal = calPattern;\n this.event = eventPattern;\n }\n\n static defaultPatternEntry = (idx) => new PatternEntry('', idx, Pattern.emptyPattern(), Pattern.anyPattern());\n static revive = obj => new PatternEntry(\n obj.name, obj.idx,\n Pattern.revive(obj.cal), Pattern.revive(obj.event));\n}\n","import React from 'react';\nimport PropTypes from 'prop-types';\nimport { withStyles } from '@material-ui/core/styles';\nimport Grid from '@material-ui/core/Grid';\nimport deepOrange from '@material-ui/core/colors/deepOrange';\nimport cyan from '@material-ui/core/colors/cyan';\nimport { PieChart, Pie, Cell, Tooltip } from 'recharts';\n\nconst styles = theme => ({\n pieChart: {\n margin: '0 auto',\n }\n});\n\nfunction customizedLabel(props) {\n const {cx, cy, x, y, fill, name} = props;\n let anchor = \"middle\";\n const EPS = 2;\n let dx = 0;\n let dy = 0;\n if (x < cx - EPS) {\n dx = -5;\n anchor = \"end\"\n } else if (x > cx + EPS) {\n dx = 5;\n anchor = \"start\";\n }\n\n if (y < cy - EPS) {\n dy = -5;\n } else if (y > cy + EPS) {\n dy = 10;\n }\n\n return ({`${name}`});\n}\n\nfunction ChromiclePieChart(props) {\n return (\n \n \n
\n \n \n `${value.toFixed(2)} hr`}/>\n \n
\n
\n \n
\n \n \n {props.calendarGraphData.map((d, i) => )}\n \n `${value.toFixed(2)} hr`}/>\n \n
\n
\n
);\n}\n\nChromiclePieChart.propTypes = {\n patternGraphData: PropTypes.array.isRequired,\n calendarGraphData: PropTypes.array.isRequired,\n};\n\nexport default withStyles(styles)(ChromiclePieChart);\n","import React from 'react';\nimport PropTypes from 'prop-types';\nimport { withStyles } from '@material-ui/core/styles';\nimport Select from '@material-ui/core/Select';\nimport MenuItem from '@material-ui/core/MenuItem';\nimport TextField from '@material-ui/core/TextField';\nimport FormControl from '@material-ui/core/FormControl';\nimport { Pattern } from './pattern';\n\nconst styles = theme => ({\n fieldNoRegex: {\n width: 200\n },\n fieldRegex: {\n marginRight: '0.5em'\n }\n});\n\nclass RegexField extends React.Component {\n render() {\n const { classes } = this.props;\n let items = [];\n var pitems = this.props.options;\n const p0 = new Pattern.emptyPattern();\n pitems[p0.id] = p0;\n for (let id in pitems)\n {\n const label = !pitems[id].isEmpty ? pitems[id].label :\n Custom;\n items.push({label});\n }\n const selectOnClick = event => {\n let value;\n if (pitems[event.target.value].label == null) {\n value = new Pattern(0, true,\n this.props.value.isRegex ?\n this.props.value.value :\n `^${this.props.value.value}$`, null);\n } else {\n value = pitems[event.target.value];\n }\n this.props.onChange({target: {value}});\n };\n\n const regexTextOnChange = event => this.props.onChange({\n target: { value: new Pattern(0, true, event.target.value, null)}});\n\n const className = this.props.value.isRegex ? classes.fieldRegex: classes.fieldNoRegex;\n return (\n \n \n {items}\n \n {this.props.value.label == null && (\n \n )}\n \n );\n }\n}\n\nRegexField.propTypes = {\n classes: PropTypes.object.isRequired,\n};\n\nconst RegexFieldWithStyles = withStyles(styles)(RegexField);\n\nexport function CalendarField(props) {\n let options = {};\n for (let id in props.calendars) {\n options[id] = new Pattern(id, false,\n props.calendars[id].name,\n props.calendars[id].name);\n }\n return (\n );\n}\n\nexport function EventField(props) {\n let any = Pattern.anyPattern();\n let options = {};\n options[any.id] = any;\n return (\n );\n}\n","import { createMuiTheme } from '@material-ui/core/styles';\nimport orange from '@material-ui/core/colors/orange';\n\nconst theme = createMuiTheme({\n palette: {\n primary: {\n light: orange[300],\n main: orange[500],\n dark: orange[700],\n contrastText: \"#fff\"\n }\n },\n typography: {\n useNextVariants: true,\n }\n});\n\nexport default theme;\n","import React from 'react';\nimport PropTypes from 'prop-types';\nimport { withStyles, withTheme } from '@material-ui/core/styles';\nimport TextField from '@material-ui/core/TextField';\nimport Table from '@material-ui/core/Table';\nimport TableBody from '@material-ui/core/TableBody';\nimport TableRow from '@material-ui/core/TableRow';\nimport TableCell from '@material-ui/core/TableCell';\nimport TableHead from '@material-ui/core/TableHead';\nimport TablePagination from '@material-ui/core/TablePagination';\nimport DeleteOutlinedIcon from '@material-ui/icons/DeleteOutlined';\nimport { CalendarField, EventField } from './RegexField';\nimport theme from './theme';\n\nconst styles = theme => ({\n deleteButtonShow: {\n position: 'absolute',\n right: 0,\n height: 48\n },\n deleteButtonHide: {\n display: 'none'\n },\n deleteIcon: {\n height: '100%',\n cursor: 'pointer'\n },\n patternTableWrapper: {\n overflowX: 'auto',\n overflowY: 'hidden'\n },\n patternTable: {\n minWidth: 600\n }\n});\n\nconst patternHead = [\n {label: \"Name\", field: \"name\", elem: TextField},\n {label: \"Calendar\", field: \"cal\", elem: withTheme(theme)(CalendarField)},\n {label: \"Event\", field: 'event', elem: withTheme(theme)(EventField)}];\n\nclass PatternTable extends React.Component {\n state = {\n page: 0,\n rowsPerPage: 5,\n };\n\n handleChangePage = (event, page) => {\n this.setState({ page });\n }\n\n handleChangeRowsPerPage = event => {\n this.setState({ rowsPerPage: event.target.value });\n }\n\n render() {\n const { classes, calendars, patterns } = this.props;\n const { rowsPerPage, page } = this.state;\n const nDummy = rowsPerPage - Math.min(rowsPerPage, patterns.length - page * rowsPerPage);\n let rows = patterns.slice(page * rowsPerPage, (page + 1) * rowsPerPage).map(p => (\n this.setState({ activePattern: p.idx })}\n onMouseOut={() => this.setState({ activePattern: null })}>\n {\n patternHead.map(s => {\n const CustomText = s.elem;\n return (\n \n this.props.onUpdatePattern(s.field, p.idx, event.target.value)}/>\n )})\n }\n \n this.props.onRemovePattern(p.idx)} />\n \n ));\n\n return (\n
\n
\n \n \n {patternHead.map((s, i) => ({s.label}))}\n \n \n {rows}\n {\n nDummy > 0 && (\n \n \n )\n }\n \n
\n
\n \n
);\n }\n}\n\n\nPatternTable.propTypes = {\n classes: PropTypes.object.isRequired,\n patterns: PropTypes.array.isRequired,\n calendars: PropTypes.object.isRequired,\n onRemovePattern: PropTypes.func.isRequired,\n onUpdatePattern: PropTypes.func.isRequired,\n};\n\nexport default withStyles(styles)(PatternTable);\n","/* global chrome */\nimport React from 'react';\nimport PropTypes from 'prop-types';\nimport 'typeface-roboto';\nimport 'react-dates/initialize';\nimport 'react-dates/lib/css/_datepicker.css';\nimport { DateRangePicker } from 'react-dates';\nimport { withStyles } from '@material-ui/core/styles';\nimport { MuiThemeProvider } from '@material-ui/core/styles';\nimport cyan from '@material-ui/core/colors/cyan';\nimport CssBaseline from '@material-ui/core/CssBaseline';\nimport AppBar from '@material-ui/core/AppBar';\nimport Toolbar from '@material-ui/core/Toolbar';\nimport Typography from '@material-ui/core/Typography';\nimport Button from '@material-ui/core/Button';\nimport FormControl from '@material-ui/core/FormControl';\nimport FormGroup from '@material-ui/core/FormGroup';\nimport Grid from '@material-ui/core/Grid';\nimport AddCircleIcon from '@material-ui/icons/AddCircle';\nimport IconButton from '@material-ui/core/IconButton';\nimport Logo from './Logo';\nimport * as gapi from './gapi';\nimport { Pattern, PatternEntry } from './pattern';\nimport PieChart from './Chart';\nimport PatternTable from './PatternTable';\nimport theme from './theme';\n\nconst default_chart_data = [\n {name: 'Work', value: 10, color: cyan[300]},\n {name: 'Wasted', value: 10, color: cyan[300]}];\n\nfunction filterPatterns(patterns, calName) {\n return patterns.filter(p => {\n return p.cal.regex.test(calName);\n });\n}\n\nconst styles = theme => ({\n root: {\n display: 'flex',\n height: '100vh',\n },\n appBar: {\n zIndex: theme.zIndex.drawer + 1,\n transition: theme.transitions.create(['width', 'margin'], {\n easing: theme.transitions.easing.sharp,\n duration: theme.transitions.duration.leavingScreen,\n }),\n },\n title: {\n flexGrow: 1,\n },\n sectionTitle: {\n flex: '0 0 auto'\n },\n appBarSpacer: theme.mixins.toolbar,\n content: {\n flexGrow: 1,\n padding: theme.spacing.unit * 3,\n overflow: 'auto',\n },\n buttonSpacer: {\n marginBottom: theme.spacing.unit * 4,\n },\n fab: {\n margin: theme.spacing.unit,\n },\n});\n\nclass Dashboard extends React.Component {\n state = {\n patterns: [],\n calendars: [],\n timeRange: null,\n token: gapi.getAuthToken(),\n patternGraphData: default_chart_data,\n calendarGraphData: default_chart_data,\n activePattern: null\n };\n\n constructor(props) {\n super(props);\n let port = chrome.runtime.connect({name: 'main'});\n const getCallBack = t => this.requestCallback[t];\n port.onMessage.addListener(function(msg) {\n console.log(msg);\n let t = getCallBack(msg.type);\n let e = t.inFlight[msg.id];\n console.assert(e !== undefined);\n t.ids.push(msg.id);\n e(msg);\n });\n this.port = port;\n this.requestCallback = {};\n this.sendMsg({ type: 1 }).then(msg => {\n this.setState({ patterns: msg.data.map(p => PatternEntry.revive(p)) });\n });\n this.sendMsg({ type: 3 }).then(msg => {\n this.setState({ calendars: msg.data });\n });\n }\n\n updatePattern = (field, idx, value) => {\n let patterns = this.state.patterns;\n patterns[idx][field] = value;\n this.setState({ patterns });\n this.sendMsg({ type: 0, data: patterns });\n };\n\n removePattern = idx => {\n let patterns = this.state.patterns;\n patterns.splice(idx, 1);\n for (let i = 0; i < patterns.length; i++)\n patterns[i].idx = i;\n this.setState({ patterns });\n this.sendMsg({ type: 0, data: patterns });\n };\n\n newPattern = () => {\n let patterns = [PatternEntry.defaultPatternEntry(0), ...this.state.patterns];\n for (let i = 1; i < patterns.length; i++)\n patterns[i].idx = i;\n this.setState({ patterns });\n this.sendMsg({ type: 0, data: patterns });\n };\n\n loadPatterns = patterns => {\n this.setState({ patterns });\n this.sendMsg({ type: 0, data: patterns });\n };\n\n loadCalendars = calendars => {\n this.setState({ calendars });\n this.sendMsg({ type: 5, data: calendars });\n };\n\n sendMsg = msg => {\n if (!this.requestCallback.hasOwnProperty(msg.type))\n this.requestCallback[msg.type] = {inFlight: {}, ids: [], maxId: 0};\n let t = this.requestCallback[msg.type];\n let cb;\n let pm = new Promise(resolve => { cb = resolve; });\n let id;\n if (t.ids.length > 0) {\n id = t.ids.pop();\n } else {\n id = t.maxId++;\n }\n t.inFlight[id] = cb;\n msg.id = id;\n this.port.postMessage(msg);\n return pm;\n }\n\n getCalEvents = (id, start, end) => {\n return this.sendMsg({ type: 4, data: { id,\n start: start.getTime(),\n end: end.getTime() } })\n .then(({ data }) => data.map(e => {\n return {\n id: e.id,\n start: new Date(e.start),\n end: new Date(e.end) }\n }));\n }\n\n analyze = () => {\n if (!(this.state.startDate && this.state.endDate)) {\n alert(\"Please choose a valid time range.\");\n return;\n }\n let start = this.state.startDate.startOf('day').toDate();\n let end = this.state.endDate.startOf('day').toDate();\n let event_pms = [];\n let cals = this.state.calendars;\n for (let id in cals)\n event_pms.push(this.getCalEvents(id, start, end)\n .then(r => { return { id, events: r }; }));\n console.log(cals);\n Promise.all(event_pms).then(all_events => {\n console.log(all_events);\n let events = {};\n let results = {}; // pattern idx => time\n let cal_results = {}; // cal id => time\n all_events.forEach(e => events[e.id] = e.events);\n for (let i = 0; i < this.state.patterns.length; i++)\n results[i] = 0;\n for (let id in cals) {\n if (!events[id]) continue;\n let patterns = filterPatterns(this.state.patterns, cals[id].name);\n events[id].forEach(event => {\n patterns.forEach(p => {\n if (!p.event.regex.test(event.summary)) return;\n if (!cal_results.hasOwnProperty(id)) {\n cal_results[id] = 0;\n }\n let duration = (event.end - event.start) / 60000;\n results[p.idx] += duration;\n cal_results[id] += duration;\n });\n });\n }\n let patternGraphData = [];\n let calendarGraphData = [];\n for (let i = 0; i < this.state.patterns.length; i++) {\n patternGraphData.push({ name: this.state.patterns[i].name, value: results[i] / 60.0 });\n }\n for (let id in cal_results) {\n calendarGraphData.push({\n name: cals[id].name,\n value: (cal_results[id] / 60.0),\n color: cals[id].color.background});\n }\n console.log(patternGraphData, calendarGraphData);\n this.setState({ patternGraphData, calendarGraphData });\n });\n };\n\n load = () => {\n let token = this.state.token;\n let colors = token.then(gapi.getColors).then(color => {\n return color.calendar;\n });\n let cals = token.then(gapi.getCalendars);\n Promise.all([colors, cals]).then(([colors, items]) => {\n var cals = {};\n items.forEach(item => {\n cals[item.id] = {\n name: item.summary,\n color: colors[item.colorId],\n //cal: new gapi.GCalendar(item.id, item.summary)\n }});\n this.loadCalendars(cals);\n this.loadPatterns(items.map((item, idx) => {\n return new PatternEntry(item.summary, idx,\n new Pattern(item.id, false, item.summary, item.summary),\n Pattern.anyPattern());\n }));\n });\n };\n\n render() {\n const { classes } = this.props;\n\n return (\n \n
\n \n \n \n Chromicle\n \n \n \n
\n
\n \n \n \n \n \n \n Event Patterns\n this.newPattern()}>\n \n \n \n \n \n Time Range\n \n
\n {\n this.setState({ startDate, endDate });\n }} \n focusedInput={this.state.focusedInput}\n onFocusChange={focusedInput => this.setState({ focusedInput })}\n isOutsideRange={() => false}/>\n
\n
\n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n Graph\n \n \n \n \n
\n
\n
);\n }\n}\n\nDashboard.propTypes = {\n classes: PropTypes.object.isRequired,\n};\n\nexport default withStyles(styles)(Dashboard);\n","// This optional code is used to register a service worker.\n// register() is not called by default.\n\n// This lets the app load faster on subsequent visits in production, and gives\n// it offline capabilities. However, it also means that developers (and users)\n// will only see deployed updates on subsequent visits to a page, after all the\n// existing tabs open on the page have been closed, since previously cached\n// resources are updated in the background.\n\n// To learn more about the benefits of this model and instructions on how to\n// opt-in, read http://bit.ly/CRA-PWA\n\nconst isLocalhost = Boolean(\n window.location.hostname === 'localhost' ||\n // [::1] is the IPv6 localhost address.\n window.location.hostname === '[::1]' ||\n // 127.0.0.1/8 is considered localhost for IPv4.\n window.location.hostname.match(\n /^127(?:\\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/\n )\n);\n\nexport function register(config) {\n if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {\n // The URL constructor is available in all browsers that support SW.\n const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);\n if (publicUrl.origin !== window.location.origin) {\n // Our service worker won't work if PUBLIC_URL is on a different origin\n // from what our page is served on. This might happen if a CDN is used to\n // serve assets; see https://github.com/facebook/create-react-app/issues/2374\n return;\n }\n\n window.addEventListener('load', () => {\n const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;\n\n if (isLocalhost) {\n // This is running on localhost. Let's check if a service worker still exists or not.\n checkValidServiceWorker(swUrl, config);\n\n // Add some additional logging to localhost, pointing developers to the\n // service worker/PWA documentation.\n navigator.serviceWorker.ready.then(() => {\n console.log(\n 'This web app is being served cache-first by a service ' +\n 'worker. To learn more, visit http://bit.ly/CRA-PWA'\n );\n });\n } else {\n // Is not localhost. Just register service worker\n registerValidSW(swUrl, config);\n }\n });\n }\n}\n\nfunction registerValidSW(swUrl, config) {\n navigator.serviceWorker\n .register(swUrl)\n .then(registration => {\n registration.onupdatefound = () => {\n const installingWorker = registration.installing;\n if (installingWorker == null) {\n return;\n }\n installingWorker.onstatechange = () => {\n if (installingWorker.state === 'installed') {\n if (navigator.serviceWorker.controller) {\n // At this point, the updated precached content has been fetched,\n // but the previous service worker will still serve the older\n // content until all client tabs are closed.\n console.log(\n 'New content is available and will be used when all ' +\n 'tabs for this page are closed. See http://bit.ly/CRA-PWA.'\n );\n\n // Execute callback\n if (config && config.onUpdate) {\n config.onUpdate(registration);\n }\n } else {\n // At this point, everything has been precached.\n // It's the perfect time to display a\n // \"Content is cached for offline use.\" message.\n console.log('Content is cached for offline use.');\n\n // Execute callback\n if (config && config.onSuccess) {\n config.onSuccess(registration);\n }\n }\n }\n };\n };\n })\n .catch(error => {\n console.error('Error during service worker registration:', error);\n });\n}\n\nfunction checkValidServiceWorker(swUrl, config) {\n // Check if the service worker can be found. If it can't reload the page.\n fetch(swUrl)\n .then(response => {\n // Ensure service worker exists, and that we really are getting a JS file.\n const contentType = response.headers.get('content-type');\n if (\n response.status === 404 ||\n (contentType != null && contentType.indexOf('javascript') === -1)\n ) {\n // No service worker found. Probably a different app. Reload the page.\n navigator.serviceWorker.ready.then(registration => {\n registration.unregister().then(() => {\n window.location.reload();\n });\n });\n } else {\n // Service worker found. Proceed as normal.\n registerValidSW(swUrl, config);\n }\n })\n .catch(() => {\n console.log(\n 'No internet connection found. App is running in offline mode.'\n );\n });\n}\n\nexport function unregister() {\n if ('serviceWorker' in navigator) {\n navigator.serviceWorker.ready.then(registration => {\n registration.unregister();\n });\n }\n}\n","import React from 'react';\nimport ReactDOM from 'react-dom';\nimport App from './App';\nimport * as serviceWorker from './serviceWorker';\n\nReactDOM.render(, document.getElementById('root'));\n\n// If you want your app to work offline and load faster, you can change\n// unregister() to register() below. Note this comes with some pitfalls.\n// Learn more about service workers: http://bit.ly/CRA-PWA\nserviceWorker.unregister();\n"],"sourceRoot":""} \ No newline at end of file -- cgit v1.2.3-70-g09d2