<commit_before>/*! cal-heatmap v3.3.5 (Wed Oct 16 2013 23:56:36)
 *  ---------------------------------------------
 *  Cal-Heatmap is a javascript module to create calendar heatmap to visualize time series data
 *  https://github.com/kamisama/cal-heatmap
 *  Licensed under the MIT license
 *  Copyright 2013 <NAME>
 */
function mergeRecursive(t,e){"use strict";for(var n in e)try{t[n]=e[n].constructor===Object?mergeRecursive(t[n],e[n]):e[n]}catch(i){t[n]=e[n]}return t}function arrayEquals(t,e){"use strict";if(!e||!t)return!1;if(t.length!==e.length)return!1;for(var n=0;t.length>n;n++)if(t[n]instanceof Array&&e[n]instanceof Array){if(!arrayEquals(t[n],e[n]))return!1}else if(t[n]!==e[n])return!1;return!0}var CalHeatMap=function(){"use strict";function t(){i.verticalDomainLabel="top"===i.options.label.position||"bottom"===i.options.label.position,i.domainVerticalLabelHeight=null===i.options.label.height?Math.max(25,2*i.options.cellSize):i.options.label.height,i.domainHorizontalLabelWidth=0,""===i.options.domainLabelFormat&&null===i.options.label.height&&(i.domainVerticalLabelHeight=0),i.verticalDomainLabel||(i.domainVerticalLabelHeight=0,i.domainHorizontalLabelWidth=i.options.label.width),i.paint(),i.options.nextSelector!==!1&&d3.select(i.options.nextSelector).on("click."+i.options.itemNamespace,function(){return d3.event.preventDefault(),i.loadNextDomain(1)}),i.options.previousSelector!==!1&&d3.select(i.options.previousSelector).on("click."+i.options.itemNamespace,function(){return d3.event.preventDefault(),i.loadPreviousDomain(1)}),i.Legend.redraw(i.graphDim.width-i.options.domainGutter-i.options.cellPadding),i.afterLoad();var t=i.getDomainKeys();i.options.loadOnInit?i.getDatas(i.options.data,new Date(t[0]),i.getSubDomain(t[t.length-1]).pop(),function(){i.fill(),i.onComplete()}):i.onComplete(),i.checkIfMinDomainIsReached(t[0]),i.checkIfMaxDomainIsReached(i.getNextDomain().getTime())}function e(t,e){var n=i.options.cellSize*i._domainType[i.options.subDomain].column(t)+i.options.cellPadding*i._domainType[i.options.subDomain].column(t);return 2===arguments.length&&e===!0?n+=i.domainHorizontalLabelWidth+i.options.domainGutter+i.options.domainMargin[1]+i.options.domainMargin[3]:n}function n(t,e){var n=i.options.cellSize*i._domainType[i.options.subDomain].row(t)+i.options.cellPadding*i._domainType[i.options.subDomain].row(t);return 2===arguments.length&&e===!0&&(n+=i.options.domainGutter+i.domainVerticalLabelHeight+i.options.domainMargin[0]+i.options.domainMargin[2]),n}var i=this;this.allowedDataType=["json","csv","tsv","txt"],this.options={itemSelector:"#cal-heatmap",paintOnLoad:!0,range:12,cellSize:10,cellPadding:2,cellRadius:0,domainGutter:2,domainMargin:[0,0,0,0],domain:"hour",subDomain:"min",colLimit:null,rowLimit:null,weekStartOnMonday:!0,start:new Date,minDate:null,maxDate:null,data:"",dataType:this.allowedDataType[0],considerMissingDataAsZero:!1,loadOnInit:!0,verticalOrientation:!1,domainDynamicDimension:!0,label:{position:"bottom",align:"center",offset:{x:0,y:0},rotate:null,width:100,height:null},legend:[10,20,30,40],displayLegend:!0,legendCellSize:10,legendCellPadding:2,legendMargin:[0,0,0,0],legendVerticalPosition:"bottom",legendHorizontalPosition:"left",legendOrientation:"horizontal",legendColors:null,highlight:[],itemName:["item","items"],domainLabelFormat:null,subDomainTitleFormat:{empty:"{date}",filled:"{count} {name} {connector} {date}"},subDomainDateFormat:null,subDomainTextFormat:null,legendTitleFormat:{lower:"less than {min} {name}",inner:"between {down} and {up} {name}",upper:"more than {max} {name}"},animationDuration:500,nextSelector:!1,previousSelector:!1,itemNamespace:"cal-heatmap",tooltip:!1,onClick:null,afterLoad:null,afterLoadNextDomain:null,afterLoadPreviousDomain:null,onComplete:null,afterLoadData:function(t){return t},onMaxDomainReached:null,onMinDomainReached:null},this._domainType={min:{name:"minute",level:10,row:function(){return i.options.colLimit>0?Math.ceil(60/i.options.colLimit):i.options.rowLimit||10},column:function(){return i.options.rowLimit>0?Math.ceil(60/i.options.rowLimit):i.options.colLimit||6},position:{x:function(t){return Math.floor(t.getMinutes()/i._domainType.min.row(t))},y:function(t){return t.getMinutes()%i._domainType.min.row(t)}},format:{date:"%H:%M, %A %B %-e, %Y",legend:"",connector:"at"},extractUnit:function(t){return new Date(t.getFullYear(),t.getMonth(),t.getDate(),t.getHours(),t.getMinutes()).getTime()}},hour:{name:"hour",level:20,row:function(t){if(i.options.colLimit>0){var e=24;return"week"===i.options.domain?e=168:"month"===i.options.domain&&(e=24*i.getDayCountInMonth(t)),Math.ceil(e/i.options.colLimit)}return i.options.rowLimit||6},column:function(t){if(i.options.colLimit>0)return i.options.colLimit;switch(i.options.domain){case"day":return i.options.rowLimit>0?Math.ceil(24/i.options.rowLimit):4;case"week":return i.options.rowLimit>0?Math.ceil(168/i.options.rowLimit):28;case"month":return i.options.rowLimit>0?Math.ceil(744/i.options.rowLimit):4*(i.options.domainDynamicDimension?i.getEndOfMonth(t).getDate():31)}},position:{x:function(t){return"month"===i.options.domain?i.options.colLimit>0||i.options.rowLimit>0?Math.floor((t.getHours()+24*(t.getDate()-1))/i._domainType.hour.row(t)):Math.floor(t.getHours()/i._domainType.hour.row(t))+4*(t.getDate()-1):"week"===i.options.domain?i.options.colLimit>0||i.options.rowLimit>0?Math.floor((t.getHours()+24*i.getWeekDay(t))/i._domainType.hour.row(t)):Math.floor(t.getHours()/i._domainType.hour.row(t))+4*i.getWeekDay(t):Math.floor(t.getHours()/i._domainType.hour.row(t))},y:function(t){if(i.options.colLimit>0||i.options.rowLimit>0)switch(i.options.domain){case"month":return Math.floor((t.getHours()+24*(t.getDate()-1))%i._domainType.hour.row(t));case"week":return Math.floor((t.getHours()+24*i.getWeekDay(t))%i._domainType.hour.row(t))}return t.getHours()%i._domainType.hour.row(t)}},format:{date:"%Hh, %A %B %-e, %Y",legend:"%H:00",connector:"at"},extractUnit:function(t){return new Date(t.getFullYear(),t.getMonth(),t.getDate(),t.getHours()).getTime()}},day:{name:"day",level:30,row:function(t){if(i.options.colLimit>0){var e=0;switch(i.options.domain){case"year":e=i.getDayCountInYear(t);break;case"month":e=i.getDayCountInMonth(t);break;case"week":e=7}return Math.ceil(e/i.options.colLimit)}return i.options.rowLimit||7},column:function(t){if(i.options.colLimit>0)return i.options.colLimit;switch(t=new Date(t),i.options.domain){case"year":if(i.options.rowLimit>0){var e=i.options.domainDynamicDimension?i.getDayCountInYear(t):366;return Math.ceil(e/i.options.rowLimit)}return i.options.domainDynamicDimension?i.getWeekNumber(new Date(t.getFullYear(),11,31))-i.getWeekNumber(new Date(t.getFullYear(),0))+1:54;case"month":if(i.options.rowLimit>0){var n=i.options.domainDynamicDimension?new Date(t.getFullYear(),t.getMonth()+1,0).getDate():31;return Math.ceil(n/i.options.rowLimit)}return i.options.verticalOrientation?6:i.options.domainDynamicDimension?i.getWeekNumber(new Date(t.getFullYear(),t.getMonth()+1,0))-i.getWeekNumber(t)+1:6;case"week":return Math.ceil(7/i._domainType.day.row(t))}},position:{x:function(t){switch(i.options.domain){case"week":return Math.floor(i.getWeekDay(t)/i._domainType.day.row(t));case"month":return i.options.colLimit>0||i.options.rowLimit>0?Math.floor((t.getDate()-1)/i._domainType.day.row(t)):i.getWeekNumber(t)-i.getWeekNumber(new Date(t.getFullYear(),t.getMonth()));case"year":return i.options.colLimit>0||i.options.rowLimit>0?Math.floor((i.getDayOfYear(t)-1)/i._domainType.day.row(t)):i.getWeekNumber(t)}},y:function(t){if(i.options.colLimit>0||i.options.rowLimit>0)switch(i.options.domain){case"year":return Math.floor((i.getDayOfYear(t)-1)%i._domainType.day.row(t));case"week":return Math.floor(i.getWeekDay(t)%i._domainType.day.row(t));case"month":return Math.floor((t.getDate()-1)%i._domainType.day.row(t))}return i.getWeekDay(t)%i._domainType.day.row(t)}},format:{date:"%A %B %-e, %Y",legend:"%e %b",connector:"on"},extractUnit:function(t){return new Date(t.getFullYear(),t.getMonth(),t.getDate()).getTime()}},week:{name:"week",level:40,row:function(){return i.options.colLimit>0?Math.ceil(54/i.options.colLimit):i.options.rowLimit||1},column:function(t){if(i.options.colLimit>0)return i.options.colLimit;switch(t=new Date(t),i.options.domain){case"year":return 54;case"month":return i.getWeekNumber(new Date(t.getFullYear(),t.getMonth()+1,0))-i.getWeekNumber(t);default:return 1}},position:{x:function(t){switch(i.options.domain){case"year":return i.options.colLimit>0||i.options.rowLimit>0?Math.floor(i.getWeekNumber(t)/i._domainType.week.row(t)):i.getWeekNumber(t);case"month":var e=i.getMonthWeekNumber(t);return i.options.colLimit>0||i.options.rowLimit>0?Math.floor((e-1)/i._domainType.week.row(t)):e}},y:function(t){return i.getWeekNumber(t)%i._domainType.week.row(t)}},format:{date:"%B Week #%W",legend:"%B Week #%W",connector:"on"},extractUnit:function(t){var e=new Date(t.getFullYear(),t.getMonth(),t.getDate()),n=e.getDay()-1;return 0>n&&(n=6),e.setDate(e.getDate()-n),e.getTime()}},month:{name:"month",level:50,row:function(){return i.options.colLimit>0?Math.ceil(12/i.options.colLimit):i.options.rowLimit||1},column:function(){return i.options.rowLimit>0?Math.ceil(12/i.options.rowLimit):i.options.colLimit||12},position:{x:function(t){return Math.floor(t.getMonth()/i._domainType.month.row(t))},y:function(t){return t.getMonth()%i._domainType.month.row(t)}},format:{date:"%B %Y",legend:"%B",connector:"on"},extractUnit:function(t){return new Date(t.getFullYear(),t.getMonth()).getTime()}},year:{name:"year",level:60,row:function(){return i.options.rowLimit||1},column:function(){return i.options.colLimit||1},position:{x:function(){return 1},y:function(){return 1}},format:{date:"%Y",legend:"%Y",connector:"on"},extractUnit:function(t){return new Date(t.getFullYear()).getTime()}}};for(var o in this._domainType)this._domainType.hasOwnProperty(o)&&(this._domainType["x_"+o]={},this._domainType["x_"+o].name="x_"+o,this._domainType["x_"+o].level=this._domainType[o].level,this._domainType["x_"+o].row=this._domainType[o].column,this._domainType["x_"+o].column=this._domainType[o].row,this._domainType["x_"+o].position={},this._domainType["x_"+o].position.x=this._domainType[o].position.y,this._domainType["x_"+o].position.y=this._domainType[o].position.x,this._domainType["x_"+o].format=this._domainType[o].format,this._domainType["x_"+o].extractUnit=this._domainType[o].extractUnit);this._domainType.x_day.row=function(t){switch(t=new Date(t),i.options.domain){case"year":return i.options.domainDynamicDimension?i.getWeekNumber(new Date(t.getFullYear(),11,31))-i.getWeekNumber(new Date(t.getFullYear(),0))+1:54;case"month":return i.options.verticalOrientation?i.options.domainDynamicDimension?i.getWeekNumber(new Date(t.getFullYear(),t.getMonth()+1,0))-i.getWeekNumber(t)+1:6:6;case"week":return 1}},this.lastInsertedSvg=null,this._completed=!1,this._domains=d3.map(),this.graphDim={width:0,height:0},this.legendDim={width:0,height:0},this.NAVIGATE_LEFT=1,this.NAVIGATE_RIGHT=2,this.RESET_ALL_ON_UPDATE=0,this.RESET_SINGLE_ON_UPDATE=1,this.APPEND_ON_UPDATE=2,this.DEFAULT_LEGEND_MARGIN=10,this.root=null,this.tooltip=null,this._maxDomainReached=!1,this._minDomainReached=!1,this.domainPosition=new DomainPosition,this.Legend=null,this.legendScale=null,this._init=function(){return i.getDomain(i.options.start).map(function(t){return t.getTime()}).map(function(t){i._domains.set(t,i.getSubDomain(t).map(function(t){return{t:i._domainType[i.options.subDomain].extractUnit(t),v:null}}))}),i.root=d3.select(i.options.itemSelector).append("svg").attr("class","cal-heatmap-container"),i.tooltip=d3.select(i.options.itemSelector).attr("style",d3.select(i.options.itemSelector).attr("style")+"position:relative;").append("div").attr("class","ch-tooltip"),i.root.attr("x",0).attr("y",0).append("svg").attr("class","graph"),i.Legend=new Legend(i),i.options.paintOnLoad&&t(),!0},this.paint=function(t){function o(e,n,o,a){var r=0;switch(t){case!1:return r=n[o],n[o]+=a,i.domainPosition.setPosition(e,r),r;case i.NAVIGATE_RIGHT:return i.domainPosition.setPosition(e,n[o]),l=a,u=i.domainPosition.getPositionFromIndex(1),i.domainPosition.shiftRightBy(u),n[o];case i.NAVIGATE_LEFT:return r=-a,l=-r,u=n[o]-i.domainPosition.getLast(),i.domainPosition.setPosition(e,r),i.domainPosition.shiftLeftBy(l),r}}function a(t){switch(r.label.rotate){case"right":t.attr("transform",function(t){var n="rotate(90), ";switch(r.label.position){case"right":n+="translate(-"+e(t)+" , -"+e(t)+")";break;case"left":n+="translate(0, -"+i.domainHorizontalLabelWidth+")"}return n});break;case"left":t.attr("transform",function(t){var n="rotate(270), ";switch(r.label.position){case"right":n+="translate(-"+(e(t)+i.domainHorizontalLabelWidth)+" , "+e(t)+")";break;case"left":n+="translate(-"+i.domainHorizontalLabelWidth+" , "+i.domainHorizontalLabelWidth+")"}return n})}}var r=i.options;0===arguments.length&&(t=!1);var s=i.root.select(".graph").selectAll(".graph-domain").data(function(){var e=i.getDomainKeys();return t===i.NAVIGATE_LEFT?e.reverse():e},function(t){return t}),l=0,u=0,c=s.enter().append("svg").attr("width",function(t){return e(t,!0)}).attr("height",function(t){return n(t,!0)}).attr("x",function(t){return r.verticalOrientation?(i.graphDim.width=e(t,!0),0):o(t,i.graphDim,"width",e(t,!0))}).attr("y",function(t){return r.verticalOrientation?o(t,i.graphDim,"height",n(t,!0)):(i.graphDim.height=n(t,!0),0)}).attr("class",function(t){var e="graph-domain",n=new Date(t);switch(r.domain){case"hour":e+=" h_"+n.getHours();case"day":e+=" d_"+n.getDate()+" dy_"+n.getDay();case"week":e+=" w_"+i.getWeekNumber(n);case"month":e+=" m_"+(n.getMonth()+1);case"year":e+=" y_"+n.getFullYear()}return e});i.lastInsertedSvg=c,c.append("rect").attr("width",function(t){return e(t,!0)-r.domainGutter-r.cellPadding}).attr("height",function(t){return n(t,!0)-r.domainGutter-r.cellPadding}).attr("class","domain-background");var m=c.append("svg").attr("x",function(){return"left"===r.label.position?i.domainHorizontalLabelWidth+r.domainMargin[3]:r.domainMargin[3]}).attr("y",function(){return"top"===r.label.position?i.domainVerticalLabelHeight+r.domainMargin[0]:r.domainMargin[0]}).attr("class","graph-subdomain-group"),h=m.selectAll("g").data(function(t){return i._domains.get(t)}).enter().append("g");h.append("rect").attr("class",function(t){return"graph-rect"+i.getHighlightClassName(t.t)+(null!==r.onClick?" hover_cursor":"")}).attr("width",r.cellSize).attr("height",r.cellSize).attr("x",function(t){return i.positionSubDomainX(t.t)}).attr("y",function(t){return i.positionSubDomainY(t.t)}).on("click",function(t){return null!==r.onClick?i.onClick(new Date(t.t),t.v):void 0}).call(function(t){r.cellRadius>0&&t.attr("rx",r.cellRadius).attr("ry",r.cellRadius),null!==i.legendScale&&null!==r.legendColors&&r.legendColors.hasOwnProperty("base")&&t.attr("fill",r.legendColors.base),r.tooltip&&(t.on("mouseover",function(t){var e=this.parentNode.parentNode.parentNode;i.tooltip.html(i.getSubDomainTitle(t)).attr("style","display: block;"),i.tooltip.attr("style","display: block; left: "+(i.positionSubDomainX(t.t)-i.tooltip[0][0].offsetWidth/2+r.cellSize/2+parseInt(e.getAttribute("x"),10))+"px; "+"top: "+(i.positionSubDomainY(t.t)-i.tooltip[0][0].offsetHeight-r.cellSize/2+parseInt(e.getAttribute("y"),10))+"px;")}),t.on("mouseout",function(){i.tooltip.attr("style","display:none").html("")}))}),r.tooltip||h.append("title").text(function(t){return i.formatDate(new Date(t.t),r.subDomainDateFormat)}),""!==r.domainLabelFormat&&c.append("text").attr("class","graph-label").attr("y",function(t){var e=r.domainMargin[0];switch(r.label.position){case"top":e+=i.domainVerticalLabelHeight/2;break;case"bottom":e+=n(t)+i.domainVerticalLabelHeight/2}return e+r.label.offset.y*("right"===r.label.rotate&&"right"===r.label.position||"left"===r.label.rotate&&"left"===r.label.position?-1:1)}).attr("x",function(t){var n=r.domainMargin[3];switch(r.label.position){case"right":n+=e(t);break;case"bottom":case"top":n+=e(t)/2}return"right"===r.label.align?n+i.domainHorizontalLabelWidth-r.label.offset.x*("right"===r.label.rotate?-1:1):n+r.label.offset.x}).attr("text-anchor",function(){switch(r.label.align){case"start":case"left":return"start";case"end":case"right":return"end";default:return"middle"}}).attr("dominant-baseline",function(){return i.verticalDomainLabel?"middle":"top"}).text(function(t){return i.formatDate(new Date(t),r.domainLabelFormat)}).call(a),null!==r.subDomainTextFormat&&h.append("text").attr("class",function(t){return"subdomain-text"+i.getHighlightClassName(t.t)}).attr("x",function(t){return i.positionSubDomainX(t.t)+r.cellSize/2}).attr("y",function(t){return i.positionSubDomainY(t.t)+r.cellSize/2}).attr("text-anchor","middle").attr("dominant-baseline","central").text(function(t){return i.formatDate(new Date(t.t),r.subDomainTextFormat)}),t!==!1&&s.transition().duration(r.animationDuration).attr("x",function(t){return r.verticalOrientation?0:i.domainPosition.getPosition(t)}).attr("y",function(t){return r.verticalOrientation?i.domainPosition.getPosition(t):0});var g=i.graphDim.width,d=i.graphDim.height;r.verticalOrientation?i.graphDim.height+=l-u:i.graphDim.width+=l-u,s.exit().transition().duration(r.animationDuration).attr("x",function(n){if(r.verticalOrientation)return 0;switch(t){case i.NAVIGATE_LEFT:return Math.min(i.graphDim.width,g);case i.NAVIGATE_RIGHT:return-e(n,!0)}}).attr("y",function(e){if(!r.verticalOrientation)return 0;switch(t){case i.NAVIGATE_LEFT:return Math.min(i.graphDim.height,d);case i.NAVIGATE_RIGHT:return-n(e,!0)}}).remove(),i.resize()}};CalHeatMap.prototype={init:function(t){"use strict";function e(t,e,n){if((e&&t===!1||t instanceof Element||"string"==typeof t)&&""!==t)return!0;throw Error("The "+n+" is not valid")}function n(t){switch(t){case"year":return"month";case"month":return"day";case"week":return"day";case"day":return"hour";default:return"min"}}function i(){if(!c._domainType.hasOwnProperty(m.domain)||"min"===m.domain||"x_"===m.domain.substring(0,2))throw Error("The domain '"+m.domain+"' is not valid");if(!c._domainType.hasOwnProperty(m.subDomain)||"year"===m.subDomain)throw Error("The subDomain '"+m.subDomain+"' is not valid");if(c._domainType[m.domain].level<=c._domainType[m.subDomain].level)throw Error("'"+m.subDomain+"' is not a valid subDomain to '"+m.domain+"'");return!0}function o(){if(!t.hasOwnProperty("label")||t.hasOwnProperty("label")&&!t.label.hasOwnProperty("align")){switch(m.label.position){case"left":m.label.align="right";break;case"right":m.label.align="left";break;default:m.label.align="center"}"left"===m.label.rotate?m.label.align="right":"right"===m.label.rotate&&(m.label.align="left")}(!t.hasOwnProperty("label")||t.hasOwnProperty("label")&&!t.label.hasOwnProperty("offset"))&&("left"===m.label.position||"right"===m.label.position)&&(m.label.offset={x:10,y:15})}function a(){switch(m.legendVerticalPosition){case"top":m.legendMargin[2]=c.DEFAULT_LEGEND_MARGIN;break;case"bottom":m.legendMargin[0]=c.DEFAULT_LEGEND_MARGIN;break;case"middle":case"center":m.legendMargin["right"===m.legendHorizontalPosition?3:1]=c.DEFAULT_LEGEND_MARGIN}}function r(t){switch("number"==typeof t&&(t=[t]),Array.isArray(t)||(console.log("Margin only takes an integer or an array of integers"),t=[0]),t.length){case 0:return[0,0,0,0];case 1:return[t[0],t[0],t[0],t[0]];case 2:return[t[0],t[1],t[0],t[1]];case 3:return[t[0],t[1],t[2],t[1]];case 4:return t;default:return t.slice(0,4)}}function s(t){return"string"==typeof t?[t,t+(""!==t?"s":"")]:Array.isArray(t)?1===t.length?[t[0],t[0]+"s"]:t.length>2?t.slice(0,2):t:["item","items"]}function l(t){return t>0?t:null}function u(t){return t>0&&m.colLimit>0?(console.log("colLimit and rowLimit are mutually exclusive, rowLimit will be ignored"),null):t>0?t:null}var c=this;c.options=mergeRecursive(c.options,t);var m=c.options;if(i(),e(m.itemSelector,!1,"itemSelector"),0>c.allowedDataType.indexOf(m.dataType))throw Error("The data type '"+m.dataType+"' is not valid data type");if(null===d3.select(m.itemSelector)[0][0])throw Error("The node '"+m.itemSelector+"' specified in itemSelector does not exists");try{e(m.nextSelector,!0,"nextSelector"),e(m.previousSelector,!0,"previousSelector")}catch(h){return console.log(h.message),!1}t.hasOwnProperty("subDomain")||(this.options.subDomain=n(t.domain)),("string"!=typeof m.itemNamespace||""===m.itemNamespace)&&(console.log("itemNamespace can not be empty, falling back to cal-heatmap"),m.itemNamespace="cal-heatmap");var g=["data","onComplete","onClick","afterLoad","afterLoadData","afterLoadPreviousDomain","afterLoadNextDomain"];for(var d in g)t.hasOwnProperty(g[d])&&(m[g[d]]=t[g[d]]);return m.subDomainDateFormat="string"==typeof m.subDomainDateFormat||"function"==typeof m.subDomainDateFormat?m.subDomainDateFormat:this._domainType[m.subDomain].format.date,m.domainLabelFormat="string"==typeof m.domainLabelFormat||"function"==typeof m.domainLabelFormat?m.domainLabelFormat:this._domainType[m.domain].format.legend,m.subDomainTextFormat="string"==typeof m.subDomainTextFormat&&""!==m.subDomainTextFormat||"function"==typeof m.subDomainTextFormat?m.subDomainTextFormat:null,m.domainMargin=r(m.domainMargin),m.legendMargin=r(m.legendMargin),m.highlight=c.expandDateSetting(m.highlight),m.itemName=s(m.itemName),m.colLimit=l(m.colLimit),m.rowLimit=u(m.rowLimit),t.hasOwnProperty("legendMargin")||a(),o(),this._init()},expandDateSetting:function(t){"use strict";return Array.isArray(t)||(t=[t]),t.map(function(t){return"now"===t?new Date:t instanceof Date?t:!1}).filter(function(t){return t!==!1})},fill:function(t){"use strict";function e(t){return null===n.legendScale?!1:(t.attr("fill",function(t){return 0===t.v&&null!==i.legendColors&&i.legendColors.hasOwnProperty("empty")?i.legendColors.empty:0>t.v&&i.legend[0]>0&&null!==i.legendColors&&i.legendColors.hasOwnProperty("overflow")?i.legendColors.overflow:n.legendScale(Math.min(t.v,i.legend[i.legend.length-2]))}),void 0)}var n=this,i=n.options;0===arguments.length&&(t=n.root.selectAll(".graph-domain"));var o=t.selectAll("svg").selectAll("g").data(function(t){return n._domains.get(t)});o.transition().duration(i.animationDuration).select("rect").attr("class",function(t){var e=n.getHighlightClassName(t.t);return null===n.legendScale&&(e+=" graph-rect"),null!==t.v?e+=" "+n.Legend.getClass(t.v,null===n.legendScale):i.considerMissingDataAsZero&&(e+=" "+n.Legend.getClass(0,null===n.legendScale)),null!==i.onClick&&(e+=" hover_cursor"),e}).call(e),o.transition().duration(i.animationDuration).select("title").text(function(t){return n.getSubDomainTitle(t)})},triggerEvent:function(t,e,n){"use strict";return 3===arguments.length&&n||null===this.options[t]?!0:"function"==typeof this.options[t]?("function"==typeof e&&(e=e()),this.options[t].apply(this,e)):(console.log("Provided callback for "+t+" is not a function."),!1)},onClick:function(t,e){"use strict";return this.triggerEvent("onClick",[t,e])},afterLoad:function(){"use strict";return this.triggerEvent("afterLoad")},onComplete:function(){"use strict";var t=this.triggerEvent("onComplete",[],this._completed);return this._completed=!0,t},afterLoadPreviousDomain:function(t){"use strict";var e=this;return this.triggerEvent("afterLoadPreviousDomain",function(){var n=e.getSubDomain(t);return[n.shift(),n.pop()]})},afterLoadNextDomain:function(t){"use strict";var e=this;return this.triggerEvent("afterLoadNextDomain",function(){var n=e.getSubDomain(t);return[n.shift(),n.pop()]})},onMinDomainReached:function(t){"use strict";return this._minDomainReached=t,this.triggerEvent("onMinDomainReached",[t])},onMaxDomainReached:function(t){"use strict";return this._maxDomainReached=t,this.triggerEvent("onMaxDomainReached",[t])},checkIfMinDomainIsReached:function(t,e){"use strict";this.minDomainIsReached(t)&&this.onMinDomainReached(!0),2===arguments.length&&this._maxDomainReached&&!this.maxDomainIsReached(e)&&this.onMaxDomainReached(!1)},checkIfMaxDomainIsReached:function(t,e){"use strict";this.maxDomainIsReached(t)&&this.onMaxDomainReached(!0),2===arguments.length&&this._minDomainReached&&!this.minDomainIsReached(e)&&this.onMinDomainReached(!1)},formatNumber:d3.format(",g"),formatDate:function(t,e){"use strict";if(2>arguments.length&&(e="title"),"function"==typeof e)return e(t);var n=d3.time.format(e);return n(t)},getSubDomainTitle:function(t){"use strict";if(null!==t.v||this.options.considerMissingDataAsZero){var e=t.v;return null===e&&this.options.considerMissingDataAsZero&&(e=0),this.options.subDomainTitleFormat.filled.format({count:this.formatNumber(e),name:this.options.itemName[1!==e?1:0],connector:this._domainType[this.options.subDomain].format.connector,date:this.formatDate(new Date(t.t),this.options.subDomainDateFormat)})}return this.options.subDomainTitleFormat.empty.format({date:this.formatDate(new Date(t.t),this.options.subDomainDateFormat)})},loadNextDomain:function(t){"use strict";if(this._maxDomainReached||0===t)return!1;var e=this.loadNewDomains(this.NAVIGATE_RIGHT,this.getDomain(this.getNextDomain(),t));return this.afterLoadNextDomain(e.end),this.checkIfMaxDomainIsReached(this.getNextDomain().getTime(),e.start),!0},loadPreviousDomain:function(t){"use strict";if(this._minDomainReached||0===t)return!1;var e=this.loadNewDomains(this.NAVIGATE_LEFT,this.getDomain(this.getDomainKeys()[0],-t).reverse());return this.afterLoadPreviousDomain(e.start),this.checkIfMinDomainIsReached(e.start,e.end),!0},loadNewDomains:function(t,e){"use strict";function n(t){return{t:i._domainType[i.options.subDomain].extractUnit(t),v:null}}for(var i=this,o=t===this.NAVIGATE_LEFT,a=-1,r=e.length,s=this.getDomainKeys();r>++a;){if(o&&this.minDomainIsReached(e[a])){e=e.slice(0,a+1);break}if(!o&&this.maxDomainIsReached(e[a])){e=e.slice(0,a);break}}for(e=e.slice(-this.options.range),a=0,r=e.length;r>a;a++)this._domains.set(e[a].getTime(),this.getSubDomain(e[a]).map(n)),this._domains.remove(o?s.pop():s.shift());return s=this.getDomainKeys(),o&&(e=e.reverse()),this.paint(t),this.getDatas(this.options.data,e[0],this.getSubDomain(e[e.length-1]).pop(),function(){i.fill(i.lastInsertedSvg)}),{start:e[o?0:1],end:s[s.length-1]}},maxDomainIsReached:function(t){"use strict";return null!==this.options.maxDate&&t>this.options.maxDate.getTime()},minDomainIsReached:function(t){"use strict";return null!==this.options.minDate&&this.options.minDate.getTime()>=t},getDomainKeys:function(){"use strict";return this._domains.keys().map(function(t){return parseInt(t,10)}).sort(function(t,e){return t-e})},positionSubDomainX:function(t){"use strict";var e=this._domainType[this.options.subDomain].position.x(new Date(t));return e*this.options.cellSize+e*this.options.cellPadding},positionSubDomainY:function(t){"use strict";var e=this._domainType[this.options.subDomain].position.y(new Date(t));return e*this.options.cellSize+e*this.options.cellPadding},getHighlightClassName:function(t){"use strict";if(t=new Date(t),this.options.highlight.length>0)for(var e in this.options.highlight)if(this.options.highlight[e]instanceof Date&&this.dateIsEqual(this.options.highlight[e],t))return" highlight"+(this.isNow(this.options.highlight[e])?" now":"");return""},isNow:function(t){"use strict";return this.dateIsEqual(t,new Date)},dateIsEqual:function(t,e){"use strict";switch(this.options.subDomain){case"x_min":case"min":return t.getFullYear()===e.getFullYear()&&t.getMonth()===e.getMonth()&&t.getDate()===e.getDate()&&t.getHours()===e.getHours()&&t.getMinutes()===e.getMinutes();case"x_hour":case"hour":return t.getFullYear()===e.getFullYear()&&t.getMonth()===e.getMonth()&&t.getDate()===e.getDate()&&t.getHours()===e.getHours();case"x_day":case"day":return t.getFullYear()===e.getFullYear()&&t.getMonth()===e.getMonth()&&t.getDate()===e.getDate();case"x_week":case"week":case"x_month":case"month":return t.getFullYear()===e.getFullYear()&&t.getMonth()===e.getMonth();default:return!1}},getDayOfYear:d3.time.format("%j"),getWeekNumber:function(t){"use strict";var e=this.options.weekStartOnMonday===!0?d3.time.format("%W"):d3.time.format("%U");return e(t)},getMonthWeekNumber:function(t){"use strict";"number"==typeof t&&(t=new Date(t));var e=this.getWeekNumber(new Date(t.getFullYear(),t.getMonth()));return this.getWeekNumber(t)-e-1},getWeekNumberInYear:function(t){"use strict";"number"==typeof t&&(t=new Date(t))},getDayCountInMonth:function(t){"use strict";return this.getEndOfMonth(t).getDate()},getDayCountInYear:function(t){"use strict";return"number"==typeof t&&(t=new Date(t)),0===t.getFullYear()%400?366:365},getWeekDay:function(t){"use strict";return this.options.weekStartOnMonday===!1?t.getDay():0===t.getDay()?6:t.getDay()-1},getEndOfMonth:function(t){"use strict";return"number"==typeof t&&(t=new Date(t)),new Date(t.getFullYear(),t.getMonth()+1,0)},jumpDate:function(t,e,n){"use strict";var i=new Date(t);switch(n){case"hour":i.setHours(i.getHours()+e);break;case"day":i.setHours(i.getHours()+24*e);break;case"week":i.setHours(i.getHours()+7*24*e);break;case"month":i.setMonth(i.getMonth()+e);break;case"year":i.setFullYear(i.getFullYear()+e)}return new Date(i)},getMinuteDomain:function(t,e){"use strict";var n=new Date(t.getFullYear(),t.getMonth(),t.getDate(),t.getHours()),i=null;return i=e instanceof Date?new Date(e.getFullYear(),e.getMonth(),e.getDate(),e.getHours()):new Date(n.getTime()+6e4*e),d3.time.minutes(Math.min(n,i),Math.max(n,i))},getHourDomain:function(t,e){"use strict";var n=new Date(t.getFullYear(),t.getMonth(),t.getDate(),t.getHours()),i=null;return i=e instanceof Date?new Date(e.getFullYear(),e.getMonth(),e.getDate(),e.getHours()):new Date(n.getTime()+36e5*e),d3.time.hours(Math.min(n,i),Math.max(n,i))},getDayDomain:function(t,e){"use strict";var n=new Date(t.getFullYear(),t.getMonth(),t.getDate()),i=null;return e instanceof Date?i=new Date(e.getFullYear(),e.getMonth(),e.getDate()):(i=new Date(n),i=new Date(i.setDate(i.getDate()+parseInt(e,10)))),d3.time.days(Math.min(n,i),Math.max(n,i))},getWeekDomain:function(t,e){"use strict";var n;this.options.weekStartOnMonday===!1?n=new Date(t.getFullYear(),t.getMonth(),t.getDate()-t.getDay()):1===t.getDay()?n=new Date(t.getFullYear(),t.getMonth(),t.getDate()):0===t.getDay()?(n=new Date(t.getFullYear(),t.getMonth(),t.getDate()),n.setDate(n.getDate()-6)):n=new Date(t.getFullYear(),t.getMonth(),t.getDate()-t.getDay()+1);var i=new Date(n),o=e;return"object"!=typeof e&&(o=new Date(i.setDate(i.getDate()+7*e))),this.options.weekStartOnMonday===!0?d3.time.mondays(Math.min(n,o),Math.max(n,o)):d3.time.sundays(Math.min(n,o),Math.max(n,o))},getMonthDomain:function(t,e){"use strict";var n=new Date(t.getFullYear(),t.getMonth()),i=null;return e instanceof Date?i=new Date(e.getFullYear(),e.getMonth()):(i=new Date(n),i=i.setMonth(i.getMonth()+e)),d3.time.months(Math.min(n,i),Math.max(n,i))},getYearDomain:function(t,e){"use strict";var n=new Date(t.getFullYear(),0),i=null;return i=e instanceof Date?new Date(e.getFullYear(),0):new Date(t.getFullYear()+e,0),d3.time.years(Math.min(n,i),Math.max(n,i))},getDomain:function(t,e){"use strict";switch("number"==typeof t&&(t=new Date(t)),2>arguments.length&&(e=this.options.range),this.options.domain){case"hour":return this.getHourDomain(t,e);case"day":return this.getDayDomain(t,e);case"week":return this.getWeekDomain(t,e);case"month":return this.getMonthDomain(t,e);case"year":return this.getYearDomain(t,e)}},getSubDomain:function(t){"use strict";"number"==typeof t&&(t=new Date(t));var e=this,n=function(t,n){switch(n){case"year":return e.getDayCountInYear(t);case"month":return e.getDayCountInMonth(t);case"week":return 7}},i=function(t,e){switch(e){case"hour":return 60;case"day":return 1440;case"week":return 10080}},o=function(t,n){switch(n){case"day":return 24;case"week":return 168;case"month":return 24*e.getDayCountInMonth(t)}},a=function(t,n){if("month"===n){var i=new Date(t.getFullYear(),t.getMonth()+1,0),o=e.getWeekNumber(i),a=e.getWeekNumber(new Date(t.getFullYear(),t.getMonth()));return a>o&&(a=0,o++),o-a+1}return"year"===n?e.getWeekNumber(new Date(t.getFullYear(),11,31)):void 0};switch(this.options.subDomain){case"x_min":case"min":return this.getMinuteDomain(t,i(t,this.options.domain));case"x_hour":case"hour":return this.getHourDomain(t,o(t,this.options.domain));case"x_day":case"day":return this.getDayDomain(t,n(t,this.options.domain));case"x_week":case"week":return this.getWeekDomain(t,a(t,this.options.domain));
case"x_month":case"month":return this.getMonthDomain(t,12)}},getNextDomain:function(t){"use strict";return 0===arguments.length&&(t=1),this.getDomain(this.jumpDate(this.getDomainKeys().pop(),t,this.options.domain),1)[0]},getPreviousDomain:function(t){"use strict";return 0===arguments.length&&(t=1),this.getDomain(this.jumpDate(this.getDomainKeys().shift(),-t,this.options.domain),1)[0]},getDatas:function(t,e,n,i,o,a){"use strict";var r=this;5>arguments.length&&(o=!0),6>arguments.length&&(a=this.APPEND_ON_UPDATE);var s=function(t){o!==!1?"function"==typeof o?t=o(t):"function"==typeof r.options.afterLoadData?t=r.options.afterLoadData(t):console.log("Provided callback for afterLoadData is not a function."):("csv"===r.options.dataType||"tsv"===r.options.dataType)&&(t=this.interpretCSV(t)),r.parseDatas(t,a,e,n),"function"==typeof i&&i()};switch(typeof t){case"string":if(""===t)return s({}),!0;switch(this.options.dataType){case"json":d3.json(this.parseURI(t,e,n),s);break;case"csv":d3.csv(this.parseURI(t,e,n),s);break;case"tsv":d3.tsv(this.parseURI(t,e,n),s);break;case"txt":d3.text(this.parseURI(t,e,n),"text/plain",s)}return!1;case"object":if(t===Object(t)&&"[object Array]"!==Object.prototype.toString.call(t))return s(t),!1;default:return s({}),!0}},parseDatas:function(t,e,n,i){"use strict";e===this.RESET_ALL_ON_UPDATE&&this._domains.forEach(function(t,e){e.forEach(function(t,e,n){n[e].v=null})});var o=this._domains.keys(),a=this._domains.get(o[0])[1].t-this._domains.get(o[0])[0].t;for(var r in t){var s=new Date(1e3*r),l=this.getDomain(s)[0].getTime();if(!isNaN(r)&&t.hasOwnProperty(r)&&this._domains.has(l)&&l>=+n&&+i>l){var u=this._domainType[this.options.subDomain].extractUnit(s),c=this._domains.get(l),m=Math.round((u-l)/a);e===this.RESET_SINGLE_ON_UPDATE?c[m].v=t[r]:isNaN(c[m].v)?c[m].v=t[r]:c[m].v+=t[r]}}},parseURI:function(t,e,n){"use strict";return t=t.replace(/\{\{t:start\}\}/g,e.getTime()/1e3),t=t.replace(/\{\{t:end\}\}/g,n.getTime()/1e3),t=t.replace(/\{\{d:start\}\}/g,e.toISOString()),t=t.replace(/\{\{d:end\}\}/g,n.toISOString())},interpretCSV:function(t){"use strict";var e,n,i={},o=Object.keys(t[0]);for(e=0,n=t.length;n>e;e++)i[t[e][o[0]]]=+t[e][o[1]];return i},resize:function(){"use strict";var t=this,e=t.options,n=e.displayLegend?t.Legend.getDim("width")+e.legendMargin[1]+e.legendMargin[3]:0,i=e.displayLegend?t.Legend.getDim("height")+e.legendMargin[0]+e.legendMargin[2]:0,o=t.graphDim.width-e.domainGutter-e.cellPadding,a=t.graphDim.height-e.domainGutter-e.cellPadding;this.root.transition().duration(e.animationDuration).attr("width",function(){return"middle"===e.legendVerticalPosition||"center"===e.legendVerticalPosition?o+n:Math.max(o,n)}).attr("height",function(){return"middle"===e.legendVerticalPosition||"center"===e.legendVerticalPosition?Math.max(a,i):a+i}),this.root.select(".graph").transition().duration(e.animationDuration).attr("y",function(){return"top"===e.legendVerticalPosition?i:0}).attr("x",function(){return"middle"!==e.legendVerticalPosition&&"center"!==e.legendVerticalPosition||"left"!==e.legendHorizontalPosition?0:n})},next:function(t){"use strict";return 0===arguments.length&&(t=1),this.loadNextDomain(t)},previous:function(t){"use strict";return 0===arguments.length&&(t=1),this.loadPreviousDomain(t)},jumpTo:function(t,e){"use strict";2>arguments.length&&(e=!1);var n=this.getDomainKeys(),i=n[0],o=n[n.length-1];return i>t?this.loadPreviousDomain(this.getDomain(i,t).length):e?this.loadNextDomain(this.getDomain(i,t).length):t>o?this.loadNextDomain(this.getDomain(o,t).length):!1},update:function(t,e,n){"use strict";2>arguments.length&&(e=!0),3>arguments.length&&(n=this.RESET_ALL_ON_UPDATE);var i=this.getDomainKeys(),o=this;this.getDatas(t,new Date(i[0]),this.getSubDomain(i[i.length-1]).pop(),function(){o.fill()},e,n)},setLegend:function(){"use strict";var t=this.options.legend.slice(0);arguments.length>=1&&Array.isArray(arguments[0])&&(this.options.legend=arguments[0]),arguments.length>=2&&(this.options.legendColors=Array.isArray(arguments[1])&&arguments[1].length>=2?[arguments[1][0],arguments[1][1]]:arguments[1]),(arguments.length>0&&!arrayEquals(t,this.options.legend)||arguments.length>=2)&&(this.Legend.buildColors(),this.fill()),this.Legend.redraw(this.graphDim.width-this.options.domainGutter-this.options.cellPadding)},removeLegend:function(){"use strict";return this.options.displayLegend?(this.options.displayLegend=!1,this.Legend.remove(),!0):!1},showLegend:function(){"use strict";return this.options.displayLegend?!1:(this.options.displayLegend=!0,this.Legend.redraw(this.graphDim.width-this.options.domainGutter-this.options.cellPadding),!0)},highlight:function(t){"use strict";return(this.options.highlight=this.expandDateSetting(t))!==[]?(this.fill(),!0):!1},getSVG:function(){"use strict";for(var t={".graph":{},".graph-rect":{},"rect.highlight":{},"rect.now":{},"text.highlight":{},"text.now":{},".domain-background":{},".graph-label":{},".subdomain-text":{},".qi":{}},e=0,n=this.options.legend.length;n>e;e++)t[".q"+e]={};var i=this.root,o=["stroke","stroke-width","stroke-opacity","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-miterlimit","fill","fill-opacity","fill-rule","marker","marker-start","marker-mid","marker-end","alignement-baseline","baseline-shift","dominant-baseline","glyph-orientation-horizontal","glyph-orientation-vertical","kerning","text-anchor","shape-rendering","text-transform","font-family","font","font-size","font-weight"],a=function(e,n,i){-1!==o.indexOf(n)&&(t[e][n]=i)},r=function(t){return i.select(t)[0][0]};for(var s in t)if(t.hasOwnProperty(s)){var l=r(s);if(null!==l)if("getComputedStyle"in window){var u=getComputedStyle(l,null);if(0!==u.length)for(var c=0;u.length>c;c++)a(s,u.item(c),u.getPropertyValue(u.item(c)));else for(var m in u)u.hasOwnProperty(m)&&a(s,m,u[m])}else if("currentStyle"in l){var h=l.currentStyle;for(var g in h)a(s,g,h[g])}}var d='<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><style type="text/css"><![CDATA[ ';for(var p in t){d+=p+" {\n";for(var f in t[p])d+="	"+f+":"+t[p][f]+";\n";d+="}\n"}return d+="]]></style>",d+=(new XMLSerializer).serializeToString(this.root.selectAll("svg")[0][0]),d+=(new XMLSerializer).serializeToString(this.root.selectAll("svg")[0][1]),d+="</svg>"}};var DomainPosition=function(){"use strict";this.positions=d3.map()};DomainPosition.prototype.getPosition=function(t){"use strict";return this.positions.get(t)},DomainPosition.prototype.getPositionFromIndex=function(t){"use strict";var e=this.getKeys();return this.positions.get(e[t])},DomainPosition.prototype.getLast=function(){"use strict";var t=this.getKeys();return this.positions.get(t[t.length-1])},DomainPosition.prototype.setPosition=function(t,e){"use strict";this.positions.set(t,e)},DomainPosition.prototype.shiftRightBy=function(t){"use strict";this.positions.forEach(function(e,n){this.set(e,n-t)});var e=this.getKeys();this.positions.remove(e[0])},DomainPosition.prototype.shiftLeftBy=function(t){"use strict";this.positions.forEach(function(e,n){this.set(e,n+t)});var e=this.getKeys();this.positions.remove(e[e.length-1])},DomainPosition.prototype.getKeys=function(){"use strict";return this.positions.keys().sort(function(t,e){return parseInt(t,10)-parseInt(e,10)})};var Legend=function(t){"use strict";this.calendar=t,this.computeDim(),null!==t.options.legendColors&&this.buildColors()};Legend.prototype.computeDim=function(){"use strict";var t=this.calendar.options;this.dim={width:t.legendCellSize*(t.legend.length+1)+t.legendCellPadding*t.legend.length,height:t.legendCellSize}},Legend.prototype.remove=function(){"use strict";this.calendar.root.select(".graph-legend").remove(),this.calendar.resize()},Legend.prototype.redraw=function(t){"use strict";function e(t){t.attr("width",l.legendCellSize).attr("height",l.legendCellSize).attr("x",function(t,e){return e*(l.legendCellSize+l.legendCellPadding)})}function n(){switch(l.legendHorizontalPosition){case"right":return"center"===l.legendVerticalPosition||"middle"===l.legendVerticalPosition?t+l.legendMargin[3]:t-a.getDim("width")-l.legendMargin[1];case"middle":case"center":return Math.round(t/2-a.getDim("width")/2);default:return l.legendMargin[3]}}function i(){switch(l.legendVerticalPosition){case"center":case"middle":case"top":return l.legendMargin[0];case"bottom":return r.graphDim.height+l.legendMargin[0]-l.domainGutter-l.cellPadding}}if(!this.calendar.options.displayLegend)return!1;var o,a=this,r=this.calendar,s=r.root,l=r.options;this.computeDim();var u=l.legend.slice(0);u.push(u[u.length-1]+1);var c=r.root.select(".graph-legend");null!==c[0][0]?(s=c,o=s.select("g").selectAll("rect").data(u)):(s="top"===l.legendVerticalPosition?s.insert("svg",".graph"):s.append("svg"),s.attr("x",n()).attr("y",i()),o=s.attr("class","graph-legend").attr("height",a.getDim("height")).attr("width",a.getDim("width")).append("g").selectAll().data(u)),o.enter().append("rect").call(e).attr("class",function(t){return r.Legend.getClass(t,null===r.legendScale)}).attr("fill-opacity",0).call(function(t){null!==r.legendScale&&null!==l.legendColors&&l.legendColors.hasOwnProperty("base")&&t.attr("fill",l.legendColors.base)}).append("title"),o.exit().transition().duration(l.animationDuration).attr("fill-opacity",0).remove(),o.transition().delay(function(t,e){return l.animationDuration*e/10}).call(e).attr("fill-opacity",1).call(function(t){t.attr("fill",function(t,e){return null===r.legendScale?"":0===e?r.legendScale(t-1):r.legendScale(l.legend[e-1])}),t.attr("class",function(t){return r.Legend.getClass(t,null===r.legendScale)})}),o.select("title").text(function(t,e){return 0===e?l.legendTitleFormat.lower.format({min:l.legend[e],name:l.itemName[1]}):e===u.length-1?l.legendTitleFormat.upper.format({max:l.legend[e-1],name:l.itemName[1]}):l.legendTitleFormat.inner.format({down:l.legend[e-1],up:l.legend[e],name:l.itemName[1]})}),s.transition().duration(l.animationDuration).attr("x",n()).attr("y",i()).attr("width",a.getDim("width")).attr("height",a.getDim("height")),s.select("g").transition().duration(l.animationDuration).attr("transform",function(){return"vertical"===l.legendOrientation?"rotate(90 "+l.legendCellSize/2+" "+l.legendCellSize/2+")":""}),r.resize()},Legend.prototype.getDim=function(t){"use strict";switch(t){case"width":return this.dim["horizontal"===this.calendar.options.legendOrientation?"width":"height"];case"height":return this.dim["horizontal"===this.calendar.options.legendOrientation?"height":"width"]}},Legend.prototype.buildColors=function(){"use strict";var t=this.calendar.options;if(null===t.legendColors)return this.calendar.legendScale=null,!1;var e=[];if(Array.isArray(t.legendColors))e=t.legendColors;else{if(!t.legendColors.hasOwnProperty("min")||!t.legendColors.hasOwnProperty("max"))return t.legendColors=null,!1;e=[t.legendColors.min,t.legendColors.max]}var n=t.legend.slice(0);n[0]>0?n.unshift(0):0>n[0]&&n.unshift(n[0]-(n[n.length-1]-n[0])/n.length);var i=d3.scale.linear().range(e).interpolate(d3.interpolateHcl).domain([d3.min(n),d3.max(n)]),o=n.map(function(t){return i(t)});return this.calendar.legendScale=d3.scale.threshold().domain(t.legend).range(o),!0},Legend.prototype.getClass=function(t,e){"use strict";if(null===t||isNaN(t))return"";for(var n=[this.calendar.options.legend.length+1],i=0,o=this.calendar.options.legend.length-1;o>=i;i++){if(this.calendar.options.legend[0]>0&&0>t){n=["1","i"];break}if(this.calendar.options.legend[i]>=t){n=[i+1];break}}return 0===t&&n.push(0),n.unshift(""),(n.join(" r")+(e?n.join(" q"):"")).trim()},String.prototype.format=function(){"use strict";var t=this;for(var e in arguments[0])if(arguments[0].hasOwnProperty(e)){var n=RegExp("\\{"+e+"\\}","gi");t=t.replace(n,arguments[0][e])}return t},"function"==typeof define&&define.amd&&define(["d3"],function(){"use strict";return CalHeatMap});
//@ sourceMappingURL=cal-heatmap.source-map.js<commit_msg>fix 'lastestJobHeatmapController' memory leak<commit_after>/*! cal-heatmap v2.2.0 (Tue May 14 2013 11:32:39)
 *  ---------------------------------------------
 *  A module to create calendar heat map to visualise time data series a la github contribution graph
 *  https://github.com/kamisama/cal-heatmap
 *  Licensed under the MIT license
 *  Copyright 2013 <NAME>
 */

var CalHeatMap = function() {

    "use strict";

    var self = this;

    var allowedDataType = ["json", "csv", "txt"];

    // Default settings
    this.options = {
        // DOM ID of the container to append the graph to
        id : "cal-heatmap",

        // Whether to paint the calendar on init()
        // Used by testsuite to reduce testing time
        paintOnLoad : true,

        // ================================================
        // DOMAIN
        // ================================================

        // Number of domain to display on the graph
        range : 12,

        // Size of each cell, in pixel
        cellsize : 10,

        // Padding between each cell, in pixel
        cellpadding : 2,

        // For rounded subdomain rectangles, in pixels
        cellradius: 0,

        domainGutter : 2,

        domain : "hour",

        subDomain : "min",

        // First day of the week is Monday
        // 0 to start the week on Sunday
        weekStartOnMonday : 1,

        // Start date of the graph
        // @default now
        start : new Date(),

        // URL, where to fetch the original datas
        data : "",

        dataType: allowedDataType[0],

        // Load remote data on calendar creation
        // When false, the calendar will be left empty
        loadOnInit : true,

        // ================================================
        // SCALE
        // ================================================

        // Threshold for the scale
        scale : [10,20,30,40],

        // Whether to display the scale
        displayScale : true,

        // ================================================
        // TEXT FORMATTING
        // ================================================

        format : {
            // Formatting of the date when hovering an subdomain block
            // @default : null, will use the formatting according to domain type
            // Accept a string used as specifier by d3.time.format()
            // or a function
            date : null,

            // Formatting of domain label
            // @default : null, will use the formatting according to domain type
            legend : null

            // Refer to https://github.com/mbostock/d3/wiki/Time-Formatting
            // for accepted date formatting
        },

        // Name of the items to represent in the calendar
        itemName : ["item", "items"],

        cellLabel : {
            empty: "{date}",
            filled: "{count} {name} {connector} {date}"
        },

        scaleLabel : {
            lower: "less than {min} {name}",
            inner: "between {down} and {up} {name}",
            upper: "more than {max} {name}"
        },

        // ================================================
        // BROWSING
        // ================================================

        // Animation duration
        duration : 500,

        // Domain browsing
        // Dynamically change calendar domain by loading
        // next/previous domain
        browsing: false,

        browsingOptions: {
            nextLabel : "Next",
            previousLabel : "Previous"
        },

        // ================================================
        // CALLBACK
        // ================================================

        // Callback when clicking on a time block
        onClick : null,

        // Callback after painting the empty calendar
        afterLoad : null,

        // Callback after loading the next domain in the calendar
        afterLoadNextDomain : function(start) {},

        // Callback after loading the previous domain in the calendar
        afterLoadPreviousDomain : function(start) {},

        // Callback after finishing all actions on the calendar
        onComplete : null,

        // Callback after fetching the datas, but before applying them to the calendar
        // Used mainly to convert the datas if they're not formatted like expected
        // Takes the fetched "data" object as argument, must return a json object
        // formatted like {timestamp:count, timestamp2:count2},
        afterLoadData : function(data) { return data; }
    };



    this._domainType = {
        "min" : {
            row: function(d) {return 10;},
            column: function(d) { return 6; },
            position: {
                x : function(d) { return Math.floor(d.getMinutes() / self._domainType.min.row(d)); },
                y : function(d) { return d.getMinutes() % self._domainType.min.row(d);}
            },
            format: {
                date: "%H:%M, %A %B %-e, %Y",
                legend: "",
                connector: "at"
            },
            extractUnit : function(d) { return d.getMinutes(); }
        },
        "hour" : {
            name: "hour",
            row: function(d) {return 6;},
            column: function(d) {
                switch(self.options.domain) {
                    case "day" : return 4;
                    case "week" : return 28;
                    case "month" : return self.getEndOfMonth(d).getDate() * 4;
                }
            },
            position: {
                x : function(d) {
                    if (self.options.domain === "month") {
                        return Math.floor(d.getHours() / self._domainType.hour.row(d)) + (d.getDate()-1)*4;
                    } else if (self.options.domain === "week") {
                        return Math.floor(d.getHours() / self._domainType.hour.row(d)) + self.getWeekDay(d)*4;
                    }
                    return Math.floor(d.getHours() / self._domainType.hour.row(d));
                },
                y : function(d) { return d.getHours() % self._domainType.hour.row(d);}
            },
            format: {
                date: "%Hh, %A %B %-e, %Y",
                legend: "%H:00",
                connector: "at"
            },
            extractUnit : function(d) {
                var formatHour = d3.time.format("%H");
                return d.getFullYear() + "" +  self.getDayOfYear(d) + "" + formatHour(d);
            }
        },
        "day" : {
            name: "day",
            row: function(d) {return 7;},
            column: function(d) {
                d = new Date(d);
                switch(self.options.domain) {
                    case "year" : return 54;
                    case "month" : return self.getWeekNumber(new Date(d.getFullYear(), d.getMonth()+1, 0)) - self.getWeekNumber(d) + 1;
                    case "week" : return 1;
                }
            },
            position: {
                x : function(d) {
                    switch(self.options.domain) {
                        case "week" : return 0;
                        case "month" :
                            return self.getWeekNumber(d) - self.getWeekNumber(new Date(d.getFullYear(), d.getMonth()));
                        case "year" : return self.getWeekNumber(d) ;
                    }
                },
                y : function(d) { return self.getWeekDay(d);}
            },
            format: {
                date: "%A %B %-e, %Y",
                legend: "%e %b",
                connector: "on"
            },
            extractUnit : function(d) { return d.getFullYear() + "" + self.getDayOfYear(d); }
        },
        "x_day" : {
            name: "x_day",
            row: function(d) {
                switch(self.options.domain) {
                    case "year" : return 54;
                    case "month" : return 6;
                    case "week" : return 1;
                }
            },
            column: function(d) {
                return 7;
            },
            position: {
                x : function(d) { return self.getWeekDay(d);},
                y : function(d) {
                    switch(self.options.domain) {
                        case "week" : return 0;
                        case "month" :
                            return self.getWeekNumber(d) - self.getWeekNumber(new Date(d.getFullYear(), d.getMonth()));
                        case "year" : return self.getWeekNumber(d) ;
                    }
                }
            },
            format: {
                date: "%A %B %-e, %Y",
                legend: "%e %b",
                connector: "on"
            },
            extractUnit : function(d) { return d.getFullYear() + "" + self.getDayOfYear(d); }
        },
        "week" : {
            name: "week",
            row: function(d) {return 1;},
            column: function(d) {
                d = new Date(d);
                switch(self.options.domain) {
                    case "year" : return 54;
                    case "month" : return self.getWeekNumber(new Date(d.getFullYear(), d.getMonth()+1, 0)) - self.getWeekNumber(d);
                }
                return 1;
            },
            position: {
                x: function(d) {
                    switch(self.options.domain) {
                        case "year" : return self.getWeekNumber(d);
                        case "month" : return self.getWeekNumber(d) - self.getWeekNumber(new Date(d.getFullYear(), d.getMonth())) - 1;
                    }
                },
                y: function(d) {
                    return 0;
                }
            },
            format: {
                date: "%B Week #%W",
                legend: "%B Week #%W",
                connector: "on"
            },
            extractUnit : function(d) { return self.getWeekNumber(d); }
        },
        "month" : {
            name: "month",
            row: function(d) {return 1;},
            column: function(d) {return 12;},
            position: {
                x : function(d) { return Math.floor(d.getMonth() / self._domainType.month.row(d)); },
                y : function(d) { return d.getMonth() % self._domainType.month.row(d);}
            },
            format: {
                date: "%B %Y",
                legend: "%B",
                connector: "on"
            },
            extractUnit : function(d) { return d.getMonth(); }
        },
        "year" : {
            name: "year",
            row: function(d) {return 1;},
            column: function(d) {return 12;},
            position: {
                x : function(d) { return Math.floor(d.getFullYear() / this._domainType.year.row(d)); },
                y : function(d) { return d.getFullYear() % this._domainType.year.row(d);}
            },
            format: {
                date: "%Y",
                legend: "%Y",
                connector: "on"
            },
            extractUnit : function(d) { return d.getFullYear(); }
        }
    };

    this.svg = null;

    this._completed = false;

    // Record all the valid domains
    // Each domain value is a timestamp in milliseconds
    this._domains = [];

    // Total width of the graph
    var width = 0;

    // Save domains width
    var domainsWidth = [];

    /**
     * Display the graph for the first time
     * @return bool True if the calendar is created
     */
    var _init = function() {

        if (typeof self.options.format.date === "function") {
            self.formatDate = self.options.format.date;
        } else {
            self.formatDate = d3.time.format(self.options.format.date);
        }

        self._domains = self.getDomain(self.options.start).map(function(d) { return d.getTime(); });

        if (self.options.browsing) {
            d3.select("#" + self.options.id).append("a")
                .attr("href", "#")
                .attr("rel", "prev")
                .attr("class", "graph-browse-previous")
                .attr("title", "Load previous " + self._domainType[self.options.domain].name)
                .on("click", function(d) { self.loadPreviousDomain(); })
                .html(self.options.browsingOptions.previousLabel);

            d3.select("#" + self.options.id).append("a")
                .attr("href", "#")
                .attr("rel", "next")
                .attr("class", "graph-browse-next")
                .attr("title", "Load next " + self._domainType[self.options.domain].name)
                .on("click", function(d) { self.loadNextDomain(); })
                .html(self.options.browsingOptions.nextLabel);
        }

        d3.select("#" + self.options.id).append("svg")
            .attr("class", "graph");


        if (self.options.paintOnLoad) {
            self.paint();

            // Display scale if needed
            if (self.options.displayScale) {
                self.displayScale();
            }

            if (self.options.afterLoad !== null) {
                self.afterLoad();
            }

            // Fill the graph with some datas
            if (self.options.loadOnInit) {
                self.fill(
                    self.getDatas(
                        self.options.data,
                        new Date(self._domains[0]),
                        self.getSubDomain(self._domains[self._domains.length-1]).pop()
                    ),
                    self.svg);
            } else if (typeof self.options.onComplete === "function") {
                self.onComplete();
            }
        }

        return true;
    };

    this.loadNextDomain = function() {
        if (d3.event) {
            d3.event.preventDefault();
        }

        self._domains.push(self.getNextDomain().getTime());
        self._domains.shift();

        self.paint();

        self.getDatas(
            self.options.data,
            new Date(self._domains[self._domains.length-1]),
            self.getSubDomain(self._domains[self._domains.length-1]).pop(),
            self.svg
        );

        self.afterLoadNextDomain(new Date(self._domains[self._domains.length-1]));

    };

    this.loadPreviousDomain = function() {
        if (d3.event) {
            d3.event.preventDefault();
        }

        self._domains.unshift(self.getPreviousDomain().getTime());
        self._domains.pop();

        self.paint(true);

        self.getDatas(
            self.options.data,
            new Date(self._domains[0]),
            self.getSubDomain(self._domains[0]).pop(),
            self.svg
        );

        self.afterLoadPreviousDomain(new Date(self._domains[0]));
    };

    this.paint = function(reverse) {

        if (typeof reverse === "undefined") {
            reverse = false;
        }

        var graphLegendHeight = Math.max(25, self.options.cellsize*2);

        // Compute the width of the domain block
        // @param int d Domain start timestamp
        var w = function(d) {
            return self.options.cellsize*self._domainType[self.options.subDomain].column(d) + self.options.cellpadding*self._domainType[self.options.subDomain].column(d);
        };

        // Compute the height of the domain block
        var h = function(d) {
            return self.options.cellsize*self._domainType[self.options.subDomain].row(d) + self.options.cellpadding*self._domainType[self.options.subDomain].row(d) + self.options.cellpadding;
        };

        // Format the domain legend according to the domain type
        var legendFormat = d3.time.format(self.options.format.legend);

        var positionX = function(i) {
            if (width === 0) {
                return domainsWidth[i];
            } else {
                return reverse ? domainsWidth[0] : domainsWidth[i+1];
            }
        };

        var domainPositionXExit = function(d) {
            if (reverse) {
                return width;
            } else {
                return w(d) * -1 - self.options.domainGutter;
            }
        };

        var labelPositionXExit = function(d) {
            if (reverse) {
                return width + w(d)/2;
            } else {
                return (self.options.domainGutter + w(d)/2) * -1;
            }
        };

        // Painting all the domains
        var domainSvg = d3.select("#" + self.options.id + " .graph")
            .attr("height", function(d) { return h(d) + graphLegendHeight;})
            .selectAll("svg")
            .data(self._domains, function(d) { return d;});

        var tempWidth = 0;
        var tempLastDomainWidth = 0;


        var svg = domainSvg
                .enter()
                .insert("svg:svg")
                .attr("width", function(d){
                    var wd = w(d);

                    tempWidth += tempLastDomainWidth = wd+self.options.domainGutter;

                    if (width === 0) {
                        domainsWidth.push(tempWidth - tempLastDomainWidth);
                    } else {
                        if (reverse) {
                            domainsWidth.unshift(tempLastDomainWidth * -1);
                        } else {
                            domainsWidth.push(width);
                        }

                    }

                    return wd;
                })
                .attr("height", function(d) { return h(d) + graphLegendHeight;})
                .attr("x", function(d, i){ return positionX(i); })
            ;


        // Appending a label to each domain
        var label = d3.select("#" + self.options.id + " .graph").selectAll("text")
            .data(self._domains, function(d) { return d;});

        label
            .enter().insert("text")
            .attr("y", function(d) { return h(d) + graphLegendHeight/2; })
            .attr("x", function(d, i){ return positionX(i) + w(d) / 2; })
            .attr("class", "graph-label")
            .attr("text-anchor", "middle")
            .attr("dominant-baseline", "middle")
            .text(function(d) { return legendFormat(new Date(d)); });


        // Drawing the sudomain inside each domain
        var rect = domainSvg.selectAll("rect")
                .data(function(d) { return self.getSubDomain(d); })
                .enter().append("svg:rect")
                .attr("class", "graph-rect")
                .attr("width", self.options.cellsize)
                .attr("height", self.options.cellsize)
                .attr("x", function(d) { return self.positionSubDomainX(d); })
                .attr("y", function(d) { return self.positionSubDomainY(d); })
                .call(radius)
            ;

        function radius(selection) {
            if (self.options.cellradius > 0) {
                selection
                    .attr("rx", self.options.cellradius)
                    .attr("ry", self.options.cellradius)
                ;
            }
        }

        // Appeding a title to each subdomain
        rect.append("svg:title").text(function(d){ return self.formatDate(d); });


        var exitDomainWidth = reverse ? (width-domainsWidth[domainsWidth.length-1]) : domainsWidth[1];

        if (width !== 0) {
            var i = domainsWidth.length-1;
            while (i >= 0) {
                if (reverse) {
                    domainsWidth[i] -= domainsWidth[0];
                } else if (i >= 1) {
                    domainsWidth[i] -= domainsWidth[1];
                }

                i--;
            }
            if (reverse) {
                domainsWidth.pop() ;
            } else {
                domainsWidth.shift();
            }
        }

        domainSvg.transition().duration(self.options.duration)
            .attr("x", function(d, i){ return domainsWidth[i]; })
        ;

        domainSvg.exit().transition().duration(self.options.duration)
            .attr("x", function(d){ return domainPositionXExit(d); })
            .remove();

        label.transition().duration(self.options.duration)
            .attr("x", function(d, i){ return domainsWidth[i] + w(d) / 2; });

        label.exit().transition().duration(self.options.duration)
            .attr("x", function(d){ return labelPositionXExit(d); })
            .remove();

        if (width === 0) {
            width = tempWidth;
            d3.select("#" + self.options.id + " .graph").attr("width", width);
        } else if (tempLastDomainWidth !== exitDomainWidth) {
            // Compute the new width
            var tw = width + tempLastDomainWidth - exitDomainWidth;

            // If the new width is different, resize the graph
            if (tw !== width) {
                width = tw;
                d3.select("#" + self.options.id + " .graph")
                    .transition().duration(self.options.duration)
                    .attr("width", width)
                ;
            }
        }

        if (self.svg === null) {
            self.svg = svg;
        } else {
            self.svg = d3.select("#" + self.options.id + " .graph").selectAll("svg")
                .data(self._domains, function(d) {return d;});
        }
    };


    this.init = function(settings) {

        // Merge settings with default
        if ( settings !== null && settings !== undefined && settings !== "undefined" ){
            for ( var opt in self.options ) {
                if ( settings[ opt ] !== null &&
                    settings[ opt ] !== undefined &&
                    settings[ opt ] !== "undefined" ){
                    self.options[ opt ] = settings[ opt ];
                }
            }
        }

        if (!this._domainType.hasOwnProperty(self.options.domain) || self.options.domain === "min") {
            console.log("The domain '" + self.options.domain + "' is not valid domain");
            return false;
        }

        if (allowedDataType.indexOf(self.options.dataType) < 0) {
            console.log("The data type '" + self.options.dataType + "' is not valid data type");
            return false;
        }

        var domain = self.getDomain(self.options.start);

        if (self.options.format.date === null) {
            self.options.format.date = this._domainType[self.options.subDomain].format.date;
        }

        if (self.options.format.legend === null) {
            self.options.format.legend = this._domainType[self.options.domain].format.legend;
        }

        return _init();

    };

};



CalHeatMap.prototype = {


    // =========================================================================//
    // CALLBACK																	//
    // =========================================================================//

    /**
     * Callback when clicking on a subdomain cell
     * @param  Date		d		Date of the subdomain block
     * @param  int		itemNb	Number of items in that date
     */
    onClick : function(d, itemNb) {
        if (typeof (this.options.onClick) === "function") {
            return this.options.onClick(d, itemNb);
        } else {
            console.log("Provided callback for onClick is not a function.");
            return false;
        }
    },

    /**
     * Callback to fire after drawing the calendar, but before filling it
     */
    afterLoad : function() {
        if (typeof (this.options.afterLoad) === "function") {
            return this.options.afterLoad();
        } else {
            console.log("Provided callback for afterLoad is not a function.");
            return false;
        }
    },

    /**
     * Callback to fire at the end, when all actions on the calendar are completed
     */
    onComplete : function() {
        if (typeof (this.options.onComplete) === "function") {
            return this.options.onComplete();
        } else {
            console.log("Provided callback for onComplete is not a function.");
            return false;
        }
    },

    /**
     * Callback after shifting the calendar one domain back
     * @param  Date		start	Domain start date
     * @param  Date		end		Domain end date
     */
    afterLoadPreviousDomain: function(start) {
        if (typeof (this.options.afterLoadPreviousDomain) === "function") {
            var subDomain = this.getSubDomain(start);
            return this.options.afterLoadPreviousDomain(subDomain.shift(), subDomain.pop());
        } else {
            console.log("Provided callback for afterLoadPreviousDomain is not a function.");
            return false;
        }
    },

    /**
     * Callback after shifting the calendar one domain above
     * @param  Date		start	Domain start date
     * @param  Date		end		Domain end date
     */
    afterLoadNextDomain: function(start) {
        if (typeof (this.options.afterLoadNextDomain) === "function") {
            var subDomain = this.getSubDomain(start);
            return this.options.afterLoadNextDomain(subDomain.shift(), subDomain.pop());
        } else {
            console.log("Provided callback for afterLoadNextDomain is not a function.");
            return false;
        }
    },

    formatNumber: d3.format(",g"),

    // =========================================================================//
    // PAINTING : SCALE															//
    // =========================================================================//

    displayScale: function() {

        var parent = this;

        var scale = d3.select("#" + this.options.id)
            .append("svg:svg")
            .attr("class", "graph-scale")
            .attr("height", this.options.cellsize + (this.options.cellpadding*2))
            .selectAll().data(d3.range(0, this.options.scale.length+1));

        var scaleItem = scale
                .enter()
                .append("svg:rect")
                .attr("width", this.options.cellsize)
                .attr("height", this.options.cellsize)
                .attr("class", function(d){ return "graph-rect q" + (d+1); })
                .attr("transform", function(d) { return "translate(" + (d * (parent.options.cellsize + parent.options.cellpadding))  + ", " + parent.options.cellpadding + ")"; })
                .attr("fill-opacity", 0)
            ;

        scaleItem.transition().delay(function(d, i) { return parent.options.duration * i/10;}).attr("fill-opacity", 1);

        scaleItem
            .append("svg:title")
            .text(function(d) {
                var nextThreshold = parent.options.scale[d+1];
                if (d === 0) {
                    return (parent.options.scaleLabel.lower).format({
                        min: parent.options.scale[d],
                        name: parent.options.itemName[1]});
                } else if (d === parent.options.scale.length) {
                    return (parent.options.scaleLabel.upper).format({
                        max: parent.options.scale[d-1],
                        name: parent.options.itemName[1]});
                } else {
                    return (parent.options.scaleLabel.inner).format({
                        down: parent.options.scale[d-1],
                        up: parent.options.scale[d],
                        name: parent.options.itemName[1]});
                }
            })
        ;
    },

    // =========================================================================//
    // PAINTING : SUBDOMAIN FILLING												//
    // =========================================================================//

    /**
     * Colorize all rectangles according to their items count
     *
     * @param  {[type]} data  [description]
     */
    display: function(data, domain) {
        var parent = this;
        domain.each(function(domainUnit) {

                if (data.hasOwnProperty(domainUnit)) {
                    d3.select(this).selectAll("rect")
                        .attr("class", function(d) {
                            var subDomainUnit = parent._domainType[parent.options.subDomain].extractUnit(d);

                            var htmlClass = "graph-rect" +
                                (data[domainUnit].hasOwnProperty(subDomainUnit) ?
                                    (" " + parent.scale(data[domainUnit][subDomainUnit])) : ""
                                    );

                            if (parent.options.onClick !== null) {
                                htmlClass += " hover_cursor";
                            }

                            return htmlClass;
                        })
                        .on("click", function(d) {
                            if (parent.options.onClick !== null) {
                                var subDomainUnit = parent._domainType[parent.options.subDomain].extractUnit(d);
                                return parent.onClick(
                                    d,
                                    (data[domainUnit].hasOwnProperty(subDomainUnit) ? data[domainUnit][subDomainUnit] : 0)
                                );
                            }
                        })
                        .select("title")
                        .text(function(d) {
                            var subDomainUnit = parent._domainType[parent.options.subDomain].extractUnit(d);

                            return (
                                (data[domainUnit].hasOwnProperty(subDomainUnit) && data[domainUnit][subDomainUnit] !== null) ?
                                    (parent.options.cellLabel.filled).format({
                                        count: parent.formatNumber(data[domainUnit][subDomainUnit]),
                                        name: parent.options.itemName[(data[domainUnit][subDomainUnit] > 1 ? 1 : 0)],
                                        connector: parent._domainType[parent.options.subDomain].format.connector,
                                        date: parent.formatDate(d)
                                    }) :
                                    (parent.options.cellLabel.empty).format({
                                        date: parent.formatDate(d)
                                    })
                                );
                        });
                }
            }
        );
        return true;
    },

    // =========================================================================//
    // POSITIONNING																//
    // =========================================================================//

    positionSubDomainX: function(d) {
        var index = this._domainType[this.options.subDomain].position.x(d);
        return index * this.options.cellsize + index * this.options.cellpadding;
    },

    positionSubDomainY: function(d) {
        var index = this._domainType[this.options.subDomain].position.y(d);
        return index * this.options.cellsize + index * this.options.cellpadding;
    },

    // =========================================================================//
    // DOMAIN COMPUTATION														//
    // =========================================================================//

    /**
     * Return the day of the year for the date
     * @param	Date
     * @return  int Day of the year [1,366]
     */
    getDayOfYear : d3.time.format("%j"),

    /**
     * Return the week number of the year
     * Monday as the first day of the week
     * @return int	Week number [0-53]
     */
    getWeekNumber : function(d) {
        var f = this.options.weekStartOnMonday === 1 ? d3.time.format("%W") : d3.time.format("%U");
        return f(d);
    },


    getWeekDay : function(d) {
        if (this.options.weekStartOnMonday === 0) {
            return d.getDay();
        }
        else if (d.getDay() === 0) {
            return 6;
        }
        return d.getDay()-1;
    },


    /**
     * Get the last day of the month
     * @param  Date|int	d	Date or timestamp in milliseconds
     * @return Date			Last day of the month
     */
    getEndOfMonth : function(d) {
        if (typeof d === "number") {
            d = new Date(d);
        }
        return new Date(d.getFullYear(), d.getMonth()+1, 0);
    },

    /**
     * Return a range of week number
     * @param  number|Date	d	A date, or timestamp in milliseconds
     * @return Date				The start of the hour
     */
    getWeekDomain: function (d, range) {
        var weekStart;

        if (this.options.weekStartOnMonday === 0) {
            weekStart = new Date(d.getFullYear(), d.getMonth(), d.getDate() - d.getDay());
        } else {
            if (d.getDay() === 1) {
                weekStart = new Date(d.getFullYear(), d.getMonth(), d.getDate());
            } else if (d.getDay() === 0) {
                weekStart = new Date(d.getFullYear(), d.getMonth(), d.getDate());
                weekStart.setDate(weekStart.getDate() - 6);
            } else {
                weekStart = new Date(d.getFullYear(), d.getMonth(), d.getDate()-d.getDay()+1);
            }
        }

        var endDate = new Date(weekStart);

        var stop = new Date(endDate.setDate(endDate.getDate() + range * 7));

        return (this.options.weekStartOnMonday === 1) ?
            d3.time.mondays(Math.min(weekStart, stop), Math.max(weekStart, stop)) :
            d3.time.sundays(Math.min(weekStart, stop), Math.max(weekStart, stop))
            ;
    },

    getYearDomain: function(d, range){
        var start = new Date(d.getFullYear(), 0);
        var stop = new Date(d.getFullYear()+range, 0);

        return d3.time.years(Math.min(start, stop), Math.max(start, stop));
    },

    /**
     * Return all the minutes between from the same hour
     * @param  number|Date	d	A date, or timestamp in milliseconds
     * @return Date				The start of the hour
     */
    getMinuteDomain: function (d, range) {
        var start = new Date(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours());
        var stop = new Date(start.getTime() + 60 * 1000 * range);

        return d3.time.minutes(Math.min(start, stop), Math.max(start, stop));
    },

    /**
     * Return the start of an hour
     * @param  number|Date	d	A date, or timestamp in milliseconds
     * @return Date				The start of the hour
     */
    getHourDomain: function (d, range) {
        var start = new Date(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours());
        var stop = range;
        if (typeof range === "number") {
            stop = new Date(start.getTime() + 3600 * 1000 * range);
        }

        return d3.time.hours(Math.min(start, stop), Math.max(start, stop));
    },

    /**
     * Return the start of an hour
     * @param  number|Date	d		A date, or timestamp in milliseconds
     * @param  int			range	Number of days in the range
     * @return Date					The start of the hour
     */
    getDayDomain: function (d, range) {
        var start = new Date(d.getFullYear(), d.getMonth(), d.getDate());
        var stop = new Date(start);
        stop = new Date(stop.setDate(stop.getDate() + parseInt(range, 10)));

        return d3.time.days(Math.min(start, stop), Math.max(start, stop));
    },

    /**
     * Return the month domain for the current date
     * @param  Date		d	A date
     * @return Array
     */
    getMonthDomain: function (d, range) {
        var start = new Date(d.getFullYear(), d.getMonth());
        var stop = new Date(start);
        stop = stop.setMonth(stop.getMonth()+range);

        return d3.time.months(Math.min(start, stop), Math.max(start, stop));
    },

    getDomain: function(date, range) {
        if (typeof date === "number") {
            date = new Date(date);
        }

        if (typeof range === "undefined") {
            range = this.options.range;
        }

        switch(this.options.domain) {
            case "hour"  : return this.getHourDomain(date, range);
            case "x_day" :
            case "day"   : return this.getDayDomain(date, range);
            case "week"  : return this.getWeekDomain(date, range);
            case "month" : return this.getMonthDomain(date, range);
            case "year"  : return this.getYearDomain(date, range);
        }
    },

    getSubDomain: function(date) {
        if (typeof date === "number") {
            date = new Date(date);
        }

        var parent = this;

        var computeDaySubDomainSize = function(date, domain) {
            if (domain === "year") {
                return parent.getDayOfYear(new Date(date.getFullYear()+1, 0, 0));
            } else if (domain === "month") {
                var lastDayOfMonth = new Date(date.getFullYear(), date.getMonth()+1, 0);
                return lastDayOfMonth.getDate();
            } else if (domain === "week") {
                return 7;
            }
        };

        var computeMinSubDomainSize = function(date, domain) {
            switch (domain) {
                case "hour" : return 60;
                case "x_day" :
                case "day" : return 60 * 24;
                case "week" : return 60 * 24 * 7;
            }
        };

        var computeHourSubDomainSize = function(date, domain) {
            if (domain === "day" || domain === "x_day") {
                return 24;
            } else if (domain === "week") {
                return 168;
            } else if (domain === "month") {
                var endOfMonth = new Date(date.getFullYear(), date.getMonth()+1, 0);
                return endOfMonth.getDate() * 24;
            }
        };

        var computeWeekSubDomainSize = function(date, domain) {
            if (domain === "month") {
                var endOfMonth = new Date(date.getFullYear(), date.getMonth()+1, 0);
                var endWeekNb = parent.getWeekNumber(endOfMonth);
                var startWeekNb = parent.getWeekNumber(new Date(date.getFullYear(), date.getMonth()));

                if (startWeekNb > endWeekNb) {
                    startWeekNb = 0;
                    endWeekNb++;
                }

                return endWeekNb - startWeekNb + 1;
            } else if (domain === "year") {
                return parent.getWeekNumber(new Date(date.getFullYear(), 11, 31));
            }
        };


        switch(this.options.subDomain) {
            case "min"   : return this.getMinuteDomain(date, computeMinSubDomainSize(date, this.options.domain));
            case "hour"  : return this.getHourDomain(date, computeHourSubDomainSize(date, this.options.domain));
            case "x_day" :
            case "day"   : return this.getDayDomain(date, computeDaySubDomainSize(date, this.options.domain));
            case "week"  : return this.getWeekDomain(date, computeWeekSubDomainSize(date, this.options.domain));
            case "month" : return this.getMonthDomain(date, 12);
        }
    },

    getNextDomain: function() {
        return this.getDomain(this._domains[this._domains.length-1], 2).pop();
    },

    getPreviousDomain: function() {
        return this.getDomain(this._domains[0], -1)[0];
    },

    /**
     * Return the classname on the scale for the specified value
     *
     * @param  Item count n Number of items for that perdiod of time
     * @return string		Classname according to the scale
     */
    scale: function(n) {

        if (isNaN(n)) {
            return "qi";
        } else if (n === null) {
            return "";
        }

        for (var i = 0, total = this.options.scale.length-1; i <= total; i++) {

            if (n === 0 && this.options.scale[0] > 0) {
                return "";
            } else if (this.options.scale[0] > 0 && n < 0) {
                return "qi";
            }

            if (n <= this.options.scale[i]) {
                return "q" + (i+1);
            }
        }
        return "q" + (this.options.scale.length + 1);
    },

    // =========================================================================//
    // DATAS																	//
    // =========================================================================//

    /**
     * @todo Add check for empty data
     */
    fill: function(datas, domain) {
        if (datas !== false && datas !== true) {
            if (this.options.onComplete !== null && this._completed === false) {
                this.onComplete();
                this._completed = true;
            }
            return this.display(this.parseDatas(datas), domain);
        }
        return false;
    },

    getDatas: function(source, startDate, endDate, domain) {
        var parent = this;

        if (typeof domain === "undefined") {
            domain = parent.svg;
        }

        switch(typeof source) {
            case "string" :
                if (source === "") {
                    return false;
                } else {

                    var fillData = function(data) {
                        parent.fill(data, domain);
                    };

                    switch(this.options.dataType) {
                        case "json" :
                            d3.json(this.parseURI(source, startDate, endDate), fillData);
                            break;
                        case "csv" :
                            d3.csv(this.parseURI(source, startDate, endDate), fillData);
                            break;
                        case "text" :
                            d3.text(this.parseURI(source, startDate, endDate), "text/plain", fillData);
                            break;
                    }

                    return true;
                }
                break;
            case "object" :
                // @todo Check that it's a valid JSON object
                return source;
        }

        return false;
    },

    /**
     * Convert a JSON result into the expected format
     *
     * @param  {[type]} data [description]
     * @return {[type]}      [description]
     */
    parseDatas: function(data) {
        var stats = {};

        if (typeof (this.options.afterLoadData) === "function") {
            data = this.options.afterLoadData(data);
        } else {
            console.log("Provided callback for afterLoadData is not a function.");
            return {};
        }

        for (var d in data) {
            var date = new Date(d*1000);
            var domainUnit = this.getDomain(date)[0].getTime();

            // Don't record datas not relevant to the current domain
            if (this._domains.indexOf(domainUnit) < 0) {
                continue;
            }

            var subDomainUnit = this._domainType[this.options.subDomain].extractUnit(date);
            if (typeof stats[domainUnit] === "undefined") {
                stats[domainUnit] = {};
            }

            if (typeof stats[domainUnit][subDomainUnit] !== "undefined") {
                stats[domainUnit][subDomainUnit] += data[d];
            } else {
                stats[domainUnit][subDomainUnit] = data[d];
            }
        }

        return stats;
    },

    parseURI: function(str, startDate, endDate) {
        // Use a timestamp in seconds
        str = str.replace(/\{\{t:start\}\}/g, startDate.getTime()/1000);
        str = str.replace(/\{\{t:end\}\}/g, endDate.getTime()/1000);

        // Use a string date, following the ISO-8601
        str = str.replace(/\{\{d:start\}\}/g, startDate.toISOString());
        str = str.replace(/\{\{d:end\}\}/g, endDate.toISOString());

        return str;
    }
};

/**
 * Sprintf like function
 * @source http://stackoverflow.com/a/4795914/805649
 * @return String
 */
String.prototype.format = function () {
    var formatted = this;
    for (var prop in arguments[0]) {
        var regexp = new RegExp("\\{" + prop + "\\}", "gi");
        formatted = formatted.replace(regexp, arguments[0][prop]);
    }
    return formatted;
};

/**
 * AMD Loader
 */
if (typeof define === "function" && define.amd) {
    define(["d3"], function(d3) {
        return CalHeatMap;
    });
}
{'fraction_non_alphanumeric': 0.2005091429805321, 'fraction_numerical': 0.011160232296484867, 'mean_word_length': 3.3424961752948725, 'pattern_counts': {'":': 128, '<': 16, '<?xml version=': 0, '>': 90, 'https://': 3, 'lorem ipsum': 0, 'www.': 2, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 15, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7552313', 'n_tokens_mistral': 29028, 'n_tokens_neox': 27844, 'n_words': 3410}