aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDeterminant <[email protected]>2019-01-31 15:14:28 -0500
committerDeterminant <[email protected]>2019-01-31 15:14:28 -0500
commit374fb92c58c503287dab35c985060916b7c86617 (patch)
tree65ba4935f71e4e0ed4317dae76505b2628e5c871
parentf9f537e3dd28aa543770aea158e4eff65be0b261 (diff)
...
-rw-r--r--build/asset-manifest.json6
-rw-r--r--build/index.html2
-rw-r--r--build/precache-manifest.6f3255a92338a4917c393f15fc8d5469.js (renamed from build/precache-manifest.7f3035649a53aed3489415908914e0f9.js)38
-rw-r--r--build/service-worker.js2
-rw-r--r--build/static/js/main.36efdf67.chunk.js2
-rw-r--r--build/static/js/main.36efdf67.chunk.js.map1
-rw-r--r--build/static/js/main.47fd8d39.chunk.js2
-rw-r--r--build/static/js/main.47fd8d39.chunk.js.map1
-rwxr-xr-xsrc/App.js8
-rw-r--r--src/gapi.js24
10 files changed, 48 insertions, 38 deletions
diff --git a/build/asset-manifest.json b/build/asset-manifest.json
index cdbe19d..d3228d7 100644
--- a/build/asset-manifest.json
+++ b/build/asset-manifest.json
@@ -1,6 +1,6 @@
{
- "main.js": "/static/js/main.47fd8d39.chunk.js",
- "main.js.map": "/static/js/main.47fd8d39.chunk.js.map",
+ "main.js": "/static/js/main.36efdf67.chunk.js",
+ "main.js.map": "/static/js/main.36efdf67.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.7f3035649a53aed3489415908914e0f9.js": "/precache-manifest.7f3035649a53aed3489415908914e0f9.js",
+ "precache-manifest.6f3255a92338a4917c393f15fc8d5469.js": "/precache-manifest.6f3255a92338a4917c393f15fc8d5469.js",
"service-worker.js": "/service-worker.js"
} \ No newline at end of file
diff --git a/build/index.html b/build/index.html
index 2f5e823..6b1aa38 100644
--- a/build/index.html
+++ b/build/index.html
@@ -1 +1 @@
-<!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"/><meta name="theme-color" content="#000000"/><link rel="manifest" href="/manifest.json"/><link rel="stylesheet" href="/fonts/TypoPRO-FantasqueSansMono-Regular.css"/><title>Chromicle</title><link href="/static/css/1.297ee474.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(l){function e(e){for(var r,t,n=e[0],o=e[1],u=e[2],f=0,i=[];f<n.length;f++)t=n[f],p[t]&&i.push(p[t][0]),p[t]=0;for(r in o)Object.prototype.hasOwnProperty.call(o,r)&&(l[r]=o[r]);for(s&&s(e);i.length;)i.shift()();return c.push.apply(c,u||[]),a()}function a(){for(var e,r=0;r<c.length;r++){for(var t=c[r],n=!0,o=1;o<t.length;o++){var u=t[o];0!==p[u]&&(n=!1)}n&&(c.splice(r--,1),e=f(f.s=t[0]))}return e}var t={},p={2:0},c=[];function f(e){if(t[e])return t[e].exports;var r=t[e]={i:e,l:!1,exports:{}};return l[e].call(r.exports,r,r.exports,f),r.l=!0,r.exports}f.m=l,f.c=t,f.d=function(e,r,t){f.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},f.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.t=function(r,e){if(1&e&&(r=f(r)),8&e)return r;if(4&e&&"object"==typeof r&&r&&r.__esModule)return r;var t=Object.create(null);if(f.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:r}),2&e&&"string"!=typeof r)for(var n in r)f.d(t,n,function(e){return r[e]}.bind(null,n));return t},f.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return f.d(r,"a",r),r},f.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},f.p="/";var r=window.webpackJsonp=window.webpackJsonp||[],n=r.push.bind(r);r.push=e,r=r.slice();for(var o=0;o<r.length;o++)e(r[o]);var s=n;a()}([])</script><script src="/static/js/1.b5cbbf9b.chunk.js"></script><script src="/static/js/main.47fd8d39.chunk.js"></script></body></html> \ No newline at end of file
+<!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"/><meta name="theme-color" content="#000000"/><link rel="manifest" href="/manifest.json"/><link rel="stylesheet" href="/fonts/TypoPRO-FantasqueSansMono-Regular.css"/><title>Chromicle</title><link href="/static/css/1.297ee474.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(l){function e(e){for(var r,t,n=e[0],o=e[1],u=e[2],f=0,i=[];f<n.length;f++)t=n[f],p[t]&&i.push(p[t][0]),p[t]=0;for(r in o)Object.prototype.hasOwnProperty.call(o,r)&&(l[r]=o[r]);for(s&&s(e);i.length;)i.shift()();return c.push.apply(c,u||[]),a()}function a(){for(var e,r=0;r<c.length;r++){for(var t=c[r],n=!0,o=1;o<t.length;o++){var u=t[o];0!==p[u]&&(n=!1)}n&&(c.splice(r--,1),e=f(f.s=t[0]))}return e}var t={},p={2:0},c=[];function f(e){if(t[e])return t[e].exports;var r=t[e]={i:e,l:!1,exports:{}};return l[e].call(r.exports,r,r.exports,f),r.l=!0,r.exports}f.m=l,f.c=t,f.d=function(e,r,t){f.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},f.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.t=function(r,e){if(1&e&&(r=f(r)),8&e)return r;if(4&e&&"object"==typeof r&&r&&r.__esModule)return r;var t=Object.create(null);if(f.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:r}),2&e&&"string"!=typeof r)for(var n in r)f.d(t,n,function(e){return r[e]}.bind(null,n));return t},f.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return f.d(r,"a",r),r},f.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},f.p="/";var r=window.webpackJsonp=window.webpackJsonp||[],n=r.push.bind(r);r.push=e,r=r.slice();for(var o=0;o<r.length;o++)e(r[o]);var s=n;a()}([])</script><script src="/static/js/1.b5cbbf9b.chunk.js"></script><script src="/static/js/main.36efdf67.chunk.js"></script></body></html> \ No newline at end of file
diff --git a/build/precache-manifest.7f3035649a53aed3489415908914e0f9.js b/build/precache-manifest.6f3255a92338a4917c393f15fc8d5469.js
index 33c0eb1..282089e 100644
--- a/build/precache-manifest.7f3035649a53aed3489415908914e0f9.js
+++ b/build/precache-manifest.6f3255a92338a4917c393f15fc8d5469.js
@@ -4,8 +4,8 @@ self.__precacheManifest = [
"url": "/static/media/roboto-latin-400italic.d8bcbe72.woff2"
},
{
- "revision": "47fd8d395221717d92ee",
- "url": "/static/js/main.47fd8d39.chunk.js"
+ "revision": "36efdf6701903316bed6",
+ "url": "/static/js/main.36efdf67.chunk.js"
},
{
"revision": "bc833e725c137257c2c42a789845d82f",
@@ -20,16 +20,12 @@ self.__precacheManifest = [
"url": "/static/media/roboto-latin-100.987b8457.woff2"
},
{
- "revision": "e9dbbe8a693dd275c16d32feb101f1c1",
- "url": "/static/media/roboto-latin-100.e9dbbe8a.woff"
- },
- {
"revision": "6232f43d15b0e7a0bf0fe82e295bdd06",
"url": "/static/media/roboto-latin-100italic.6232f43d.woff2"
},
{
- "revision": "d704bb3d579b7d5e40880c75705c8a71",
- "url": "/static/media/roboto-latin-100italic.d704bb3d.woff"
+ "revision": "e9dbbe8a693dd275c16d32feb101f1c1",
+ "url": "/static/media/roboto-latin-100.e9dbbe8a.woff"
},
{
"revision": "55536c8e9e9a532651e3cf374f290ea3",
@@ -40,6 +36,10 @@ self.__precacheManifest = [
"url": "/static/media/roboto-latin-300.a1471d1d.woff"
},
{
+ "revision": "d704bb3d579b7d5e40880c75705c8a71",
+ "url": "/static/media/roboto-latin-100italic.d704bb3d.woff"
+ },
+ {
"revision": "210a7c781f5a354a0e4985656ab456d9",
"url": "/static/media/roboto-latin-300italic.210a7c78.woff"
},
@@ -60,14 +60,14 @@ self.__precacheManifest = [
"url": "/static/media/roboto-latin-900italic.7b770d6c.woff2"
},
{
- "revision": "285467176f7fe6bb6a9c6873b3dad2cc",
- "url": "/static/media/roboto-latin-500.28546717.woff2"
- },
- {
"revision": "9680d5a0c32d2fd084e07bbc4c8b2923",
"url": "/static/media/roboto-latin-400italic.9680d5a0.woff"
},
{
+ "revision": "285467176f7fe6bb6a9c6873b3dad2cc",
+ "url": "/static/media/roboto-latin-500.28546717.woff2"
+ },
+ {
"revision": "de8b7431b74642e830af4d4f4b513ec9",
"url": "/static/media/roboto-latin-500.de8b7431.woff"
},
@@ -84,22 +84,22 @@ self.__precacheManifest = [
"url": "/static/media/roboto-latin-700.037d8304.woff2"
},
{
- "revision": "010c1aeee3c6d1cbb1d5761d80353823",
- "url": "/static/media/roboto-latin-700italic.010c1aee.woff2"
- },
- {
"revision": "cf6613d1adf490972c557a8e318e0868",
"url": "/static/media/roboto-latin-700.cf6613d1.woff"
},
{
- "revision": "19b7a0adfdd4f808b53af7e2ce2ad4e5",
- "url": "/static/media/roboto-latin-900.19b7a0ad.woff2"
+ "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"
},
@@ -112,7 +112,7 @@ self.__precacheManifest = [
"url": "/static/css/1.297ee474.chunk.css"
},
{
- "revision": "f3b7e0c8e0a17fe97264bc302e5b9ef5",
+ "revision": "41d3415b63e510212e25ae08824f3386",
"url": "/index.html"
}
]; \ No newline at end of file
diff --git a/build/service-worker.js b/build/service-worker.js
index 8a231a2..274873b 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.7f3035649a53aed3489415908914e0f9.js"
+ "/precache-manifest.6f3255a92338a4917c393f15fc8d5469.js"
);
workbox.clientsClaim();
diff --git a/build/static/js/main.36efdf67.chunk.js b/build/static/js/main.36efdf67.chunk.js
new file mode 100644
index 0000000..4ef4419
--- /dev/null
+++ b/build/static/js/main.36efdf67.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),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<n;r++)this.getSlot(r)[t.id]={start:e.slotStartDate(r),end:e.slotEndDate(r),id:t.id}}}},{key:"removeEvent",value:function(t){for(var a=e.dateToCacheKey(t.start),n=e.dateToCacheKey(new Date(t.end.getTime()-1)),r=a;r<=n;r++)delete this.getSlot(r)[t.id]}},{key:"getSlotEvents",value:function(e,t,a){var n=this.getSlot(e),r=[];for(var c in n){if(!(n[c].start>=a||n[c].end<=t))(n[c].start<t?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].start<t?t:n[c].start,end:n[c].end>a?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;o<r;o++){var i=this.getSlot(o);for(var s in i)c.push(i[s])}return r>n&&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 n<t-2?(s=-5,l="end"):n>t+2&&(s=5,l="start"),c<a-2?u=-5:c>a+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;c<n;c++)r[c]=arguments[c];return(a=Object(h.a)(this,(e=Object(d.a)(t)).call.apply(e,[this].concat(r)))).state={page:0,rowsPerPage:5},a.handleChangePage=function(e,t){a.setState({page:t})},a.handleChangeRowsPerPage=function(e){a.setState({rowsPerPage:e.target.value})},a}return Object(m.a)(t,e),Object(u.a)(t,[{key:"render",value:function(){var e=this,t=this.props,a=t.classes,n=t.cached,c=t.patterns,o=this.state,i=o.rowsPerPage,l=o.page,s=i-Math.min(i,c.length-l*i),u=c.slice(l*i,(l+1)*i).map(function(t){return r.a.createElement(se.a,{onMouseOver:function(){return e.setState({activePattern:t.idx})},onMouseOut:function(){return e.setState({activePattern:null})}},Ce.map(function(a){var c=a.elem;return r.a.createElement(he.a,null,r.a.createElement(c,{value:t[a.field],cached:n,onChange:function(n){return e.props.onUpdatePattern(a.field,t.idx,n.target.value)}}))}),r.a.createElement("span",{className:e.state.activePattern===t.idx?a.deleteButtonShow:a.deleteButtonHide},r.a.createElement(ge.a,{className:a.deleteIcon,onClick:function(){return e.props.onRemovePattern(t.idx)}})))});return r.a.createElement("div",null,r.a.createElement("div",{className:a.patternTableWrapper},r.a.createElement(ce.a,{className:a.patternTable},r.a.createElement(me.a,null,r.a.createElement(se.a,null,Ce.map(function(e,t){return r.a.createElement(he.a,{key:t},e.label)}))),r.a.createElement(ie.a,null,u,s>0&&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;c++)r[c]=arguments[c];return(a=Object(h.a)(this,(e=Object(d.a)(t)).call.apply(e,[this].concat(r)))).state={patterns:[],timeRange:null,token:F(),patternGraphData:je,calendarGraphData:je,activePattern:null},a.cached={calendars:{}},a.updatePattern=function(e,t,n){var r=a.state.patterns;r[t][e]=n,a.setState({patterns:r})},a.removePattern=function(e){var t=a.state.patterns;t.splice(e,1);for(var n=0;n<t.length;n++)t[n].idx=n;a.setState({patterns:t})},a.newPattern=function(){for(var e=[J.defaultPatternEntry()].concat(Object(l.a)(a.state.patterns)),t=1;t<e.length;t++)e[t].idx=t;a.setState({patterns:e})},a.analyze=function(){if(a.state.startDate&&a.state.endDate){var e=a.state.startDate.toDate(),t=a.state.endDate.toDate();console.log(e,t);var n=[],r=function(r){n.push(a.cached.calendars[r].cal.getEvents(e,t).then(function(e){return{id:r,events:e}}).catch(function(e){return console.log("cannot load calendar ".concat(r)),{id:r,events:[]}}))};for(var c in a.cached.calendars)r(c);Promise.all(n).then(function(e){var t={},n={},r={};e.forEach(function(e){return t[e.id]=e.events});for(var c=0;c<a.state.patterns.length;c++)n[c]=0;var o=function(e){if(!t[e])return"continue";var c=function(e,t){return e.filter(function(e){return e.cal.regex.test(t)})}(a.state.patterns,a.cached.calendars[e].name);t[e].forEach(function(t){c.forEach(function(a){if(a.event.regex.test(t.summary)){r.hasOwnProperty(e)||(r[e]=0);var c=(t.end-t.start)/6e4;n[a.idx]+=c,r[e]+=c}})})};for(var i in a.cached.calendars)o(i);for(var l=[],s=[],u=0;u<a.state.patterns.length;u++)l.push({name:a.state.patterns[u].name,value:n[u]/60});for(var i in r)s.push({name:a.cached.calendars[i].name,value:r[i]/60,color:a.cached.calendars[i].color.background});a.setState({patternGraphData:l,calendarGraphData:s})})}else alert("Please choose a valid time range.")},a.loadPatterns=function(){var e=a.state.token,t=e.then(L).then(function(e){return e.calendar}),n=e.then(U);Promise.all([t,n]).then(function(e){var t=Object(i.a)(e,2),n=t[0],r=t[1];r.forEach(function(e){a.cached.calendars[e.id]={name:e.summary,color:n[e.colorId],cal:new $(e.id,e.summary)}}),a.setState({patterns:r.map(function(e,t){return new J(e.summary,t,new H(e.id,!1,e.summary,e.summary),H.anyPattern())})})})},a}return Object(m.a)(t,e),Object(u.a)(t,[{key:"render",value:function(){var e=this,t=this.props.classes;return r.a.createElement(f.MuiThemeProvider,{theme:Te},r.a.createElement("div",{className:t.root},r.a.createElement(b.a,{position:"absolute",className:t.appBar},r.a.createElement(x.a,{className:t.toolbar},r.a.createElement(S.a,{component:"h1",variant:"h6",color:"inherit",noWrap:!0,className:t.title},r.a.createElement(A,{style:{width:"2em",verticalAlign:"bottom",marginRight:"0.2em"}}),"Chromicle"))),r.a.createElement("main",{className:t.content},r.a.createElement("div",{className:t.appBarSpacer}),r.a.createElement(B.a,{container:!0,spacing:16},r.a.createElement(E.a,null),r.a.createElement(B.a,{item:!0,md:6,xs:12},r.a.createElement(O.a,{fullWidth:!0},r.a.createElement(R.a,null,r.a.createElement(S.a,{variant:"h6",component:"h1",gutterBottom:!0},"Event Patterns",r.a.createElement(K.a,{style:{marginBottom:"0.12em",marginLeft:"0.5em"},onClick:function(){return e.newPattern()}},r.a.createElement(I.a,null))),r.a.createElement(Oe,{patterns:this.state.patterns,cached:this.cached,onRemovePattern:this.removePattern,onUpdatePattern:this.updatePattern})),r.a.createElement(R.a,null,r.a.createElement(S.a,{variant:"h6",component:"h1",gutterBottom:!0},"Time Range"),r.a.createElement("div",{style:{textAlign:"center"}},r.a.createElement(p.DateRangePicker,{startDate:this.state.startDate,startDateId:"start_date_id",endDate:this.state.endDate,endDateId:"end_date_id",onDatesChange:function(t){var a=t.startDate,n=t.endDate;e.setState({startDate:a,endDate:n})},focusedInput:this.state.focusedInput,onFocusChange:function(t){return e.setState({focusedInput:t})},isOutsideRange:function(){return!1}}))),r.a.createElement("div",{className:t.buttonSpacer}),r.a.createElement(B.a,{container:!0,spacing:16},r.a.createElement(B.a,{item:!0,md:6,xs:12},r.a.createElement(R.a,null,r.a.createElement(C.a,{variant:"contained",color:"primary",onClick:this.loadPatterns},"Load"))),r.a.createElement(B.a,{item:!0,md:6,xs:12},r.a.createElement(R.a,null,r.a.createElement(C.a,{variant:"contained",color:"primary",onClick:this.analyze},"Analyze")))))),r.a.createElement(B.a,{item:!0,md:6,xs:12},r.a.createElement(S.a,{variant:"h6",component:"h1",gutterBottom:!0},"Graph"),r.a.createElement(te,{patternGraphData:this.state.patternGraphData,calendarGraphData:this.state.calendarGraphData}))))))}}]),t}(r.a.Component),Ne=Object(f.withStyles)(function(e){return{root:{display:"flex",height:"100vh"},appBar:{zIndex:e.zIndex.drawer+1,transition:e.transitions.create(["width","margin"],{easing:e.transitions.easing.sharp,duration:e.transitions.duration.leavingScreen})},title:{flexGrow:1},sectionTitle:{flex:"0 0 auto"},appBarSpacer:e.mixins.toolbar,content:{flexGrow:1,padding:3*e.spacing.unit,overflow:"auto"},buttonSpacer:{marginBottom:4*e.spacing.unit},fab:{margin:e.spacing.unit}}})(Re);Boolean("localhost"===window.location.hostname||"[::1]"===window.location.hostname||window.location.hostname.match(/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/));o.a.render(r.a.createElement(Ne,null),document.getElementById("root")),"serviceWorker"in navigator&&navigator.serviceWorker.ready.then(function(e){e.unregister()})}},[[308,2,1]]]);
+//# sourceMappingURL=main.36efdf67.chunk.js.map \ No newline at end of file
diff --git a/build/static/js/main.36efdf67.chunk.js.map b/build/static/js/main.36efdf67.chunk.js.map
new file mode 100644
index 0000000..05283ad
--- /dev/null
+++ b/build/static/js/main.36efdf67.chunk.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["Logo.js","gapi.js","pattern.js","Chart.js","RegexField.js","theme.js","PatternTable.js","App.js","serviceWorker.js","index.js"],"names":["Logo","props","react_default","a","createElement","xmlns","viewBox","version","style","id","transform","points","fill","fontStyle","fontVariant","fontWeight","fontStretch","fontSize","fontFamily","gapi_base","GApiError","invalidSyncToken","otherError","to_params","dict","Object","entries","map","_ref","_ref2","slicedToArray","k","v","concat","encodeURIComponent","join","getAuthToken","Promise","resolver","chrome","identity","interactive","token","getCalendars","fetch","access_token","method","async","then","response","json","data","items","getColors","GCalendar","calId","name","classCallCheck","this","syncToken","cache","createClass","key","value","e","ks","dateToCacheKey","start","ke","Date","end","getTime","getSlot","slotEndDate","slotStartDate","s","results","console","log","push","getSlotEvents","apply","toConsumableArray","_this","resultsPerRequest","arguments","length","undefined","singleFetch","pageToken","maxResults","status","otherErrors","nextPageToken","nextSyncToken","getEvents","r","pm_results","resolve","eventId","getEvent","all","forEach","dateTime","addEvent","removeEvent","catch","sync","_this2","getCachedEvents","date","Math","floor","Pattern","isRegex","label","get","RegExp","emptyPattern","anyPattern","PatternEntry","idx","calPattern","eventPattern","cal","event","defaultPatternEntry","customizedLabel","cx","cy","x","y","anchor","dx","dy","textAnchor","withStyles","theme","pieChart","margin","Grid_default","container","spacing","item","xs","lg","className","classes","patternTableWrapper","PieChart","width","height","Pie","patternGraphData","dataKey","outerRadius","deepOrange","Tooltip","formatter","toFixed","calendarGraphData","innerRadius","cyan","d","i","Cell","color","RegexField","pitems","options","p0","isEmpty","palette","primary","dark","MenuItem_default","fieldRegex","fieldNoRegex","FormControl_default","Select_default","onChange","target","TextField_default","React","Component","RegexFieldWithStyles","marginRight","createMuiTheme","light","orange","main","contrastText","typography","useNextVariants","patternHead","field","elem","TextField","withTheme","cached","calendars","any","PatternTable","state","page","rowsPerPage","handleChangePage","setState","handleChangeRowsPerPage","_this$props","patterns","_this$state","nDummy","min","rows","slice","p","TableRow_default","onMouseOver","activePattern","onMouseOut","CustomText","TableCell_default","onUpdatePattern","deleteButtonShow","deleteButtonHide","DeleteOutlined_default","deleteIcon","onClick","onRemovePattern","Table_default","patternTable","TableHead_default","TableBody_default","colSpan","TablePagination_default","rowsPerPageOptions","component","count","backIconButtonProps","aria-label","nextIconButtonProps","onChangePage","onChangeRowsPerPage","position","right","display","cursor","overflowX","overflowY","minWidth","default_chart_data","Dashboard","timeRange","gapi","updatePattern","removePattern","splice","newPattern","analyze","startDate","endDate","toDate","event_pms","_loop","events","all_events","cal_results","_loop2","calName","filter","regex","test","filterPatterns","summary","hasOwnProperty","duration","background","alert","loadPatterns","colors","calendar","cals","colorId","styles","root","AppBar_default","appBar","Toolbar_default","toolbar","Typography_default","variant","noWrap","title","verticalAlign","content","appBarSpacer","CssBaseline_default","md","fullWidth","FormGroup_default","gutterBottom","IconButton_default","marginBottom","marginLeft","AddCircle_default","src_PatternTable","textAlign","react_dates","startDateId","endDateId","onDatesChange","_ref3","focusedInput","onFocusChange","isOutsideRange","buttonSpacer","Button_default","Chart","zIndex","drawer","transition","transitions","create","easing","sharp","leavingScreen","flexGrow","sectionTitle","flex","mixins","padding","unit","overflow","fab","Boolean","window","location","hostname","match","ReactDOM","render","App","document","getElementById","navigator","serviceWorker","ready","registration","unregister"],"mappings":"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","file":"static/js/main.36efdf67.chunk.js","sourcesContent":["import React from 'react';\nexport default (props) =>\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 98.905998 93.557997\"\n version=\"1.1\"\n style={props.style}>\n <g id=\"g13\"\n transform=\"translate(-153.533,-203.047)\">\n <g id=\"g29\">\n <g\n id=\"g27\">\n <polygon\n id=\"polygon7\"\n 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 \"\n style={{fill: '#ff8000'}} />\n <g\n id=\"g11\"\n transform=\"translate(167.24355,224.20734)\">\n <text\n id=\"text9\"\n style={{fontStyle:'normal',\n fontVariant:'normal',\n fontWeight:'normal',\n fontStretch:'normal',\n fontSize:75,\n fontFamily:'TypoPRO Fantasque Sans Mono',\n fill:'#ffeade'}}\n transform=\"translate(0.586,49.072)\">Cr</text>\n </g>\n </g>\n </g>\n </g>\n </svg>\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 (<text x={x} y={y} dx={dx} dy={dy} fill={fill} textAnchor={anchor}>{`${name}`}</text>);\n}\n\nfunction ChromiclePieChart(props) {\n return (\n <Grid container spacing={0}>\n <Grid item xs={12} lg={6}>\n <div className={props.classes.patternTableWrapper}>\n <PieChart width={400} height={250} className={props.classes.pieChart}>\n <Pie data={props.patternGraphData}\n dataKey='value'\n cx={200}\n cy={125}\n outerRadius={60}\n fill={deepOrange[300]}\n label={customizedLabel}/>\n <Tooltip formatter={(value) => `${value.toFixed(2)} hr`}/>\n </PieChart>\n </div>\n </Grid>\n <Grid item xs={12} lg={6}>\n <div className={props.classes.patternTableWrapper}>\n <PieChart width={400} height={250} className={props.classes.pieChart}>\n <Pie data={props.calendarGraphData}\n dataKey='value'\n cx={200}\n cy={125}\n innerRadius={40}\n outerRadius={70}\n fill={cyan[300]}\n label={customizedLabel}>\n {props.calendarGraphData.map((d, i) => <Cell key={i} fill={d.color}/>)}\n </Pie>\n <Tooltip formatter={(value) => `${value.toFixed(2)} hr`}/>\n </PieChart>\n </div>\n </Grid>\n </Grid>);\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 <span style={{color: this.props.theme.palette.primary.dark}}>Custom</span>;\n items.push(<MenuItem key={id} value={id}>{label}</MenuItem>);\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 <FormControl>\n <span>\n <Select\n value={this.props.value.id}\n onChange={selectOnClick}\n className={className}>{items}\n </Select>\n {this.props.value.label == null && (\n <TextField\n value={this.props.value.value}\n onChange={regexTextOnChange} />\n )}\n </span>\n </FormControl>);\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 <RegexFieldWithStyles\n value={props.value}\n options={options}\n onChange={props.onChange}\n theme={props.theme} />);\n}\n\nexport function EventField(props) {\n let any = Pattern.anyPattern();\n let options = {};\n options[any.id] = any;\n return (\n <RegexFieldWithStyles\n value={props.value}\n options={options}\n onChange={props.onChange}\n theme={props.theme} />);\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 <TableRow\n onMouseOver={() => this.setState({ activePattern: p.idx })}\n onMouseOut={() => this.setState({ activePattern: null })}>\n {\n patternHead.map(s => {\n const CustomText = s.elem;\n return (\n <TableCell>\n <CustomText\n value={p[s.field]}\n cached={cached}\n onChange={event => this.props.onUpdatePattern(s.field, p.idx, event.target.value)}/>\n </TableCell>)})\n }\n <span className={this.state.activePattern === p.idx ? classes.deleteButtonShow : classes.deleteButtonHide}>\n <DeleteOutlinedIcon\n className={classes.deleteIcon}\n onClick={() => this.props.onRemovePattern(p.idx)} />\n </span>\n </TableRow>));\n\n return (\n <div>\n <div className={classes.patternTableWrapper}>\n <Table className={classes.patternTable}>\n <TableHead>\n <TableRow>{patternHead.map((s, i) => (<TableCell key={i}>{s.label}</TableCell>))}</TableRow>\n </TableHead>\n <TableBody>\n {rows}\n {\n nDummy > 0 && (\n <TableRow style={{ height: 48 * nDummy }}>\n <TableCell colSpan={patternHead.length} />\n </TableRow>)\n }\n </TableBody>\n </Table>\n </div>\n <TablePagination\n rowsPerPageOptions={[5, 10, 25]}\n component=\"div\"\n count={patterns.length}\n rowsPerPage={rowsPerPage}\n page={page}\n backIconButtonProps={{'aria-label': 'Previous Page'}}\n nextIconButtonProps={{'aria-label': 'Next Page'}}\n onChangePage={this.handleChangePage}\n onChangeRowsPerPage={this.handleChangeRowsPerPage} />\n </div>);\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.toDate();\n let end = this.state.endDate.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 <MuiThemeProvider theme={theme}>\n <div className={classes.root}>\n <AppBar\n position=\"absolute\"\n className={classes.appBar}>\n <Toolbar className={classes.toolbar}>\n <Typography component=\"h1\" variant=\"h6\" color=\"inherit\" noWrap className={classes.title}>\n <Logo style={{width: '2em', verticalAlign: 'bottom', marginRight: '0.2em'}}/>Chromicle\n </Typography>\n </Toolbar>\n </AppBar>\n <main className={classes.content}>\n <div className={classes.appBarSpacer} />\n <Grid container spacing={16}>\n <CssBaseline />\n <Grid item md={6} xs={12}>\n <FormControl fullWidth={true}>\n <FormGroup>\n <Typography variant=\"h6\" component=\"h1\" gutterBottom>\n Event Patterns\n <IconButton\n style={{marginBottom: '0.12em', marginLeft: '0.5em'}}\n onClick={() => this.newPattern()}><AddCircleIcon /></IconButton>\n </Typography>\n <PatternTable\n patterns={this.state.patterns}\n cached={this.cached}\n onRemovePattern={this.removePattern}\n onUpdatePattern={this.updatePattern} />\n </FormGroup>\n <FormGroup>\n <Typography variant=\"h6\" component=\"h1\" gutterBottom>\n Time Range\n </Typography>\n <div style={{textAlign: 'center'}}>\n <DateRangePicker\n startDate={this.state.startDate}\n startDateId=\"start_date_id\"\n endDate={this.state.endDate}\n endDateId=\"end_date_id\"\n onDatesChange={({ startDate, endDate }) => {\n this.setState({ startDate, endDate });\n }} \n focusedInput={this.state.focusedInput}\n onFocusChange={focusedInput => this.setState({ focusedInput })}\n isOutsideRange={() => false}/>\n </div>\n </FormGroup>\n <div className={classes.buttonSpacer} />\n <Grid container spacing={16}>\n <Grid item md={6} xs={12}>\n <FormGroup>\n <Button variant=\"contained\" color=\"primary\" onClick={this.loadPatterns}>Load</Button>\n </FormGroup>\n </Grid>\n <Grid item md={6} xs={12}>\n <FormGroup>\n <Button variant=\"contained\" color=\"primary\" onClick={this.analyze}>Analyze</Button>\n </FormGroup>\n </Grid>\n </Grid>\n </FormControl>\n </Grid>\n <Grid item md={6} xs={12}>\n <Typography variant=\"h6\" component=\"h1\" gutterBottom>\n Graph\n </Typography>\n <PieChart\n patternGraphData={this.state.patternGraphData}\n calendarGraphData={this.state.calendarGraphData}/>\n </Grid>\n </Grid>\n </main>\n </div>\n </MuiThemeProvider>);\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(<App />, 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.47fd8d39.chunk.js b/build/static/js/main.47fd8d39.chunk.js
deleted file mode 100644
index ada8021..0000000
--- a/build/static/js/main.47fd8d39.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),m=a(74),d=a(79),p=(a(313),a(315),a(341),a(286)),f=a(31),v=a(99),g=a.n(v),E=a(306),y=a.n(E),w=a(305),b=a.n(w),P=a(173),x=a.n(P),k=a(81),S=a.n(k),C=a(177),D=a.n(C),T=a(93),O=a.n(T),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";function M(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 F(e){return fetch("".concat(_,"/users/me/calendarList?").concat(M({access_token:e})),{method:"GET",async:!0}).then(function(e){return e.json()}).then(function(e){return e.items})}function U(e){return fetch("".concat(_,"/colors?").concat(M({access_token:e})),{method:"GET",async:!0}).then(function(e){return e.json()})}var L=function(){function e(t,a){Object(s.a)(this,e),this.calId=t,this.name=a,this.token=z(),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<n;r++)this.getSlot(r)[t.id]={start:e.slotStartDate(r),end:e.slotEndDate(r),id:t.id}}}},{key:"removeEvent",value:function(t){for(var a=e.dateToCacheKey(t.start),n=e.dateToCacheKey(new Date(t.end.getTime()-1)),r=a;r<=n;r++)delete this.getSlot(r)[t.id]}},{key:"getSlotEvents",value:function(e,t,a){var n=this.getSlot(e),r=[];for(var c in n){if(!(n[c].start>=a||n[c].end<=t))(n[c].start<t?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].start<t?t:n[c].start,end:n[c].end>a?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;o<r;o++){var i=this.getSlot(o);for(var s in i)c.push(i[s])}return r>n&&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]:"",r=[];return function a(c,o){return fetch("".concat(_,"/calendars/").concat(e,"/events?").concat(M({access_token:t,pageToken:c,syncToken:o,maxResults:n})),{method:"GET",async:!0}).then(function(e){if(200===e.status)return e.json();throw{}}).catch(function(e){return e}).then(function(e){return e.items?(r.push.apply(r,Object(l.a)(e.items)),e.nextPageToken?a(e.nextPageToken,""):{nextSyncToken:e.nextSyncToken,results:r}):{nextSyncToken:"",results:[]}})}("",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(M({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)})})})})}},{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}(),$=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}();$.emptyPattern=function(){return new $(0,!0,"",null)},$.anyPattern=function(){return new $("any",!0,".*","Any")};var H=function e(t,a,n,r){Object(s.a)(this,e),this.name=t,this.idx=a,this.cal=n,this.event=r};H.defaultPatternEntry=function(e){return new H("",e,$.emptyPattern(),$.anyPattern())};var J=a(299),V=a.n(J),q=a(659),X=a(657),Y=a(656),Q=a(554);function Z(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 n<t-2?(s=-5,l="end"):n>t+2&&(s=5,l="start"),c<a-2?u=-5:c>a+2&&(u=10),r.a.createElement("text",{x:n,y:c,dx:s,dy:u,fill:o,textAnchor:l},"".concat(i))}var ee=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(q.a,{width:400,height:250,className:e.classes.pieChart},r.a.createElement(X.a,{data:e.patternGraphData,dataKey:"value",cx:200,cy:125,outerRadius:60,fill:V.a[300],label:Z}),r.a.createElement(Y.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(q.a,{width:400,height:250,className:e.classes.pieChart},r.a.createElement(X.a,{data:e.calendarGraphData,dataKey:"value",cx:200,cy:125,innerRadius:40,outerRadius:70,fill:g.a[300],label:Z},e.calendarGraphData.map(function(e,t){return r.a.createElement(Q.a,{key:t,fill:e.color})})),r.a.createElement(Y.a,{formatter:function(e){return"".concat(e.toFixed(2)," hr")}})))))}),te=a(136),ae=a.n(te),ne=a(301),re=a.n(ne),ce=a(303),oe=a.n(ce),ie=a(140),le=a.n(ie),se=a(100),ue=a.n(se),he=a(302),me=a.n(he),de=a(304),pe=a.n(de),fe=a(300),ve=a.n(fe),ge=a(131),Ee=a.n(ge),ye=a(172),we=a.n(ye),be=function(e){function t(){return Object(s.a)(this,t),Object(h.a)(this,Object(m.a)(t).apply(this,arguments))}return Object(d.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 $.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(we.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 $(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(ae.a,{value:this.props.value.value,onChange:function(t){return e.props.onChange({target:{value:new $(0,!0,t.target.value,null)}})}})))}}]),t}(r.a.Component),Pe=Object(f.withStyles)(function(e){return{fieldNoRegex:{width:200},fieldRegex:{marginRight:"0.5em"}}})(be);var xe=a(139),ke=a.n(xe),Se=Object(f.createMuiTheme)({palette:{primary:{light:ke.a[300],main:ke.a[500],dark:ke.a[700],contrastText:"#fff"}},typography:{useNextVariants:!0}}),Ce=[{label:"Name",field:"name",elem:ae.a},{label:"Calendar",field:"cal",elem:Object(f.withTheme)(Se)(function(e){var t={};for(var a in e.cached.calendars)t[a]=new $(a,!1,e.cached.calendars[a].name,e.cached.calendars[a].name);return r.a.createElement(Pe,{value:e.value,options:t,onChange:e.onChange,theme:e.theme})})},{label:"Event",field:"event",elem:Object(f.withTheme)(Se)(function(e){var t=$.anyPattern(),a={};return a[t.id]=t,r.a.createElement(Pe,{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;c<n;c++)r[c]=arguments[c];return(a=Object(h.a)(this,(e=Object(m.a)(t)).call.apply(e,[this].concat(r)))).state={page:0,rowsPerPage:5},a.handleChangePage=function(e,t){a.setState({page:t})},a.handleChangeRowsPerPage=function(e){a.setState({rowsPerPage:e.target.value})},a}return Object(d.a)(t,e),Object(u.a)(t,[{key:"render",value:function(){var e=this,t=this.props,a=t.classes,n=t.cached,c=t.patterns,o=this.state,i=o.rowsPerPage,l=o.page,s=i-Math.min(i,c.length-l*i),u=c.slice(l*i,(l+1)*i).map(function(t){return r.a.createElement(le.a,{onMouseOver:function(){return e.setState({activePattern:t.idx})},onMouseOut:function(){return e.setState({activePattern:null})}},Ce.map(function(a){var c=a.elem;return r.a.createElement(ue.a,null,r.a.createElement(c,{value:t[a.field],cached:n,onChange:function(n){return e.props.onUpdatePattern(a.field,t.idx,n.target.value)}}))}),r.a.createElement("span",{className:e.state.activePattern===t.idx?a.deleteButtonShow:a.deleteButtonHide},r.a.createElement(ve.a,{className:a.deleteIcon,onClick:function(){return e.props.onRemovePattern(t.idx)}})))});return r.a.createElement("div",null,r.a.createElement("div",{className:a.patternTableWrapper},r.a.createElement(re.a,{className:a.patternTable},r.a.createElement(me.a,null,r.a.createElement(le.a,null,Ce.map(function(e,t){return r.a.createElement(ue.a,{key:t},e.label)}))),r.a.createElement(oe.a,null,u,s>0&&r.a.createElement(le.a,{style:{height:48*s}},r.a.createElement(ue.a,{colSpan:Ce.length}))))),r.a.createElement(pe.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),Te=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),Oe=[{name:"Work",value:10,color:g.a[300]},{name:"Wasted",value:10,color:g.a[300]}];var je=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;c++)r[c]=arguments[c];return(a=Object(h.a)(this,(e=Object(m.a)(t)).call.apply(e,[this].concat(r)))).state={patterns:[],timeRange:null,token:z(),patternGraphData:Oe,calendarGraphData:Oe,activePattern:null},a.cached={calendars:{}},a.updatePattern=function(e,t,n){var r=a.state.patterns;r[t][e]=n,a.setState({patterns:r})},a.removePattern=function(e){var t=a.state.patterns;t.splice(e,1);for(var n=0;n<t.length;n++)t[n].idx=n;a.setState({patterns:t})},a.newPattern=function(){for(var e=[H.defaultPatternEntry()].concat(Object(l.a)(a.state.patterns)),t=1;t<e.length;t++)e[t].idx=t;a.setState({patterns:e})},a.analyze=function(){if(a.state.startDate&&a.state.endDate){var e=a.state.startDate.toDate(),t=a.state.endDate.toDate();console.log(e,t);var n=[],r=function(r){n.push(a.cached.calendars[r].cal.getEvents(e,t).then(function(e){return{id:r,events:e}}))};for(var c in a.cached.calendars)r(c);Promise.all(n).then(function(e){var t={},n={},r={};e.forEach(function(e){return t[e.id]=e.events});for(var c=0;c<a.state.patterns.length;c++)n[c]=0;var o=function(e){if(!t[e])return"continue";var c=function(e,t){return e.filter(function(e){return e.cal.regex.test(t)})}(a.state.patterns,a.cached.calendars[e].name);t[e].forEach(function(t){c.forEach(function(a){if(a.event.regex.test(t.summary)){r.hasOwnProperty(e)||(r[e]=0);var c=(t.end-t.start)/6e4;n[a.idx]+=c,r[e]+=c}})})};for(var i in a.cached.calendars)o(i);for(var l=[],s=[],u=0;u<a.state.patterns.length;u++)l.push({name:a.state.patterns[u].name,value:n[u]/60});for(var i in r)s.push({name:a.cached.calendars[i].name,value:r[i]/60,color:a.cached.calendars[i].color.background});a.setState({patternGraphData:l,calendarGraphData:s})})}else alert("Please choose a valid time range.")},a.loadPatterns=function(){var e=a.state.token,t=e.then(U).then(function(e){return e.calendar}),n=e.then(F);Promise.all([t,n]).then(function(e){var t=Object(i.a)(e,2),n=t[0],r=t[1];r.forEach(function(e){a.cached.calendars[e.id]={name:e.summary,color:n[e.colorId],cal:new L(e.id,e.summary)}}),a.setState({patterns:r.map(function(e,t){return new H(e.summary,t,new $(e.id,!1,e.summary,e.summary),$.anyPattern())})})})},a}return Object(d.a)(t,e),Object(u.a)(t,[{key:"render",value:function(){var e=this,t=this.props.classes;return r.a.createElement(f.MuiThemeProvider,{theme:Se},r.a.createElement("div",{className:t.root},r.a.createElement(b.a,{position:"absolute",className:t.appBar},r.a.createElement(x.a,{className:t.toolbar},r.a.createElement(S.a,{component:"h1",variant:"h6",color:"inherit",noWrap:!0,className:t.title},r.a.createElement(A,{style:{width:"2em",verticalAlign:"bottom",marginRight:"0.2em"}}),"Chromicle"))),r.a.createElement("main",{className:t.content},r.a.createElement("div",{className:t.appBarSpacer}),r.a.createElement(B.a,{container:!0,spacing:16},r.a.createElement(y.a,null),r.a.createElement(B.a,{item:!0,md:6,xs:12},r.a.createElement(O.a,{fullWidth:!0},r.a.createElement(R.a,null,r.a.createElement(S.a,{variant:"h6",component:"h1",gutterBottom:!0},"Event Patterns",r.a.createElement(K.a,{style:{marginBottom:"0.12em",marginLeft:"0.5em"},onClick:function(){return e.newPattern()}},r.a.createElement(I.a,null))),r.a.createElement(Te,{patterns:this.state.patterns,cached:this.cached,onRemovePattern:this.removePattern,onUpdatePattern:this.updatePattern})),r.a.createElement(R.a,null,r.a.createElement(S.a,{variant:"h6",component:"h1",gutterBottom:!0},"Time Range"),r.a.createElement("div",{style:{textAlign:"center"}},r.a.createElement(p.DateRangePicker,{startDate:this.state.startDate,startDateId:"start_date_id",endDate:this.state.endDate,endDateId:"end_date_id",onDatesChange:function(t){var a=t.startDate,n=t.endDate;e.setState({startDate:a,endDate:n})},focusedInput:this.state.focusedInput,onFocusChange:function(t){return e.setState({focusedInput:t})},isOutsideRange:function(){return!1}}))),r.a.createElement("div",{className:t.buttonSpacer}),r.a.createElement(B.a,{container:!0,spacing:16},r.a.createElement(B.a,{item:!0,md:6,xs:12},r.a.createElement(R.a,null,r.a.createElement(D.a,{variant:"contained",color:"primary",onClick:this.loadPatterns},"Load"))),r.a.createElement(B.a,{item:!0,md:6,xs:12},r.a.createElement(R.a,null,r.a.createElement(D.a,{variant:"contained",color:"primary",onClick:this.analyze},"Analyze")))))),r.a.createElement(B.a,{item:!0,md:6,xs:12},r.a.createElement(S.a,{variant:"h6",component:"h1",gutterBottom:!0},"Graph"),r.a.createElement(ee,{patternGraphData:this.state.patternGraphData,calendarGraphData:this.state.calendarGraphData}))))))}}]),t}(r.a.Component),Re=Object(f.withStyles)(function(e){return{root:{display:"flex",height:"100vh"},appBar:{zIndex:e.zIndex.drawer+1,transition:e.transitions.create(["width","margin"],{easing:e.transitions.easing.sharp,duration:e.transitions.duration.leavingScreen})},title:{flexGrow:1},sectionTitle:{flex:"0 0 auto"},appBarSpacer:e.mixins.toolbar,content:{flexGrow:1,padding:3*e.spacing.unit,overflow:"auto"},buttonSpacer:{marginBottom:4*e.spacing.unit},fab:{margin:e.spacing.unit}}})(je);Boolean("localhost"===window.location.hostname||"[::1]"===window.location.hostname||window.location.hostname.match(/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/));o.a.render(r.a.createElement(Re,null),document.getElementById("root")),"serviceWorker"in navigator&&navigator.serviceWorker.ready.then(function(e){e.unregister()})}},[[308,2,1]]]);
-//# sourceMappingURL=main.47fd8d39.chunk.js.map \ No newline at end of file
diff --git a/build/static/js/main.47fd8d39.chunk.js.map b/build/static/js/main.47fd8d39.chunk.js.map
deleted file mode 100644
index 5dc27b0..0000000
--- a/build/static/js/main.47fd8d39.chunk.js.map
+++ /dev/null
@@ -1 +0,0 @@
-{"version":3,"sources":["Logo.js","gapi.js","pattern.js","Chart.js","RegexField.js","theme.js","PatternTable.js","App.js","serviceWorker.js","index.js"],"names":["Logo","props","react_default","a","createElement","xmlns","viewBox","version","style","id","transform","points","fill","fontStyle","fontVariant","fontWeight","fontStretch","fontSize","fontFamily","gapi_base","to_params","dict","Object","entries","map","_ref","_ref2","slicedToArray","k","v","concat","encodeURIComponent","join","getAuthToken","Promise","resolver","chrome","identity","interactive","token","getCalendars","fetch","access_token","method","async","then","response","json","data","items","getColors","GCalendar","calId","name","classCallCheck","this","syncToken","cache","createClass","key","value","e","ks","dateToCacheKey","start","ke","Date","end","getTime","getSlot","slotEndDate","slotStartDate","s","results","console","log","push","getSlotEvents","apply","toConsumableArray","_this","resultsPerRequest","arguments","length","undefined","singleFetch","pageToken","maxResults","status","catch","nextPageToken","nextSyncToken","getEvents","r","pm_results","resolve","eventId","getEvent","all","forEach","dateTime","addEvent","removeEvent","_this2","sync","getCachedEvents","date","Math","floor","Pattern","isRegex","label","get","RegExp","emptyPattern","anyPattern","PatternEntry","idx","calPattern","eventPattern","cal","event","defaultPatternEntry","customizedLabel","cx","cy","x","y","anchor","dx","dy","textAnchor","withStyles","theme","pieChart","margin","Grid_default","container","spacing","item","xs","lg","className","classes","patternTableWrapper","PieChart","width","height","Pie","patternGraphData","dataKey","outerRadius","deepOrange","Tooltip","formatter","toFixed","calendarGraphData","innerRadius","cyan","d","i","Cell","color","RegexField","pitems","options","p0","isEmpty","palette","primary","dark","MenuItem_default","fieldRegex","fieldNoRegex","FormControl_default","Select_default","onChange","target","TextField_default","React","Component","RegexFieldWithStyles","marginRight","createMuiTheme","light","orange","main","contrastText","typography","useNextVariants","patternHead","field","elem","TextField","withTheme","cached","calendars","any","PatternTable","state","page","rowsPerPage","handleChangePage","setState","handleChangeRowsPerPage","_this$props","patterns","_this$state","nDummy","min","rows","slice","p","TableRow_default","onMouseOver","activePattern","onMouseOut","CustomText","TableCell_default","onUpdatePattern","deleteButtonShow","deleteButtonHide","DeleteOutlined_default","deleteIcon","onClick","onRemovePattern","Table_default","patternTable","TableHead_default","TableBody_default","colSpan","TablePagination_default","rowsPerPageOptions","component","count","backIconButtonProps","aria-label","nextIconButtonProps","onChangePage","onChangeRowsPerPage","position","right","display","cursor","overflowX","overflowY","minWidth","default_chart_data","Dashboard","timeRange","gapi","updatePattern","removePattern","splice","newPattern","analyze","startDate","endDate","toDate","event_pms","_loop","events","all_events","cal_results","_loop2","calName","filter","regex","test","filterPatterns","summary","hasOwnProperty","duration","background","alert","loadPatterns","colors","calendar","cals","colorId","styles","root","AppBar_default","appBar","Toolbar_default","toolbar","Typography_default","variant","noWrap","title","verticalAlign","content","appBarSpacer","CssBaseline_default","md","fullWidth","FormGroup_default","gutterBottom","IconButton_default","marginBottom","marginLeft","AddCircle_default","src_PatternTable","textAlign","react_dates","startDateId","endDateId","onDatesChange","_ref3","focusedInput","onFocusChange","isOutsideRange","buttonSpacer","Button_default","Chart","zIndex","drawer","transition","transitions","create","easing","sharp","leavingScreen","flexGrow","sectionTitle","flex","mixins","padding","unit","overflow","fab","Boolean","window","location","hostname","match","ReactDOM","render","App","document","getElementById","navigator","serviceWorker","ready","registration","unregister"],"mappings":"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","file":"static/js/main.47fd8d39.chunk.js","sourcesContent":["import React from 'react';\nexport default (props) =>\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 98.905998 93.557997\"\n version=\"1.1\"\n style={props.style}>\n <g id=\"g13\"\n transform=\"translate(-153.533,-203.047)\">\n <g id=\"g29\">\n <g\n id=\"g27\">\n <polygon\n id=\"polygon7\"\n 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 \"\n style={{fill: '#ff8000'}} />\n <g\n id=\"g11\"\n transform=\"translate(167.24355,224.20734)\">\n <text\n id=\"text9\"\n style={{fontStyle:'normal',\n fontVariant:'normal',\n fontWeight:'normal',\n fontStretch:'normal',\n fontSize:75,\n fontFamily:'TypoPRO Fantasque Sans Mono',\n fill:'#ffeade'}}\n transform=\"translate(0.586,49.072)\">Cr</text>\n </g>\n </g>\n </g>\n </g>\n </svg>\n","/* global chrome */\nconst gapi_base = 'https://www.googleapis.com/calendar/v3';\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 = '') {\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 throw {};\n })\n .catch(e => e)\n .then(data => {\n if (!data.items)\n return ({\n nextSyncToken: '',\n results: []\n });\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 }));\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 (<text x={x} y={y} dx={dx} dy={dy} fill={fill} textAnchor={anchor}>{`${name}`}</text>);\n}\n\nfunction ChromiclePieChart(props) {\n return (\n <Grid container spacing={0}>\n <Grid item xs={12} lg={6}>\n <div className={props.classes.patternTableWrapper}>\n <PieChart width={400} height={250} className={props.classes.pieChart}>\n <Pie data={props.patternGraphData}\n dataKey='value'\n cx={200}\n cy={125}\n outerRadius={60}\n fill={deepOrange[300]}\n label={customizedLabel}/>\n <Tooltip formatter={(value) => `${value.toFixed(2)} hr`}/>\n </PieChart>\n </div>\n </Grid>\n <Grid item xs={12} lg={6}>\n <div className={props.classes.patternTableWrapper}>\n <PieChart width={400} height={250} className={props.classes.pieChart}>\n <Pie data={props.calendarGraphData}\n dataKey='value'\n cx={200}\n cy={125}\n innerRadius={40}\n outerRadius={70}\n fill={cyan[300]}\n label={customizedLabel}>\n {props.calendarGraphData.map((d, i) => <Cell key={i} fill={d.color}/>)}\n </Pie>\n <Tooltip formatter={(value) => `${value.toFixed(2)} hr`}/>\n </PieChart>\n </div>\n </Grid>\n </Grid>);\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 <span style={{color: this.props.theme.palette.primary.dark}}>Custom</span>;\n items.push(<MenuItem key={id} value={id}>{label}</MenuItem>);\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 <FormControl>\n <span>\n <Select\n value={this.props.value.id}\n onChange={selectOnClick}\n className={className}>{items}\n </Select>\n {this.props.value.label == null && (\n <TextField\n value={this.props.value.value}\n onChange={regexTextOnChange} />\n )}\n </span>\n </FormControl>);\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 <RegexFieldWithStyles\n value={props.value}\n options={options}\n onChange={props.onChange}\n theme={props.theme} />);\n}\n\nexport function EventField(props) {\n let any = Pattern.anyPattern();\n let options = {};\n options[any.id] = any;\n return (\n <RegexFieldWithStyles\n value={props.value}\n options={options}\n onChange={props.onChange}\n theme={props.theme} />);\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 <TableRow\n onMouseOver={() => this.setState({ activePattern: p.idx })}\n onMouseOut={() => this.setState({ activePattern: null })}>\n {\n patternHead.map(s => {\n const CustomText = s.elem;\n return (\n <TableCell>\n <CustomText\n value={p[s.field]}\n cached={cached}\n onChange={event => this.props.onUpdatePattern(s.field, p.idx, event.target.value)}/>\n </TableCell>)})\n }\n <span className={this.state.activePattern === p.idx ? classes.deleteButtonShow : classes.deleteButtonHide}>\n <DeleteOutlinedIcon\n className={classes.deleteIcon}\n onClick={() => this.props.onRemovePattern(p.idx)} />\n </span>\n </TableRow>));\n\n return (\n <div>\n <div className={classes.patternTableWrapper}>\n <Table className={classes.patternTable}>\n <TableHead>\n <TableRow>{patternHead.map((s, i) => (<TableCell key={i}>{s.label}</TableCell>))}</TableRow>\n </TableHead>\n <TableBody>\n {rows}\n {\n nDummy > 0 && (\n <TableRow style={{ height: 48 * nDummy }}>\n <TableCell colSpan={patternHead.length} />\n </TableRow>)\n }\n </TableBody>\n </Table>\n </div>\n <TablePagination\n rowsPerPageOptions={[5, 10, 25]}\n component=\"div\"\n count={patterns.length}\n rowsPerPage={rowsPerPage}\n page={page}\n backIconButtonProps={{'aria-label': 'Previous Page'}}\n nextIconButtonProps={{'aria-label': 'Next Page'}}\n onChangePage={this.handleChangePage}\n onChangeRowsPerPage={this.handleChangeRowsPerPage} />\n </div>);\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.toDate();\n let end = this.state.endDate.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).then(\n r => { return { id, events: r } }));\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 <MuiThemeProvider theme={theme}>\n <div className={classes.root}>\n <AppBar\n position=\"absolute\"\n className={classes.appBar}>\n <Toolbar className={classes.toolbar}>\n <Typography component=\"h1\" variant=\"h6\" color=\"inherit\" noWrap className={classes.title}>\n <Logo style={{width: '2em', verticalAlign: 'bottom', marginRight: '0.2em'}}/>Chromicle\n </Typography>\n </Toolbar>\n </AppBar>\n <main className={classes.content}>\n <div className={classes.appBarSpacer} />\n <Grid container spacing={16}>\n <CssBaseline />\n <Grid item md={6} xs={12}>\n <FormControl fullWidth={true}>\n <FormGroup>\n <Typography variant=\"h6\" component=\"h1\" gutterBottom>\n Event Patterns\n <IconButton\n style={{marginBottom: '0.12em', marginLeft: '0.5em'}}\n onClick={() => this.newPattern()}><AddCircleIcon /></IconButton>\n </Typography>\n <PatternTable\n patterns={this.state.patterns}\n cached={this.cached}\n onRemovePattern={this.removePattern}\n onUpdatePattern={this.updatePattern} />\n </FormGroup>\n <FormGroup>\n <Typography variant=\"h6\" component=\"h1\" gutterBottom>\n Time Range\n </Typography>\n <div style={{textAlign: 'center'}}>\n <DateRangePicker\n startDate={this.state.startDate}\n startDateId=\"start_date_id\"\n endDate={this.state.endDate}\n endDateId=\"end_date_id\"\n onDatesChange={({ startDate, endDate }) => {\n this.setState({ startDate, endDate });\n }} \n focusedInput={this.state.focusedInput}\n onFocusChange={focusedInput => this.setState({ focusedInput })}\n isOutsideRange={() => false}/>\n </div>\n </FormGroup>\n <div className={classes.buttonSpacer} />\n <Grid container spacing={16}>\n <Grid item md={6} xs={12}>\n <FormGroup>\n <Button variant=\"contained\" color=\"primary\" onClick={this.loadPatterns}>Load</Button>\n </FormGroup>\n </Grid>\n <Grid item md={6} xs={12}>\n <FormGroup>\n <Button variant=\"contained\" color=\"primary\" onClick={this.analyze}>Analyze</Button>\n </FormGroup>\n </Grid>\n </Grid>\n </FormControl>\n </Grid>\n <Grid item md={6} xs={12}>\n <Typography variant=\"h6\" component=\"h1\" gutterBottom>\n Graph\n </Typography>\n <PieChart\n patternGraphData={this.state.patternGraphData}\n calendarGraphData={this.state.calendarGraphData}/>\n </Grid>\n </Grid>\n </main>\n </div>\n </MuiThemeProvider>);\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(<App />, 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/src/App.js b/src/App.js
index 4d23440..1d708f9 100755
--- a/src/App.js
+++ b/src/App.js
@@ -111,8 +111,12 @@ class Dashboard extends React.Component {
console.log(start, end);
let event_pms = [];
for (let id in this.cached.calendars)
- event_pms.push(this.cached.calendars[id].cal.getEvents(start, end).then(
- r => { return { id, events: r } }));
+ event_pms.push(this.cached.calendars[id].cal.getEvents(start, end)
+ .then(r => { return { id, events: r }; })
+ .catch(e => {
+ console.log(`cannot load calendar ${id}`);
+ return { id, events: [] };
+ }));
Promise.all(event_pms).then(all_events => {
let events = {};
diff --git a/src/gapi.js b/src/gapi.js
index c66a9ff..34fc9e9 100644
--- a/src/gapi.js
+++ b/src/gapi.js
@@ -1,6 +1,11 @@
/* global chrome */
const gapi_base = 'https://www.googleapis.com/calendar/v3';
+const GApiError = {
+ invalidSyncToken: 1,
+ otherError: 2,
+};
+
function to_params(dict) {
return Object.entries(dict).map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`).join('&');
}
@@ -30,7 +35,7 @@ function getEvent(calId, eventId, token) {
.then(response => response.json());
}
-function getEvents(calId, token, syncToken, resultsPerRequest = '') {
+function getEvents(calId, token, syncToken, resultsPerRequest=100) {
let results = [];
const singleFetch = (pageToken, syncToken) => fetch(`${gapi_base}/calendars/${calId}/events?${to_params({
access_token: token,
@@ -41,15 +46,11 @@ function getEvents(calId, token, syncToken, resultsPerRequest = '') {
.then(response => {
if (response.status === 200)
return response.json();
- else throw {};
+ else if (response.status == 410)
+ throw GApiError.invalidSyncToken;
+ else throw GApiError.otherErrors;
})
- .catch(e => e)
.then(data => {
- if (!data.items)
- return ({
- nextSyncToken: '',
- results: []
- });
results.push(...data.items);
if (data.nextPageToken) {
return singleFetch(data.nextPageToken, '');
@@ -165,7 +166,12 @@ export class GCalendar {
else if (e.status === 'cancelled')
this.removeEvent(e);
}));
- }));
+ })).catch(e => {
+ if (e == GApiError.invalidSyncToken) {
+ this.syncToken = '';
+ this.sync();
+ } else throw e;
+ });
}
getEvents(start, end) {