text: // Copyright Erik Weitnauer 2014.
  var uid=function(){var t=4294967296,e=15,r=[];str=["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"];function n(){var n=0;var a=Math.random()*t;r[n++]=str[a&e];r[n++]=str[a>>>4&e];r[n++]=str[a>>>8&e];r[n++]=str[a>>>12&e];r[n++]=str[a>>>16&e];r[n++]=str[a>>>20&e];r[n++]=str[a>>>24&e];r[n++]=str[a>>>28&e];a=Math.random()*t;r[n++]=str[a&e];r[n++]=str[a>>>4&e];r[n++]=str[a>>>8&e];r[n++]=str[a>>>12&e];r[n++]=str[a>>>16&e];r[n++]=str[a>>>20&e];r[n++]=str[a>>>24&e];r[n++]=str[a>>>28&e];return"_"+r.join("")}return n}();function IntervalList(){this.ivs=[]}if(typeof exports!=="undefined")exports.IntervalList=IntervalList;IntervalList.prototype.overlap=function(t,e){return t[0]<e[1]&&e[0]<t[1]};IntervalList.prototype.overlapOrTouch=function(t,e){return t[0]<=e[1]&&e[0]<=t[1]};IntervalList.prototype.getMissingIntervals=function(t){var e=[];var r=t.slice();for(var n=0;n<this.ivs.length;n++){var a=this.ivs[n];if(!this.overlap(a,r)){if(a[0]>r[1])break;else continue}if(r[0]<a[0])e.push([r[0],a[0]]);r[0]=a[1]}if(r[1]>r[0])e.push(r);return e};IntervalList.prototype.insert=function(t){var e=-1,r=-1,n=0;for(var a=0;a<this.ivs.length;a++){var i=this.ivs[a];if(i[1]<t[0])n++;if(this.overlapOrTouch(i,t)){e=e===-1?a:e;r=a}else{if(e!==-1)break}}var s=e===-1?t[0]:Math.min(t[0],this.ivs[e][0]),o=r===-1?t[1]:Math.max(t[1],this.ivs[r][1]);if(e===-1)this.ivs.splice(n,0,[s,o]);else this.ivs.splice(e,r-e+1,[s,o])};function DataSource(t,e){var r=t.split("/");this.ex=r[0];this.pair=r[1];this.loaded_ivs={"1min":new IntervalList,"5min":new IntervalList,"30min":new IntervalList,"4h":new IntervalList,"1d":new IntervalList};this.data={"1min":[],"5min":[],"30min":[],"4h":[],"1d":[]};this.loading=false;this.bisect=d3.bisector(function(t){return t.time_end}).right;this.server_url=e||"http://localhost:3000";this.active=true}DataSource.prototype.loadData=function(t,e,r){var n=this.loaded_ivs[e].getMissingIntervals(t);if(n.length===0)r(this.getDataFromCache(t,e));var a=n.length,i=this;var s=function(){a-=1;if(a===0){i.loading=false;r(i.getDataFromCache(t,e))}};this.loading=true;n.forEach(function(t){i.queryDataFromServer(t,e,s)})};DataSource.prototype.getDataFromCache=function(t,e,r){var n=this.data[e];var a=+new Date(t[0]),i=+new Date(t[1]);var s=this.bisect(n,a),o=this.bisect(n,i,s);var u=n.slice(s,o);if(r)r(u);return u};DataSource.prototype.queryDataFromServer=function(t,e,r){var n=200;var a=this.server_url+"/api/trades/"+this.ex+"/"+this.pair;a+="?limit="+n+"&group_by="+e+"&time="+t[0]+"&time_end="+t[1];var i=this;d3.json(a,function(a){if(!a||a.length===0){r();return}i.convertDates(a);a.sort(function(t,e){return-e.time_start+t.time_start});i.insertData(a,e);if(a.length===n){console.info("more data on the server for this interval...");i.loaded_ivs[e].insert([a[0].time_start,t[1]]);i.queryDataFromServer([t[0],a[0].time_start],e,r)}else{i.loaded_ivs[e].insert(t);r()}})};DataSource.prototype.queryTradeCountFromServer=function(t){var e=this.server_url+"/api/trades/"+this.ex+"/"+this.pair;e+="?count=1";d3.json(e,t)};DataSource.prototype.convertDates=function(t){for(var e=0;e<t.length;e++){t[e].time_start=+new Date(t[e].time_start);t[e].time_end=+new Date(t[e].time_end)}};DataSource.prototype.insertData=function(t,e){var r=t[0];var n=this.data[e];var a=this.bisect(n,r.time_start);this.data[e]=n.slice(0,a).concat(t).concat(n.slice(a))};function PlotData(t){t=t||{};this.label=t.label||"???";this.sources=t.sources||[];this.mode=t.mode||"vwap";this.group_by=t.group_by||"1min"}var VolumePlot=function(){var t,e,r,n=uid(),a=100,i=100,s,o,u,l,c,d=.25,p=d3.scale.category10(),f,v=false,h=d3.bisector(function(t){return t.time_end}).right,m=d3.bisector(function(t){return t.time_start}).right,_="volume",g;var y=function(t){u=t;y.init();return this};y.x_scale=function(t){if(arguments.length===0)return r;r=t;if(v)y.update_x(0);return this};y.color=function(t){if(arguments.length===0)return p;p=t;if(v)y.update_x(0);return this};y.size=function(e){if(arguments.length===0)return[a,i];a=e[0];i=e[1];if(v){t.range([i,0]);y.update(0);c.attr({width:a,height:i});o.attr("transform","translate("+a+",0)")}return this};y.vis_type=function(t){if(arguments.length===0)return _;_=t;if(v)y.clear();return this};y.data_layers=function(t,e){if(arguments.length===0)return f;f=t;if(v)y.update(e);return this};y.init=function(){v=true;t=d3.scale.linear().range([i,0]).domain([0,0]);c=u.append("clipPath").attr("id","clip_"+n).append("rect").attr({width:a,height:i});s=d3.svg.axis().scale(t).ticks(Math.round(i/20)).tickSize(i>100?-a:0).outerTickSize(0).orient("right");o=u.append("g").attr("class","y axis").attr("transform","translate("+a+",0)");u.append("rect").attr("width",a).attr("height",i).classed("border",true);l=u.append("g").attr("clip-path","url(#clip_"+n+")").append("g")};y.update=function(t){t=t||0;y.update_x_axis(t);y.scale_y_axis(t);var e=l.selectAll(".layer").data(f,function(t){return t.id});e.enter().append("g").classed("layer",true);e.exit().remove();e.each(function(e){var r=d3.select(this);y.update_layer(r,e,t)})};y.update_layer=function(t,e,r){if(_==="volume")y.update_volume_layer(t,e,r);if(_==="candles")y.update_candles_layer(t,e,r);if(_==="vwap")y.update_vwap_layer(t,e,r)};y.update_volume_layer=function(e,n,a){var i=p(n.id);var s=e.selectAll(".box");s=s.data(n.data,function(t){return t._id});var o,u;if(n.data.length>0)o=r(n.data[0].time_end)-r(n.data[0].time_start);u=o*d/2;o=o-2*u;var l=s.enter().append("g").attr("class","box").attr("transform",function(t){return"translate("+r(t.time_start)+",0)"}).style("opacity",1e-5);l.append("rect").attr("x",u).attr("width",o).attr("y",function(e){return t(e.volume)}).attr("height",function(e){return t(0)-t(e.volume)}).style("stroke",i).style("fill",i).style("fill-opacity",.3);s.transition().duration(a).attr("transform",function(t){return"translate("+r(t.time_start)+",0)"}).style("opacity",1).select("rect").attr("y",function(e){return t(e.volume)}).attr("height",function(e){return t(0)-t(e.volume)});s.exit().remove()};y.update_candles_layer=function(e,n,a){var i=p(n.id);var s=e.selectAll(".box");s=s.data(n.data,function(t){return t._id});var o,u;if(n.data.length>0)o=r(n.data[0].time_end)-r(n.data[0].time_start);u=o*d/2;o=o-2*u;var l=s.enter().append("g").attr("class","box").attr("transform",function(t){return"translate("+r(t.time_start)+",0)"}).style("opacity",1e-5);l.append("line").attr("x1",u+o/2).attr("x2",u+o/2).attr("y1",function(e){return t(e.price_min)}).attr("y2",function(e){return t(e.price_max)}).style("stroke","silver");l.append("rect").attr("x",u).attr("width",o).attr("y",function(e){return Math.min(t(e.price_start),t(e.price_end))}).attr("height",function(e){return Math.max(.5,Math.abs(-t(e.price_start)+t(e.price_end)))}).style("fill",function(t){return t.price_start<t.price_end?"#64FF64":"#FF6464"}).style("stroke","black");var c=s.transition().duration(a).attr("transform",function(t){return"translate("+r(t.time_start)+",0)"}).style("opacity",1);c.select("line").attr("y1",function(e){return t(e.price_min)}).attr("y2",function(e){return t(e.price_max)});c.select("rect").attr("y",function(e){return Math.min(t(e.price_start),t(e.price_end))}).attr("height",function(e){return Math.max(.5,Math.abs(-t(e.price_start)+t(e.price_end)))});s.exit().remove()};y.update_vwap_layer_single_path=function(n,a,i){var s=p(a.id);var o=n.selectAll("circle.vwap").data(a.data,function(t){return t._id});o.enter().append("circle").classed("vwap",true).style("fill",s).attr("r",1.5);o.transition().duration(i).attr("cx",function(t){return r((+t.time_start+ +t.time_end)/2)}).attr("cy",function(e){return t(e.vwap)});o.exit().remove();var u=n.selectAll("path.vwap").data([a.data]);u.enter().append("path").classed("vwap",true).style("fill","none").attr("d",g).style("stroke",s);if(i>0){var l=t.domain();if(e)t.domain(e);u.attr("d",g);t.domain(l)}u.transition().duration(i).attr("d",g);u.exit().remove()};y.set_vwap_line=function(e){e.style("display",function(t){var e=t[1].time_start-t[0].time_start;var r=t[0].time_end-t[0].time_start;return e<=3*r?"auto":"none"}).attr("x1",function(t){return r((+t[0].time_start+ +t[0].time_end)/2)}).attr("y1",function(e){return t(e[0].vwap)}).attr("x2",function(t){return r((+t[1].time_start+ +t[1].time_end)/2)}).attr("y2",function(e){return t(e[1].vwap)})};y.update_vwap_layer=function(n,a,i){var s=p(a.id);var o=n.selectAll("circle.vwap").data(a.data,function(t){return t._id});o.enter().append("circle").classed("vwap",true).style("fill",s).attr("r",1.5);var u=n.selectAll("line.vwap").data(d3.pairs(a.data),function(t){return t[0]._id});u.enter().append("line").classed("vwap",true).style("fill","none").call(this.set_vwap_line).style("stroke",s);if(i>0){var l=t.domain();if(e)t.domain(e);u.call(this.set_vwap_line);o.attr("cx",function(t){return r((+t.time_start+ +t.time_end)/2)}).attr("cy",function(e){return t(e.vwap)});t.domain(l)}o.transition().duration(i).attr("cx",function(t){return r((+t.time_start+ +t.time_end)/2)}).attr("cy",function(e){return t(e.vwap)});o.exit().remove();u.transition().duration(i).call(this.set_vwap_line);u.exit().remove()};y.scale_y_axis=function(n){var a=[],i=[];var u=d3.max(f,function(t){var e=h(t.data,r.domain()[0]),n=m(t.data,r.domain()[1],e),s=t.data.filter(function(t,r){return r>=e&&r<n});if(_==="volume"){i.push(d3.max(s,function(t){return t.volume}))}else{a.push(d3.min(s,function(t){return t.price_min}));i.push(d3.max(s,function(t){return t.price_max}))}});if(i.length===0||i[0]===undefined)return false;var l=_==="volume"?0:d3.min(a)||0,c=d3.max(i)||0,d=c-l,p=t.domain(),v=p[1]-p[0],g=_==="volume"?0:.2,y=_==="volume"?.1:.2;e=p;if(l<p[0]||l>p[0]+g*d||c>p[1]||c<p[1]-y*d){if(d===0)t.domain([l-v/2,c+v/2]);else t.domain([l-d*g/2,c+d*y/2]);s.scale(t);o.transition().duration(n).call(s);return true}return false};y.update_x_axis=function(t){};y.clear=function(){l.selectAll(".layer").remove()};y.shift_x=function(t,e){e=e||0;l.transition().duration(e).ease("linear").attr("transform","translate("+t+",0)")};return y};var MainPlot=function(){var t,e,r,n=400,a={top:10,right:70,bottom:10,left:10,between:35},i,s,o,u,l=[],c=[],d=null,p=.75,f=true,v="4h",h=["1min","5min","30min","4h","1d"],m="vwap",_=["vwap","candles"],g={"1min":1e3*60,"5min":1e3*60*5,"30min":1e3*60*30,"4h":1e3*3600*4,"1d":1e3*3600*24},y=10,x,w,b=d3.time.scale(),D,k,S=d3.scale.category10(),L=d3.time.format("%b/%d %I:%M:%S %p"),C,I,M,A,P=0;var F=function(t){e=d3.select(t);if(!d)d=Date.now();F.init();return this};var z=function(){return(n-a.between)*.8};var E=function(){return(n-a.between)*.2};F.width=function(){return o?o.node().getBoundingClientRect().width-a.left-a.right:0};F.pairSources=function(t){if(arguments.length===0)return c;c=t;F.setPairByIndex(0);return this};F.setPairByIndex=function(t){if(t<0||t>=c.length)return;var e=c[0];c[0]=c[t];c[t]=e;F.label(c[0].name);F.dataSources(c[0].sources);return this};F.dataSources=function(t){if(arguments.length===0)return l;l=t;return this};F.addDataSource=function(t,e){if(typeof e==="undefined")e=true;l.push(t);t.active=e;return this};F.label=function(e){if(arguments.length===0)return t;t=e;if(r)r.select("span").text(t);return this};F.height=function(t){if(arguments.length===0)return n;n=t;return this};F.int_mode=function(t){if(arguments.length===0)return v;v=t;if(o){F.clear();F.update()}return this};F.plot_type=function(t){if(arguments.length===0)return m;if(t!==m){if(t==="candles"){var e=0;for(var r=0;r<l.length;r++)if(l[r].active)e++;if(e>1){var n=0;for(var a=0;a<l.length;a++){if(n>0)l[a].active=false;if(l[a].active)n++}}F.updateLegend()}m=t;I.vis_type(t);F.update(true,false)}return this};F.time_end=function(t){if(arguments.length===0)return d;d=t;return this};F.init=function(){j();V()};F.clear=function(){I.clear();C.clear()};F.update=function(t,e){if(typeof t==="undefined")t=true;if(typeof e==="undefined")e=true;var r=B();var n=O();b.domain(r);var a=[],i=0;function s(r,n){if(r)a.push({id:r,data:n});if(++i==l.length){F.update_x_axis(250);if(t)I.data_layers(a,250);if(e)C.data_layers(a,250)}}l.forEach(function(t){if(!t.active)s();else t.loadData(n,v,function(e){s(t.ex,e)})})};F.shiftData=function(t){var e=b.invert(t)-b.invert(0);var r=b.domain();var n=b.range();t=b(e)-b(0);P+=t;d-=e;b.range([b(r[0]-e),b(r[1]-e)]);b.domain([r[0]-e,r[1]-e]);var i=k.transition().duration(0).ease("linear").attr("transform","translate("+P+",0)").call(D);i.selectAll("text").attr("y",-a.between/2+4);i.selectAll("line").style("stroke-dasharray",[5,a.between-10-1,5]);C.shift_x(P);I.shift_x(P)};F.update_x_axis=function(t){var e=k.transition().duration(t).call(D);e.selectAll("text").attr("y",-a.between/2+4);e.selectAll("line").style("stroke-dasharray",[5,a.between-10-1,5])};function T(){M.attr("display","none");f=false;var t=d3.event.dx;if(!t)return;F.shiftData(t)}function q(){M.attr("display","auto");F.update()}function j(){var l=d3.behavior.drag().origin(function(t){return{x:0,y:0}}).on("drag",T).on("dragend",q);s=e.append("div").classed("right-col-wrapper",true).append("div").classed("right-col",true);i=e.append("div").classed("left-col",true);r=i.append("h2").on("click",F.choosePair);r.append("span").text(t);r.append("svg").attr({width:21,height:21}).append("path").attr("d","M15,16 L10,11 M15,16 L20,11").style({stroke:"black",fill:"none"});var c=i.append("div").classed("interval-selection",true).selectAll("div.selector").data(h).enter().append("div").classed("selector",true).classed("selected",function(t){return t===v}).text(function(t){return{"1min":"1 min","5min":"5 min","30min":"30 min","4h":"4 h","1d":"1 d"}[t]}).on("click",function(t){c.classed("selected",false);d3.select(this).classed("selected",true);F.int_mode(t)});var d=i.append("div").classed("plot-type-selection",true).selectAll("div.selector").data(_).enter().append("div").classed("selector",true).classed("selected",function(t){return t===m}).text(function(t){return t}).on("click",function(t){d.classed("selected",false);d3.select(this).classed("selected",true);F.plot_type(t)});x=i.append("div").classed("legend",true);F.setupLegend();o=s.append("svg").attr({width:"100%",height:n+a.top+a.bottom+a.between});u=o.append("g").attr("transform","translate("+a.left+","+a.top+")");o.append("rect").style({fill:"none",stroke:"none","pointer-events":"all"}).attr({width:"100%",height:"100%"}).on("mousemove",function(){var t=d3.mouse(u.node());var e=b.invert(t[0]-P);M.attr("transform","translate("+(t[0]-.5)+",0)");A.text(L(e))}).on("mouseleave",function(){M.attr("display","none")}).on("mouseenter",function(){M.attr("display","auto")}).call(l);D=d3.svg.axis().scale(b).orient("top").outerTickSize(0).tickSize(a.between).tickPadding(0);k=u.append("g").attr("transform","translate(0, "+(z()+a.between)+")").append("g").attr("class","x axis");u.append("g").classed("price-plot",true);u.append("g").classed("volume-plot",true).attr("transform","translate(0, "+(z()+a.between)+")");M=u.append("g").attr("transform","translate(0,0)").attr("display","none");M.append("line").classed("ruler",true).attr({y1:0,y2:n});M.append("rect").attr({fill:"white",rx:3,ry:3,stroke:"silver",width:100,height:16,x:-50,y:z()+a.between/2-6});A=M.append("text").classed("ruler-text",true).attr({x:-46,y:z()+a.between/2+5})}F.setupLegend=function(){x.selectAll("div").remove();w=x.selectAll("div.legend-item").data(l);var t=w.enter().append("div").classed("legend-item",true);t.append("span").classed("label",true).text(function(t){return t.ex}).on("click",F.toggleSource);t.append("span").classed("marker",true).on("click",F.toggleSource);F.updateLegend()};F.choosePair=function(){r.insert("div").classed("on_top",true).selectAll("span").data(c).enter().append("span").text(function(t){return t.name}).on("click",function(t,e){d3.event.stopPropagation();r.select("div.on_top").remove();F.setPairByIndex(e);F.setupLegend();F.update()})};F.toggleSource=function(t){var e=0;for(var r=0;r<l.length;r++)if(l[r].active)e++;if(e===1){if(m==="candles"){for(var r=0;r<l.length;r++)l[r].active=false}}t.active=!t.active;F.updateLegend();F.update()};F.updateLegend=function(){w.select(".marker").style("background",function(t){return t.active?S(t.ex):"silver"})};function B(){var t=f?Date.now():d;d=t;return[Math.round(t-F.width()/y*g[v]),t]}function O(){var t=B();t[0]-=p*(t[1]-t[0]);t[1]+=p*(t[1]-t[0]);return[t[0],t[1]]}function V(){b.range([0,F.width()]);S=d3.scale.category10();I=VolumePlot().x_scale(b).size([F.width(),z()]).color(S).vis_type(m);o.select(".price-plot").call(I);C=VolumePlot().x_scale(b).size([F.width(),E()]).color(S).vis_type("volume");o.select(".volume-plot").call(C);F.update()}return F};CCClient={};CCClient.init=function(t){plots=[];pair2source={};pair_sources=[];e(i);function e(e){var n=t+"/api/trades/";d3.json(n,function(n){for(var a in n){var i=n[a];for(var s=0;s<i.length;s++){addServerPair(i[s],a)}}for(var o in pair2source){var u=pair2source[o].map(function(e){return new DataSource(e.ex+"/"+e.pair,t)});pair_sources.push({sources:u,name:o})}r(function(){plots.push(MainPlot().pairSources(pair_sources));e()})})}function r(t){var e=0;pair_sources.forEach(function(t){e+=t.sources.length});function r(r,n,a){if(r.tradesCount)r.tradesCount+=a;else r.tradesCount=a;if(--e===0){r.sort(function(t,e){return e.tradesCount-t.tradesCount});t()}}pair_sources.forEach(function(t){t.sources.forEach(function(t){t.queryTradeCountFromServer(function(e){r(pair_sources,t,e)})})})}function n(t){var e;if(t.indexOf("_")===-1){e=[t.substring(0,3),t.substring(3)]}else e=t.split("_");return e[0].toUpperCase()+" / "+e[1].toUpperCase()}function a(t){var e=n(t).split(" / ");return e[1]+" / "+e[0]}addServerPair=function(t,e){var r=n(t);var i=a(t);var s;if(r in pair2source||!(i in pair2source))s=r;else s=i;pair2source[s]=pair2source[s]||[];pair2source[s].push({ex:e,pair:t})};function i(){var t=d3.select("body").selectAll("div.plot").data(plots);var e=t.enter().append("div").classed("plot",true).each(function(t){t(this)});setInterval(s,6e4)}function s(){plots.forEach(function(t){t.update()})}};