Date.ext={};Date.ext.util={};Date.ext.util.xPad=function(x,pad,r){if(typeof (r)=="undefined"){r=10}for(;parseInt(x,10)<r&&r>1;r/=10){x=pad.toString()+x}return x.toString()};Date.prototype.locale="en-GB";if(document.getElementsByTagName("html")&&document.getElementsByTagName("html")[0].lang){Date.prototype.locale=document.getElementsByTagName("html")[0].lang}Date.ext.locales={};Date.ext.locales.en={a:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],A:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],b:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],B:["January","February","March","April","May","June","July","August","September","October","November","December"],c:"%a %d %b %Y %T %Z",p:["AM","PM"],P:["am","pm"],x:"%d/%m/%y",X:"%T"};Date.ext.locales["en-US"]=Date.ext.locales.en;Date.ext.locales["en-US"].c="%a %d %b %Y %r %Z";Date.ext.locales["en-US"].x="%D";Date.ext.locales["en-US"].X="%r";Date.ext.locales["en-GB"]=Date.ext.locales.en;Date.ext.locales["en-AU"]=Date.ext.locales["en-GB"];Date.ext.formats={a:function(d){return Date.ext.locales[d.locale].a[d.getDay()]},A:function(d){return Date.ext.locales[d.locale].A[d.getDay()]},b:function(d){return Date.ext.locales[d.locale].b[d.getMonth()]},B:function(d){return Date.ext.locales[d.locale].B[d.getMonth()]},c:"toLocaleString",C:function(d){return Date.ext.util.xPad(parseInt(d.getFullYear()/100,10),0)},d:["getDate","0"],e:["getDate"," "],g:function(d){return Date.ext.util.xPad(parseInt(Date.ext.util.G(d)/100,10),0)},G:function(d){var y=d.getFullYear();var V=parseInt(Date.ext.formats.V(d),10);var W=parseInt(Date.ext.formats.W(d),10);if(W>V){y++}else{if(W===0&&V>=52){y--}}return y},H:["getHours","0"],I:function(d){var I=d.getHours()%12;return Date.ext.util.xPad(I===0?12:I,0)},j:function(d){var ms=d-new Date(""+d.getFullYear()+"/1/1 GMT");ms+=d.getTimezoneOffset()*60000;var doy=parseInt(ms/60000/60/24,10)+1;return Date.ext.util.xPad(doy,0,100)},m:function(d){return Date.ext.util.xPad(d.getMonth()+1,0)},M:["getMinutes","0"],p:function(d){return Date.ext.locales[d.locale].p[d.getHours()>=12?1:0]},P:function(d){return Date.ext.locales[d.locale].P[d.getHours()>=12?1:0]},S:["getSeconds","0"],u:function(d){var dow=d.getDay();return dow===0?7:dow},U:function(d){var doy=parseInt(Date.ext.formats.j(d),10);var rdow=6-d.getDay();var woy=parseInt((doy+rdow)/7,10);return Date.ext.util.xPad(woy,0)},V:function(d){var woy=parseInt(Date.ext.formats.W(d),10);var dow1_1=(new Date(""+d.getFullYear()+"/1/1")).getDay();var idow=woy+(dow1_1>4||dow1_1<=1?0:1);if(idow==53&&(new Date(""+d.getFullYear()+"/12/31")).getDay()<4){idow=1}else{if(idow===0){idow=Date.ext.formats.V(new Date(""+(d.getFullYear()-1)+"/12/31"))}}return Date.ext.util.xPad(idow,0)},w:"getDay",W:function(d){var doy=parseInt(Date.ext.formats.j(d),10);var rdow=7-Date.ext.formats.u(d);var woy=parseInt((doy+rdow)/7,10);return Date.ext.util.xPad(woy,0,10)},y:function(d){return Date.ext.util.xPad(d.getFullYear()%100,0)},Y:"getFullYear",z:function(d){var o=d.getTimezoneOffset();var H=Date.ext.util.xPad(parseInt(Math.abs(o/60),10),0);var M=Date.ext.util.xPad(o%60,0);return(o>0?"-":"+")+H+M},Z:function(d){return d.toString().replace(/^.*\(([^)]+)\)$/,"$1")},"%":function(d){return"%"}};Date.ext.aggregates={c:"locale",D:"%m/%d/%y",h:"%b",n:"\n",r:"%I:%M:%S %p",R:"%H:%M",t:"\t",T:"%H:%M:%S",x:"locale",X:"locale"};Date.ext.aggregates.z=Date.ext.formats.z(new Date());Date.ext.aggregates.Z=Date.ext.formats.Z(new Date());Date.ext.unsupported={};Date.prototype.strftime=function(fmt){if(!(this.locale in Date.ext.locales)){if(this.locale.replace(/-[a-zA-Z]+$/,"") in Date.ext.locales){this.locale=this.locale.replace(/-[a-zA-Z]+$/,"")}else{this.locale="en-GB"}}var d=this;while(fmt.match(/%[cDhnrRtTxXzZ]/)){fmt=fmt.replace(/%([cDhnrRtTxXzZ])/g,function(m0,m1){var f=Date.ext.aggregates[m1];return(f=="locale"?Date.ext.locales[d.locale][m1]:f)})}var str=fmt.replace(/%([aAbBCdegGHIjmMpPSuUVwWyY%])/g,function(m0,m1){var f=Date.ext.formats[m1];if(typeof (f)=="string"){return d[f]()}else{if(typeof (f)=="function"){return f.call(d,d)}else{if(typeof (f)=="object"&&typeof (f[0])=="string"){return Date.ext.util.xPad(d[f[0]](),f[1])}else{return m1}}}});d=null;return str};
DygraphLayout=function(_1,_2){
this.dygraph_=_1;
this.options={};
Dygraph.update(this.options,_2?_2:{});
this.datasets=new Array();
};
DygraphLayout.prototype.attr_=function(_3){
return this.dygraph_.attr_(_3);
};
DygraphLayout.prototype.addDataset=function(_4,_5){
this.datasets[_4]=_5;
};
DygraphLayout.prototype.evaluate=function(){
this._evaluateLimits();
this._evaluateLineCharts();
this._evaluateLineTicks();
};
DygraphLayout.prototype._evaluateLimits=function(){
this.minxval=this.maxxval=null;
for(var _6 in this.datasets){
var _7=this.datasets[_6];
var x1=_7[0][0];
if(!this.minxval||x1<this.minxval){
this.minxval=x1;
}
var x2=_7[_7.length-1][0];
if(!this.maxxval||x2>this.maxxval){
this.maxxval=x2;
}
}
this.xrange=this.maxxval-this.minxval;
this.xscale=(this.xrange!=0?1/this.xrange:1);
this.minyval=this.options.yAxis[0];
this.maxyval=this.options.yAxis[1];
this.yrange=this.maxyval-this.minyval;
this.yscale=(this.yrange!=0?1/this.yrange:1);
};
DygraphLayout.prototype._evaluateLineCharts=function(){
this.points=new Array();
for(var _10 in this.datasets){
var _11=this.datasets[_10];
for(var j=0;j<_11.length;j++){
var _13=_11[j];
var _14={x:((parseFloat(_13[0])-this.minxval)*this.xscale),y:1-((parseFloat(_13[1])-this.minyval)*this.yscale),xval:parseFloat(_13[0]),yval:parseFloat(_13[1]),name:_10};
if(_14.y<=0){
_14.y=0;
}
if(_14.y>=1){
_14.y=1;
}
if((_14.x>=0)&&(_14.x<=1)){
this.points.push(_14);
}
}
}
};
DygraphLayout.prototype._evaluateLineTicks=function(){
this.xticks=new Array();
for(var i=0;i<this.options.xTicks.length;i++){
var _16=this.options.xTicks[i];
var _17=_16.label;
var pos=this.xscale*(_16.v-this.minxval);
if((pos>=0)&&(pos<=1)){
this.xticks.push([pos,_17]);
}
}
this.yticks=new Array();
for(var i=0;i<this.options.yTicks.length;i++){
var _16=this.options.yTicks[i];
var _17=_16.label;
var pos=1-(this.yscale*(_16.v-this.minyval));
if((pos>=0)&&(pos<=1)){
this.yticks.push([pos,_17]);
}
}
};
DygraphLayout.prototype.evaluateWithError=function(){
this.evaluate();
if(!this.options.errorBars){
return;
}
var i=0;
for(var _19 in this.datasets){
var j=0;
var _20=this.datasets[_19];
for(var j=0;j<_20.length;j++,i++){
var _21=_20[j];
var xv=parseFloat(_21[0]);
var yv=parseFloat(_21[1]);
if(xv==this.points[i].xval&&yv==this.points[i].yval){
this.points[i].errorMinus=parseFloat(_21[2]);
this.points[i].errorPlus=parseFloat(_21[3]);
}
}
}
};
DygraphLayout.prototype.removeAllDatasets=function(){
delete this.datasets;
this.datasets=new Array();
};
DygraphLayout.prototype.updateOptions=function(_24){
Dygraph.update(this.options,_24?_24:{});
};
DygraphCanvasRenderer=function(_25,_26,_27,_28){
this.dygraph_=_25;
this.options={"strokeWidth":0.5,"drawXAxis":true,"drawYAxis":true,"axisLineColor":"black","axisLineWidth":0.5,"axisTickSize":3,"axisLabelColor":"black","axisLabelFont":"Arial","axisLabelFontSize":9,"axisLabelWidth":50,"drawYGrid":true,"drawXGrid":true,"gridLineColor":"rgb(128,128,128)"};
Dygraph.update(this.options,_28);
this.layout=_27;
this.element=_26;
this.container=this.element.parentNode;
this.height=this.element.height;
this.width=this.element.width;
if(!this.isIE&&!(DygraphCanvasRenderer.isSupported(this.element))){
throw "Canvas is not supported.";
}
this.xlabels=new Array();
this.ylabels=new Array();
this.area={x:this.options.yAxisLabelWidth+2*this.options.axisTickSize,y:0};
this.area.w=this.width-this.area.x-this.options.rightGap;
this.area.h=this.height-this.options.axisLabelFontSize-2*this.options.axisTickSize;
this.container.style.position="relative";
this.container.style.width=this.width+"px";
};
DygraphCanvasRenderer.prototype.clear=function(){
if(this.isIE){
try{
if(this.clearDelay){
this.clearDelay.cancel();
this.clearDelay=null;
}
var _29=this.element.getContext("2d");
}
catch(e){
this.clearDelay=MochiKit.Async.wait(this.IEDelay);
this.clearDelay.addCallback(bind(this.clear,this));
return;
}
}
var _29=this.element.getContext("2d");
_29.clearRect(0,0,this.width,this.height);
for(var i=0;i<this.xlabels.length;i++){
var el=this.xlabels[i];
el.parentNode.removeChild(el);
}
for(var i=0;i<this.ylabels.length;i++){
var el=this.ylabels[i];
el.parentNode.removeChild(el);
}
this.xlabels=new Array();
this.ylabels=new Array();
};
DygraphCanvasRenderer.isSupported=function(_31){
var _32=null;
try{
if(typeof (_31)=="undefined"||_31==null){
_32=document.createElement("canvas");
}else{
_32=_31;
}
var _33=_32.getContext("2d");
}
catch(e){
var ie=navigator.appVersion.match(/MSIE (\d\.\d)/);
var _35=(navigator.userAgent.toLowerCase().indexOf("opera")!=-1);
if((!ie)||(ie[1]<6)||(_35)){
return false;
}
return true;
}
return true;
};
DygraphCanvasRenderer.prototype.render=function(){
var ctx=this.element.getContext("2d");
if(this.options.drawYGrid){
var _37=this.layout.yticks;
ctx.save();
ctx.strokeStyle=this.options.gridLineColor;
ctx.lineWidth=this.options.axisLineWidth;
for(var i=0;i<_37.length;i++){
var x=this.area.x;
var y=this.area.y+_37[i][0]*this.area.h;
ctx.beginPath();
ctx.moveTo(x,y);
ctx.lineTo(x+this.area.w,y);
ctx.closePath();
ctx.stroke();
}
}
if(this.options.drawXGrid){
var _37=this.layout.xticks;
ctx.save();
ctx.strokeStyle=this.options.gridLineColor;
ctx.lineWidth=this.options.axisLineWidth;
for(var i=0;i<_37.length;i++){
var x=this.area.x+_37[i][0]*this.area.w;
var y=this.area.y+this.area.h;
ctx.beginPath();
ctx.moveTo(x,y);
ctx.lineTo(x,this.area.y);
ctx.closePath();
ctx.stroke();
}
}
this._renderLineChart();
this._renderAxis();
};
DygraphCanvasRenderer.prototype._renderAxis=function(){
if(!this.options.drawXAxis&&!this.options.drawYAxis){
return;
}
var _40=this.element.getContext("2d");
var _41={"position":"absolute","fontSize":this.options.axisLabelFontSize+"px","zIndex":10,"color":this.options.axisLabelColor,"width":this.options.axisLabelWidth+"px","overflow":"hidden"};
var _42=function(txt){
var div=document.createElement("div");
for(var _45 in _41){
div.style[_45]=_41[_45];
}
div.appendChild(document.createTextNode(txt));
return div;
};
_40.save();
_40.strokeStyle=this.options.axisLineColor;
_40.lineWidth=this.options.axisLineWidth;
if(this.options.drawYAxis){
if(this.layout.yticks){
for(var i=0;i<this.layout.yticks.length;i++){
var _46=this.layout.yticks[i];
if(typeof (_46)=="function"){
return;
}
var x=this.area.x;
var y=this.area.y+_46[0]*this.area.h;
_40.beginPath();
_40.moveTo(x,y);
_40.lineTo(x-this.options.axisTickSize,y);
_40.closePath();
_40.stroke();
var _47=_42(_46[1]);
var top=(y-this.options.axisLabelFontSize/2);
if(top<0){
top=0;
}
if(top+this.options.axisLabelFontSize+3>this.height){
_47.style.bottom="0px";
}else{
_47.style.top=top+"px";
}
_47.style.left="0px";
_47.style.textAlign="right";
_47.style.width=this.options.yAxisLabelWidth+"px";
this.container.appendChild(_47);
this.ylabels.push(_47);
}
var _49=this.ylabels[0];
var _50=this.options.axisLabelFontSize;
var _51=parseInt(_49.style.top)+_50;
if(_51>this.height-_50){
_49.style.top=(parseInt(_49.style.top)-_50/2)+"px";
}
}
_40.beginPath();
_40.moveTo(this.area.x,this.area.y);
_40.lineTo(this.area.x,this.area.y+this.area.h);
_40.closePath();
_40.stroke();
}
if(this.options.drawXAxis){
if(this.layout.xticks){
for(var i=0;i<this.layout.xticks.length;i++){
var _46=this.layout.xticks[i];
if(typeof (dataset)=="function"){
return;
}
var x=this.area.x+_46[0]*this.area.w;
var y=this.area.y+this.area.h;
_40.beginPath();
_40.moveTo(x,y);
_40.lineTo(x,y+this.options.axisTickSize);
_40.closePath();
_40.stroke();
var _47=_42(_46[1]);
_47.style.textAlign="center";
_47.style.bottom="0px";
var _52=(x-this.options.axisLabelWidth/2);
if(_52+this.options.axisLabelWidth>this.width){
_52=this.width-this.options.xAxisLabelWidth;
_47.style.textAlign="right";
}
if(_52<0){
_52=0;
_47.style.textAlign="left";
}
_47.style.left=_52+"px";
_47.style.width=this.options.xAxisLabelWidth+"px";
this.container.appendChild(_47);
this.xlabels.push(_47);
}
}
_40.beginPath();
_40.moveTo(this.area.x,this.area.y+this.area.h);
_40.lineTo(this.area.x+this.area.w,this.area.y+this.area.h);
_40.closePath();
_40.stroke();
}
_40.restore();
};
DygraphCanvasRenderer.prototype._renderLineChart=function(){
var _53=this.element.getContext("2d");
var _54=this.options.colorScheme.length;
var _55=this.options.colorScheme;
var _56=this.layout.options.errorBars;
var _57=[];
for(var _58 in this.layout.datasets){
_57.push(_58);
}
var _59=_57.length;
for(var i=0;i<this.layout.points.length;i++){
var _60=this.layout.points[i];
_60.canvasx=this.area.w*_60.x+this.area.x;
_60.canvasy=this.area.h*_60.y+this.area.y;
}
var _61=function(x){
return x&&!isNaN(x);
};
var ctx=_53;
if(_56){
for(var i=0;i<_59;i++){
var _62=_57[i];
var _63=_55[i%_54];
ctx.save();
ctx.strokeStyle=_63;
ctx.lineWidth=this.options.strokeWidth;
var _64=-1;
var _65=[-1,-1];
var _66=0;
var _67=this.layout.yscale;
var rgb=new RGBColor(_63);
var _69="rgba("+rgb.r+","+rgb.g+","+rgb.b+",0.15)";
ctx.fillStyle=_69;
ctx.beginPath();
for(var j=0;j<this.layout.points.length;j++){
var _60=this.layout.points[j];
_66++;
if(_60.name==_62){
if(!_60.y||isNaN(_60.y)){
_64=-1;
continue;
}
var _70=[_60.y-_60.errorPlus*_67,_60.y+_60.errorMinus*_67];
_70[0]=this.area.h*_70[0]+this.area.y;
_70[1]=this.area.h*_70[1]+this.area.y;
if(_64>=0){
ctx.moveTo(_64,_65[0]);
ctx.lineTo(_60.canvasx,_70[0]);
ctx.lineTo(_60.canvasx,_70[1]);
ctx.lineTo(_64,_65[1]);
ctx.closePath();
}
_65[0]=_70[0];
_65[1]=_70[1];
_64=_60.canvasx;
}
}
ctx.fill();
}
}
for(var i=0;i<_59;i++){
var _62=_57[i];
var _63=_55[i%_54];
_53.save();
var _60=this.layout.points[0];
var _71=this.dygraph_.attr_("pointSize");
var _64=null,prevY=null;
var _72=this.dygraph_.attr_("drawPoints");
var _73=this.layout.points;
for(var j=0;j<_73.length;j++){
var _60=_73[j];
if(_60.name==_62){
if(!_61(_60.canvasy)){
_64=prevY=null;
}else{
var _74=(!_64&&(j==_73.length-1||!_61(_73[j+1].canvasy)));
if(!_64){
_64=_60.canvasx;
prevY=_60.canvasy;
}else{
ctx.beginPath();
ctx.strokeStyle=_63;
ctx.lineWidth=this.options.strokeWidth;
ctx.moveTo(_64,prevY);
_64=_60.canvasx;
prevY=_60.canvasy;
ctx.lineTo(_64,prevY);
ctx.stroke();
}
if(_72||_74){
ctx.beginPath();
ctx.fillStyle=_63;
ctx.arc(_60.canvasx,_60.canvasy,_71,0,2*Math.PI,false);
ctx.fill();
}
}
}
}
}
_53.restore();
};
Dygraph=function(div,_75,_76){
if(arguments.length>0){
if(arguments.length==4){
this.warn("Using deprecated four-argument dygraph constructor");
this.__old_init__(div,_75,arguments[2],arguments[3]);
}else{
this.__init__(div,_75,_76);
}
}
};
Dygraph.NAME="Dygraph";
Dygraph.VERSION="1.2";
Dygraph.__repr__=function(){
return "["+this.NAME+" "+this.VERSION+"]";
};
Dygraph.toString=function(){
return this.__repr__();
};
Dygraph.DEFAULT_ROLL_PERIOD=1;
Dygraph.DEFAULT_WIDTH=480;
Dygraph.DEFAULT_HEIGHT=320;
Dygraph.AXIS_LINE_WIDTH=0.3;
Dygraph.DEFAULT_ATTRS={highlightCircleSize:3,pixelsPerXLabel:60,pixelsPerYLabel:30,labelsDivWidth:250,labelsDivStyles:{},labelsSeparateLines:false,labelsKMB:false,strokeWidth:1,axisTickSize:3,axisLabelFontSize:14,xAxisLabelWidth:50,yAxisLabelWidth:50,rightGap:5,showRoller:false,xValueFormatter:Dygraph.dateString_,xValueParser:Dygraph.dateParser,xTicker:Dygraph.dateTicker,delimiter:",",sigma:2,errorBars:false,fractions:false,wilsonInterval:true,customBars:false};
Dygraph.DEBUG=1;
Dygraph.INFO=2;
Dygraph.WARNING=3;
Dygraph.ERROR=3;
Dygraph.prototype.__old_init__=function(div,_77,_78,_79){
if(_78!=null){
var _80=["Date"];
for(var i=0;i<_78.length;i++){
_80.push(_78[i]);
}
Dygraph.update(_79,{"labels":_80});
}
this.__init__(div,_77,_79);
};
Dygraph.prototype.__init__=function(div,_81,_82){
if(_82==null){
_82={};
}
this.maindiv_=div;
this.file_=_81;
this.rollPeriod_=_82.rollPeriod||Dygraph.DEFAULT_ROLL_PERIOD;
this.previousVerticalX_=-1;
this.fractions_=_82.fractions||false;
this.dateWindow_=_82.dateWindow||null;
this.valueRange_=_82.valueRange||null;
this.wilsonInterval_=_82.wilsonInterval||true;
div.innerHTML="";
if(div.style.width==""){
div.style.width=Dygraph.DEFAULT_WIDTH+"px";
}
if(div.style.height==""){
div.style.height=Dygraph.DEFAULT_HEIGHT+"px";
}
this.width_=parseInt(div.style.width,10);
this.height_=parseInt(div.style.height,10);
this.user_attrs_={};
Dygraph.update(this.user_attrs_,_82);
this.attrs_={};
Dygraph.update(this.attrs_,Dygraph.DEFAULT_ATTRS);
this.labelsFromCSV_=(this.attr_("labels")==null);
this.createInterface_();
this.layoutOptions_={"xOriginIsZero":false};
Dygraph.update(this.layoutOptions_,this.attrs_);
Dygraph.update(this.layoutOptions_,this.user_attrs_);
Dygraph.update(this.layoutOptions_,{"errorBars":(this.attr_("errorBars")||this.attr_("customBars"))});
this.layout_=new DygraphLayout(this,this.layoutOptions_);
this.renderOptions_={colorScheme:this.colors_,strokeColor:null,axisLineWidth:Dygraph.AXIS_LINE_WIDTH};
Dygraph.update(this.renderOptions_,this.attrs_);
Dygraph.update(this.renderOptions_,this.user_attrs_);
this.plotter_=new DygraphCanvasRenderer(this,this.hidden_,this.layout_,this.renderOptions_);
this.createStatusMessage_();
this.createRollInterface_();
this.createDragInterface_();
this.start_();
};
Dygraph.prototype.attr_=function(_83){
if(typeof (this.user_attrs_[_83])!="undefined"){
return this.user_attrs_[_83];
}else{
if(typeof (this.attrs_[_83])!="undefined"){
return this.attrs_[_83];
}else{
return null;
}
}
};
Dygraph.prototype.log=function(_84,_85){
if(typeof (console)!="undefined"){
switch(_84){
case Dygraph.DEBUG:
console.debug("dygraphs: "+_85);
break;
case Dygraph.INFO:
console.info("dygraphs: "+_85);
break;
case Dygraph.WARNING:
console.warn("dygraphs: "+_85);
break;
case Dygraph.ERROR:
console.error("dygraphs: "+_85);
break;
}
}
};
Dygraph.prototype.info=function(_86){
this.log(Dygraph.INFO,_86);
};
Dygraph.prototype.warn=function(_87){
this.log(Dygraph.WARNING,_87);
};
Dygraph.prototype.error=function(_88){
this.log(Dygraph.ERROR,_88);
};
Dygraph.prototype.rollPeriod=function(){
return this.rollPeriod_;
};
Dygraph.addEvent=function(el,evt,fn){
var _91=function(e){
if(!e){
var e=window.event;
}
fn(e);
};
if(window.addEventListener){
el.addEventListener(evt,_91,false);
}else{
el.attachEvent("on"+evt,_91);
}
};
Dygraph.prototype.createInterface_=function(){
var _93=this.maindiv_;
this.graphDiv=document.createElement("div");
this.graphDiv.style.width=this.width_+"px";
this.graphDiv.style.height=this.height_+"px";
_93.appendChild(this.graphDiv);


this.canvas_=Dygraph.createCanvas();
this.canvas_.style.position="absolute";
this.canvas_.width=this.width_;
this.canvas_.height=this.height_;
this.canvas_.style.width=this.width_+"px";
this.canvas_.style.height=this.height_+"px";
this.graphDiv.appendChild(this.canvas_);

this.canvas2_=Dygraph.createCanvas();
this.canvas2_.style.position="absolute";
this.canvas2_.width=this.width_;
this.canvas2_.height=this.height_;
this.canvas2_.style.width=this.width_+"px";
this.canvas2_.style.height=this.height_+"px";
this.graphDiv.appendChild(this.canvas2_);







this.hidden_=this.createPlotKitCanvas_(this.canvas_);
var _94=this;
Dygraph.addEvent(this.hidden_,"mousemove",function(e){
_94.mouseMove_(e);
});
Dygraph.addEvent(this.hidden_,"mouseout",function(e){
_94.mouseOut_(e);
});
};
Dygraph.prototype.createPlotKitCanvas_=function(_95){
var h=Dygraph.createCanvas();
h.style.position="absolute";
h.style.top=_95.style.top;
h.style.left=_95.style.left;
h.width=this.width_;
h.height=this.height_;
h.style.width=this.width_+"px";
h.style.height=this.height_+"px";
this.graphDiv.appendChild(h);
return h;
};
Dygraph.hsvToRGB=function(hue,_98,_99){
var red;
var _101;
var blue;
if(_98===0){
red=_99;
_101=_99;
blue=_99;
}else{
var i=Math.floor(hue*6);
var f=(hue*6)-i;
var p=_99*(1-_98);
var q=_99*(1-(_98*f));
var t=_99*(1-(_98*(1-f)));
switch(i){
case 1:
red=q;
_101=_99;
blue=p;
break;
case 2:
red=p;
_101=_99;
blue=t;
break;
case 3:
red=p;
_101=q;
blue=_99;
break;
case 4:
red=t;
_101=p;
blue=_99;
break;
case 5:
red=_99;
_101=p;
blue=q;
break;
case 6:
case 0:
red=_99;
_101=t;
blue=p;
break;
}
}
red=Math.floor(255*red+0.5);
_101=Math.floor(255*_101+0.5);
blue=Math.floor(255*blue+0.5);
return "rgb("+red+","+_101+","+blue+")";
};
Dygraph.prototype.setColors_=function(){
var num=this.attr_("labels").length-1;
this.colors_=[];
var _108=this.attr_("colors");
if(!_108){
var sat=this.attr_("colorSaturation")||1;
var val=this.attr_("colorValue")||0.5;
for(var i=1;i<=num;i++){
var hue=(1*i/(1+num));
this.colors_.push(Dygraph.hsvToRGB(hue,sat,val));
}
}else{
for(var i=0;i<num;i++){
var _111=_108[i%_108.length];
this.colors_.push(_111);
}
}
this.renderOptions_.colorScheme=this.colors_;
Dygraph.update(this.plotter_.options,this.renderOptions_);
Dygraph.update(this.layoutOptions_,this.user_attrs_);
Dygraph.update(this.layoutOptions_,this.attrs_);
};
Dygraph.findPosX=function(obj){
var _113=0;
if(obj.offsetParent){
while(obj.offsetParent){
_113+=obj.offsetLeft;
obj=obj.offsetParent;
}
}else{
if(obj.x){
_113+=obj.x;
}
}
return _113;
};
Dygraph.findPosY=function(obj){
var _114=0;
if(obj.offsetParent){
while(obj.offsetParent){
_114+=obj.offsetTop;
obj=obj.offsetParent;
}
}else{
if(obj.y){
_114+=obj.y;
}
}
return _114;
};
Dygraph.prototype.createStatusMessage_=function(){
if(!this.attr_("labelsDiv")){
var _115=this.attr_("labelsDivWidth");
var _116={"position":"absolute","fontSize":"14px","zIndex":10,"width":_115+"px","top":"0px","left":(this.width_-_115-2)+"px","background":"white","textAlign":"left","overflow":"hidden"};
Dygraph.update(_116,this.attr_("labelsDivStyles"));
var div=document.createElement("div");
for(var name in _116){
div.style[name]=_116[name];
}
this.graphDiv.appendChild(div);
this.attrs_.labelsDiv=div;
}
};
Dygraph.prototype.createRollInterface_=function(){
var _118=this.attr_("showRoller")?"block":"none";
var _119={"position":"absolute","zIndex":10,"top":(this.plotter_.area.h-25)+"px","left":(this.plotter_.area.x+1)+"px","display":_118};
var _120=document.createElement("input");
_120.type="text";
_120.size="2";
_120.value=this.rollPeriod_;
for(var name in _119){
_120.style[name]=_119[name];
}
var pa=this.graphDiv;
pa.appendChild(_120);
var _122=this;
_120.onchange=function(){
_122.adjustRoll(_120.value);
};
return _120;
};
Dygraph.pageX=function(e){
if(e.pageX){
return (!e.pageX||e.pageX<0)?0:e.pageX;
}else{
var de=document;
var b=document.body;
return e.clientX+(de.scrollLeft||b.scrollLeft)-(de.clientLeft||0);
}
};
Dygraph.pageY=function(e){
if(e.pageY){
return (!e.pageY||e.pageY<0)?0:e.pageY;
}else{
var de=document;
var b=document.body;
return e.clientY+(de.scrollTop||b.scrollTop)-(de.clientTop||0);
}
};
Dygraph.prototype.createDragInterface_=function(){
var self=this;
var _126=false;
var _127=null;
var _128=null;
var _129=null;
var _130=null;
var _131=null;
var px=0;
var py=0;
var getX=function(e){
return Dygraph.pageX(e)-px;
};
var getY=function(e){
return Dygraph.pageX(e)-py;
};
Dygraph.addEvent(this.hidden_,"mousemove",function(_136){
if(_126){
_129=getX(_136);
_130=getY(_136);
self.drawZoomRect_(_127,_129,_131);
_131=_129;
}
});
Dygraph.addEvent(this.hidden_,"mousedown",function(_137){
_126=true;
px=Dygraph.findPosX(self.canvas_);
py=Dygraph.findPosY(self.canvas_);
_127=getX(_137);
_128=getY(_137);
});
Dygraph.addEvent(document,"mouseup",function(_138){
if(_126){
_126=false;
_127=null;
_128=null;
}
});
Dygraph.addEvent(this.hidden_,"mouseout",function(_139){
if(_126){
_129=null;
_130=null;
}
});
Dygraph.addEvent(this.hidden_,"mouseup",function(_140){
if(_126){
_126=false;
_129=getX(_140);
_130=getY(_140);
var _141=Math.abs(_129-_127);
var _142=Math.abs(_130-_128);
if(_141<2&&_142<2&&self.attr_("clickCallback")!=null&&self.lastx_!=undefined){
self.attr_("clickCallback")(_140,self.lastx_,self.selPoints_);
}
if(_141>=10){
self.doZoom_(Math.min(_127,_129),Math.max(_127,_129));
}else{
self.canvas_.getContext("2d").clearRect(0,0,self.canvas_.width,self.canvas_.height);
}
_127=null;
_128=null;
}
});
Dygraph.addEvent(this.hidden_,"dblclick",function(_143){
if(self.dateWindow_==null){
return;
}
self.dateWindow_=null;
self.drawGraph_(self.rawData_);
var _144=self.rawData_[0][0];
var _145=self.rawData_[self.rawData_.length-1][0];
if(self.attr_("zoomCallback")){
self.attr_("zoomCallback")(_144,_145);
}
});
};
Dygraph.prototype.drawZoomRect_=function(_146,endX,_148){
var ctx=this.canvas_.getContext("2d");
if(_148){
ctx.clearRect(Math.min(_146,_148),0,Math.abs(_146-_148),this.height_);
}
if(endX&&_146){
ctx.fillStyle="rgba(128,128,128,0.33)";
ctx.fillRect(Math.min(_146,endX),0,Math.abs(endX-_146),this.height_);
}
};
Dygraph.prototype.doZoom_=function(lowX,_150){
var _151=this.layout_.points;
var _152=null;
var _153=null;
for(var i=0;i<_151.length;i++){
var cx=_151[i].canvasx;
var x=_151[i].xval;
if(cx<lowX&&(_152==null||x>_152)){
_152=x;
}
if(cx>_150&&(_153==null||x<_153)){
_153=x;
}
}
if(_152==null){
_152=_151[0].xval;
}
if(_153==null){
_153=_151[_151.length-1].xval;
}

if(this.attr_("zoomCallback")) this.attr_("zoomCallback")(_152,_153,lowX,_150);
else this.doZoomActual_(_152,_153);
};


Dygraph.prototype.doZoomActual_ = function(zoomStart,zoomEnd){
	this.dateWindow_=[zoomStart,zoomEnd];
	this.drawGraph_(this.rawData_);
};

Dygraph.prototype.mouseMove_=function(_155){
var _156=Dygraph.pageX(_155)-Dygraph.findPosX(this.hidden_);
var _157=this.layout_.points;
var _158=-1;
var _159=-1;
var _160=1e+100;
var idx=-1;
for(var i=0;i<_157.length;i++){
var dist=Math.abs(_157[i].canvasx-_156);
if(dist>_160){
break;
}
_160=dist;
idx=i;
}
if(idx>=0){
_158=_157[idx].xval;
}
if(_156>_157[_157.length-1].canvasx){
_158=_157[_157.length-1].xval;
}
this.selPoints_=[];
for(var i=0;i<_157.length;i++){
if(_157[i].xval==_158){
this.selPoints_.push(_157[i]);
}
}
if(this.attr_("highlightCallback")){
this.attr_("highlightCallback")(_155,_158,this.selPoints_);
}
var _163=this.attr_("highlightCircleSize");
var ctx=this.canvas_.getContext("2d");
if(this.previousVerticalX_>=0){
var px=this.previousVerticalX_;
ctx.clearRect(px-_163-1,0,2*_163+2,this.height_);
}
var isOK=function(x){
return x&&!isNaN(x);
};
if(this.selPoints_.length>0){
var _156=this.selPoints_[0].canvasx;
var _165=this.attr_("xValueFormatter")(_158,this)+":";
var clen=this.colors_.length;
for(var i=0;i<this.selPoints_.length;i++){
if(!isOK(this.selPoints_[i].canvasy)){
continue;
}
if(this.attr_("labelsSeparateLines")){
_165+="<br/>";
}
var _167=this.selPoints_[i];
var c=new RGBColor(this.colors_[i%clen]);
_165+=" <b><font color='"+c.toHex()+"'>"+_167.name+"</font></b>:"+this.round_(_167.yval,2);
}
this.attr_("labelsDiv").innerHTML=_165;
this.lastx_=_158;
ctx.save();
for(var i=0;i<this.selPoints_.length;i++){
if(!isOK(this.selPoints_[i%clen].canvasy)){
continue;
}
ctx.beginPath();
ctx.fillStyle=this.colors_[i%clen];
ctx.arc(_156,this.selPoints_[i%clen].canvasy,_163,0,2*Math.PI,false);
ctx.fill();
}
ctx.restore();
this.previousVerticalX_=_156;
}
};
Dygraph.prototype.mouseOut_=function(_169){
var ctx=this.canvas_.getContext("2d");
ctx.clearRect(0,0,this.width_,this.height_);
this.attr_("labelsDiv").innerHTML="";
};
Dygraph.zeropad=function(x){
if(x<10){
return "0"+x;
}else{
return ""+x;
}
};
Dygraph.prototype.hmsString_=function(date){
var _171=Dygraph.zeropad;
var d=new Date(date);
if(d.getSeconds()){
return _171(d.getHours())+":"+_171(d.getMinutes())+":"+_171(d.getSeconds());
}else{
if(d.getMinutes()){
return _171(d.getHours())+":"+_171(d.getMinutes());
}else{
return _171(d.getHours());
}
}
};
Dygraph.dateString_=function(date,self){
var _173=Dygraph.zeropad;
var d=new Date(date);
var year=""+d.getFullYear();
var _175=_173(d.getMonth()+1);
var day=_173(d.getDate());
var ret="";
var frac=d.getHours()*3600+d.getMinutes()*60+d.getSeconds();
if(frac){
ret=" "+self.hmsString_(date);
}
return year+"/"+_175+"/"+day+ret;
};
Dygraph.prototype.round_=function(num,_179){
var _180=Math.pow(10,_179);
return Math.round(num*_180)/_180;
};
Dygraph.prototype.loadedEvent_=function(data){
this.rawData_=this.parseCSV_(data);
this.drawGraph_(this.rawData_);
};
Dygraph.prototype.months=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
Dygraph.prototype.quarters=["Jan","Apr","Jul","Oct"];
Dygraph.prototype.addXTicks_=function(){
var _182,endDate;
if(this.dateWindow_){
_182=this.dateWindow_[0];
endDate=this.dateWindow_[1];
}else{
_182=this.rawData_[0][0];
endDate=this.rawData_[this.rawData_.length-1][0];
}
var _183=this.attr_("xTicker")(_182,endDate,this);
this.layout_.updateOptions({xTicks:_183});
};
Dygraph.SECONDLY=0;
Dygraph.TEN_SECONDLY=1;
Dygraph.THIRTY_SECONDLY=2;
Dygraph.MINUTELY=3;
Dygraph.TEN_MINUTELY=4;
Dygraph.THIRTY_MINUTELY=5;
Dygraph.HOURLY=6;
Dygraph.SIX_HOURLY=7;
Dygraph.DAILY=8;
Dygraph.WEEKLY=9;
Dygraph.MONTHLY=10;
Dygraph.QUARTERLY=11;
Dygraph.BIANNUAL=12;
Dygraph.ANNUAL=13;
Dygraph.LUSTRUM=14;
Dygraph.DECADAL=15;
Dygraph.NUM_GRANULARITIES=16;
Dygraph.SHORT_SPACINGS=[];
Dygraph.SHORT_SPACINGS[Dygraph.SECONDLY]=1000*1;
Dygraph.SHORT_SPACINGS[Dygraph.TEN_SECONDLY]=1000*10;
Dygraph.SHORT_SPACINGS[Dygraph.THIRTY_SECONDLY]=1000*30;
Dygraph.SHORT_SPACINGS[Dygraph.MINUTELY]=1000*60;
Dygraph.SHORT_SPACINGS[Dygraph.TEN_MINUTELY]=1000*60*10;
Dygraph.SHORT_SPACINGS[Dygraph.THIRTY_MINUTELY]=1000*60*30;
Dygraph.SHORT_SPACINGS[Dygraph.HOURLY]=1000*3600;
Dygraph.SHORT_SPACINGS[Dygraph.HOURLY]=1000*3600*6;
Dygraph.SHORT_SPACINGS[Dygraph.DAILY]=1000*86400;
Dygraph.SHORT_SPACINGS[Dygraph.WEEKLY]=1000*604800;
Dygraph.prototype.NumXTicks=function(_184,_185,_186){
if(_186<Dygraph.MONTHLY){
var _187=Dygraph.SHORT_SPACINGS[_186];
return Math.floor(0.5+1*(_185-_184)/_187);
}else{
var _188=1;
var _189=12;
if(_186==Dygraph.QUARTERLY){
_189=3;
}
if(_186==Dygraph.BIANNUAL){
_189=2;
}
if(_186==Dygraph.ANNUAL){
_189=1;
}
if(_186==Dygraph.LUSTRUM){
_189=1;
_188=5;
}
if(_186==Dygraph.DECADAL){
_189=1;
_188=10;
}
var _190=365.2524*24*3600*1000;
var _191=1*(_185-_184)/_190;
return Math.floor(0.5+1*_191*_189/_188);
}
};
Dygraph.prototype.GetXAxis=function(_192,_193,_194){
var _195=[];
if(_194<Dygraph.MONTHLY){
var _196=Dygraph.SHORT_SPACINGS[_194];
var _197="%d%b";
if(_194<Dygraph.HOURLY){
_192=_196*Math.floor(0.5+_192/_196);
}
for(var t=_192;t<=_193;t+=_196){
var d=new Date(t);
var frac=d.getHours()*3600+d.getMinutes()*60+d.getSeconds();
if(frac==0||_194>=Dygraph.DAILY){
_195.push({v:t,label:new Date(t+3600*1000).strftime(_197)});
}else{
_195.push({v:t,label:this.hmsString_(t)});
}
}
}else{
var _198;
var _199=1;
if (_194 == Dygraph.MONTHLY) {
	_198 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
}
else {
if (_194 == Dygraph.QUARTERLY) {
_198 = [0, 3, 6, 9];
}
else {
if (_194 == Dygraph.BIANNUAL) {
_198 = [0, 6];
}
else {
if (_194 == Dygraph.ANNUAL) {
_198 = [0];
}
else {
if (_194 == Dygraph.LUSTRUM) {
_198 = [0];
_199 = 5;
}
else {
if (_194 == Dygraph.DECADAL) {
_198 = [0];
_199 = 10;
}
}
}
}
}
}
var _200=new Date(_192).getFullYear();
var _201=new Date(_193).getFullYear();
var _202=Dygraph.zeropad;
for(var i=_200;i<=_201;i++){
if(i%_199!=0){
continue;
}
for(var j=0;j<_198.length;j++){
var _203=i+"/"+_202(1+_198[j])+"/01";
var t=Date.parse(_203);
if(t<_192||t>_193){
continue;
}
_195.push({v:t,label:rmtrailingzero(new Date(t).strftime("%m/%Y"))});
}
}
}
return _195;
};
Dygraph.dateTicker=function(_204,_205,self){
var _206=-1;
for(var i=0;i<Dygraph.NUM_GRANULARITIES;i++){
var _207=self.NumXTicks(_204,_205,i);
if(self.width_/_207>=self.attr_("pixelsPerXLabel")){
_206=i;
break;
}
}
if(_206>=0){
return self.GetXAxis(_204,_205,_206);
}else{
}
};
Dygraph.numericTicks=function(minV,maxV,self){
var _210=[1,2,5];
var _211,low_val,high_val,nTicks;
var _212=self.attr_("pixelsPerYLabel");
for(var i=-10;i<50;i++){
var _213=Math.pow(10,i);
for(var j=0;j<_210.length;j++){
_211=_213*_210[j];
low_val=Math.floor(minV/_211)*_211;
high_val=Math.ceil(maxV/_211)*_211;
nTicks=(high_val-low_val)/_211;
var _214=self.height_/nTicks;
if(_214>_212){
break;
}
}
if(_214>_212){
break;
}
}
var _215=[];
for(var i=0;i<nTicks;i++){
var _216=low_val+i*_211;
var _217=self.round_(_216,2);
if(self.attr_("labelsKMB")){
var k=1000;
if(_216>=k*k*k){
_217=self.round_(_216/(k*k*k),1)+"B";
}else{
if(_216>=k*k){
_217=self.round_(_216/(k*k),1)+"M";
}else{
if(_216>=k){
_217=self.round_(_216/k,1)+"K";
}
}
}
}
if (self.attr_("labelsMeasureUnit"))_217 += self.attr_("labelsMeasureUnit");
_215.push({label:_217,v:_216});
}
return _215;
};
Dygraph.prototype.addYTicks_=function(minY,maxY){
var _221=Dygraph.numericTicks(minY,maxY,this);
this.layout_.updateOptions({yAxis:[minY,maxY],yTicks:_221});
};
Dygraph.prototype.extremeValues_=function(_222){
var minY=null,maxY=null;
var bars=this.attr_("errorBars")||this.attr_("customBars");
if(bars){
for(var j=0;j<_222.length;j++){
var y=_222[j][1][0];
if(!y){
continue;
}
var low=y-_222[j][1][1];
var high=y+_222[j][1][2];
if(low>y){
low=y;
}
if(high<y){
high=y;
}
if(maxY==null||high>maxY){
maxY=high;
}
if(minY==null||low<minY){
minY=low;
}
}
}else{
for(var j=0;j<_222.length;j++){
var y=_222[j][1];
if(!y){
continue;
}
if(maxY==null||y>maxY){
maxY=y;
}
if(minY==null||y<minY){
minY=y;
}
}
}
return [minY,maxY];
};
Dygraph.prototype.drawGraph_=function(data){
var minY=null,maxY=null;
this.layout_.removeAllDatasets();
this.setColors_();
this.attrs_["pointSize"]=0.5*this.attr_("highlightCircleSize");
for(var i=1;i<data[0].length;i++){
var _226=[];
for(var j=0;j<data.length;j++){
var date=data[j][0];
_226[j]=[date,data[j][i]];
}
_226=this.rollingAverage(_226,this.rollPeriod_);
var bars=this.attr_("errorBars")||this.attr_("customBars");
if(this.dateWindow_){
var low=this.dateWindow_[0];
var high=this.dateWindow_[1];
var _227=[];
for(var k=0;k<_226.length;k++){
if(_226[k][0]>=low&&_226[k][0]<=high){
_227.push(_226[k]);
}
}
_226=_227;
}
var _228=this.extremeValues_(_226);
var _229=_228[0];
var _230=_228[1];
if(!minY||_229<minY){
minY=_229;
}
if(!maxY||_230>maxY){
maxY=_230;
}
if(bars){
var vals=[];
for(var j=0;j<_226.length;j++){
vals[j]=[_226[j][0],_226[j][1][0],_226[j][1][1],_226[j][1][2]];
}
this.layout_.addDataset(this.attr_("labels")[i],vals);
}else{
this.layout_.addDataset(this.attr_("labels")[i],_226);
}
}
if(this.valueRange_!=null){
this.addYTicks_(this.valueRange_[0],this.valueRange_[1]);
}else{
var span=maxY-minY;
var _233=maxY+0.1*span;
var _234=minY-0.1*span;
if(_234<0&&minY>=0){
_234=0;
}
if(_233>0&&maxY<=0){
_233=0;
}
if(this.attr_("includeZero")){
if(maxY<0){
_233=0;
}
if(minY>0){
_234=0;
}
}
this.addYTicks_(_234,_233);
}
this.addXTicks_();
this.layout_.evaluateWithError();
this.plotter_.clear();
this.plotter_.render();
this.canvas_.getContext("2d").clearRect(0,0,this.canvas_.width,this.canvas_.height);
};
Dygraph.prototype.rollingAverage=function(_235,_236){
if(_235.length<2){
return _235;
}
var _236=Math.min(_236,_235.length-1);
var _237=[];
var _238=this.attr_("sigma");
if(this.fractions_){
var num=0;
var den=0;
var mult=100;
for(var i=0;i<_235.length;i++){
num+=_235[i][1][0];
den+=_235[i][1][1];
if(i-_236>=0){
num-=_235[i-_236][1][0];
den-=_235[i-_236][1][1];
}
var date=_235[i][0];
var _241=den?num/den:0;
if(this.attr_("errorBars")){
if(this.wilsonInterval_){
if(den){
var p=_241<0?0:_241,n=den;
var pm=_238*Math.sqrt(p*(1-p)/n+_238*_238/(4*n*n));
var _243=1+_238*_238/den;
var low=(p+_238*_238/(2*den)-pm)/_243;
var high=(p+_238*_238/(2*den)+pm)/_243;
_237[i]=[date,[p*mult,(p-low)*mult,(high-p)*mult]];
}else{
_237[i]=[date,[0,0,0]];
}
}else{
var _244=den?_238*Math.sqrt(_241*(1-_241)/den):1;
_237[i]=[date,[mult*_241,mult*_244,mult*_244]];
}
}else{
_237[i]=[date,mult*_241];
}
}
}else{
if(this.attr_("customBars")){
var low=0;
var mid=0;
var high=0;
var _246=0;
for(var i=0;i<_235.length;i++){
var data=_235[i][1];
var y=data[1];
_237[i]=[_235[i][0],[y,y-data[0],data[2]-y]];
if(y&&!isNaN(y)){
low+=data[0];
mid+=y;
high+=data[2];
_246+=1;
}
if(i-_236>=0){
var prev=_235[i-_236];
if(prev[1][1]&&!isNaN(prev[1][1])){
low-=prev[1][0];
mid-=prev[1][1];
high-=prev[1][2];
_246-=1;
}
}
_237[i]=[_235[i][0],[1*mid/_246,1*(mid-low)/_246,1*(high-mid)/_246]];
}
}else{
var _248=Math.min(_236-1,_235.length-2);
if(!this.attr_("errorBars")){
if(_236==1){
return _235;
}
for(var i=0;i<_235.length;i++){
var sum=0;
var _250=0;
for(var j=Math.max(0,i-_236+1);j<i+1;j++){
var y=_235[j][1];
if(!y||isNaN(y)){
continue;
}
_250++;
sum+=_235[j][1];
}
if(_250){
_237[i]=[_235[i][0],sum/_250];
}else{
_237[i]=[_235[i][0],null];
}
}
}else{
for(var i=0;i<_235.length;i++){
var sum=0;
var _251=0;
var _250=0;
for(var j=Math.max(0,i-_236+1);j<i+1;j++){
var y=_235[j][1][0];
if(!y||isNaN(y)){
continue;
}
_250++;
sum+=_235[j][1][0];
_251+=Math.pow(_235[j][1][1],2);
}
if(_250){
var _244=Math.sqrt(_251)/_250;
_237[i]=[_235[i][0],[sum/_250,_238*_244,_238*_244]];
}else{
_237[i]=[_235[i][0],[null,null,null]];
}
}
}
}
}
return _237;
};
Dygraph.dateParser=function(_252,self){
var _253;
var d;
if(_252.length==10&&_252.search("-")!=-1){
_253=_252.replace("-","/","g");
while(_253.search("-")!=-1){
_253=_253.replace("-","/");
}
d=Date.parse(_253);
}else{
if(_252.length==8){
_253=_252.substr(0,4)+"/"+_252.substr(4,2)+"/"+_252.substr(6,2);
d=Date.parse(_253);
}else{
d=Date.parse(_252);
}
}
if(!d||isNaN(d)){
self.error("Couldn't parse "+_252+" as a date");
}
return d;
};
Dygraph.prototype.detectTypeFromString_=function(str){
var _255=false;
if(str.indexOf("-")>=0||str.indexOf("/")>=0||isNaN(parseFloat(str))){
_255=true;
}else{
if(str.length==8&&str>"19700101"&&str<"20371231"){
_255=true;
}
}
if(_255){
this.attrs_.xValueFormatter=Dygraph.dateString_;
this.attrs_.xValueParser=Dygraph.dateParser;
this.attrs_.xTicker=Dygraph.dateTicker;
}else{
this.attrs_.xValueFormatter=function(x){
return x;
};
this.attrs_.xValueParser=function(x){
return parseFloat(x);
};
this.attrs_.xTicker=Dygraph.numericTicks;
}
};
Dygraph.prototype.parseCSV_=function(data){
var ret=[];
var _256=data.split("\n");
var _257=this.attr_("delimiter");
if(_256[0].indexOf(_257)==-1&&_256[0].indexOf("\t")>=0){
_257="\t";
}
var _258=0;
if(this.labelsFromCSV_){
_258=1;
this.attrs_.labels=_256[0].split(_257);
}
var _259;
var _260=false;
var _261=this.attr_("labels").length;
for(var i=_258;i<_256.length;i++){
var line=_256[i];
if(line.length==0){
continue;
}
if(line[0]=="#"){
continue;
}
var _263=line.split(_257);
if(_263.length<2){
continue;
}
var _264=[];
if(!_260){
this.detectTypeFromString_(_263[0]);
_259=this.attr_("xValueParser");
_260=true;
}
_264[0]=_259(_263[0],this);
if(this.fractions_){
for(var j=1;j<_263.length;j++){
var vals=_263[j].split("/");
_264[j]=[parseFloat(vals[0]),parseFloat(vals[1])];
}
}else{
if(this.attr_("errorBars")){
for(var j=1;j<_263.length;j+=2){
_264[(j+1)/2]=[parseFloat(_263[j]),parseFloat(_263[j+1])];
}
}else{
if(this.attr_("customBars")){
for(var j=1;j<_263.length;j++){
var vals=_263[j].split(";");
_264[j]=[parseFloat(vals[0]),parseFloat(vals[1]),parseFloat(vals[2])];
}
}else{
for(var j=1;j<_263.length;j++){
_264[j]=parseFloat(_263[j]);
}
}
}
}
ret.push(_264);
if(_264.length!=_261){
this.error("Number of columns in line "+i+" ("+_264.length+") does not agree with number of labels ("+_261+") "+line);
}
}
return ret;
};
Dygraph.prototype.parseArray_=function(data){
if(data.length==0){
this.error("Can't plot empty data set");
return null;
}
if(data[0].length==0){
this.error("Data set cannot contain an empty row");
return null;
}
if(this.attr_("labels")==null){
this.warn("Using default labels. Set labels explicitly via 'labels' "+"in the options parameter");
this.attrs_.labels=["X"];
for(var i=1;i<data[0].length;i++){
this.attrs_.labels.push("Y"+i);
}
}
if(Dygraph.isDateLike(data[0][0])){
this.attrs_.xValueFormatter=Dygraph.dateString_;
this.attrs_.xTicker=Dygraph.dateTicker;
var _265=Dygraph.clone(data);
for(var i=0;i<data.length;i++){
if(_265[i].length==0){
this.error("Row "<<(1+i)<<" of data is empty");
return null;
}
if(_265[i][0]==null||typeof (_265[i][0].getTime)!="function"){
this.error("x value in row "<<(1+i)<<" is not a Date");
return null;
}
_265[i][0]=_265[i][0].getTime();
}
return _265;
}else{
this.attrs_.xValueFormatter=function(x){
return x;
};
this.attrs_.xTicker=Dygraph.numericTicks;
return data;
}
};
Dygraph.prototype.parseDataTable_=function(data){
var cols=data.getNumberOfColumns();
var rows=data.getNumberOfRows();
var _268=[];
for(var i=0;i<cols;i++){
_268.push(data.getColumnLabel(i));
}
this.attrs_.labels=_268;
var _269=data.getColumnType(0);
if(_269=="date"){
this.attrs_.xValueFormatter=Dygraph.dateString_;
this.attrs_.xValueParser=Dygraph.dateParser;
this.attrs_.xTicker=Dygraph.dateTicker;
}else{
if(_269=="number"){
this.attrs_.xValueFormatter=function(x){
return x;
};
this.attrs_.xValueParser=function(x){
return parseFloat(x);
};
this.attrs_.xTicker=Dygraph.numericTicks;
}else{
this.error("only 'date' and 'number' types are supported for column 1 "+"of DataTable input (Got '"+_269+"')");
return null;
}
}
var ret=[];
for(var i=0;i<rows;i++){
var row=[];
if(!data.getValue(i,0)){
continue;
}
if(_269=="date"){
row.push(data.getValue(i,0).getTime());
}else{
row.push(data.getValue(i,0));
}
for(var j=1;j<cols;j++){
row.push(data.getValue(i,j));
}
ret.push(row);
}
return ret;
};
Dygraph.update=function(self,o){
if(typeof (o)!="undefined"&&o!==null){
for(var k in o){
self[k]=o[k];
}
}
return self;
};
Dygraph.isArrayLike=function(o){
var typ=typeof (o);
if((typ!="object"&&!(typ=="function"&&typeof (o.item)=="function"))||o===null||typeof (o.length)!="number"||o.nodeType===3){
return false;
}
return true;
};
Dygraph.isDateLike=function(o){
if(typeof (o)!="object"||o===null||typeof (o.getTime)!="function"){
return false;
}
return true;
};
Dygraph.clone=function(o){
var r=[];
for(var i=0;i<o.length;i++){
if(Dygraph.isArrayLike(o[i])){
r.push(Dygraph.clone(o[i]));
}else{
r.push(o[i]);
}
}
return r;
};
Dygraph.prototype.start_=function(){
if(typeof this.file_=="function"){
this.loadedEvent_(this.file_());
}else{
if(Dygraph.isArrayLike(this.file_)){
this.rawData_=this.parseArray_(this.file_);
this.drawGraph_(this.rawData_);
}else{
if(typeof this.file_=="object"&&typeof this.file_.getColumnRange=="function"){
this.rawData_=this.parseDataTable_(this.file_);
this.drawGraph_(this.rawData_);
}else{
if(typeof this.file_=="string"){
if(this.file_.indexOf("\n")>=0){
this.loadedEvent_(this.file_);
}else{
var req=new XMLHttpRequest();
var _275=this;
req.onreadystatechange=function(){
if(req.readyState==4){
if(req.status==200){
_275.loadedEvent_(req.responseText);
}
}
};
req.open("GET",this.file_,true);
req.send(null);
}
}else{
this.error("Unknown data format: "+(typeof this.file_));
}
}
}
}
};
Dygraph.prototype.updateOptions=function(_276){
if(_276.rollPeriod){
this.rollPeriod_=_276.rollPeriod;
}
if(_276.dateWindow){
this.dateWindow_=_276.dateWindow;
}
if(_276.valueRange){
this.valueRange_=_276.valueRange;
}
Dygraph.update(this.user_attrs_,_276);
this.labelsFromCSV_=(this.attr_("labels")==null);
this.layout_.updateOptions({"errorBars":this.attr_("errorBars")});
if(_276["file"]&&_276["file"]!=this.file_){
this.file_=_276["file"];
this.start_();
}else{
this.drawGraph_(this.rawData_);
}
};
Dygraph.prototype.adjustRoll=function(_277){
this.rollPeriod_=_277;
this.drawGraph_(this.rawData_);
};
Dygraph.createCanvas=function(){
var _278=document.createElement("canvas");
isIE=(/MSIE/.test(navigator.userAgent)&&!window.opera);
if(isIE){
_278=G_vmlCanvasManager.initElement(_278);
}
return _278;
};
Dygraph.GVizChart=function(_279){
this.container=_279;
};
Dygraph.GVizChart.prototype.draw=function(data,_280){
this.container.innerHTML="";
this.date_graph=new Dygraph(this.container,data,_280);
};
DateGraph=Dygraph;
function RGBColor(_281){
this.ok=false;
if(_281.charAt(0)=="#"){
_281=_281.substr(1,6);
}
_281=_281.replace(/ /g,"");
_281=_281.toLowerCase();
var _282={aliceblue:"f0f8ff",antiquewhite:"faebd7",aqua:"00ffff",aquamarine:"7fffd4",azure:"f0ffff",beige:"f5f5dc",bisque:"ffe4c4",black:"000000",blanchedalmond:"ffebcd",blue:"0000ff",blueviolet:"8a2be2",brown:"a52a2a",burlywood:"deb887",cadetblue:"5f9ea0",chartreuse:"7fff00",chocolate:"d2691e",coral:"ff7f50",cornflowerblue:"6495ed",cornsilk:"fff8dc",crimson:"dc143c",cyan:"00ffff",darkblue:"00008b",darkcyan:"008b8b",darkgoldenrod:"b8860b",darkgray:"a9a9a9",darkgreen:"006400",darkkhaki:"bdb76b",darkmagenta:"8b008b",darkolivegreen:"556b2f",darkorange:"ff8c00",darkorchid:"9932cc",darkred:"8b0000",darksalmon:"e9967a",darkseagreen:"8fbc8f",darkslateblue:"483d8b",darkslategray:"2f4f4f",darkturquoise:"00ced1",darkviolet:"9400d3",deeppink:"ff1493",deepskyblue:"00bfff",dimgray:"696969",dodgerblue:"1e90ff",feldspar:"d19275",firebrick:"b22222",floralwhite:"fffaf0",forestgreen:"228b22",fuchsia:"ff00ff",gainsboro:"dcdcdc",ghostwhite:"f8f8ff",gold:"ffd700",goldenrod:"daa520",gray:"808080",green:"008000",greenyellow:"adff2f",honeydew:"f0fff0",hotpink:"ff69b4",indianred:"cd5c5c",indigo:"4b0082",ivory:"fffff0",khaki:"f0e68c",lavender:"e6e6fa",lavenderblush:"fff0f5",lawngreen:"7cfc00",lemonchiffon:"fffacd",lightblue:"add8e6",lightcoral:"f08080",lightcyan:"e0ffff",lightgoldenrodyellow:"fafad2",lightgrey:"d3d3d3",lightgreen:"90ee90",lightpink:"ffb6c1",lightsalmon:"ffa07a",lightseagreen:"20b2aa",lightskyblue:"87cefa",lightslateblue:"8470ff",lightslategray:"778899",lightsteelblue:"b0c4de",lightyellow:"ffffe0",lime:"00ff00",limegreen:"32cd32",linen:"faf0e6",magenta:"ff00ff",maroon:"800000",mediumaquamarine:"66cdaa",mediumblue:"0000cd",mediumorchid:"ba55d3",mediumpurple:"9370d8",mediumseagreen:"3cb371",mediumslateblue:"7b68ee",mediumspringgreen:"00fa9a",mediumturquoise:"48d1cc",mediumvioletred:"c71585",midnightblue:"191970",mintcream:"f5fffa",mistyrose:"ffe4e1",moccasin:"ffe4b5",navajowhite:"ffdead",navy:"000080",oldlace:"fdf5e6",olive:"808000",olivedrab:"6b8e23",orange:"ffa500",orangered:"ff4500",orchid:"da70d6",palegoldenrod:"eee8aa",palegreen:"98fb98",paleturquoise:"afeeee",palevioletred:"d87093",papayawhip:"ffefd5",peachpuff:"ffdab9",peru:"cd853f",pink:"ffc0cb",plum:"dda0dd",powderblue:"b0e0e6",purple:"800080",red:"ff0000",rosybrown:"bc8f8f",royalblue:"4169e1",saddlebrown:"8b4513",salmon:"fa8072",sandybrown:"f4a460",seagreen:"2e8b57",seashell:"fff5ee",sienna:"a0522d",silver:"c0c0c0",skyblue:"87ceeb",slateblue:"6a5acd",slategray:"708090",snow:"fffafa",springgreen:"00ff7f",steelblue:"4682b4",tan:"d2b48c",teal:"008080",thistle:"d8bfd8",tomato:"ff6347",turquoise:"40e0d0",violet:"ee82ee",violetred:"d02090",wheat:"f5deb3",white:"ffffff",whitesmoke:"f5f5f5",yellow:"ffff00",yellowgreen:"9acd32"};
for(var key in _282){
if(_281==key){
_281=_282[key];
}
}
var _284=[{re:/^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/,example:["rgb(123, 234, 45)","rgb(255,234,245)"],process:function(bits){
return [parseInt(bits[1]),parseInt(bits[2]),parseInt(bits[3])];
}},{re:/^(\w{2})(\w{2})(\w{2})$/,example:["#00ff00","336699"],process:function(bits){
return [parseInt(bits[1],16),parseInt(bits[2],16),parseInt(bits[3],16)];
}},{re:/^(\w{1})(\w{1})(\w{1})$/,example:["#fb0","f0f"],process:function(bits){
return [parseInt(bits[1]+bits[1],16),parseInt(bits[2]+bits[2],16),parseInt(bits[3]+bits[3],16)];
}}];
for(var i=0;i<_284.length;i++){
var re=_284[i].re;
var _287=_284[i].process;
var bits=re.exec(_281);
if(bits){
channels=_287(bits);
this.r=channels[0];
this.g=channels[1];
this.b=channels[2];
this.ok=true;
}
}
this.r=(this.r<0||isNaN(this.r))?0:((this.r>255)?255:this.r);
this.g=(this.g<0||isNaN(this.g))?0:((this.g>255)?255:this.g);
this.b=(this.b<0||isNaN(this.b))?0:((this.b>255)?255:this.b);
this.toRGB=function(){
return "rgb("+this.r+", "+this.g+", "+this.b+")";
};
this.toHex=function(){
var r=this.r.toString(16);
var g=this.g.toString(16);
var b=this.b.toString(16);
if(r.length==1){
r="0"+r;
}
if(g.length==1){
g="0"+g;
}
if(b.length==1){
b="0"+b;
}
return "#"+r+g+b;
};
}

function rmtrailingzero(s) {if (s[0] == '0') return s.slice(1,100);else return s;}

/**
 * Convert from data coordinates to canvas/div X/Y coordinates.
 * Returns a two-element array: [X, Y]
 */
Dygraph.prototype.toXDomCoords = function(x) {
  var ret = null;
  var area = this.plotter_.area;
  if (x !== null) {
    var xRange = this.xAxisRange();
    ret = area.x + (x - xRange[0]) / (xRange[1] - xRange[0]) * area.w;
  }

  return ret;
};

/**
 * Returns the currently-visible x-range. This can be affected by zooming,
 * panning or a call to updateOptions.
 * Returns a two-element array: [left, right].
 * If the Dygraph has dates on the x-axis, these will be millis since epoch.
 */
Dygraph.prototype.xAxisRange = function() {
  if (this.dateWindow_) return this.dateWindow_;

  // The entire chart is visible.
  var left = this.rawData_[0][0];
  var right = this.rawData_[this.rawData_.length - 1][0];
  return [left, right];
};


/*
    http://www.JSON.org/json2.js
    2009-09-29

    Public Domain.

    NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.

    See http://www.JSON.org/js.html


    This code should be minified before deployment.
    See http://javascript.crockford.com/jsmin.html

    USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
    NOT CONTROL.


    This file creates a global JSON object containing two methods: stringify
    and parse.

        JSON.stringify(value, replacer, space)
            value       any JavaScript value, usually an object or array.

            replacer    an optional parameter that determines how object
                        values are stringified for objects. It can be a
                        function or an array of strings.

            space       an optional parameter that specifies the indentation
                        of nested structures. If it is omitted, the text will
                        be packed without extra whitespace. If it is a number,
                        it will specify the number of spaces to indent at each
                        level. If it is a string (such as '\t' or '&nbsp;'),
                        it contains the characters used to indent at each level.

            This method produces a JSON text from a JavaScript value.

            When an object value is found, if the object contains a toJSON
            method, its toJSON method will be called and the result will be
            stringified. A toJSON method does not serialize: it returns the
            value represented by the name/value pair that should be serialized,
            or undefined if nothing should be serialized. The toJSON method
            will be passed the key associated with the value, and this will be
            bound to the value

            For example, this would serialize Dates as ISO strings.

                Date.prototype.toJSON = function (key) {
                    function f(n) {
                        // Format integers to have at least two digits.
                        return n < 10 ? '0' + n : n;
                    }

                    return this.getUTCFullYear()   + '-' +
                         f(this.getUTCMonth() + 1) + '-' +
                         f(this.getUTCDate())      + 'T' +
                         f(this.getUTCHours())     + ':' +
                         f(this.getUTCMinutes())   + ':' +
                         f(this.getUTCSeconds())   + 'Z';
                };

            You can provide an optional replacer method. It will be passed the
            key and value of each member, with this bound to the containing
            object. The value that is returned from your method will be
            serialized. If your method returns undefined, then the member will
            be excluded from the serialization.

            If the replacer parameter is an array of strings, then it will be
            used to select the members to be serialized. It filters the results
            such that only members with keys listed in the replacer array are
            stringified.

            Values that do not have JSON representations, such as undefined or
            functions, will not be serialized. Such values in objects will be
            dropped; in arrays they will be replaced with null. You can use
            a replacer function to replace those with JSON values.
            JSON.stringify(undefined) returns undefined.

            The optional space parameter produces a stringification of the
            value that is filled with line breaks and indentation to make it
            easier to read.

            If the space parameter is a non-empty string, then that string will
            be used for indentation. If the space parameter is a number, then
            the indentation will be that many spaces.

            Example:

            text = JSON.stringify(['e', {pluribus: 'unum'}]);
            // text is '["e",{"pluribus":"unum"}]'


            text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
            // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'

            text = JSON.stringify([new Date()], function (key, value) {
                return this[key] instanceof Date ?
                    'Date(' + this[key] + ')' : value;
            });
            // text is '["Date(---current time---)"]'


        JSON.parse(text, reviver)
            This method parses a JSON text to produce an object or array.
            It can throw a SyntaxError exception.

            The optional reviver parameter is a function that can filter and
            transform the results. It receives each of the keys and values,
            and its return value is used instead of the original value.
            If it returns what it received, then the structure is not modified.
            If it returns undefined then the member is deleted.

            Example:

            // Parse the text. Values that look like ISO date strings will
            // be converted to Date objects.

            myData = JSON.parse(text, function (key, value) {
                var a;
                if (typeof value === 'string') {
                    a =
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
                    if (a) {
                        return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
                            +a[5], +a[6]));
                    }
                }
                return value;
            });

            myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
                var d;
                if (typeof value === 'string' &&
                        value.slice(0, 5) === 'Date(' &&
                        value.slice(-1) === ')') {
                    d = new Date(value.slice(5, -1));
                    if (d) {
                        return d;
                    }
                }
                return value;
            });


    This is a reference implementation. You are free to copy, modify, or
    redistribute.
*/

/*jslint evil: true, strict: false */

/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
    call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
    getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
    lastIndex, length, parse, prototype, push, replace, slice, stringify,
    test, toJSON, toString, valueOf
*/


// Create a JSON object only if one does not already exist. We create the
// methods in a closure to avoid creating global variables.

if (!this.JSON) {
    this.JSON = {};
}

(function () {

    function f(n) {
        // Format integers to have at least two digits.
        return n < 10 ? '0' + n : n;
    }

    if (typeof Date.prototype.toJSON !== 'function') {

        Date.prototype.toJSON = function (key) {

            return isFinite(this.valueOf()) ?
                   this.getUTCFullYear()   + '-' +
                 f(this.getUTCMonth() + 1) + '-' +
                 f(this.getUTCDate())      + 'T' +
                 f(this.getUTCHours())     + ':' +
                 f(this.getUTCMinutes())   + ':' +
                 f(this.getUTCSeconds())   + 'Z' : null;
        };

        String.prototype.toJSON =
        Number.prototype.toJSON =
        Boolean.prototype.toJSON = function (key) {
            return this.valueOf();
        };
    }

    var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
        escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
        gap,
        indent,
        meta = {    // table of character substitutions
            '\b': '\\b',
            '\t': '\\t',
            '\n': '\\n',
            '\f': '\\f',
            '\r': '\\r',
            '"' : '\\"',
            '\\': '\\\\'
        },
        rep;


    function quote(string) {

// If the string contains no control characters, no quote characters, and no
// backslash characters, then we can safely slap some quotes around it.
// Otherwise we must also replace the offending characters with safe escape
// sequences.

        escapable.lastIndex = 0;
        return escapable.test(string) ?
            '"' + string.replace(escapable, function (a) {
                var c = meta[a];
                return typeof c === 'string' ? c :
                    '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
            }) + '"' :
            '"' + string + '"';
    }


    function str(key, holder) {

// Produce a string from holder[key].

        var i,          // The loop counter.
            k,          // The member key.
            v,          // The member value.
            length,
            mind = gap,
            partial,
            value = holder[key];

// If the value has a toJSON method, call it to obtain a replacement value.

        if (value && typeof value === 'object' &&
                typeof value.toJSON === 'function') {
            value = value.toJSON(key);
        }

// If we were called with a replacer function, then call the replacer to
// obtain a replacement value.

        if (typeof rep === 'function') {
            value = rep.call(holder, key, value);
        }

// What happens next depends on the value's type.

        switch (typeof value) {
        case 'string':
            return quote(value);

        case 'number':

// JSON numbers must be finite. Encode non-finite numbers as null.

            return isFinite(value) ? String(value) : 'null';

        case 'boolean':
        case 'null':

// If the value is a boolean or null, convert it to a string. Note:
// typeof null does not produce 'null'. The case is included here in
// the remote chance that this gets fixed someday.

            return String(value);

// If the type is 'object', we might be dealing with an object or an array or
// null.

        case 'object':

// Due to a specification blunder in ECMAScript, typeof null is 'object',
// so watch out for that case.

            if (!value) {
                return 'null';
            }

// Make an array to hold the partial results of stringifying this object value.

            gap += indent;
            partial = [];

// Is the value an array?

            if (Object.prototype.toString.apply(value) === '[object Array]') {

// The value is an array. Stringify every element. Use null as a placeholder
// for non-JSON values.

                length = value.length;
                for (i = 0; i < length; i += 1) {
                    partial[i] = str(i, value) || 'null';
                }

// Join all of the elements together, separated with commas, and wrap them in
// brackets.

                v = partial.length === 0 ? '[]' :
                    gap ? '[\n' + gap +
                            partial.join(',\n' + gap) + '\n' +
                                mind + ']' :
                          '[' + partial.join(',') + ']';
                gap = mind;
                return v;
            }

// If the replacer is an array, use it to select the members to be stringified.

            if (rep && typeof rep === 'object') {
                length = rep.length;
                for (i = 0; i < length; i += 1) {
                    k = rep[i];
                    if (typeof k === 'string') {
                        v = str(k, value);
                        if (v) {
                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
                        }
                    }
                }
            } else {

// Otherwise, iterate through all of the keys in the object.

                for (k in value) {
                    if (Object.hasOwnProperty.call(value, k)) {
                        v = str(k, value);
                        if (v) {
                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
                        }
                    }
                }
            }

// Join all of the member texts together, separated with commas,
// and wrap them in braces.

            v = partial.length === 0 ? '{}' :
                gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
                        mind + '}' : '{' + partial.join(',') + '}';
            gap = mind;
            return v;
        }
    }

// If the JSON object does not yet have a stringify method, give it one.

    if (typeof JSON.stringify !== 'function') {
        JSON.stringify = function (value, replacer, space) {

// The stringify method takes a value and an optional replacer, and an optional
// space parameter, and returns a JSON text. The replacer can be a function
// that can replace values, or an array of strings that will select the keys.
// A default replacer method can be provided. Use of the space parameter can
// produce text that is more easily readable.

            var i;
            gap = '';
            indent = '';

// If the space parameter is a number, make an indent string containing that
// many spaces.

            if (typeof space === 'number') {
                for (i = 0; i < space; i += 1) {
                    indent += ' ';
                }

// If the space parameter is a string, it will be used as the indent string.

            } else if (typeof space === 'string') {
                indent = space;
            }

// If there is a replacer, it must be a function or an array.
// Otherwise, throw an error.

            rep = replacer;
            if (replacer && typeof replacer !== 'function' &&
                    (typeof replacer !== 'object' ||
                     typeof replacer.length !== 'number')) {
                throw new Error('JSON.stringify');
            }

// Make a fake root object containing our value under the key of ''.
// Return the result of stringifying the value.

            return str('', {'': value});
        };
    }


// If the JSON object does not yet have a parse method, give it one.

    if (typeof JSON.parse !== 'function') {
        JSON.parse = function (text, reviver) {

// The parse method takes a text and an optional reviver function, and returns
// a JavaScript value if the text is a valid JSON text.

            var j;

            function walk(holder, key) {

// The walk method is used to recursively walk the resulting structure so
// that modifications can be made.

                var k, v, value = holder[key];
                if (value && typeof value === 'object') {
                    for (k in value) {
                        if (Object.hasOwnProperty.call(value, k)) {
                            v = walk(value, k);
                            if (v !== undefined) {
                                value[k] = v;
                            } else {
                                delete value[k];
                            }
                        }
                    }
                }
                return reviver.call(holder, key, value);
            }


// Parsing happens in four stages. In the first stage, we replace certain
// Unicode characters with escape sequences. JavaScript handles many characters
// incorrectly, either silently deleting them, or treating them as line endings.

            cx.lastIndex = 0;
            if (cx.test(text)) {
                text = text.replace(cx, function (a) {
                    return '\\u' +
                        ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
                });
            }

// In the second stage, we run the text against regular expressions that look
// for non-JSON patterns. We are especially concerned with '()' and 'new'
// because they can cause invocation, and '=' because it can cause mutation.
// But just to be safe, we want to reject all unexpected forms.

// We split the second stage into 4 regexp operations in order to work around
// crippling inefficiencies in IE's and Safari's regexp engines. First we
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
// replace all simple value tokens with ']' characters. Third, we delete all
// open brackets that follow a colon or comma or that begin the text. Finally,
// we look to see that the remaining characters are only whitespace or ']' or
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.

            if (/^[\],:{}\s]*$/.
test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {

// In the third stage we use the eval function to compile the text into a
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.

                j = eval('(' + text + ')');

// In the optional fourth stage, we recursively walk the new structure, passing
// each name/value pair to a reviver function for possible transformation.

                return typeof reviver === 'function' ?
                    walk({'': j}, '') : j;
            }

// If the text is not JSON parseable, then a SyntaxError is thrown.

            throw new SyntaxError('JSON.parse');
        };
    }
}());

/*	SWFObject v2.0 <http://code.google.com/p/swfobject/>
	Copyright (c) 2007 Geoff Stearns, Michael Williams, and Bobby van der Sluis
	This software is released under the MIT License <http://www.opensource.org/licenses/mit-license.php>
*/
var swfobject=function(){var Z="undefined",P="object",B="Shockwave Flash",h="ShockwaveFlash.ShockwaveFlash",W="application/x-shockwave-flash",K="SWFObjectExprInst",G=window,g=document,N=navigator,f=[],H=[],Q=null,L=null,T=null,S=false,C=false;var a=function(){var l=typeof g.getElementById!=Z&&typeof g.getElementsByTagName!=Z&&typeof g.createElement!=Z&&typeof g.appendChild!=Z&&typeof g.replaceChild!=Z&&typeof g.removeChild!=Z&&typeof g.cloneNode!=Z,t=[0,0,0],n=null;if(typeof N.plugins!=Z&&typeof N.plugins[B]==P){n=N.plugins[B].description;if(n){n=n.replace(/^.*\s+(\S+\s+\S+$)/,"$1");t[0]=parseInt(n.replace(/^(.*)\..*$/,"$1"),10);t[1]=parseInt(n.replace(/^.*\.(.*)\s.*$/,"$1"),10);t[2]=/r/.test(n)?parseInt(n.replace(/^.*r(.*)$/,"$1"),10):0}}else{if(typeof G.ActiveXObject!=Z){var o=null,s=false;try{o=new ActiveXObject(h+".7")}catch(k){try{o=new ActiveXObject(h+".6");t=[6,0,21];o.AllowScriptAccess="always"}catch(k){if(t[0]==6){s=true}}if(!s){try{o=new ActiveXObject(h)}catch(k){}}}if(!s&&o){try{n=o.GetVariable("$version");if(n){n=n.split(" ")[1].split(",");t=[parseInt(n[0],10),parseInt(n[1],10),parseInt(n[2],10)]}}catch(k){}}}}var v=N.userAgent.toLowerCase(),j=N.platform.toLowerCase(),r=/webkit/.test(v)?parseFloat(v.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,i=false,q=j?/win/.test(j):/win/.test(v),m=j?/mac/.test(j):/mac/.test(v);/*@cc_on i=true;@if(@_win32)q=true;@elif(@_mac)m=true;@end@*/return{w3cdom:l,pv:t,webkit:r,ie:i,win:q,mac:m}}();var e=function(){if(!a.w3cdom){return }J(I);if(a.ie&&a.win){try{g.write("<script id=__ie_ondomload defer=true src=//:><\/script>");var i=c("__ie_ondomload");if(i){i.onreadystatechange=function(){if(this.readyState=="complete"){this.parentNode.removeChild(this);V()}}}}catch(j){}}if(a.webkit&&typeof g.readyState!=Z){Q=setInterval(function(){if(/loaded|complete/.test(g.readyState)){V()}},10)}if(typeof g.addEventListener!=Z){g.addEventListener("DOMContentLoaded",V,null)}M(V)}();function V(){if(S){return }if(a.ie&&a.win){var m=Y("span");try{var l=g.getElementsByTagName("body")[0].appendChild(m);l.parentNode.removeChild(l)}catch(n){return }}S=true;if(Q){clearInterval(Q);Q=null}var j=f.length;for(var k=0;k<j;k++){f[k]()}}function J(i){if(S){i()}else{f[f.length]=i}}function M(j){if(typeof G.addEventListener!=Z){G.addEventListener("load",j,false)}else{if(typeof g.addEventListener!=Z){g.addEventListener("load",j,false)}else{if(typeof G.attachEvent!=Z){G.attachEvent("onload",j)}else{if(typeof G.onload=="function"){var i=G.onload;G.onload=function(){i();j()}}else{G.onload=j}}}}}function I(){var l=H.length;for(var j=0;j<l;j++){var m=H[j].id;if(a.pv[0]>0){var k=c(m);if(k){H[j].width=k.getAttribute("width")?k.getAttribute("width"):"0";H[j].height=k.getAttribute("height")?k.getAttribute("height"):"0";if(O(H[j].swfVersion)){if(a.webkit&&a.webkit<312){U(k)}X(m,true)}else{if(H[j].expressInstall&&!C&&O("6.0.65")&&(a.win||a.mac)){D(H[j])}else{d(k)}}}}else{X(m,true)}}}function U(m){var k=m.getElementsByTagName(P)[0];if(k){var p=Y("embed"),r=k.attributes;if(r){var o=r.length;for(var n=0;n<o;n++){if(r[n].nodeName.toLowerCase()=="data"){p.setAttribute("src",r[n].nodeValue)}else{p.setAttribute(r[n].nodeName,r[n].nodeValue)}}}var q=k.childNodes;if(q){var s=q.length;for(var l=0;l<s;l++){if(q[l].nodeType==1&&q[l].nodeName.toLowerCase()=="param"){p.setAttribute(q[l].getAttribute("name"),q[l].getAttribute("value"))}}}m.parentNode.replaceChild(p,m)}}function F(i){if(a.ie&&a.win&&O("8.0.0")){G.attachEvent("onunload",function(){var k=c(i);if(k){for(var j in k){if(typeof k[j]=="function"){k[j]=function(){}}}k.parentNode.removeChild(k)}})}}function D(j){C=true;var o=c(j.id);if(o){if(j.altContentId){var l=c(j.altContentId);if(l){L=l;T=j.altContentId}}else{L=b(o)}if(!(/%$/.test(j.width))&&parseInt(j.width,10)<310){j.width="310"}if(!(/%$/.test(j.height))&&parseInt(j.height,10)<137){j.height="137"}g.title=g.title.slice(0,47)+" - Flash Player Installation";var n=a.ie&&a.win?"ActiveX":"PlugIn",k=g.title,m="MMredirectURL="+G.location+"&MMplayerType="+n+"&MMdoctitle="+k,p=j.id;if(a.ie&&a.win&&o.readyState!=4){var i=Y("div");p+="SWFObjectNew";i.setAttribute("id",p);o.parentNode.insertBefore(i,o);o.style.display="none";G.attachEvent("onload",function(){o.parentNode.removeChild(o)})}R({data:j.expressInstall,id:K,width:j.width,height:j.height},{flashvars:m},p)}}function d(j){if(a.ie&&a.win&&j.readyState!=4){var i=Y("div");j.parentNode.insertBefore(i,j);i.parentNode.replaceChild(b(j),i);j.style.display="none";G.attachEvent("onload",function(){j.parentNode.removeChild(j)})}else{j.parentNode.replaceChild(b(j),j)}}function b(n){var m=Y("div");if(a.win&&a.ie){m.innerHTML=n.innerHTML}else{var k=n.getElementsByTagName(P)[0];if(k){var o=k.childNodes;if(o){var j=o.length;for(var l=0;l<j;l++){if(!(o[l].nodeType==1&&o[l].nodeName.toLowerCase()=="param")&&!(o[l].nodeType==8)){m.appendChild(o[l].cloneNode(true))}}}}}return m}function R(AE,AC,q){var p,t=c(q);if(typeof AE.id==Z){AE.id=q}if(a.ie&&a.win){var AD="";for(var z in AE){if(AE[z]!=Object.prototype[z]){if(z=="data"){AC.movie=AE[z]}else{if(z.toLowerCase()=="styleclass"){AD+=' class="'+AE[z]+'"'}else{if(z!="classid"){AD+=" "+z+'="'+AE[z]+'"'}}}}}var AB="";for(var y in AC){if(AC[y]!=Object.prototype[y]){AB+='<param name="'+y+'" value="'+AC[y]+'" />'}}t.outerHTML='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"'+AD+">"+AB+"</object>";F(AE.id);p=c(AE.id)}else{if(a.webkit&&a.webkit<312){var AA=Y("embed");AA.setAttribute("type",W);for(var x in AE){if(AE[x]!=Object.prototype[x]){if(x=="data"){AA.setAttribute("src",AE[x])}else{if(x.toLowerCase()=="styleclass"){AA.setAttribute("class",AE[x])}else{if(x!="classid"){AA.setAttribute(x,AE[x])}}}}}for(var w in AC){if(AC[w]!=Object.prototype[w]){if(w!="movie"){AA.setAttribute(w,AC[w])}}}t.parentNode.replaceChild(AA,t);p=AA}else{var s=Y(P);s.setAttribute("type",W);for(var v in AE){if(AE[v]!=Object.prototype[v]){if(v.toLowerCase()=="styleclass"){s.setAttribute("class",AE[v])}else{if(v!="classid"){s.setAttribute(v,AE[v])}}}}for(var u in AC){if(AC[u]!=Object.prototype[u]&&u!="movie"){E(s,u,AC[u])}}t.parentNode.replaceChild(s,t);p=s}}return p}function E(k,i,j){var l=Y("param");l.setAttribute("name",i);l.setAttribute("value",j);k.appendChild(l)}function c(i){return g.getElementById(i)}function Y(i){return g.createElement(i)}function O(k){var j=a.pv,i=k.split(".");i[0]=parseInt(i[0],10);i[1]=parseInt(i[1],10);i[2]=parseInt(i[2],10);return(j[0]>i[0]||(j[0]==i[0]&&j[1]>i[1])||(j[0]==i[0]&&j[1]==i[1]&&j[2]>=i[2]))?true:false}function A(m,j){if(a.ie&&a.mac){return }var l=g.getElementsByTagName("head")[0],k=Y("style");k.setAttribute("type","text/css");k.setAttribute("media","screen");if(!(a.ie&&a.win)&&typeof g.createTextNode!=Z){k.appendChild(g.createTextNode(m+" {"+j+"}"))}l.appendChild(k);if(a.ie&&a.win&&typeof g.styleSheets!=Z&&g.styleSheets.length>0){var i=g.styleSheets[g.styleSheets.length-1];if(typeof i.addRule==P){i.addRule(m,j)}}}function X(k,i){var j=i?"visible":"hidden";if(S){c(k).style.visibility=j}else{A("#"+k,"visibility:"+j)}}return{registerObject:function(l,i,k){if(!a.w3cdom||!l||!i){return }var j={};j.id=l;j.swfVersion=i;j.expressInstall=k?k:false;H[H.length]=j;X(l,false)},getObjectById:function(l){var i=null;if(a.w3cdom&&S){var j=c(l);if(j){var k=j.getElementsByTagName(P)[0];if(!k||(k&&typeof j.SetVariable!=Z)){i=j}else{if(typeof k.SetVariable!=Z){i=k}}}}return i},embedSWF:function(n,u,r,t,j,m,k,p,s){if(!a.w3cdom||!n||!u||!r||!t||!j){return }r+="";t+="";if(O(j)){X(u,false);var q=(typeof s==P)?s:{};q.data=n;q.width=r;q.height=t;var o=(typeof p==P)?p:{};if(typeof k==P){for(var l in k){if(k[l]!=Object.prototype[l]){if(typeof o.flashvars!=Z){o.flashvars+="&"+l+"="+k[l]}else{o.flashvars=l+"="+k[l]}}}}J(function(){R(q,o,u);if(q.id==u){X(u,true)}})}else{if(m&&!C&&O("6.0.65")&&(a.win||a.mac)){X(u,false);J(function(){var i={};i.id=i.altContentId=u;i.width=r;i.height=t;i.expressInstall=m;D(i)})}}},getFlashPlayerVersion:function(){return{major:a.pv[0],minor:a.pv[1],release:a.pv[2]}},hasFlashPlayerVersion:O,createSWF:function(k,j,i){if(a.w3cdom&&S){return R(k,j,i)}else{return undefined}},createCSS:function(j,i){if(a.w3cdom){A(j,i)}},addDomLoadEvent:J,addLoadEvent:M,getQueryParamValue:function(m){var l=g.location.search||g.location.hash;if(m==null){return l}if(l){var k=l.substring(1).split("&");for(var j=0;j<k.length;j++){if(k[j].substring(0,k[j].indexOf("="))==m){return k[j].substring((k[j].indexOf("=")+1))}}}return""},expressInstallCallback:function(){if(C&&L){var i=c(K);if(i){i.parentNode.replaceChild(L,i);if(T){X(T,true);if(a.ie&&a.win){L.style.display="block"}}L=null;T=null;C=false}}}}}();

/**
 * @author Daniele Mazzini (c) Copyright 2010
 */


// current global status of this page
var g_page_status = { 
	form_changed: true, // was the form changed from the one showed? always true for the "demo" plan
	scenario_customized: false, // if the scenario was customized from the loaded one
	comparison: false, // is comparison on?
	comparison_plan_id: null, // if comparison in active, set id, otherwise null
	upper_panel_hidden: false
};

var g_totals_json = null;
var g_payments_json = null;

var g_loginNextStep = null;

var g_plan = null;
var g_payments = null;
var g_rates = null;

var g_comparison_plan = null;
var g_comparison_payments = null;
var g_comparison_rates = null;

var g_logged_in = null;

var g_submit_original_onsubmit_source = null;
var g_logged_in = null;

var g_mortgage_type_names = {
	variable: "Variabile",
	variable_capped: "Con cap",
	variable_fixed_payment: "Rata fissa",
	fixed: "Fisso"
}

function formSetChanged() {
	submitSetStatus('compute');
	
	g_page_status.form_changed = true;
	$('#mortgage_plan_submit').attr("disabled", false);
}

// null: no default
g_hidden_defaults = { 
	spread_row: ['#mortgage_plan_spread',null],
	fixed_rate_row: ['#mortgage_plan_fixed_rate',null],
	cap_row: ['#mortgage_plan_cap','5.5'],
	scenario_row: ['#scenario','Medio'],
	max_additional_years_row: ['#max_additional_years','10'],
	predetermined_principal_plan_span: ['#predetermined_principal_plan',null]
};

g_hidden_table = {
	fixed: {
		spread_row: true,
		fixed_rate_row: false,
		cap_row: true,
		scenario_row: true,
		max_additional_years_row: true,
		predetermined_principal_plan_span: true
	},
	variable: {
		spread_row: false,
		fixed_rate_row: true,
		cap_row: true,
		scenario_row: false,
		max_additional_years_row: true,
		predetermined_principal_plan_span: false
	},
	variable_capped: {
		spread_row: false,
		fixed_rate_row: true,
		cap_row: false,
		scenario_row: false,
		max_additional_years_row: true,
		predetermined_principal_plan_span: false
	},
	variable_fixed_payment: {
		spread_row: false,
		fixed_rate_row: true,
		cap_row: true,
		scenario_row: false,
		max_additional_years_row: false,
		predetermined_principal_plan_span: true
	}
};

// hide/show the relevant controls
// also reset values for hidden ones
function mortgageTypeChanged(type, prefix) {
	if (typeof(type) != 'string') type = $(this).val();
	var c = g_hidden_table[type];
	var j;
	
	for (var i in c) {
		if (prefix) j = '#'+prefix+i;
		else j ='#'+i; 
			
		if (c[i]) {			
			$(j).hide();
			if (!prefix) {
				var x = g_hidden_defaults[i];
				if (x[1]) $(x[0]).val(x[1]);
			}
		}
		else $(j).show(); 
	}
	
	// exception: for capped rate the default in Italy is predetermined principal plan
	// TODO don't treat it as an exception?
	switch (type) {
		case 'variable_capped':
			$('#mortgage_plan_predetermined_principal_plan').attr('checked', true);
			break;
		default:
			$('#mortgage_plan_predetermined_principal_plan').attr('checked', false)
			break;
	}
}

// check interaction with custom scenarios
function scenarioSelected() {
	if (g_page_status.scenario_customized) {
		g_page_status.scenario_customized = false;
		// MISSING do other cleanup...
	}
}

function submitSetStatus(status) {
	switch (status) {
		case 'compute':
			$('#mortgage_plan_submit').val('Calcola').unbind('click').click(planSubmitClick).attr("disabled", false);
		break;
		case 'save':
			$('#mortgage_plan_submit').val('Salva').unbind('click').click(planSaveClick).attr("disabled", false);
		break;
	}
}

function planSubmitClick() { 
    $('#lower_panel').block({ 
        message: 'Sto calcolando... <img alt="Ajax-waiting" src="/images/ajax-waiting.gif" />', 
        css: { border: '2px solid #55b', padding: '10px' }
    });
	
	$("#skyscraper").show();
	
	_gaq.push(['_trackEvent', 'Plans', 'Submit', 'Click']);
	
	g_page_status.form_changed = false;
	
	// if a new custom scenario, save it and use it for the plan
	if (g_page_status.scenario_customized) {
		// serialize the rates series
		var rates = [];
		for (var i=0;i<g_rawData.length;i++) rates[i] = g_rawData[i][2];
		var rates_json = JSON.stringify(rates);
		
		$('#custom_scenario_rates').val(rates_json);
	}
}

function planSaveClick() {
	// check if registered and logged in
	if (!g_logged_in) {
		log('planSaveClick.request');
		_gaq.push(['_trackEvent', 'Plans', 'Save', 'Click']);
		
		// log in or create user, then return here
		askLogin(planSaveClick);
	}
	else {
		// MISSING check if already saved
		//		if (g_plan.name) {
		//			$.blockUI({ message: $('#question'), css: { width: '275px' } }); 
		//		}
		
		// get a name
		var name = "";
		while (name != null && name.length == 0) 
			name = prompt("Scegli un nome per il piano", "");
		
		// "save" using ajax
		if (name) {
			$('#lower_panel').block({ 
	            message: 'Sto salvando... <img alt="Ajax-waiting" src="/images/ajax-waiting.gif" />', 
	            css: { border: '2px solid #55b', padding: '10px' }
	        });
			
			jQuery.post("/mortgage_plans/save_plan", {
				name: name,
				id: g_plan.id,
				prev_id: null
			}, // add the new item to the list and select it
			function(data){
				$('#plans').append($("<option></option>").attr("value", data.id).text(data.name)).val(data.name);
				$('#plans_compare').append($("<option></option>").attr("value", data.id).text(data.name)).val(data.name);
				if (g_page_status.comparison && g_page_status.comparison_plan_id)
					$('#plans_compare').val(g_comparison_plan.name);
				else $('#plans_compare').val("Scegli il piano");
				
				$('#mortgage_plan_submit').attr("disabled", true);
				$('#lower_panel').unblock();
				g_plan.name = name;
			}, "json")
		}
	}
	
	// don't submit the form
	return false;
}

// load selected plan if single choice.
// if multiple choice, 
function loadPlan(e) {
	var selections = $("#plans :selected").length;
	
	if (selections == 1) { // single selection {
		var plan_id = $(this).val();
		
		if (plan_id) {
			jQuery.get("/mortgage_plans/load_plan", { id: plan_id }, function(data){ 			
				showGraphs(data, true); 
				
				// reset form
				mortgageTypeChanged(g_plan.mortgage_type);
				
				// update form values 
				$("#mortgage_plan_amount").val(g_plan.amount);
				$("#mortgage_plan_years").val(g_plan.years);
				$("#mortgage_plan_spread").val(g_plan.spread);
				$("#mortgage_plan_cap").val(g_plan.cap);
				$("#mortgage_plan_fixed_rate").val(g_plan.fixed_rate);
				$("#mortgage_plan_mortgage_type").val(g_plan.mortgage_type);
				$('#mortgage_plan_predetermined_principal_plan').attr('checked', g_plan.predetermined_principal_plan)
				
				$("#scenario").val(g_plan.scenario);
				
				$('#mortgage_plan_submit').attr("disabled", true);
			});
			
			$('#lower_panel').block({ 
	            message: 'Sto caricando il piano... <img alt="Ajax-waiting" src="/images/ajax-waiting.gif" />', 
	            css: { border: '2px solid #55b', padding: '10px' }
	        });
			
			g_page_status.form_changed = false;	
		}
	} else if (selections > 1) { // multiple selections
		// activate comparison, this is most likely what the user wanted to do
		if (!g_page_status.comparison) compareCurrentPlan();
		
		// only leave selected the previously selected item, but find the new one
		var vals = $("#plans :selected");
		var newsel = null;
		var oldsel = null;
		
		vals.each(function(){
			if (this.value == g_plan.id) 
				oldsel = this;
			else {
				newsel = this;
				jQuery(newsel).removeAttr("selected");  
			}
		});
		
		// use the new item for comparison
		$("#plans_compare").val(newsel.text).trigger("change");
		
		return false;
	}
}

function loadPlanComparison(e) {
	var plan_id = $(this).val();
	
	if (plan_id && plan_id != "") {
		g_page_status.comparison_plan_id = plan_id;
		
		jQuery.get("/mortgage_plans/load_plan", { id: plan_id }, function(data){
			if (data.responseText) 
				g_comparison_plan = JSON.parse(data.responseText).mortgage_plan;
			else g_comparison_plan = JSON.parse(data).mortgage_plan;
			
			var series = getSeries(g_comparison_plan);
			g_comparison_payments = series[1];
			g_comparison_rates = series[0];
			
			setComparisonTableData(g_comparison_plan);
			 			
			// show graphs with current plan and comparison plan
			showGraphs(null, true); 
		});
		
		$('#lower_panel').block({ 
            message: 'Sto caricando il piano... <img alt="Ajax-waiting" src="/images/ajax-waiting.gif" />', 
            css: { border: '2px solid #55b', padding: '10px' }
        });
		
		g_page_status.form_changed = false;
	}
}

// ask for login or create new user, then (if successfull) execute function nextStep
function askLogin(nextStep) {
	g_loginNextStep = nextStep;
	$.blockUI({ message: $('#login_dialog'), css: { width: '450px' } });
}

function setupLogin() {
	if (!g_logged_in) $("#login_link").attr("href", "#").click(askLogin);
	
	$("#login_dialog").tabs();
	
	$('#login_cancel').click(function() { 
        $.unblockUI({onUnblock: function(){ g_loginNextStep=null; } }); 
        return false; 
    });
	
	$('#create_cancel').click(function() { 
        $.unblockUI({onUnblock: function(){ g_loginNextStep=null; } }); 
        return false; 
    });
	
	$('#login').click(function() {
		$.blockUI({ 
            message: 'Attendi... <img alt="Ajax-waiting" src="/images/ajax-waiting.gif" />', 
            css: { border: '2px solid #55b', padding: '10px' }
    	});
		// do ajax login
		$.post("/user_sessions/create_ajax",{email:$("#email").val(), password:$("#password").val()},function(data){ 
			var d = JSON.parse(data);
			
			if (d.user) { // logged in
				// update the "user" menu
				setUser(d.user.user);
				
				// update list
				loadPlansList(d.plans_options);
				
				// update scenarios
				loadScenariosList(d.scenarios_options);
				
				g_logged_in = true;
				
				$.unblockUI({onUnblock: function(){ if (typeof(g_loginNextStep) == "function") g_loginNextStep(); g_loginNextStep=null; } }); 
			} else {
				alert("Email o password non riconosciuti")
				$.unblockUI({onUnblock: function(){ g_loginNextStep=null; } }); 
			}
			
		});
	}); 
		
	$('#create_user').click(function() {
		$.blockUI({ 
            message: 'Attendi... <img alt="Ajax-waiting" src="/images/ajax-waiting.gif" />', 
            css: { border: '2px solid #55b', padding: '10px' }
    	});
		// do ajax login
		$.post("/user_sessions/create_with_new_user_ajax",{email:$("#email_create").val()},function(data){ 
			var d = JSON.parse(data);
			
			if (d.user) { // logged in
				// update the "user" menu
				setUser(d.user.user);
				
				// update list
				loadPlansList(d.plans_options);
				
				// update scenarios
				loadScenariosList(d.custom_scenarios_options);
				
				g_logged_in = true;
				
				$.unblockUI({onUnblock: function(){ if (typeof(g_loginNextStep) == "function") g_loginNextStep(); g_loginNextStep=null; } }); 			
			} else {
				switch (d.error[0]) {
					case "generic":
						alert(d.error[1]);
						$.unblockUI();
						break;
					case "used_email":
						alert("Indirizzo email già registrato");
						break;
					case "invalid_email":
						alert("Indirizzo email non valido")
						break;
					default:
						$.unblockUI({onUnblock: function(){ g_loginNextStep=null; } }); 
						alert("Errore sconosciuto")
						break;
				}					
			}
			
		});
	
    	return false; 
    }); 
}

function loadPlansList(options) {
	$("#plans").html(options);
	$("#plans_compare").html(options).prepend("<option value='' selected>Scegli il piano</option>");

	$("#saved_plans").show();
}

function loadScenariosList(options) { 
	if (options) {
		// save currently selected scenario, then restore it
		var sel = $('#scenario :selected').val();
		
		$("#scenario").html(options).append($("<option></option>").attr("value", 'new_custom').attr("disabled", 'disabled').text('personale')).val(sel);
	}
}

function deleteCurrentPlan() {
	// only if a plan is selected
	var plan_id = $("#plans").val();
	
	if (plan_id) {
		if (confirm('Elimino il piano "'+g_plan.name+'"?')) {
			$('#lower_panel').block({ 
	            message: 'Attendi... <img alt="Ajax-waiting" src="/images/ajax-waiting.gif" />', 
	            css: { border: '2px solid #55b', padding: '10px' }
	        });
			
			jQuery.post("/mortgage_plans/delete_plan", {
				id: g_plan.id
			}, // delete the plan from the select box
			function(data){
				if (data.deleted) {
					$('#plans :selected').remove();
					$('#plans_compare option[value="'+plan_id+'"]').remove();
				}
				else 
					alert(data.error[1]);
				
				//$('#plans').append($("<option></option>").attr("value", data.id).text(data.name)).val(data.name);
				$('#lower_panel').unblock();
			}, "json");
		}
		
	}
}

// toggle plans comparison
function compareCurrentPlan() {
	if (g_page_status.comparison) {
		$("#plans_comparison").slideUp("slow");
		$("#plans_compare").val("Scegli il piano");
		$("#plan_compare").val("Confronta");
		
		g_page_status.comparison_plan_id = null;
		// show graphs without comparison plan
		showGraphs(null, true);
		
		// clear comparison plan table
		setComparisonTableData(null);
	} else {
		$("#plans_comparison").slideDown("slow");
		$("#plan_compare").val("Stop conf.");
		_gaq.push(['_trackEvent', 'Plans', 'Compare', 'On']);
		log('plans:compare');
	}
	
	g_page_status.comparison = ! g_page_status.comparison;
}

var g_numberLookup = null;
var g_rawData = null;
var g_rates_graph = null;

// find the position of data based on "date" (d)
function numberLookup(d) {
	if (!g_numberLookup) {
		g_numberLookup = {};
		g_rawData = g_rates_graph.rawData_;
		
		for (i=0;i<g_rawData.length;i++) {
		  	g_numberLookup[g_rawData[i][0]] = i+1;
		}
	}

	return g_numberLookup[d];
}

function dyZoomCallback(zoomStart, zoomEnd,lowX,highX) {
	// only if zooming in
	if (lowX) {
		// find the interval
		var n1 = numberLookup(zoomStart);
		var n2 = numberLookup(zoomEnd);
		
		$("#zoom_dialog")
				.mouseenter(function(){g_zoomDialog.hoveringDialog = true;})
				.mouseleave(function(){g_zoomDialog.hoveringDialog = false; setTimeout('g_zoomDialog.manageLeave()',50);})
				.show();
		
		$(g_rates_graph.graphDiv)
			.mouseleave(function(){g_zoomDialog.hoveringRates = false; setTimeout('g_zoomDialog.manageLeave()',50);});
			
		// draw the "new" zoom rectangle, clear the old one (not to interfere with other dygraphs operations)
		var ctx=g_rates_graph.canvas_.getContext("2d");
		ctx.clearRect(0,0,g_rates_graph.width_,g_rates_graph.height_);
		
		var ctx2=g_rates_graph.canvas2_.getContext("2d");
		// clear from previous drawings
		ctx2.clearRect(0,0,g_rates_graph.width_,g_rates_graph.height_);
		
		// draw the action rect
		ctx2.fillStyle = "rgba(256,128,128,0.33)";
	    ctx2.fillRect(lowX, 0,
	                 highX-lowX, g_rates_graph.height_);
					 
		g_zoomDialog.zoomStart = zoomStart;
		g_zoomDialog.zoomEnd = zoomEnd;
		g_zoomDialog.startDate = n1;
		g_zoomDialog.endDate = n2;
		g_zoomDialog.lowX = lowX;
		g_zoomDialog.highX = highX;	
		
		return false;
	}
	else return true;
	
	
}

function dyClickCallback(e, x, pts){
	if (!g_page_status.comparison && (e.altKey || e.ctrlKey)) {
		var n = numberLookup(x);
		
		var delta = 0.5;
		if (e.altKey) 
			delta = -delta;
		
		//console.debug(e);
		
		if (g_rawData) {
			var spread = g_rawData[n - 1][1] - g_rawData[n - 1][2];
			
			g_rawData[n - 1][2] += delta;
			if (g_rawData[n - 1][2] < 0.0) 
				g_rawData[n - 1][2] = 0.0;
				
			g_rawData[n - 1][1] = g_rawData[n - 1][2] + spread;
				
			if (e.shiftKey && n>2 && n<g_rawData.length-2) {
				var delta2 = delta/2;
				g_rawData[n - 2][2] += delta2;
				if (g_rawData[n - 2][2] < 0.0) g_rawData[n - 2][2] = 0.0;
				g_rawData[n - 2][1] = g_rawData[n - 2][2] + spread;
				
				g_rawData[n][2] += delta2;
				if (g_rawData[n][2] < 0.0) g_rawData[n][2] = 0.0;
				g_rawData[n][1] = g_rawData[n][2] + spread;
			}
				
			g_rates_graph.drawGraph_(g_rawData);
		}
		
		scenarioCustomized();
	}
}

function scenarioCustomized() {
	// the scenario has changed to custom
	if (!g_page_status.scenario_customized) {
		g_page_status.scenario_customized = true;
		
		// change to customized not saved
		$('#scenario').val('personale');						  
		formSetChanged();
	}
}

var g_ratesTips = {
	hoveringRates: false,
	hoveringTips: false,
	manageLeave: function() {
		if (!this.hoveringRates && !this.hoveringTips) $('#rates_graph_tips').hide();
	}
};

var g_zoomDialog = {
	modal: false,
	hoveringRates: false,
	hoveringDialog: false,
	manageLeave: function() {
		if (!this.hoveringRates && !this.hoveringDialog && !this.modal) {
			this.endDialog();
		}
	},
	zoomStart: null,
	zoomEnd: null,
	startDate: null,
	endDate: null,
	lowX: null,
	highX: null,
	subtract: false,
	doZoom: function() { 
		g_rates_graph.doZoomActual_(this.zoomStart,this.zoomEnd); 
		this.endDialog();
	},
	doSum: function() { 
		var delta1 = parseFloat($("#edit_sum_start_value").val().replace(',','.'));
		var delta2 = parseFloat($("#edit_sum_end_value").val().replace(',','.'));
		if (this.subtract) {
			delta1 = -delta1;
			delta2 = -delta2;
		}
		
		var n1 = this.startDate;
		var n2 = this.endDate;
		
		if (typeof(delta1) == 'number' && typeof(delta2) == 'number') {
			var spread = g_rawData[n1 - 1][1] - g_rawData[n1 - 1][2];
			
			var deltadelta = (delta2-delta1)/(n2-n1);
			
			for (var n=n1;n<=n2;n++) {
				g_rawData[n][2] += delta1;
				if (g_rawData[n][2] < 0.0) 
						g_rawData[n][2] = 0.0;
						
				g_rawData[n][1] = g_rawData[n][2] + spread;
				
				delta1 += deltadelta;
			}
			
			g_rates_graph.drawGraph_(g_rawData);		
		}
		
		scenarioCustomized();
		this.endDialog();
	},
	doSet: function() { 
		var val1 = parseFloat($("#edit_set_start_value").val().replace(',','.'));
		var val2 = parseFloat($("#edit_set_end_value").val().replace(',','.'));
		var n1 = this.startDate;
		var n2 = this.endDate;
		
		if (typeof(val1) == 'number' && typeof(val2) == 'number') {
			var spread = g_rawData[n1 - 1][1] - g_rawData[n1 - 1][2];
			
			var deltadelta = (val2-val1)/(n2-n1);
			
			for (var n=n1;n<=n2;n++) {
				g_rawData[n][2] = val1;
						
				g_rawData[n][1] = g_rawData[n][2] + spread;
				
				val1 += deltadelta;
			}
			
			g_rates_graph.drawGraph_(g_rawData);		
		}
		
		scenarioCustomized();
		this.endDialog();
	},
	endDialog: function() {
		// clear selection rectangle
		var ctx2=g_rates_graph.canvas2_.getContext("2d");
		ctx2.clearRect(0,0,g_rates_graph.width_,g_rates_graph.height_);
		
		$('#zoom_dialog_choice').show();
		$('#zoom_dialog_edit').hide();
		$('#zoom_dialog').hide();
		
		this.modal = false;
	},
	startEdit: function() {
		// reset the dialog
		$('#zoom_dialog_choice').hide();
		$('#zoom_dialog_edit').show();
		$('#zoom_dialog_edit_sum').hide();
		$('#button_sum').hide();
		$('#zoom_dialog_edit_set').show();
		$('#button_set').show();
		$('#zoom_dialog_edit_choice_select').val("Sostituisci");
		
		$('#edit_sum_start_value').val("0.5");
		$('#edit_sum_end_value').val("0.5");
		
		$('#edit_set_start_value').val(g_rawData[this.startDate][2]);
		$('#edit_set_end_value').val(g_rawData[this.endDate][2]);
		
		this.modal = true;
	},
	editChoiceChange: function() {
		var action = $('#zoom_dialog_edit_choice_select').val();
		switch(action) {
		case 'add':
			$('#zoom_dialog_edit_sum').show();
			$('#button_sum').show();
			$('#zoom_dialog_edit_set').hide();
			$('#button_set').hide();
			this.subtract = false;
			break;
		case 'subtract':
			$('#zoom_dialog_edit_sum').show();
			$('#button_sum').show();
			$('#zoom_dialog_edit_set').hide();
			$('#button_set').hide();
			this.subtract = true;
			break;
		case 'set':
			$('#zoom_dialog_edit_sum').hide();
			$('#button_sum').hide();
			$('#zoom_dialog_edit_set').show();
			$('#button_set').show();
			break;
		}
	}
};

// show graphs
// if comparison is on, get data from the global variables
// if request is null, show the current plan (the comparison plan has probably changed)
function showGraphs(request, update_flash) {
	if (request) {
		if (request.responseText) 
			g_plan = JSON.parse(request.responseText).mortgage_plan;
		else g_plan = JSON.parse(request).mortgage_plan;
		
		var series = getSeries(g_plan);
		g_payments = series[1];
		g_rates = series[0];
		
		// reset custom scenario rates (they will be loaded anyway)
		$('#custom_scenario_rates').val('');
		g_page_status.scenario_customized = false;
	}
	
	// disable the current plan in comparison list (and enable all the other plans)
	$("#plans_compare option").removeAttr("disabled");
	$("#plans_compare option[value='"+g_plan.id+"']").attr("disabled","disabled");
	
	var rates = g_rates;
	var payments = g_payments;
	
	// previous rawdata aren't valid anymore
	g_numberLookup = null;
	g_rawData = null;
	
	// if comparing plans, create "mixed" series
	if (g_page_status.comparison && g_page_status.comparison_plan_id) {
		rates = mergeSeries(g_rates, g_comparison_rates);
		payments = mergeSeries(g_payments, g_comparison_payments);
		
		var ratesLabels = ['Data','Tasso', 'Euribor', 'Tasso2', 'Euribor2'];
		var paymentsLables = ['Data','Rata', 'Interessi', 'Rata2', 'Interessi2'];
		var colors = ['#0000aa','#9999ff','#00dd00','#88ff88'];
	} else {
		var ratesLabels = ['Data','Tasso', 'Euribor'];
		var paymentsLables = ['Data','Rata', 'Interessi'];
		var colors = ['#0000aa','#9999ff'];
	}	
	
	// save these divs from deletion when rebuilding the graph
	$("body")
		.append($('#rates_graph_tips'))
		.append($("#zoom_dialog"));
	
	var g = new Dygraph(// containing div
		document.getElementById("graphdiv_rates"), // CSV or path to a CSV file.
		rates
		, {
			includeZero: true,
			labels: ratesLabels,
			colors: colors,
			labelsMeasureUnit: '%',
			zoomCallback: dyZoomCallback,
			clickCallback: dyClickCallback
			//valueRange: [0, 5.0],
	});
	
	g_rates_graph = g;
	
	$('#rates_graph_tips')
			.mouseenter(function(){g_ratesTips.hoveringTips = true;})
			.mouseleave(function(){g_ratesTips.hoveringTips = false; setTimeout('g_ratesTips.manageLeave()',50);})
			.appendTo($("#graphdiv_rates"));
	
	$(g_rates_graph.graphDiv)
		.mouseenter(function(){g_ratesTips.hoveringRates = true; $('#rates_graph_tips').show();})
		.mouseleave(function(){g_ratesTips.hoveringRates = false; setTimeout('g_ratesTips.manageLeave()',50);});
		
	$("#zoom_dialog")
			.appendTo($("#graphdiv_rates"));
				
	var g = new Dygraph(// containing div
	document.getElementById("graphdiv_payments"), // CSV or path to a CSV file.
		payments
		, {
			includeZero: true,
			labels: paymentsLables,
			colors: colors,
			labelsMeasureUnit: '€'
			//valueRange: [0, 5.0],
	});
	
	if (update_flash) {
		if (g_page_status.comparison && g_page_status.comparison_plan_id) {
			var tt = JSON.parse(g_totals_comparison_json);
		} else {
			var tt = JSON.parse(g_totals_json);
		}

		tt['elements'][0]['values'] = [g_plan.amount,g_plan.computed_total_interest,g_plan.computed_total_refund];
		if (g_page_status.comparison && g_page_status.comparison_plan_id) {
			tt['elements'][1]['values'] = [g_comparison_plan.amount,g_comparison_plan.computed_total_interest,g_comparison_plan.computed_total_refund];
			
			tt['elements'][0]['text'] = g_plan.name ? g_plan.name : "demo";
			tt['elements'][1]['text'] = g_comparison_plan.name;
		}
			
		var max = Math.max(g_plan.amount,g_plan.computed_total_interest)*1.10;
		if (g_page_status.comparison && g_page_status.comparison_plan_id) 
			max = Math.max(max, Math.max(g_comparison_plan.amount,g_comparison_plan.computed_total_interest)*1.10)
		tt.y_axis.max = max;
		tt.y_axis.steps = g_plan.amount/5;
		
		var to_show = JSON.stringify(tt);

		var tmp = findSWF("chart_totals");
		var x = tmp.load(to_show);
		
		if (g_page_status.comparison && g_page_status.comparison_plan_id) {
			var tt = JSON.parse(g_payments_comparison_json);
		} else {
			var tt = JSON.parse(g_payments_json);
		}
		
		tt['elements'][0]['values'] = [g_plan.computed_min_payment,g_plan.computed_avg_payment,g_plan.computed_max_payment];
		if (g_page_status.comparison && g_page_status.comparison_plan_id) {
			tt['elements'][1]['values'] = [g_comparison_plan.computed_min_payment,g_comparison_plan.computed_avg_payment,g_comparison_plan.computed_max_payment];
			
			tt['elements'][0]['text'] = g_plan.name ? g_plan.name : "demo";
			tt['elements'][1]['text'] = g_comparison_plan.name;
		}
			
		var max = g_plan.computed_max_payment*1.10;
		if (g_page_status.comparison && g_page_status.comparison_plan_id) 
			max = Math.max(max, g_comparison_plan.computed_max_payment*1.10)
		tt.y_axis.max = max;
		tt.y_axis.steps = g_plan.computed_avg_payment * 1.5 > max ? Math.floor(g_plan.computed_avg_payment/5.0) : Math.floor(max/5.0/1.10);
		
		to_show = JSON.stringify(tt);
		
		var tmp = findSWF("chart_payments");
		var x = tmp.load(to_show);
	}
	
	$('#lower_panel').unblock();
	if (g_plan.id != 1) {
		submitSetStatus('save'); // only if not in demo mode
		$('#mortgage_plan_submit').attr("disabled", false);
	}
	else 
		$('#mortgage_plan_submit').attr("disabled", true);
	
	// only if there is a super last payment
	if (!g_plan.name && g_plan.mortgage_type == "variable_fixed_payment" && g_plan.computed_final_payment > g_plan.computed_first_payment) alert("Attenzione: questo piano comporta una maxirata finale di "+Math.floor(g_plan.computed_final_payment)+" euro!");
}

// merge two series using dates from the longest one
function mergeSeries(s1, s2) {
	var ret = [];
	
	var l1 = s1.length;
	var l2 = s2.length;
	var l = Math.max(l1,l2);
	var lmin = Math.min(l1,l2);
	
	if (l1 >= l2) {
		var smax = s1;
	} else {
		smax = s2;
	}
	
	for (var n=0;n<lmin;n++) {
		ret.push( [smax[n][0], s1[n][1],s1[n][2],s2[n][1],s2[n][2]] );
	}
	
	if (l1 >= l2) {
		for (;n<l;n++) {
			ret.push( [smax[n][0], s1[n][1],s1[n][2],null, null] );
		}
	} else {
		for (;n<l;n++) {
			ret.push( [smax[n][0], null,null,s2[n][1],s2[n][2]] );
		}
	}
	
	return ret;
}

function getSeries(plan) {
	var payments = [];
	var rates = [];
	
	var pps = plan.payment_periods;
	
	for (var i=0;i<pps.length;i++) {
		var pp = pps[i];
		
		var d = pp.date.split('-');
		var date = new Date(d[0],d[1]-1,d[2]); // months are zero-indexed
		
		payments.push([date, pp.payment_due, pp.payment_interest]);
		rates.push([date, pp.interest_rate, pp.interest_rate_base]);
	}
	
	return [rates, payments];
}

function findSWF(movieName) {
	if (navigator.appName.indexOf("Microsoft")!= -1) {
		return window[movieName];
	} else {
		return document[movieName];
	}
}

function setComparisonTableData(plan) {
	$("#comparison_plan_amount_td").text(plan && plan.amount ? plan.amount : "");
	$("#comparison_plan_years_td").text(plan && plan.years ? plan.years : "");
	$("#comparison_plan_spread_td").text(plan && plan.spread ? plan.spread : "");
	$("#comparison_plan_cap_td").text(plan && plan.cap ? plan.cap : "");
	$("#comparison_plan_max_additional_years_td").text(plan && plan.max_additional_years ? plan.max_additional_years : "");
	$("#comparison_plan_fixed_rate_td").text(plan && plan.fixed_rate ? plan.fixed_rate : "");
	$("#comparison_plan_scenario_td").text(plan && plan.scenario ? $("#scenario option[value='"+plan.scenario+"']").text() : "");
	
	var type_suffix = '';
	if (plan.predetermined_principal_plan) type_suffix = ' qcp';
	$("#comparison_plan_mortgage_type_td").text(plan && plan.mortgage_type ? g_mortgage_type_names[plan.mortgage_type]+type_suffix : "");
	
	if (plan && plan.mortgage_type) mortgageTypeChanged(plan.mortgage_type,"comparison_");
}

function log(name) {
	jQuery.post( "/log_events/log", { name: name })
}

function togglePrivacyCheck() {
	if ($(this).attr('checked')) $("#create_user").removeAttr("disabled");
	else $("#create_user").attr("disabled","disabled");
}


/*!
 * jQuery blockUI plugin
 * Version 2.29 (10-DEC-2009)
 * @requires jQuery v1.2.3 or later
 *
 * Examples at: http://malsup.com/jquery/block/
 * Copyright (c) 2007-2008 M. Alsup
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 *
 * Thanks to Amir-Hossein Sobhi for some excellent contributions!
 */

;(function($) {

if (/1\.(0|1|2)\.(0|1|2)/.test($.fn.jquery) || /^1.1/.test($.fn.jquery)) {
	alert('blockUI requires jQuery v1.2.3 or later!  You are using v' + $.fn.jquery);
	return;
}

$.fn._fadeIn = $.fn.fadeIn;

// this bit is to ensure we don't call setExpression when we shouldn't (with extra muscle to handle
// retarded userAgent strings on Vista)
var mode = document.documentMode || 0;
var setExpr = $.browser.msie && (($.browser.version < 8 && !mode) || mode < 8);
var ie6 = $.browser.msie && /MSIE 6.0/.test(navigator.userAgent) && !mode;

// global $ methods for blocking/unblocking the entire page
$.blockUI   = function(opts) { install(window, opts); };
$.unblockUI = function(opts) { remove(window, opts); };

// convenience method for quick growl-like notifications  (http://www.google.com/search?q=growl)
$.growlUI = function(title, message, timeout, onClose) {
	var $m = $('<div class="growlUI"></div>');
	if (title) $m.append('<h1>'+title+'</h1>');
	if (message) $m.append('<h2>'+message+'</h2>');
	if (timeout == undefined) timeout = 3000;
	$.blockUI({
		message: $m, fadeIn: 700, fadeOut: 1000, centerY: false,
		timeout: timeout, showOverlay: false,
		onUnblock: onClose, 
		css: $.blockUI.defaults.growlCSS
	});
};

// plugin method for blocking element content
$.fn.block = function(opts) {
	return this.unblock({ fadeOut: 0 }).each(function() {
		if ($.css(this,'position') == 'static')
			this.style.position = 'relative';
		if ($.browser.msie)
			this.style.zoom = 1; // force 'hasLayout'
		install(this, opts);
	});
};

// plugin method for unblocking element content
$.fn.unblock = function(opts) {
	return this.each(function() {
		remove(this, opts);
	});
};

$.blockUI.version = 2.29; // 2nd generation blocking at no extra cost!

// override these in your code to change the default behavior and style
$.blockUI.defaults = {
	// message displayed when blocking (use null for no message)
	message:  '<h1>Please wait...</h1>',

	title: null,	  // title string; only used when theme == true
	draggable: true,  // only used when theme == true (requires jquery-ui.js to be loaded)
	
	theme: false, // set to true to use with jQuery UI themes
	
	// styles for the message when blocking; if you wish to disable
	// these and use an external stylesheet then do this in your code:
	// $.blockUI.defaults.css = {};
	css: {
		padding:	0,
		margin:		0,
		width:		'30%',
		top:		'40%',
		left:		'35%',
		textAlign:	'center',
		color:		'#000',
		border:		'3px solid #aaa',
		backgroundColor:'#fff',
		cursor:		'wait'
	},
	
	// minimal style set used when themes are used
	themedCSS: {
		width:	'30%',
		top:	'40%',
		left:	'35%'
	},

	// styles for the overlay
	overlayCSS:  {
		backgroundColor: '#000',
		opacity:	  	 0.6,
		cursor:		  	 'wait'
	},

	// styles applied when using $.growlUI
	growlCSS: {
		width:  	'350px',
		top:		'10px',
		left:   	'',
		right:  	'10px',
		border: 	'none',
		padding:	'5px',
		opacity:	0.6,
		cursor: 	'default',
		color:		'#fff',
		backgroundColor: '#000',
		'-webkit-border-radius': '10px',
		'-moz-border-radius':	 '10px'
	},
	
	// IE issues: 'about:blank' fails on HTTPS and javascript:false is s-l-o-w
	// (hat tip to Jorge H. N. de Vasconcelos)
	iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank',

	// force usage of iframe in non-IE browsers (handy for blocking applets)
	forceIframe: false,

	// z-index for the blocking overlay
	baseZ: 1000,

	// set these to true to have the message automatically centered
	centerX: true, // <-- only effects element blocking (page block controlled via css above)
	centerY: true,

	// allow body element to be stetched in ie6; this makes blocking look better
	// on "short" pages.  disable if you wish to prevent changes to the body height
	allowBodyStretch: true,

	// enable if you want key and mouse events to be disabled for content that is blocked
	bindEvents: true,

	// be default blockUI will supress tab navigation from leaving blocking content
	// (if bindEvents is true)
	constrainTabKey: true,

	// fadeIn time in millis; set to 0 to disable fadeIn on block
	fadeIn:  200,

	// fadeOut time in millis; set to 0 to disable fadeOut on unblock
	fadeOut:  400,

	// time in millis to wait before auto-unblocking; set to 0 to disable auto-unblock
	timeout: 0,

	// disable if you don't want to show the overlay
	showOverlay: true,

	// if true, focus will be placed in the first available input field when
	// page blocking
	focusInput: true,

	// suppresses the use of overlay styles on FF/Linux (due to performance issues with opacity)
	applyPlatformOpacityRules: true,

	// callback method invoked when unblocking has completed; the callback is
	// passed the element that has been unblocked (which is the window object for page
	// blocks) and the options that were passed to the unblock call:
	//	 onUnblock(element, options)
	onUnblock: null,

	// don't ask; if you really must know: http://groups.google.com/group/jquery-en/browse_thread/thread/36640a8730503595/2f6a79a77a78e493#2f6a79a77a78e493
	quirksmodeOffsetHack: 4
};

// private data and functions follow...

var pageBlock = null;
var pageBlockEls = [];

function install(el, opts) {
	var full = (el == window);
	var msg = opts && opts.message !== undefined ? opts.message : undefined;
	opts = $.extend({}, $.blockUI.defaults, opts || {});
	opts.overlayCSS = $.extend({}, $.blockUI.defaults.overlayCSS, opts.overlayCSS || {});
	var css = $.extend({}, $.blockUI.defaults.css, opts.css || {});
	var themedCSS = $.extend({}, $.blockUI.defaults.themedCSS, opts.themedCSS || {});
	msg = msg === undefined ? opts.message : msg;

	// remove the current block (if there is one)
	if (full && pageBlock)
		remove(window, {fadeOut:0});

	// if an existing element is being used as the blocking content then we capture
	// its current place in the DOM (and current display style) so we can restore
	// it when we unblock
	if (msg && typeof msg != 'string' && (msg.parentNode || msg.jquery)) {
		var node = msg.jquery ? msg[0] : msg;
		var data = {};
		$(el).data('blockUI.history', data);
		data.el = node;
		data.parent = node.parentNode;
		data.display = node.style.display;
		data.position = node.style.position;
		if (data.parent)
			data.parent.removeChild(node);
	}

	var z = opts.baseZ;

	// blockUI uses 3 layers for blocking, for simplicity they are all used on every platform;
	// layer1 is the iframe layer which is used to supress bleed through of underlying content
	// layer2 is the overlay layer which has opacity and a wait cursor (by default)
	// layer3 is the message content that is displayed while blocking

	var lyr1 = ($.browser.msie || opts.forceIframe) 
		? $('<iframe class="blockUI" style="z-index:'+ (z++) +';display:none;border:none;margin:0;padding:0;position:absolute;width:100%;height:100%;top:0;left:0" src="'+opts.iframeSrc+'"></iframe>')
		: $('<div class="blockUI" style="display:none"></div>');
	var lyr2 = $('<div class="blockUI blockOverlay" style="z-index:'+ (z++) +';display:none;border:none;margin:0;padding:0;width:100%;height:100%;top:0;left:0"></div>');
	
	var lyr3;
	if (opts.theme && full) {
		var s = '<div class="blockUI blockMsg blockPage ui-dialog ui-widget ui-corner-all" style="z-index:'+z+';display:none;position:fixed">' +
					'<div class="ui-widget-header ui-dialog-titlebar blockTitle">'+(opts.title || '&nbsp;')+'</div>' +
					'<div class="ui-widget-content ui-dialog-content"></div>' +
				'</div>';
		lyr3 = $(s);
	}
	else {
		lyr3 = full ? $('<div class="blockUI blockMsg blockPage" style="z-index:'+z+';display:none;position:fixed"></div>')
					: $('<div class="blockUI blockMsg blockElement" style="z-index:'+z+';display:none;position:absolute"></div>');
	}						   

	// if we have a message, style it
	if (msg) {
		if (opts.theme) {
			lyr3.css(themedCSS);
			lyr3.addClass('ui-widget-content');
		}
		else 
			lyr3.css(css);
	}

	// style the overlay
	if (!opts.applyPlatformOpacityRules || !($.browser.mozilla && /Linux/.test(navigator.platform)))
		lyr2.css(opts.overlayCSS);
	lyr2.css('position', full ? 'fixed' : 'absolute');

	// make iframe layer transparent in IE
	if ($.browser.msie || opts.forceIframe)
		lyr1.css('opacity',0.0);

	//$([lyr1[0],lyr2[0],lyr3[0]]).appendTo(full ? 'body' : el);
	var layers = [lyr1,lyr2,lyr3], $par = full ? $('body') : $(el);
	$.each(layers, function() {
		this.appendTo($par);
	});
	
	if (opts.theme && opts.draggable && $.fn.draggable) {
		lyr3.draggable({
			handle: '.ui-dialog-titlebar',
			cancel: 'li'
		});
	}

	// ie7 must use absolute positioning in quirks mode and to account for activex issues (when scrolling)
	var expr = setExpr && (!$.boxModel || $('object,embed', full ? null : el).length > 0);
	if (ie6 || expr) {
		// give body 100% height
		if (full && opts.allowBodyStretch && $.boxModel)
			$('html,body').css('height','100%');

		// fix ie6 issue when blocked element has a border width
		if ((ie6 || !$.boxModel) && !full) {
			var t = sz(el,'borderTopWidth'), l = sz(el,'borderLeftWidth');
			var fixT = t ? '(0 - '+t+')' : 0;
			var fixL = l ? '(0 - '+l+')' : 0;
		}

		// simulate fixed position
		$.each([lyr1,lyr2,lyr3], function(i,o) {
			var s = o[0].style;
			s.position = 'absolute';
			if (i < 2) {
				full ? s.setExpression('height','Math.max(document.body.scrollHeight, document.body.offsetHeight) - (jQuery.boxModel?0:'+opts.quirksmodeOffsetHack+') + "px"')
					 : s.setExpression('height','this.parentNode.offsetHeight + "px"');
				full ? s.setExpression('width','jQuery.boxModel && document.documentElement.clientWidth || document.body.clientWidth + "px"')
					 : s.setExpression('width','this.parentNode.offsetWidth + "px"');
				if (fixL) s.setExpression('left', fixL);
				if (fixT) s.setExpression('top', fixT);
			}
			else if (opts.centerY) {
				if (full) s.setExpression('top','(document.documentElement.clientHeight || document.body.clientHeight) / 2 - (this.offsetHeight / 2) + (blah = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + "px"');
				s.marginTop = 0;
			}
			else if (!opts.centerY && full) {
				var top = (opts.css && opts.css.top) ? parseInt(opts.css.top) : 0;
				var expression = '((document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + '+top+') + "px"';
				s.setExpression('top',expression);
			}
		});
	}

	// show the message
	if (msg) {
		if (opts.theme)
			lyr3.find('.ui-widget-content').append(msg);
		else
			lyr3.append(msg);
		if (msg.jquery || msg.nodeType)
			$(msg).show();
	}

	if (($.browser.msie || opts.forceIframe) && opts.showOverlay)
		lyr1.show(); // opacity is zero
	if (opts.fadeIn) {
		if (opts.showOverlay)
			lyr2._fadeIn(opts.fadeIn);
		if (msg)
			lyr3._fadeIn(opts.fadeIn);
	}
	else {
		if (opts.showOverlay)
			lyr2.show();
		if (msg)
			lyr3.show();
	}

	// bind key and mouse events
	bind(1, el, opts);

	if (full) {
		pageBlock = lyr3[0];
		pageBlockEls = $(':input:enabled:visible',pageBlock);
		if (opts.focusInput)
			setTimeout(focus, 20);
	}
	else
		center(lyr3[0], opts.centerX, opts.centerY);

	if (opts.timeout) {
		// auto-unblock
		var to = setTimeout(function() {
			full ? $.unblockUI(opts) : $(el).unblock(opts);
		}, opts.timeout);
		$(el).data('blockUI.timeout', to);
	}
};

// remove the block
function remove(el, opts) {
	var full = (el == window);
	var $el = $(el);
	var data = $el.data('blockUI.history');
	var to = $el.data('blockUI.timeout');
	if (to) {
		clearTimeout(to);
		$el.removeData('blockUI.timeout');
	}
	opts = $.extend({}, $.blockUI.defaults, opts || {});
	bind(0, el, opts); // unbind events
	
	var els;
	if (full) // crazy selector to handle odd field errors in ie6/7
		els = $('body').children().filter('.blockUI').add('body > .blockUI');
	else
		els = $('.blockUI', el);

	if (full)
		pageBlock = pageBlockEls = null;

	if (opts.fadeOut) {
		els.fadeOut(opts.fadeOut);
		setTimeout(function() { reset(els,data,opts,el); }, opts.fadeOut);
	}
	else
		reset(els, data, opts, el);
};

// move blocking element back into the DOM where it started
function reset(els,data,opts,el) {
	els.each(function(i,o) {
		// remove via DOM calls so we don't lose event handlers
		if (this.parentNode)
			this.parentNode.removeChild(this);
	});

	if (data && data.el) {
		data.el.style.display = data.display;
		data.el.style.position = data.position;
		if (data.parent)
			data.parent.appendChild(data.el);
		$(el).removeData('blockUI.history');
	}

	if (typeof opts.onUnblock == 'function')
		opts.onUnblock(el,opts);
};

// bind/unbind the handler
function bind(b, el, opts) {
	var full = el == window, $el = $(el);

	// don't bother unbinding if there is nothing to unbind
	if (!b && (full && !pageBlock || !full && !$el.data('blockUI.isBlocked')))
		return;
	if (!full)
		$el.data('blockUI.isBlocked', b);

	// don't bind events when overlay is not in use or if bindEvents is false
	if (!opts.bindEvents || (b && !opts.showOverlay)) 
		return;

	// bind anchors and inputs for mouse and key events
	var events = 'mousedown mouseup keydown keypress';
	b ? $(document).bind(events, opts, handler) : $(document).unbind(events, handler);

// former impl...
//	   var $e = $('a,:input');
//	   b ? $e.bind(events, opts, handler) : $e.unbind(events, handler);
};

// event handler to suppress keyboard/mouse events when blocking
function handler(e) {
	// allow tab navigation (conditionally)
	if (e.keyCode && e.keyCode == 9) {
		if (pageBlock && e.data.constrainTabKey) {
			var els = pageBlockEls;
			var fwd = !e.shiftKey && e.target == els[els.length-1];
			var back = e.shiftKey && e.target == els[0];
			if (fwd || back) {
				setTimeout(function(){focus(back)},10);
				return false;
			}
		}
	}
	// allow events within the message content
	if ($(e.target).parents('div.blockMsg').length > 0)
		return true;

	// allow events for content that is not being blocked
	return $(e.target).parents().children().filter('div.blockUI').length == 0;
};

function focus(back) {
	if (!pageBlockEls)
		return;
	var e = pageBlockEls[back===true ? pageBlockEls.length-1 : 0];
	if (e)
		e.focus();
};

function center(el, x, y) {
	var p = el.parentNode, s = el.style;
	var l = ((p.offsetWidth - el.offsetWidth)/2) - sz(p,'borderLeftWidth');
	var t = ((p.offsetHeight - el.offsetHeight)/2) - sz(p,'borderTopWidth');
	if (x) s.left = l > 0 ? (l+'px') : '0';
	if (y) s.top  = t > 0 ? (t+'px') : '0';
};

function sz(el, p) {
	return parseInt($.css(el,p))||0;
};

})(jQuery);
