aboutsummaryrefslogtreecommitdiff
path: root/build/static/js/main.f0bd332c.chunk.js.map
blob: d66432b14a75cf487d26966c0854daf0c7dd5207 (plain) (blame)
1
{"version":3,"sources":["Logo.js","gapi.js","msg.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","filter","_ref","_ref2","slicedToArray","map","_ref3","_ref4","k","v","concat","encodeURIComponent","join","getAuthToken","Promise","resolver","chrome","identity","interactive","token","getCalendars","fetch","access_token","method","async","then","response","json","data","items","getColors","_updatePatterns","_getPatterns","_updateCalendars","_getCalendars","_getCalEvents","msgType","freeze","updatePatterns","Symbol","getPatterns","updateCalendars","getCalEvents","stringifyMsgType","mt","Msg","type","classCallCheck","this","createClass","key","value","inflate","obj","s","parseMsgType","Pattern","isRegex","label","get","RegExp","emptyPattern","anyPattern","revive","PatternEntry","name","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","_this","pitems","options","p0","isEmpty","palette","primary","dark","push","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","calendars","any","PatternTable","state","page","rowsPerPage","handleChangePage","setState","handleChangeRowsPerPage","_this2","_this$props","patterns","_this$state","nDummy","Math","min","length","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","possibleConstructorReturn","getPrototypeOf","call","timeRange","gapi","updatePattern","sendMsg","removePattern","splice","newPattern","toConsumableArray","loadPatterns","loadCalendars","cb","rcb","requestCallback","pm","resolve","ids","pop","maxId","inFlight","port","postMessage","deflate","start","end","getTime","e","Date","analyze","startDate","endDate","startOf","toDate","event_pms","cals","_loop","calName","regex","test","filterPatterns","r","events","all","all_events","console","log","results","cal_results","forEach","_loop2","summary","hasOwnProperty","duration","background","alert","load","colors","calendar","colorId","runtime","connect","onMessage","addListener","msg","assert","undefined","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","_ref5","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":"gdACeA,EAAA,SAACC,GAAD,OACbC,EAAAC,EAAAC,cAAA,OACGC,MAAM,6BACNC,QAAQ,0BACRC,QAAQ,MACRC,MAAOP,EAAMO,OACdN,EAAAC,EAAAC,cAAA,KAAGK,GAAG,MACHC,UAAU,gCACXR,EAAAC,EAAAC,cAAA,KAAGK,GAAG,OACJP,EAAAC,EAAAC,cAAA,KACGK,GAAG,OACJP,EAAAC,EAAAC,cAAA,WACGK,GAAG,WACHE,OAAO,mGACPH,MAAO,CAACI,KAAM,aACjBV,EAAAC,EAAAC,cAAA,KACGK,GAAG,MACHC,UAAU,kCACXR,EAAAC,EAAAC,cAAA,QACGK,GAAG,QACFD,MAAO,CAACK,UAAU,SACdC,YAAY,SACZC,WAAW,SACXC,YAAY,SACZC,SAAS,GACTC,WAAW,8BACXN,KAAK,WACVF,UAAU,2BATb,YCjBNS,UAAY,0CAOlB,SAASC,EAAUC,GACf,OAAOC,OAAOC,QAAQF,GAAMG,OAAO,SAAAC,GAAA,IAAAC,EAAAJ,OAAAK,EAAA,EAAAL,CAAAG,EAAA,GAAAC,EAAA,UAAAA,EAAA,KAAeE,IAAI,SAAAC,GAAA,IAAAC,EAAAR,OAAAK,EAAA,EAAAL,CAAAO,EAAA,GAAEE,EAAFD,EAAA,GAAKE,EAALF,EAAA,YAAAG,OAAeC,mBAAmBH,GAAlC,KAAAE,OAAwCC,mBAAmBF,MAAMG,KAAK,KAGzH,SAASC,IACZ,OAAO,IAAIC,QAAQ,SAAAC,GAAQ,OACvBC,OAAOC,SAASJ,aACZ,CAACK,aAAa,GAAO,SAAAC,GAAK,OAAIJ,EAASI,OAG5C,SAASC,EAAaD,GACzB,OAAOE,MAAK,GAAAX,OAAId,EAAJ,2BAAAc,OAAuCb,EAAU,CAACyB,aAAcH,KACpE,CAAEI,OAAQ,MAAOC,OAAO,IAC3BC,KAAK,SAAAC,GAAQ,OAAIA,EAASC,SAC1BF,KAAK,SAAAG,GAAI,OAAIA,EAAKC,QAGpB,SAASC,EAAUX,GACtB,OAAOE,MAAK,GAAAX,OAAId,EAAJ,YAAAc,OAAwBb,EAAU,CAACyB,aAAcH,KACzD,CAAEI,OAAQ,MAAOC,OAAO,IACvBC,KAAK,SAAAC,GAAQ,OAAIA,EAASC,SAyC5B,ICtEDI,EAAkB,iBAClBC,EAAe,cACfC,EAAmB,kBACnBC,EAAgB,eAChBC,EAAgB,eAETC,EAAUrC,OAAOsC,OAAO,CACjCC,eAAgBC,OAAOR,GACvBS,YAAaD,OAAOP,GACpBS,gBAAiBF,OAAON,GACxBb,aAAcmB,OAAOL,GACrBQ,aAAcH,OAAOJ,KAGzB,SAASQ,EAAiBC,GACtB,OAAQA,GACJ,KAAKR,EAAQE,eAAgB,OAAOP,EACpC,KAAKK,EAAQI,YAAa,OAAOR,EACjC,KAAKI,EAAQK,gBAAiB,OAAOR,EACrC,KAAKG,EAAQhB,aAAc,OAAOc,EAClC,KAAKE,EAAQM,aAAc,OAAOP,GAcnC,IAAMU,EAAb,WACI,SAAAA,EAAY3D,EAAI4D,EAAMlB,GAAO7B,OAAAgD,EAAA,EAAAhD,CAAAiD,KAAAH,GACzBG,KAAK9D,GAAKA,EACV8D,KAAKF,KAAOA,EACZE,KAAKpB,KAAOA,EAJpB,OAAA7B,OAAAkD,EAAA,EAAAlD,CAAA8C,EAAA,EAAAK,IAAA,UAAAC,MAAA,SAMYvB,GAAQ,OAAO,IAAIiB,EAAIG,KAAK9D,GAAI8D,KAAKF,KAAMlB,KANvD,CAAAsB,IAAA,UAAAC,MAAA,WAQQ,MAAO,CACHjE,GAAI8D,KAAK9D,GACT4D,KAAMH,EAAiBK,KAAKF,MAC5BlB,KAAMoB,KAAKpB,UAXvBiB,EAAA,GAAaA,EAcFO,QAAU,SAAAC,GAAG,OAAI,IAAIR,EAAIQ,EAAInE,GAxBxC,SAAsBoE,GAClB,OAAOA,GACH,KAAKvB,EAAiB,OAAOK,EAAQE,eACrC,KAAKN,EAAc,OAAOI,EAAQI,YAClC,KAAKP,EAAkB,OAAOG,EAAQK,gBACtC,KAAKP,EAAe,OAAOE,EAAQhB,aACnC,KAAKe,EAAe,OAAOC,EAAQM,cAkBCa,CAAaF,EAAIP,MAAOO,EAAIzB,OChDjE,IAAM4B,EAAb,WACI,SAAAA,EAAYtE,EAAIuE,EAASN,EAAOO,GAAQ3D,OAAAgD,EAAA,EAAAhD,CAAAiD,KAAAQ,GACpCR,KAAK9D,GAAKA,EACV8D,KAAKS,QAAUA,EACfT,KAAKG,MAAQA,EACbH,KAAKU,MAAQA,EALrB,OAAA3D,OAAAkD,EAAA,EAAAlD,CAAAyD,EAAA,EAAAN,IAAA,QAAAS,IAAA,WAQkB,OAAO,IAAIC,OAAOZ,KAAKS,QAAUT,KAAKG,MAApB,IAAAzC,OAAgCsC,KAAKG,MAArC,QARpC,CAAAD,IAAA,UAAAS,IAAA,WASoB,OAAsB,OAAfX,KAAKU,UAThCF,EAAA,GAAaA,EAUFK,aAAe,kBAAM,IAAIL,EAAQ,GAAG,EAAM,GAAI,OAV5CA,EAWFM,WAAa,kBAAM,IAAIN,EAAQ,OAAO,EAAM,KAAM,QAXhDA,EAYFO,OAAS,SAAAV,GAAG,OAAI,IAAIG,EAAQH,EAAInE,GAAImE,EAAII,QAASJ,EAAIF,MAAOE,EAAIK,QAGpE,IAAMM,EACT,SAAAA,EAAYC,EAAMC,EAAKC,EAAYC,GAAerE,OAAAgD,EAAA,EAAAhD,CAAAiD,KAAAgB,GAC9ChB,KAAKiB,KAAOA,EACZjB,KAAKkB,IAAMA,EACXlB,KAAKqB,IAAMF,EACXnB,KAAKsB,MAAQF,GALRJ,EAQFO,oBAAsB,SAACL,GAAD,OAAS,IAAIF,EAAa,GAAIE,EAAKV,EAAQK,eAAgBL,EAAQM,eARvFE,EASFD,OAAS,SAAAV,GAAG,OAAI,IAAIW,EACvBX,EAAIY,KAAMZ,EAAIa,IACdV,EAAQO,OAAOV,EAAIgB,KAAMb,EAAQO,OAAOV,EAAIiB,0ECZpD,SAASE,GAAgB9F,GAAO,IACrB+F,EAA4B/F,EAA5B+F,GAAIC,EAAwBhG,EAAxBgG,GAAIC,EAAoBjG,EAApBiG,EAAGC,EAAiBlG,EAAjBkG,EAAGvF,EAAcX,EAAdW,KAAM4E,EAAQvF,EAARuF,KACvBY,EAAS,SAETC,EAAK,EACLC,EAAK,EAeT,OAdIJ,EAAIF,EAHI,GAIRK,GAAM,EACND,EAAS,OACFF,EAAIF,EANH,IAORK,EAAK,EACLD,EAAS,SAGTD,EAAIF,EAXI,EAYRK,GAAM,EACCH,EAAIF,EAbH,IAcRK,EAAK,IAGDpG,EAAAC,EAAAC,cAAA,QAAM8F,EAAGA,EAAGC,EAAGA,EAAGE,GAAIA,EAAIC,GAAIA,EAAI1F,KAAMA,EAAM2F,WAAYH,GAA1D,GAAAnE,OAAsEuD,IA6CnEgB,4BAvEA,SAAAC,GAAK,MAAK,CACrBC,SAAU,CACNC,OAAQ,YAqEDH,CA1Cf,SAA2BvG,GACvB,OACAC,EAAAC,EAAAC,cAACwG,EAAAzG,EAAD,CAAM0G,WAAS,EAACC,QAAS,GACvB5G,EAAAC,EAAAC,cAACwG,EAAAzG,EAAD,CAAM4G,MAAI,EAACC,GAAI,GAAIC,GAAI,GACrB/G,EAAAC,EAAAC,cAAA,OAAK8G,UAAWjH,EAAMkH,QAAQC,qBAC9BlH,EAAAC,EAAAC,cAACiH,GAAA,EAAD,CAAUC,MAAO,IAAKC,OAAQ,IAAKL,UAAWjH,EAAMkH,QAAQT,UAC1DxG,EAAAC,EAAAC,cAACoH,GAAA,EAAD,CAAKrE,KAAMlD,EAAMwH,iBACZC,QAAQ,QACR1B,GAAI,IACJC,GAAI,IACJ0B,YAAa,GACb/G,KAAMgH,KAAW,KACjB3C,MAAOc,KACZ7F,EAAAC,EAAAC,cAACyH,GAAA,EAAD,CAASC,UAAW,SAACpD,GAAD,SAAAzC,OAAcyC,EAAMqD,QAAQ,GAA5B,aAIxB7H,EAAAC,EAAAC,cAACwG,EAAAzG,EAAD,CAAM4G,MAAI,EAACC,GAAI,GAAIC,GAAI,GACrB/G,EAAAC,EAAAC,cAAA,OAAK8G,UAAWjH,EAAMkH,QAAQC,qBAC9BlH,EAAAC,EAAAC,cAACiH,GAAA,EAAD,CAAUC,MAAO,IAAKC,OAAQ,IAAKL,UAAWjH,EAAMkH,QAAQT,UAC1DxG,EAAAC,EAAAC,cAACoH,GAAA,EAAD,CAAKrE,KAAMlD,EAAM+H,kBACZN,QAAQ,QACR1B,GAAI,IACJC,GAAI,IACJgC,YAAa,GACbN,YAAa,GACb/G,KAAMsH,IAAK,KACXjD,MAAOc,IACT9F,EAAM+H,kBAAkBpG,IAAI,SAACuG,EAAGC,GAAJ,OAAUlI,EAAAC,EAAAC,cAACiI,GAAA,EAAD,CAAM5D,IAAK2D,EAAGxH,KAAMuH,EAAEG,WAE/DpI,EAAAC,EAAAC,cAACyH,GAAA,EAAD,CAASC,UAAW,SAACpD,GAAD,SAAAzC,OAAcyC,EAAMqD,QAAQ,GAA5B,kOCjDxBQ,oLACO,IAAAC,EAAAjE,KACG4C,EAAY5C,KAAKtE,MAAjBkH,QACJ/D,EAAQ,GACRqF,EAASlE,KAAKtE,MAAMyI,QAClBC,EAAK,IAAI5D,EAAQK,aAEvB,IAAK,IAAI3E,KADTgI,EAAOE,EAAGlI,IAAMkI,EACDF,EACf,CACI,IAAMxD,EAASwD,EAAOhI,GAAImI,QACtB1I,EAAAC,EAAAC,cAAA,QAAMI,MAAO,CAAC8H,MAAO/D,KAAKtE,MAAMwG,MAAMoC,QAAQC,QAAQC,OAAtD,UADgCN,EAAOhI,GAAIwE,MAE/C7B,EAAM4F,KAAK9I,EAAAC,EAAAC,cAAC6I,GAAA9I,EAAD,CAAUsE,IAAKhE,EAAIiE,MAAOjE,GAAKwE,IAE9C,IAgBMiC,EAAY3C,KAAKtE,MAAMyE,MAAMM,QAAUmC,EAAQ+B,WAAY/B,EAAQgC,aACzE,OACIjJ,EAAAC,EAAAC,cAACgJ,EAAAjJ,EAAD,KACID,EAAAC,EAAAC,cAAA,YACIF,EAAAC,EAAAC,cAACiJ,GAAAlJ,EAAD,CACIuE,MAAOH,KAAKtE,MAAMyE,MAAMjE,GACxB6I,SAtBM,SAAAzD,GAClB,IAAInB,EAEAA,EADoC,MAApC+D,EAAO5C,EAAM0D,OAAO7E,OAAOO,MACnB,IAAIF,EAAQ,GAAG,EACnByD,EAAKvI,MAAMyE,MAAMM,QACjBwD,EAAKvI,MAAMyE,MAAMA,MADjB,IAAAzC,OAEIuG,EAAKvI,MAAMyE,MAAMA,MAFrB,KAE+B,MAE3B+D,EAAO5C,EAAM0D,OAAO7E,OAEhC8D,EAAKvI,MAAMqJ,SAAS,CAACC,OAAQ,CAAC7E,YAalBwC,UAAWA,GAAY9D,GAEA,MAA1BmB,KAAKtE,MAAMyE,MAAMO,OACd/E,EAAAC,EAAAC,cAACoJ,GAAArJ,EAAD,CACIuE,MAAOH,KAAKtE,MAAMyE,MAAMA,MACxB4E,SAfM,SAAAzD,GAAK,OAAI2C,EAAKvI,MAAMqJ,SAAS,CACnDC,OAAQ,CAAE7E,MAAO,IAAIK,EAAQ,GAAG,EAAMc,EAAM0D,OAAO7E,MAAO,qBA3B7C+E,IAAMC,WAoDzBC,GAAuBnD,qBA7Dd,SAAAC,GAAK,MAAK,CACrB0C,aAAc,CACV7B,MAAO,KAEX4B,WAAY,CACRU,YAAa,WAwDQpD,CAAmB+B,6BCrDjC9B,GAdDoD,yBAAe,CACzBhB,QAAS,CACLC,QAAS,CACLgB,MAAOC,KAAO,KACdC,KAAMD,KAAO,KACbhB,KAAMgB,KAAO,KACbE,aAAc,SAGtBC,WAAY,CACRC,iBAAiB,KCuBnBC,GAAc,CAChB,CAACnF,MAAO,OAAQoF,MAAO,OAAQC,KAAMC,MACrC,CAACtF,MAAO,WAAYoF,MAAO,MAAOC,KAAME,oBAAU/D,GAAV+D,CFkCrC,SAAuBvK,GAC1B,IAAIyI,EAAU,GACd,IAAK,IAAIjI,KAAMR,EAAMwK,UACjB/B,EAAQjI,GAAM,IAAIsE,EAAQtE,GAAI,EAC1BR,EAAMwK,UAAUhK,GAAI+E,KACpBvF,EAAMwK,UAAUhK,GAAI+E,MAE5B,OACItF,EAAAC,EAAAC,cAACuJ,GAAD,CACIjF,MAAOzE,EAAMyE,MACbgE,QAASA,EACTY,SAAUrJ,EAAMqJ,SAChB7C,MAAOxG,EAAMwG,WE7CrB,CAACxB,MAAO,QAASoF,MAAO,QAASC,KAAME,oBAAU/D,GAAV+D,CFgDpC,SAAoBvK,GACvB,IAAIyK,EAAM3F,EAAQM,aACdqD,EAAU,GAEd,OADAA,EAAQgC,EAAIjK,IAAMiK,EAEdxK,EAAAC,EAAAC,cAACuJ,GAAD,CACIjF,MAAOzE,EAAMyE,MACbgE,QAASA,EACTY,SAAUrJ,EAAMqJ,SAChB7C,MAAOxG,EAAMwG,YEvDnBkE,8MACFC,MAAQ,CACJC,KAAM,EACNC,YAAa,KAGjBC,iBAAmB,SAAClF,EAAOgF,GACvBrC,EAAKwC,SAAS,CAAEH,YAGpBI,wBAA0B,SAAApF,GACtB2C,EAAKwC,SAAS,CAAEF,YAAajF,EAAM0D,OAAO7E,iFAGrC,IAAAwG,EAAA3G,KAAA4G,EACoC5G,KAAKtE,MAAtCkH,EADHgE,EACGhE,QAASsD,EADZU,EACYV,UAAWW,EADvBD,EACuBC,SADvBC,EAEyB9G,KAAKqG,MAA3BE,EAFHO,EAEGP,YAAaD,EAFhBQ,EAEgBR,KACfS,EAASR,EAAcS,KAAKC,IAAIV,EAAaM,EAASK,OAASZ,EAAOC,GACxEY,EAAON,EAASO,MAAMd,EAAOC,GAAcD,EAAO,GAAKC,GAAalJ,IAAI,SAAAgK,GAAC,OACzE1L,EAAAC,EAAAC,cAACyL,GAAA1L,EAAD,CACI2L,YAAa,kBAAMZ,EAAKF,SAAS,CAAEe,cAAeH,EAAEnG,OACpDuG,WAAY,kBAAMd,EAAKF,SAAS,CAAEe,cAAe,SAE7C3B,GAAYxI,IAAI,SAAAiD,GACZ,IAAMoH,EAAapH,EAAEyF,KACrB,OACIpK,EAAAC,EAAAC,cAAC8L,GAAA/L,EAAD,KACID,EAAAC,EAAAC,cAAC6L,EAAD,CACIvH,MAAOkH,EAAE/G,EAAEwF,OACXI,UAAWA,EACXnB,SAAU,SAAAzD,GAAK,OAAIqF,EAAKjL,MAAMkM,gBAAgBtH,EAAEwF,MAAOuB,EAAEnG,IAAKI,EAAM0D,OAAO7E,aAG/FxE,EAAAC,EAAAC,cAAA,QAAM8G,UAAWgE,EAAKN,MAAMmB,gBAAkBH,EAAEnG,IAAM0B,EAAQiF,iBAAmBjF,EAAQkF,kBACrFnM,EAAAC,EAAAC,cAACkM,GAAAnM,EAAD,CACI+G,UAAWC,EAAQoF,WACnBC,QAAS,kBAAMtB,EAAKjL,MAAMwM,gBAAgBb,EAAEnG,YAI5D,OACIvF,EAAAC,EAAAC,cAAA,WACIF,EAAAC,EAAAC,cAAA,OAAK8G,UAAWC,EAAQC,qBACpBlH,EAAAC,EAAAC,cAACsM,GAAAvM,EAAD,CAAO+G,UAAWC,EAAQwF,cACtBzM,EAAAC,EAAAC,cAACwM,GAAAzM,EAAD,KACID,EAAAC,EAAAC,cAACyL,GAAA1L,EAAD,KAAWiK,GAAYxI,IAAI,SAACiD,EAAGuD,GAAJ,OAAWlI,EAAAC,EAAAC,cAAC8L,GAAA/L,EAAD,CAAWsE,IAAK2D,GAAIvD,EAAEI,WAEhE/E,EAAAC,EAAAC,cAACyM,GAAA1M,EAAD,KACKuL,EAEGJ,EAAS,GACLpL,EAAAC,EAAAC,cAACyL,GAAA1L,EAAD,CAAUK,MAAO,CAAE+G,OAAQ,GAAK+D,IAC5BpL,EAAAC,EAAAC,cAAC8L,GAAA/L,EAAD,CAAW2M,QAAS1C,GAAYqB,aAMxDvL,EAAAC,EAAAC,cAAC2M,GAAA5M,EAAD,CACI6M,mBAAoB,CAAC,EAAG,GAAI,IAC5BC,UAAU,MACVC,MAAO9B,EAASK,OAChBX,YAAaA,EACbD,KAAMA,EACNsC,oBAAqB,CAACC,aAAc,iBACpCC,oBAAqB,CAACD,aAAc,aACpCE,aAAc/I,KAAKwG,iBACnBwC,oBAAqBhJ,KAAK0G,kCAnEnBxB,IAAMC,WAiFlBlD,wBA5GA,SAAAC,GAAK,MAAK,CACrB2F,iBAAkB,CACdoB,SAAU,WACVC,MAAO,EACPlG,OAAQ,IAEZ8E,iBAAkB,CACdqB,QAAS,QAEbnB,WAAY,CACRhF,OAAQ,OACRoG,OAAQ,WAEZvG,oBAAqB,CACjBwG,UAAW,OACXC,UAAW,UAEflB,aAAc,CACVmB,SAAU,OA0FHtH,CAAmBmE,IC9F5BoD,GAAqB,CACvB,CAACvI,KAAM,OAAQd,MAAO,GAAI4D,MAAOJ,IAAK,MACtC,CAAC1C,KAAM,SAAUd,MAAO,GAAI4D,MAAOJ,IAAK,OAQ5C,IAgCM8F,eAWF,SAAAA,EAAY/N,GAAO,IAAAuI,EAAAlH,OAAAgD,EAAA,EAAAhD,CAAAiD,KAAAyJ,IACfxF,EAAAlH,OAAA2M,EAAA,EAAA3M,CAAAiD,KAAAjD,OAAA4M,EAAA,EAAA5M,CAAA0M,GAAAG,KAAA5J,KAAMtE,KAXV2K,MAAQ,CACJQ,SAAU,GACVX,UAAW,GACX2D,UAAW,KACX1L,MAAO2L,IACP5G,iBAAkBsG,GAClB/F,kBAAmB+F,GACnBhC,cAAe,MAGAvD,EAsBnB8F,cAAgB,SAACjE,EAAO5E,EAAKf,GACzB,IAAI0G,EAAW5C,EAAKoC,MAAMQ,SAC1BA,EAAS3F,GAAK4E,GAAS3F,EACvB8D,EAAKwC,SAAS,CAAEI,aAChB5C,EAAK+F,QAAQ,CAAElK,KAAMV,EAAQE,eAAgBV,KAAMiI,KA1BpC5C,EA6BnBgG,cAAgB,SAAA/I,GACZ,IAAI2F,EAAW5C,EAAKoC,MAAMQ,SAC1BA,EAASqD,OAAOhJ,EAAK,GACrB,IAAK,IAAI2C,EAAI,EAAGA,EAAIgD,EAASK,OAAQrD,IACjCgD,EAAShD,GAAG3C,IAAM2C,EACtBI,EAAKwC,SAAS,CAAEI,aAChB5C,EAAK+F,QAAQ,CAAElK,KAAMV,EAAQE,eAAgBV,KAAMiI,KAnCpC5C,EAsCnBkG,WAAa,WAET,IADA,IAAItD,EAAQ,CAAI7F,EAAaO,oBAAoB,IAArC7D,OAAAX,OAAAqN,EAAA,EAAArN,CAA4CkH,EAAKoC,MAAMQ,WAC1DhD,EAAI,EAAGA,EAAIgD,EAASK,OAAQrD,IACjCgD,EAAShD,GAAG3C,IAAM2C,EACtBI,EAAKwC,SAAS,CAAEI,aAChB5C,EAAK+F,QAAQ,CAAElK,KAAMV,EAAQE,eAAgBV,KAAMiI,KA3CpC5C,EA8CnBoG,aAAe,SAAAxD,GACX5C,EAAKwC,SAAS,CAAEI,aAChB5C,EAAK+F,QAAQ,CAAElK,KAAMV,EAAQE,eAAgBV,KAAMiI,KAhDpC5C,EAmDnBqG,cAAgB,SAAApE,GACZjC,EAAKwC,SAAS,CAAEP,cAChBjC,EAAK+F,QAAQ,CAAElK,KAAMV,EAAQK,gBAAiBb,KAAMsH,KArDrCjC,EAwDnB+F,QAAU,SAAA9M,GAAoB,IAEtBqN,EAEArO,EAJK4D,EAAiB5C,EAAjB4C,KAAMlB,EAAW1B,EAAX0B,KACX4L,EAAMvG,EAAKwG,gBAEXC,EAAK,IAAI5M,QAAQ,SAAA6M,GAAaJ,EAAKI,IASvC,OANIzO,EADAsO,EAAII,IAAI1D,OAAS,EACZsD,EAAII,IAAIC,MAERL,EAAIM,QAEbN,EAAIO,SAAS7O,GAAMqO,EACnBtG,EAAK+G,KAAKC,YAAa,IAAIpL,EAAI3D,EAAI4D,EAAMlB,GAAOsM,WACzCR,GApEQzG,EAuEnBvE,aAAe,SAACxD,EAAIiP,EAAOC,GACvB,OAAOnH,EAAK+F,QAAQ,CAAElK,KAAMV,EAAQM,aAAcd,KAAM,CAAE1C,KAC9CiP,MAAOA,EAAME,UACbD,IAAKA,EAAIC,aAChB5M,KAAK,SAAAtB,GAAA,OAAAA,EAAGyB,KAAgBvB,IAAI,SAAAiO,GACzB,MAAO,CACHpP,GAAIoP,EAAEpP,GACNiP,MAAO,IAAII,KAAKD,EAAEH,OAClBC,IAAK,IAAIG,KAAKD,EAAEF,WA/EbnH,EAmFnBuH,QAAU,WACN,GAAMvH,EAAKoC,MAAMoF,WAAaxH,EAAKoC,MAAMqF,QAAzC,CAIA,IAAIP,EAAQlH,EAAKoC,MAAMoF,UAAUE,QAAQ,OAAOC,SAC5CR,EAAMnH,EAAKoC,MAAMqF,QAAQC,QAAQ,OAAOC,SACxCC,EAAY,GACZC,EAAO7H,EAAKoC,MAAMH,UARV6F,EAAA,SASH7P,GAEL,IAAI2K,EA/IhB,SAAwBA,EAAUmF,GAC9B,OAAOnF,EAAS5J,OAAO,SAAAoK,GACnB,OAAOA,EAAEhG,IAAI4K,MAAMC,KAAKF,KA6ILG,CAAelI,EAAKoC,MAAMQ,SAAUiF,EAAK5P,GAAI+E,MACxD4F,EAASK,OAAS,GAClB2E,EAAUpH,KAAKR,EAAKvE,aAAaxD,EAAIiP,EAAOC,GACvC3M,KAAK,SAAA2N,GAAO,MAAO,CAAElQ,KAAImQ,OAAQD,EAAGvF,gBALjD,IAAK,IAAI3K,KAAM4P,EACfC,EADS7P,GAOT4B,QAAQwO,IAAIT,GAAWpN,KAAK,SAAA8N,GACxBC,QAAQC,IAAIF,GACZ,IAAIF,EAAS,GACTxF,EAAW,GACX6F,EAAU,GACVC,EAAc,GAClBJ,EAAWK,QAAQ,SAAAtB,GACfe,EAAOf,EAAEpP,IAAMoP,EAAEe,OACjBxF,EAASyE,EAAEpP,IAAMoP,EAAEzE,WAEvB,IAAK,IAAIhD,EAAI,EAAGA,EAAII,EAAKoC,MAAMQ,SAASK,OAAQrD,IAC5C6I,EAAQ7I,GAAK,EAXqB,IAAAgJ,EAAA,SAY7B3Q,GACL,IAAKmQ,EAAOnQ,GAAK,iBACjBmQ,EAAOnQ,GAAI0Q,QAAQ,SAAAtL,GACfuF,EAAS3K,GAAI0Q,QAAQ,SAAAvF,GACjB,GAAKA,EAAE/F,MAAM2K,MAAMC,KAAK5K,EAAMwL,SAA9B,CACKH,EAAYI,eAAe7Q,KAC5ByQ,EAAYzQ,GAAM,GAEtB,IAAI8Q,GAAY1L,EAAM8J,IAAM9J,EAAM6J,OAAS,IAC3CuB,EAAQrF,EAAEnG,MAAQ8L,EAClBL,EAAYzQ,IAAO8Q,QAV/B,IAAK,IAAI9Q,KAAM4P,EAAMe,EAAZ3Q,GAgBT,IAFA,IAAIgH,EAAmB,GACnBO,EAAoB,GACfI,EAAI,EAAGA,EAAII,EAAKoC,MAAMQ,SAASK,OAAQrD,IAC5CX,EAAiBuB,KAAK,CAAExD,KAAMgD,EAAKoC,MAAMQ,SAAShD,GAAG5C,KAAMd,MAAOuM,EAAQ7I,GAAK,KAEnF,IAAK,IAAI3H,KAAMyQ,EACXlJ,EAAkBgB,KAAK,CACnBxD,KAAM6K,EAAK5P,GAAI+E,KACfd,MAAQwM,EAAYzQ,GAAM,GAC1B6H,MAAO+H,EAAK5P,GAAI6H,MAAMkJ,aAE9BT,QAAQC,IAAIvJ,EAAkBO,GAC9BQ,EAAKwC,SAAS,CAAEvD,mBAAkBO,6BApDlCyJ,MAAM,sCArFKjJ,EA6InBkJ,KAAO,WACH,IAAIhP,EAAQ8F,EAAKoC,MAAMlI,MACnBiP,EAASjP,EAAMM,KAAKqL,GAAgBrL,KAAK,SAAAsF,GACzC,OAAOA,EAAMsJ,WAEbvB,EAAO3N,EAAMM,KAAKqL,GACtBhM,QAAQwO,IAAI,CAACc,EAAQtB,IAAOrN,KAAK,SAAAnB,GAAqB,IAAAC,EAAAR,OAAAK,EAAA,EAAAL,CAAAO,EAAA,GAAnB8P,EAAmB7P,EAAA,GAAXsB,EAAWtB,EAAA,GAC9CuO,EAAO,GACXjN,EAAM+N,QAAQ,SAAApK,GACVsJ,EAAKtJ,EAAKtG,IAAM,CACZ+E,KAAMuB,EAAKsK,QACX/I,MAAOqJ,EAAO5K,EAAK8K,YAG3BrJ,EAAKqG,cAAcwB,GACnB7H,EAAKoG,aAAaxL,EAAMxB,IAAI,SAACmF,EAAMtB,GAC/B,OAAO,IAAIF,EAAawB,EAAKsK,QAAS5L,EAClC,IAAIV,EAAQgC,EAAKtG,IAAI,EAAOsG,EAAKsK,QAAStK,EAAKsK,SAC/CtM,EAAQM,oBA7JpB,IAAIkK,EAAOhN,OAAOuP,QAAQC,QAAQ,CAACvM,KAAM,SAF1B,OAIf+J,EAAKyC,UAAUC,YAAY,SAASC,GAChCnB,QAAQC,IAAIkB,GACZ,IAAInD,GAAkBmD,EAAI7N,KAHHmE,EAAKwG,iBAIxBF,EAAKC,EAAIO,SAAS4C,EAAIzR,IAC1BsQ,QAAQoB,YAAcC,IAAPtD,GACfC,EAAII,IAAInG,KAAKkJ,EAAIzR,IACjBqO,EAAGoD,KAEP1J,EAAK+G,KAAOA,EACZ/G,EAAKwG,gBAAkB,CAACM,SAAU,GAAIH,IAAK,GAAIE,MAAO,GACtD7G,EAAK+F,QAAQ,CAAElK,KAAMV,EAAQI,cAAef,KAAK,SAAAkP,GAC7C1J,EAAKwC,SAAS,CAAEI,SAAU8G,EAAI/O,KAAKvB,IAAI,SAAAgK,GAAC,OAAIrG,EAAaD,OAAOsG,SAEpEpD,EAAK+F,QAAQ,CAAElK,KAAMV,EAAQhB,eAAgBK,KAAK,SAAAkP,GAC9C1J,EAAKwC,SAAS,CAAEP,UAAWyH,EAAI/O,SAlBpBqF,wEAoKV,IAAA0C,EAAA3G,KACG4C,EAAY5C,KAAKtE,MAAjBkH,QAER,OACIjH,EAAAC,EAAAC,cAACiS,EAAA,iBAAD,CAAkB5L,MAAOA,IACrBvG,EAAAC,EAAAC,cAAA,OAAK8G,UAAWC,EAAQmL,MACpBpS,EAAAC,EAAAC,cAACmS,EAAApS,EAAD,CACIqN,SAAS,WACTtG,UAAWC,EAAQqL,QACnBtS,EAAAC,EAAAC,cAACqS,EAAAtS,EAAD,CAAS+G,UAAWC,EAAQuL,SACxBxS,EAAAC,EAAAC,cAACuS,EAAAxS,EAAD,CAAY8M,UAAU,KAAK2F,QAAQ,KAAKtK,MAAM,UAAUuK,QAAM,EAAC3L,UAAWC,EAAQ2L,OAC9E5S,EAAAC,EAAAC,cAACJ,EAAD,CAAMQ,MAAO,CAAC8G,MAAO,MAAOyL,cAAe,SAAUnJ,YAAa,WADtE,eAKR1J,EAAAC,EAAAC,cAAA,QAAM8G,UAAWC,EAAQ6L,SACrB9S,EAAAC,EAAAC,cAAA,OAAK8G,UAAWC,EAAQ8L,eACxB/S,EAAAC,EAAAC,cAACwG,EAAAzG,EAAD,CAAM0G,WAAS,EAAEC,QAAS,IACtB5G,EAAAC,EAAAC,cAAC8S,EAAA/S,EAAD,MACAD,EAAAC,EAAAC,cAACwG,EAAAzG,EAAD,CAAM4G,MAAI,EAACoM,GAAI,EAAGnM,GAAI,IAClB9G,EAAAC,EAAAC,cAACgJ,EAAAjJ,EAAD,CAAaiT,WAAW,GACpBlT,EAAAC,EAAAC,cAACiT,EAAAlT,EAAD,KACID,EAAAC,EAAAC,cAACuS,EAAAxS,EAAD,CAAYyS,QAAQ,KAAK3F,UAAU,KAAKqG,cAAY,GAApD,iBAEIpT,EAAAC,EAAAC,cAACmT,EAAApT,EAAD,CACIK,MAAO,CAACgT,aAAc,SAAUC,WAAY,SAC5CjH,QAAS,kBAAMtB,EAAKwD,eAAcxO,EAAAC,EAAAC,cAACsT,EAAAvT,EAAD,QAE1CD,EAAAC,EAAAC,cAACuT,GAAD,CACIvI,SAAU7G,KAAKqG,MAAMQ,SACrBX,UAAWlG,KAAKqG,MAAMH,UACtBgC,gBAAiBlI,KAAKiK,cACtBrC,gBAAiB5H,KAAK+J,iBAE9BpO,EAAAC,EAAAC,cAACiT,EAAAlT,EAAD,KACID,EAAAC,EAAAC,cAACuS,EAAAxS,EAAD,CAAYyS,QAAQ,KAAK3F,UAAU,KAAKqG,cAAY,GAApD,cAGApT,EAAAC,EAAAC,cAAA,OAAKI,MAAO,CAACoT,UAAW,WACpB1T,EAAAC,EAAAC,cAACyT,EAAA,gBAAD,CACI7D,UAAWzL,KAAKqG,MAAMoF,UACtB8D,YAAY,gBACZ7D,QAAS1L,KAAKqG,MAAMqF,QACpB8D,UAAU,cACVC,cAAe,SAAAC,GAA4B,IAAzBjE,EAAyBiE,EAAzBjE,UAAWC,EAAcgE,EAAdhE,QACzB/E,EAAKF,SAAS,CAAEgF,YAAWC,aAE/BiE,aAAc3P,KAAKqG,MAAMsJ,aACzBC,cAAe,SAAAD,GAAY,OAAIhJ,EAAKF,SAAS,CAAEkJ,kBAC/CE,eAAgB,kBAAM,OAGlClU,EAAAC,EAAAC,cAAA,OAAK8G,UAAWC,EAAQkN,eACxBnU,EAAAC,EAAAC,cAACwG,EAAAzG,EAAD,CAAM0G,WAAS,EAACC,QAAS,IACrB5G,EAAAC,EAAAC,cAACwG,EAAAzG,EAAD,CAAM4G,MAAI,EAACoM,GAAI,EAAGnM,GAAI,IAClB9G,EAAAC,EAAAC,cAACiT,EAAAlT,EAAD,KACID,EAAAC,EAAAC,cAACkU,EAAAnU,EAAD,CAAQyS,QAAQ,YAAYtK,MAAM,UAAUkE,QAASjI,KAAKmN,MAA1D,UAGRxR,EAAAC,EAAAC,cAACwG,EAAAzG,EAAD,CAAM4G,MAAI,EAACoM,GAAI,EAAGnM,GAAI,IAClB9G,EAAAC,EAAAC,cAACiT,EAAAlT,EAAD,KACID,EAAAC,EAAAC,cAACkU,EAAAnU,EAAD,CAAQyS,QAAQ,YAAYtK,MAAM,UAAUkE,QAASjI,KAAKwL,SAA1D,gBAMpB7P,EAAAC,EAAAC,cAACwG,EAAAzG,EAAD,CAAM4G,MAAI,EAACoM,GAAI,EAAGnM,GAAI,IAClB9G,EAAAC,EAAAC,cAACuS,EAAAxS,EAAD,CAAYyS,QAAQ,KAAK3F,UAAU,KAAKqG,cAAY,GAApD,SAGApT,EAAAC,EAAAC,cAACmU,GAAD,CACI9M,iBAAkBlD,KAAKqG,MAAMnD,iBAC7BO,kBAAmBzD,KAAKqG,MAAM5C,gCAxP1CyB,IAAMC,WAqQflD,wBArSA,SAAAC,GAAK,MAAK,CACrB6L,KAAM,CACF5E,QAAS,OACTnG,OAAQ,SAEZiL,OAAQ,CACJgC,OAAQ/N,EAAM+N,OAAOC,OAAS,EAC9BC,WAAYjO,EAAMkO,YAAYC,OAAO,CAAC,QAAS,UAAW,CACtDC,OAAQpO,EAAMkO,YAAYE,OAAOC,MACjCvD,SAAU9K,EAAMkO,YAAYpD,SAASwD,iBAG7CjC,MAAO,CACHkC,SAAU,GAEdC,aAAc,CACVC,KAAM,YAEVjC,aAAcxM,EAAM0O,OAAOzC,QAC3BM,QAAS,CACLgC,SAAU,EACVI,QAA8B,EAArB3O,EAAMK,QAAQuO,KACvBC,SAAU,QAEdjB,aAAc,CACVb,aAAmC,EAArB/M,EAAMK,QAAQuO,MAEhCE,IAAK,CACD5O,OAAQF,EAAMK,QAAQuO,QAyQf7O,CAAmBwH,IC/TdwH,QACW,cAA7BC,OAAOC,SAASC,UAEe,UAA7BF,OAAOC,SAASC,UAEhBF,OAAOC,SAASC,SAASC,MACvB,2DCbNC,IAASC,OAAO5V,EAAAC,EAAAC,cAAC2V,GAAD,MAASC,SAASC,eAAe,SD4H3C,kBAAmBC,WACrBA,UAAUC,cAAcC,MAAMpT,KAAK,SAAAqT,GACjCA,EAAaC","file":"static/js/main.f0bd332c.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 */\nimport LRU from \"lru-cache\";\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).filter(([k, v]) => v).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=null, timeMin=null, timeMax=null, 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            timeMin,\n            timeMax,\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, options={maxCachedItems: 100, nDaysPerSlot: 10, largeQuery: 10}) {\n        this.calId = calId;\n        this.name = name;\n        this.token = getAuthToken();\n        this.syncToken = '';\n        this.cache = new LRU({\n            max: options.maxCachedItems,\n            dispose: (k, v) => this.onRemoveSlot(k, v)\n        });\n        this.eventMeta = {};\n        this.options = options;\n        this.divider = 8.64e7 * this.options.nDaysPerSlot;\n    }\n\n    dateToCacheKey(date) {\n        return Math.floor(date / this.divider);\n    }\n\n    dateRangeToCacheKeys(range) {\n        return {\n            start: this.dateToCacheKey(range.start),\n            end: this.dateToCacheKey(new Date(range.end.getTime() - 1))\n        };\n    }\n\n    getSlot(k) {\n        if (!this.cache.has(k))\n        {\n            let res = {};\n            this.cache.set(k, res);\n            return res;\n        }\n        else return this.cache.get(k);\n    }\n\n    onRemoveSlot(k, v) {\n        for (let id in v) {\n            console.assert(this.eventMeta[id]);\n            let keys = this.eventMeta[id].keys;\n            keys.delete(k);\n            if (keys.size === 0)\n                delete this.eventMeta[id];\n        }\n    }\n\n    slotStartDate(k) { return new Date(k * this.divider); }\n    slotEndDate(k) { return new Date((k + 1) * this.divider); }\n\n    addEvent(e, evict = false) {\n        //console.log('adding event', e);\n        if (this.eventMeta.hasOwnProperty(e.id))\n            this.removeEvent(e);\n        let r = this.dateRangeToCacheKeys(e);\n        let ks = r.start;\n        let ke = r.end;\n        let t = this.cache.length;\n        let keys = new Set();\n        for (let i = ks; i <= ke; i++)\n        {\n            keys.add(i);\n            if (!this.cache.has(i)) t++;\n        }\n        this.eventMeta[e.id] = {\n            keys,\n            summary: e.summary,\n        };\n        if (!evict && t > this.options.maxCachedItems) return;\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: this.slotEndDate(ks),\n                id: e.id };\n            this.getSlot(ke)[e.id] = {\n                start: this.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: this.slotStartDate(k),\n                    end: this.slotEndDate(k),\n                    id: e.id};\n        }\n    }\n\n    removeEvent(e) {\n        let keys = this.eventMeta[e.id].keys;\n        console.assert(keys);\n        keys.forEach(k => delete this.getSlot(k)[e.id]);\n        delete this.eventMeta[e.id];\n    }\n\n    getSlotEvents(k, start, end) {\n        let s = this.getSlot(k);\n        //console.log(s);\n        let results = [];\n        for (let id in s) {\n            if (!(s[id].start >= end || s[id].end <= start))\n            {\n                results.push({\n                    id,\n                    start: s[id].start < start ? start: s[id].start,\n                    end: s[id].end > end ? end: s[id].end,\n                    summary: this.eventMeta[id].summary\n                });\n            }\n        }\n        return results;\n    }\n\n    getCachedEvents(_r) {\n        let r = this.dateRangeToCacheKeys(_r);\n        let ks = r.start;\n        let ke = r.end;\n        let results = this.getSlotEvents(ks, _r.start, _r.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, _r.start, _r.end));\n        return results;\n    }\n\n    sync() {\n        return this.token.then(token => getEvents(this.calId, token, this.syncToken).then(r => {\n            let pms = r.results.map(e => e.start ? Promise.resolve(e) : getEvent(this.calId, e.id, token));\n            return Promise.all(pms).then(results => {\n                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                this.syncToken = r.nextSyncToken;\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        let r = this.dateRangeToCacheKeys({ start, end });\n        let query = {};\n        for (let k = r.start; k <= r.end; k++)\n            if (!this.cache.has(k))\n            {\n                if (!query.hasOwnProperty('start'))\n                    query.start = k;\n                query.end = k;\n            }\n        console.log(`start: ${start} end: ${end}`);\n        if (query.hasOwnProperty('start'))\n        {\n            console.assert(query.start <= query.end);\n            if (query.end - query.start + 1 > this.options.largeQuery) {\n                console.log(`encounter large query, use direct fetch`);\n                return this.token.then(token => getEvents(this.calId, token, null,\n                        start.toISOString(), end.toISOString()).then(r => {\n                    let results = [];\n                    r.results.forEach(e => {\n                        console.assert(e.start);\n                        e.start = new Date(e.start.dateTime);\n                        e.end = new Date(e.end.dateTime);\n                        results.push(e);\n                    });\n                    return results.filter(e => !(e.start >= end || e.end <= start)).map(e => {\n                        return {\n                            id: e.id,\n                            start: e.start < start ? start: e.start,\n                            end: e.end > end ? end: e.end,\n                            summary: e.summary,\n                        };\n                    });\n                }));\n            }\n\n            console.log(`fetching short event list`);\n            return this.token.then(token => getEvents(this.calId, token, null,\n                this.slotStartDate(query.start).toISOString(),\n                this.slotEndDate(query.end).toISOString()).then(r => {\n                    r.results.forEach(e => {\n                        if (e.status === 'confirmed')\n                        {\n                            console.assert(e.start);\n                            e.start = new Date(e.start.dateTime);\n                            e.end = new Date(e.end.dateTime);\n                            this.addEvent(e, true);\n                        }\n                    });\n                    if (this.syncToken === '')\n                        this.syncToken = r.nextSyncToken;\n                })).then(() => this.sync())\n                .then(() => this.getCachedEvents({ start, end }));\n        }\n        else\n        {\n            console.log(`cache hit`);\n            return this.sync().then(() => this.getCachedEvents({ start, end }));\n        }\n    }\n}\n","const _updatePatterns = \"updatePatterns\";\nconst _getPatterns = \"getPatterns\";\nconst _updateCalendars = \"updateCalendars\";\nconst _getCalendars = \"getCalendars\";\nconst _getCalEvents = \"getCalEvents\";\n\nexport const msgType = Object.freeze({\n    updatePatterns: Symbol(_updatePatterns),\n    getPatterns: Symbol(_getPatterns),\n    updateCalendars: Symbol(_updateCalendars),\n    getCalendars: Symbol(_getCalendars),\n    getCalEvents: Symbol(_getCalEvents),\n});\n\nfunction stringifyMsgType(mt) {\n    switch (mt) {\n        case msgType.updatePatterns: return _updatePatterns;\n        case msgType.getPatterns: return _getPatterns;\n        case msgType.updateCalendars: return _updateCalendars;\n        case msgType.getCalendars: return _getCalendars;\n        case msgType.getCalEvents: return _getCalEvents;\n    }\n}\n\nfunction parseMsgType(s) {\n    switch(s) {\n        case _updatePatterns: return msgType.updatePatterns;\n        case _getPatterns: return msgType.getPatterns;\n        case _updateCalendars: return msgType.updateCalendars;\n        case _getCalendars: return msgType.getCalendars;\n        case _getCalEvents: return msgType.getCalEvents;\n    }\n}\n\nexport class Msg {\n    constructor(id, type, data) {\n        this.id = id;\n        this.type = type;\n        this.data = data;\n    }\n    genResp(data) { return new Msg(this.id, this.type, data); }\n    deflate() {\n        return {\n            id: this.id,\n            type: stringifyMsgType(this.type),\n            data: this.data\n        }\n    }\n    static inflate = obj => new Msg(obj.id, parseMsgType(obj.type), obj.data);\n}\n","export class Pattern {\n    constructor(id, isRegex, value, label) {\n        this.id = id;\n        this.isRegex = isRegex;\n        this.value = value;\n        this.label = label;\n    }\n\n    get regex() { return new RegExp(this.isRegex ? this.value : `^${this.value}$`); }\n    get isEmpty() { return this.label === null; }\n    static emptyPattern = () => new Pattern(0, true, '', null);\n    static anyPattern = () => new Pattern('any', true, '.*', 'Any');\n    static revive = obj => new Pattern(obj.id, obj.isRegex, obj.value, obj.label);\n}\n\nexport class PatternEntry {\n    constructor(name, idx, calPattern, eventPattern) {\n        this.name = name;\n        this.idx = idx;\n        this.cal = calPattern;\n        this.event = eventPattern;\n    }\n\n    static defaultPatternEntry = (idx) => new PatternEntry('', idx, Pattern.emptyPattern(), Pattern.anyPattern());\n    static revive = obj => new PatternEntry(\n        obj.name, obj.idx,\n        Pattern.revive(obj.cal), Pattern.revive(obj.event));\n}\n","import React from 'react';\nimport PropTypes from 'prop-types';\nimport { withStyles } from '@material-ui/core/styles';\nimport Grid from '@material-ui/core/Grid';\nimport deepOrange from '@material-ui/core/colors/deepOrange';\nimport cyan from '@material-ui/core/colors/cyan';\nimport { PieChart, Pie, Cell, Tooltip } from 'recharts';\n\nconst styles = theme => ({\n    pieChart: {\n        margin: '0 auto',\n    }\n});\n\nfunction customizedLabel(props) {\n    const {cx, cy, x, y, fill, name} = props;\n    let anchor = \"middle\";\n    const EPS = 2;\n    let dx = 0;\n    let dy = 0;\n    if (x < cx - EPS) {\n        dx = -5;\n        anchor = \"end\"\n    } else if (x > cx + EPS) {\n        dx = 5;\n        anchor = \"start\";\n    }\n\n    if (y < cy - EPS) {\n        dy = -5;\n    } else if (y > cy + EPS) {\n        dy = 10;\n    }\n\n    return (<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.calendars) {\n        options[id] = new Pattern(id, false,\n            props.calendars[id].name,\n            props.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, calendars, patterns } = this.props;\n        const { rowsPerPage, page } = this.state;\n        const nDummy = rowsPerPage - Math.min(rowsPerPage, patterns.length - page * rowsPerPage);\n        let rows = patterns.slice(page * rowsPerPage, (page + 1) * rowsPerPage).map(p => (\n            <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                                    calendars={calendars}\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    calendars: PropTypes.object.isRequired,\n    onRemovePattern: PropTypes.func.isRequired,\n    onUpdatePattern: PropTypes.func.isRequired,\n};\n\nexport default withStyles(styles)(PatternTable);\n","/* global chrome */\nimport React from 'react';\nimport PropTypes from 'prop-types';\nimport 'typeface-roboto';\nimport 'react-dates/initialize';\nimport 'react-dates/lib/css/_datepicker.css';\nimport { DateRangePicker } from 'react-dates';\nimport { withStyles } from '@material-ui/core/styles';\nimport { MuiThemeProvider } from '@material-ui/core/styles';\nimport cyan from '@material-ui/core/colors/cyan';\nimport CssBaseline from '@material-ui/core/CssBaseline';\nimport AppBar from '@material-ui/core/AppBar';\nimport Toolbar from '@material-ui/core/Toolbar';\nimport Typography from '@material-ui/core/Typography';\nimport Button from '@material-ui/core/Button';\nimport FormControl from '@material-ui/core/FormControl';\nimport FormGroup from '@material-ui/core/FormGroup';\nimport Grid from '@material-ui/core/Grid';\nimport AddCircleIcon from '@material-ui/icons/AddCircle';\nimport IconButton from '@material-ui/core/IconButton';\nimport Logo from './Logo';\nimport * as gapi from './gapi';\nimport { msgType, Msg } from './msg';\nimport { Pattern, PatternEntry } from './pattern';\nimport PieChart from './Chart';\nimport PatternTable from './PatternTable';\nimport theme from './theme';\n\nconst default_chart_data = [\n    {name: 'Work', value: 10, color: cyan[300]},\n    {name: 'Wasted', value: 10, color: cyan[300]}];\n\nfunction filterPatterns(patterns, calName) {\n    return patterns.filter(p => {\n        return p.cal.regex.test(calName);\n    });\n}\n\nconst styles = theme => ({\n    root: {\n        display: 'flex',\n        height: '100vh',\n    },\n    appBar: {\n        zIndex: theme.zIndex.drawer + 1,\n        transition: theme.transitions.create(['width', 'margin'], {\n            easing: theme.transitions.easing.sharp,\n            duration: theme.transitions.duration.leavingScreen,\n        }),\n    },\n    title: {\n        flexGrow: 1,\n    },\n    sectionTitle: {\n        flex: '0 0 auto'\n    },\n    appBarSpacer: theme.mixins.toolbar,\n    content: {\n        flexGrow: 1,\n        padding: theme.spacing.unit * 3,\n        overflow: 'auto',\n    },\n    buttonSpacer: {\n        marginBottom: theme.spacing.unit * 4,\n    },\n    fab: {\n        margin: theme.spacing.unit,\n    },\n});\n\nclass Dashboard extends React.Component {\n    state = {\n        patterns: [],\n        calendars: [],\n        timeRange: null,\n        token: gapi.getAuthToken(),\n        patternGraphData: default_chart_data,\n        calendarGraphData: default_chart_data,\n        activePattern: null\n    };\n\n    constructor(props) {\n        super(props);\n        let port = chrome.runtime.connect({name: 'main'});\n        const getCallBack = rcb => this.requestCallback;\n        port.onMessage.addListener(function(msg) {\n            console.log(msg);\n            let rcb = getCallBack(msg.type);\n            let cb = rcb.inFlight[msg.id];\n            console.assert(cb !== undefined);\n            rcb.ids.push(msg.id);\n            cb(msg);\n        });\n        this.port = port;\n        this.requestCallback = {inFlight: {}, ids: [], maxId: 0};\n        this.sendMsg({ type: msgType.getPatterns }).then(msg => {\n            this.setState({ patterns: msg.data.map(p => PatternEntry.revive(p)) });\n        });\n        this.sendMsg({ type: msgType.getCalendars }).then(msg => {\n            this.setState({ calendars: msg.data });\n        });\n    }\n\n    updatePattern = (field, idx, value) => {\n        let patterns = this.state.patterns;\n        patterns[idx][field] = value;\n        this.setState({ patterns });\n        this.sendMsg({ type: msgType.updatePatterns, data: patterns });\n    };\n\n    removePattern = idx => {\n        let patterns = this.state.patterns;\n        patterns.splice(idx, 1);\n        for (let i = 0; i < patterns.length; i++)\n            patterns[i].idx = i;\n        this.setState({ patterns });\n        this.sendMsg({ type: msgType.updatePatterns, data: patterns });\n    };\n\n    newPattern = () => {\n        let patterns = [PatternEntry.defaultPatternEntry(0), ...this.state.patterns];\n        for (let i = 1; i < patterns.length; i++)\n            patterns[i].idx = i;\n        this.setState({ patterns });\n        this.sendMsg({ type: msgType.updatePatterns, data: patterns });\n    };\n\n    loadPatterns = patterns => {\n        this.setState({ patterns });\n        this.sendMsg({ type: msgType.updatePatterns, data: patterns });\n    };\n\n    loadCalendars = calendars => {\n        this.setState({ calendars });\n        this.sendMsg({ type: msgType.updateCalendars, data: calendars });\n    };\n\n    sendMsg = ({ type, data }) => {\n        let rcb = this.requestCallback;\n        let cb;\n        let pm = new Promise(resolve => { cb = resolve; });\n        let id;\n        if (rcb.ids.length > 0) {\n            id = rcb.ids.pop();\n        } else {\n            id = rcb.maxId++;\n        }\n        rcb.inFlight[id] = cb;\n        this.port.postMessage((new Msg(id, type, data)).deflate());\n        return pm;\n    }\n\n    getCalEvents = (id, start, end) => {\n        return this.sendMsg({ type: msgType.getCalEvents, data: { id,\n                    start: start.getTime(),\n                    end: end.getTime() } })\n            .then(({ data }) => data.map(e => {\n                return {\n                    id: e.id,\n                    start: new Date(e.start),\n                    end: new Date(e.end) }\n            }));\n    }\n\n    analyze = () => {\n        if (!(this.state.startDate && this.state.endDate)) {\n            alert(\"Please choose a valid time range.\");\n            return;\n        }\n        let start = this.state.startDate.startOf('day').toDate();\n        let end = this.state.endDate.startOf('day').toDate();\n        let event_pms = [];\n        let cals = this.state.calendars;\n        for (let id in cals)\n        {\n            let patterns = filterPatterns(this.state.patterns, cals[id].name);\n            if (patterns.length > 0)\n                event_pms.push(this.getCalEvents(id, start, end)\n                    .then(r => { return { id, events: r, patterns }; }));\n        }\n        Promise.all(event_pms).then(all_events => {\n            console.log(all_events);\n            let events = {};\n            let patterns = {};\n            let results = {}; // pattern idx => time\n            let cal_results = {}; // cal id => time\n            all_events.forEach(e => {\n                events[e.id] = e.events;\n                patterns[e.id] = e.patterns;\n            });\n            for (let i = 0; i < this.state.patterns.length; i++)\n                results[i] = 0;\n            for (let id in cals) {\n                if (!events[id]) continue;\n                events[id].forEach(event => {\n                    patterns[id].forEach(p => {\n                        if (!p.event.regex.test(event.summary)) return;\n                        if (!cal_results.hasOwnProperty(id)) {\n                            cal_results[id] = 0;\n                        }\n                        let duration = (event.end - event.start) / 60000;\n                        results[p.idx] += duration;\n                        cal_results[id] += duration;\n                    });\n                });\n            }\n            let patternGraphData = [];\n            let calendarGraphData = [];\n            for (let i = 0; i < this.state.patterns.length; i++) {\n                patternGraphData.push({ name: this.state.patterns[i].name, value: results[i] / 60.0 });\n            }\n            for (let id in cal_results) {\n                calendarGraphData.push({\n                    name: cals[id].name,\n                    value: (cal_results[id] / 60.0),\n                    color: cals[id].color.background});\n            }\n            console.log(patternGraphData, calendarGraphData);\n            this.setState({ patternGraphData, calendarGraphData });\n        });\n    };\n\n    load = () => {\n        let token = this.state.token;\n        let colors = token.then(gapi.getColors).then(color => {\n            return color.calendar;\n        });\n        let cals = token.then(gapi.getCalendars);\n        Promise.all([colors, cals]).then(([colors, items]) => {\n            var cals = {};\n            items.forEach(item => {\n                cals[item.id] = {\n                    name: item.summary,\n                    color: colors[item.colorId],\n                    //cal: new gapi.GCalendar(item.id, item.summary)\n                }});\n            this.loadCalendars(cals);\n            this.loadPatterns(items.map((item, idx) => {\n                return new PatternEntry(item.summary, idx,\n                    new Pattern(item.id, false, item.summary, item.summary),\n                    Pattern.anyPattern());\n            }));\n        });\n    };\n\n    render() {\n        const { classes } = this.props;\n\n        return (\n            <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                                            calendars={this.state.calendars}\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.load}>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":""}