m&&(m=s.x),s.y>y&&(y=s.y),f.push(s.x),h.push(s.y);else for(g=0;p>g;++g){var b=+M(s=n[g],g),_=+x(s,g);v>b&&(v=b),d>_&&(d=_),b>m&&(m=b),_>y&&(y=_),f.push(b),h.push(_)}var w=m-v,S=y-d;w>S?y=d+w:m=v+S;var k=su();if(k.add=function(n){i(k,n,+M(n,++g),+x(n,g),v,d,m,y)},k.visit=function(n){fu(n,k,v,d,m,y)},k.find=function(n){return hu(k,n[0],n[1],v,d,m,y)},g=-1,null==t){for(;++g=0?n.slice(0,t):n,r=t>=0?n.slice(t+1):"in";return e=cl.get(e)||al,r=ll.get(r)||y,Mu(r(e.apply(null,ea.call(arguments,1))))},ta.interpolateHcl=Lu,ta.interpolateHsl=Tu,ta.interpolateLab=Ru,ta.interpolateRound=Du,ta.transform=function(n){var t=ua.createElementNS(ta.ns.prefix.svg,"g");return(ta.transform=function(n){if(null!=n){t.setAttribute("transform",n);var e=t.transform.baseVal.consolidate()}return new Pu(e?e.matrix:sl)})(n)},Pu.prototype.toString=function(){return"translate("+this.translate+")rotate("+this.rotate+")skewX("+this.skew+")scale("+this.scale+")"};var sl={a:1,b:0,c:0,d:1,e:0,f:0};ta.interpolateTransform=Hu,ta.layout={},ta.layout.bundle=function(){return function(n){for(var t=[],e=-1,r=n.length;++ea*a/d){if(p>c){var l=t.charge/c;n.px-=i*l,n.py-=o*l}return!0}if(t.point&&c&&p>c){var l=t.pointCharge/c;n.px-=i*l,n.py-=o*l}}return!t.charge}}function t(n){n.px=ta.event.x,n.py=ta.event.y,a.resume()}var e,r,u,i,o,a={},c=ta.dispatch("start","tick","end"),l=[1,1],s=.9,f=fl,h=hl,g=-30,p=gl,v=.1,d=.64,m=[],M=[];return a.tick=function(){if((r*=.99)<.005)return c.end({type:"end",alpha:r=0}),!0;var t,e,a,f,h,p,d,y,x,b=m.length,_=M.length;for(e=0;_>e;++e)a=M[e],f=a.source,h=a.target,y=h.x-f.x,x=h.y-f.y,(p=y*y+x*x)&&(p=r*i[e]*((p=Math.sqrt(p))-u[e])/p,y*=p,x*=p,h.x-=y*(d=f.weight/(h.weight+f.weight)),h.y-=x*d,f.x+=y*(d=1-d),f.y+=x*d);if((d=r*v)&&(y=l[0]/2,x=l[1]/2,e=-1,d))for(;++e0?n:0:n>0&&(c.start({type:"start",alpha:r=n}),ta.timer(a.tick)),a):r},a.start=function(){function n(n,r){if(!e){for(e=new Array(c),a=0;c>a;++a)e[a]=[];for(a=0;s>a;++a){var u=M[a];e[u.source.index].push(u.target),e[u.target.index].push(u.source)}}for(var i,o=e[t],a=-1,l=o.length;++at;++t)(r=m[t]).index=t,r.weight=0;for(t=0;s>t;++t)r=M[t],"number"==typeof r.source&&(r.source=m[r.source]),"number"==typeof r.target&&(r.target=m[r.target]),++r.source.weight,++r.target.weight;for(t=0;c>t;++t)r=m[t],isNaN(r.x)&&(r.x=n("x",p)),isNaN(r.y)&&(r.y=n("y",v)),isNaN(r.px)&&(r.px=r.x),isNaN(r.py)&&(r.py=r.y);if(u=[],"function"==typeof f)for(t=0;s>t;++t)u[t]=+f.call(this,M[t],t);else for(t=0;s>t;++t)u[t]=f;if(i=[],"function"==typeof h)for(t=0;s>t;++t)i[t]=+h.call(this,M[t],t);else for(t=0;s>t;++t)i[t]=h;if(o=[],"function"==typeof g)for(t=0;c>t;++t)o[t]=+g.call(this,m[t],t);else for(t=0;c>t;++t)o[t]=g;return a.resume()},a.resume=function(){return a.alpha(.1)},a.stop=function(){return a.alpha(0)},a.drag=function(){return e||(e=ta.behavior.drag().origin(y).on("dragstart.force",Xu).on("drag.force",t).on("dragend.force",$u)),arguments.length?void this.on("mouseover.force",Bu).on("mouseout.force",Wu).call(e):e},ta.rebind(a,c,"on")};var fl=20,hl=1,gl=1/0;ta.layout.hierarchy=function(){function n(u){var i,o=[u],a=[];for(u.depth=0;null!=(i=o.pop());)if(a.push(i),(l=e.call(n,i,i.depth))&&(c=l.length)){for(var c,l,s;--c>=0;)o.push(s=l[c]),s.parent=i,s.depth=i.depth+1;r&&(i.value=0),i.children=l}else r&&(i.value=+r.call(n,i,i.depth)||0),delete i.children;return Qu(u,function(n){var e,u;t&&(e=n.children)&&e.sort(t),r&&(u=n.parent)&&(u.value+=n.value)}),a}var t=ei,e=ni,r=ti;return n.sort=function(e){return arguments.length?(t=e,n):t},n.children=function(t){return arguments.length?(e=t,n):e},n.value=function(t){return arguments.length?(r=t,n):r},n.revalue=function(t){return r&&(Ku(t,function(n){n.children&&(n.value=0)}),Qu(t,function(t){var e;t.children||(t.value=+r.call(n,t,t.depth)||0),(e=t.parent)&&(e.value+=t.value)})),t},n},ta.layout.partition=function(){function n(t,e,r,u){var i=t.children;if(t.x=e,t.y=t.depth*u,t.dx=r,t.dy=u,i&&(o=i.length)){var o,a,c,l=-1;for(r=t.value?r/t.value:0;++lf?-1:1),p=(f-c*g)/ta.sum(l),v=ta.range(c),d=[];return null!=e&&v.sort(e===pl?function(n,t){return l[t]-l[n]}:function(n,t){return e(o[n],o[t])}),v.forEach(function(n){d[n]={data:o[n],value:a=l[n],startAngle:s,endAngle:s+=a*p+g,padAngle:h}}),d}var t=Number,e=pl,r=0,u=La,i=0;return n.value=function(e){return arguments.length?(t=e,n):t},n.sort=function(t){return arguments.length?(e=t,n):e},n.startAngle=function(t){return arguments.length?(r=t,n):r},n.endAngle=function(t){return arguments.length?(u=t,n):u},n.padAngle=function(t){return arguments.length?(i=t,n):i},n};var pl={};ta.layout.stack=function(){function n(a,c){if(!(h=a.length))return a;var l=a.map(function(e,r){return t.call(n,e,r)}),s=l.map(function(t){return t.map(function(t,e){return[i.call(n,t,e),o.call(n,t,e)]})}),f=e.call(n,s,c);l=ta.permute(l,f),s=ta.permute(s,f);var h,g,p,v,d=r.call(n,s,c),m=l[0].length;for(p=0;m>p;++p)for(u.call(n,l[0][p],v=d[p],s[0][p][1]),g=1;h>g;++g)u.call(n,l[g][p],v+=s[g-1][p][1],s[g][p][1]);return a}var t=y,e=ai,r=ci,u=oi,i=ui,o=ii;return n.values=function(e){return arguments.length?(t=e,n):t},n.order=function(t){return arguments.length?(e="function"==typeof t?t:vl.get(t)||ai,n):e},n.offset=function(t){return arguments.length?(r="function"==typeof t?t:dl.get(t)||ci,n):r},n.x=function(t){return arguments.length?(i=t,n):i},n.y=function(t){return arguments.length?(o=t,n):o},n.out=function(t){return arguments.length?(u=t,n):u},n};var vl=ta.map({"inside-out":function(n){var t,e,r=n.length,u=n.map(li),i=n.map(si),o=ta.range(r).sort(function(n,t){return u[n]-u[t]}),a=0,c=0,l=[],s=[];for(t=0;r>t;++t)e=o[t],c>a?(a+=i[e],l.push(e)):(c+=i[e],s.push(e));return s.reverse().concat(l)},reverse:function(n){return ta.range(n.length).reverse()},"default":ai}),dl=ta.map({silhouette:function(n){var t,e,r,u=n.length,i=n[0].length,o=[],a=0,c=[];for(e=0;i>e;++e){for(t=0,r=0;u>t;t++)r+=n[t][e][1];r>a&&(a=r),o.push(r)}for(e=0;i>e;++e)c[e]=(a-o[e])/2;return c},wiggle:function(n){var t,e,r,u,i,o,a,c,l,s=n.length,f=n[0],h=f.length,g=[];for(g[0]=c=l=0,e=1;h>e;++e){for(t=0,u=0;s>t;++t)u+=n[t][e][1];for(t=0,i=0,a=f[e][0]-f[e-1][0];s>t;++t){for(r=0,o=(n[t][e][1]-n[t][e-1][1])/(2*a);t>r;++r)o+=(n[r][e][1]-n[r][e-1][1])/a;i+=o*n[t][e][1]}g[e]=c-=u?i/u*a:0,l>c&&(l=c)}for(e=0;h>e;++e)g[e]-=l;return g},expand:function(n){var t,e,r,u=n.length,i=n[0].length,o=1/u,a=[];for(e=0;i>e;++e){for(t=0,r=0;u>t;t++)r+=n[t][e][1];if(r)for(t=0;u>t;t++)n[t][e][1]/=r;else for(t=0;u>t;t++)n[t][e][1]=o}for(e=0;i>e;++e)a[e]=0;return a},zero:ci});ta.layout.histogram=function(){function n(n,i){for(var o,a,c=[],l=n.map(e,this),s=r.call(this,l,i),f=u.call(this,s,l,i),i=-1,h=l.length,g=f.length-1,p=t?1:1/h;++i0)for(i=-1;++i=s[0]&&a<=s[1]&&(o=c[ta.bisect(f,a,1,g)-1],o.y+=p,o.push(n[i]));return c}var t=!0,e=Number,r=pi,u=hi;return n.value=function(t){return arguments.length?(e=t,n):e},n.range=function(t){return arguments.length?(r=Et(t),n):r},n.bins=function(t){return arguments.length?(u="number"==typeof t?function(n){return gi(n,t)}:Et(t),n):u},n.frequency=function(e){return arguments.length?(t=!!e,n):t},n},ta.layout.pack=function(){function n(n,i){var o=e.call(this,n,i),a=o[0],c=u[0],l=u[1],s=null==t?Math.sqrt:"function"==typeof t?t:function(){return t};if(a.x=a.y=0,Qu(a,function(n){n.r=+s(n.value)}),Qu(a,Mi),r){var f=r*(t?1:Math.max(2*a.r/c,2*a.r/l))/2;Qu(a,function(n){n.r+=f}),Qu(a,Mi),Qu(a,function(n){n.r-=f})}return _i(a,c/2,l/2,t?1:1/Math.max(2*a.r/c,2*a.r/l)),o}var t,e=ta.layout.hierarchy().sort(vi),r=0,u=[1,1];return n.size=function(t){return arguments.length?(u=t,n):u},n.radius=function(e){return arguments.length?(t=null==e||"function"==typeof e?e:+e,n):t},n.padding=function(t){return arguments.length?(r=+t,n):r},Gu(n,e)},ta.layout.tree=function(){function n(n,u){var s=o.call(this,n,u),f=s[0],h=t(f);if(Qu(h,e),h.parent.m=-h.z,Ku(h,r),l)Ku(f,i);else{var g=f,p=f,v=f;Ku(f,function(n){n.xp.x&&(p=n),n.depth>v.depth&&(v=n)});var d=a(g,p)/2-g.x,m=c[0]/(p.x+a(p,g)/2+d),y=c[1]/(v.depth||1);Ku(f,function(n){n.x=(n.x+d)*m,n.y=n.depth*y})}return s}function t(n){for(var t,e={A:null,children:[n]},r=[e];null!=(t=r.pop());)for(var u,i=t.children,o=0,a=i.length;a>o;++o)r.push((i[o]=u={_:i[o],parent:t,children:(u=i[o].children)&&u.slice()||[],A:null,a:null,z:0,m:0,c:0,s:0,t:null,i:o}).a=u);return e.children[0]}function e(n){var t=n.children,e=n.parent.children,r=n.i?e[n.i-1]:null;if(t.length){Ni(n);var i=(t[0].z+t[t.length-1].z)/2;r?(n.z=r.z+a(n._,r._),n.m=n.z-i):n.z=i}else r&&(n.z=r.z+a(n._,r._));n.parent.A=u(n,r,n.parent.A||e[0])}function r(n){n._.x=n.z+n.parent.m,n.m+=n.parent.m}function u(n,t,e){if(t){for(var r,u=n,i=n,o=t,c=u.parent.children[0],l=u.m,s=i.m,f=o.m,h=c.m;o=Ei(o),u=ki(u),o&&u;)c=ki(c),i=Ei(i),i.a=n,r=o.z+f-u.z-l+a(o._,u._),r>0&&(Ai(Ci(o,n,e),n,r),l+=r,s+=r),f+=o.m,l+=u.m,h+=c.m,s+=i.m;o&&!Ei(i)&&(i.t=o,i.m+=f-s),u&&!ki(c)&&(c.t=u,c.m+=l-h,e=n)}return e}function i(n){n.x*=c[0],n.y=n.depth*c[1]}var o=ta.layout.hierarchy().sort(null).value(null),a=Si,c=[1,1],l=null;return n.separation=function(t){return arguments.length?(a=t,n):a},n.size=function(t){return arguments.length?(l=null==(c=t)?i:null,n):l?null:c},n.nodeSize=function(t){return arguments.length?(l=null==(c=t)?null:i,n):l?c:null},Gu(n,o)},ta.layout.cluster=function(){function n(n,i){var o,a=t.call(this,n,i),c=a[0],l=0;Qu(c,function(n){var t=n.children;t&&t.length?(n.x=qi(t),n.y=zi(t)):(n.x=o?l+=e(n,o):0,n.y=0,o=n)});var s=Li(c),f=Ti(c),h=s.x-e(s,f)/2,g=f.x+e(f,s)/2;return Qu(c,u?function(n){n.x=(n.x-c.x)*r[0],n.y=(c.y-n.y)*r[1]}:function(n){n.x=(n.x-h)/(g-h)*r[0],n.y=(1-(c.y?n.y/c.y:1))*r[1]}),a}var t=ta.layout.hierarchy().sort(null).value(null),e=Si,r=[1,1],u=!1;return n.separation=function(t){return arguments.length?(e=t,n):e},n.size=function(t){return arguments.length?(u=null==(r=t),n):u?null:r},n.nodeSize=function(t){return arguments.length?(u=null!=(r=t),n):u?r:null},Gu(n,t)},ta.layout.treemap=function(){function n(n,t){for(var e,r,u=-1,i=n.length;++ut?0:t),e.area=isNaN(r)||0>=r?0:r}function t(e){var i=e.children;if(i&&i.length){var o,a,c,l=f(e),s=[],h=i.slice(),p=1/0,v="slice"===g?l.dx:"dice"===g?l.dy:"slice-dice"===g?1&e.depth?l.dy:l.dx:Math.min(l.dx,l.dy);for(n(h,l.dx*l.dy/e.value),s.area=0;(c=h.length)>0;)s.push(o=h[c-1]),s.area+=o.area,"squarify"!==g||(a=r(s,v))<=p?(h.pop(),p=a):(s.area-=s.pop().area,u(s,v,l,!1),v=Math.min(l.dx,l.dy),s.length=s.area=0,p=1/0);s.length&&(u(s,v,l,!0),s.length=s.area=0),i.forEach(t)}}function e(t){var r=t.children;if(r&&r.length){var i,o=f(t),a=r.slice(),c=[];for(n(a,o.dx*o.dy/t.value),c.area=0;i=a.pop();)c.push(i),c.area+=i.area,null!=i.z&&(u(c,i.z?o.dx:o.dy,o,!a.length),c.length=c.area=0);r.forEach(e)}}function r(n,t){for(var e,r=n.area,u=0,i=1/0,o=-1,a=n.length;++oe&&(i=e),e>u&&(u=e));return r*=r,t*=t,r?Math.max(t*u*p/r,r/(t*i*p)):1/0}function u(n,t,e,r){var u,i=-1,o=n.length,a=e.x,l=e.y,s=t?c(n.area/t):0;if(t==e.dx){for((r||s>e.dy)&&(s=e.dy);++ie.dx)&&(s=e.dx);++ie&&(t=1),1>e&&(n=0),function(){var e,r,u;do e=2*Math.random()-1,r=2*Math.random()-1,u=e*e+r*r;while(!u||u>1);return n+t*e*Math.sqrt(-2*Math.log(u)/u)}},logNormal:function(){var n=ta.random.normal.apply(ta,arguments);return function(){return Math.exp(n())}},bates:function(n){var t=ta.random.irwinHall(n);return function(){return t()/n}},irwinHall:function(n){return function(){for(var t=0,e=0;n>e;e++)t+=Math.random();return t}}},ta.scale={};var ml={floor:y,ceil:y};ta.scale.linear=function(){return Ii([0,1],[0,1],mu,!1)};var yl={s:1,g:1,p:1,r:1,e:1};ta.scale.log=function(){return Ji(ta.scale.linear().domain([0,1]),10,!0,[1,10])};var Ml=ta.format(".0e"),xl={floor:function(n){return-Math.ceil(-n)},ceil:function(n){return-Math.floor(-n)}};ta.scale.pow=function(){return Gi(ta.scale.linear(),1,[0,1])},ta.scale.sqrt=function(){return ta.scale.pow().exponent(.5)},ta.scale.ordinal=function(){return Qi([],{t:"range",a:[[]]})},ta.scale.category10=function(){return ta.scale.ordinal().range(bl)},ta.scale.category20=function(){return ta.scale.ordinal().range(_l)},ta.scale.category20b=function(){return ta.scale.ordinal().range(wl)},ta.scale.category20c=function(){return ta.scale.ordinal().range(Sl)};var bl=[2062260,16744206,2924588,14034728,9725885,9197131,14907330,8355711,12369186,1556175].map(Mt),_l=[2062260,11454440,16744206,16759672,2924588,10018698,14034728,16750742,9725885,12955861,9197131,12885140,14907330,16234194,8355711,13092807,12369186,14408589,1556175,10410725].map(Mt),wl=[3750777,5395619,7040719,10264286,6519097,9216594,11915115,13556636,9202993,12426809,15186514,15190932,8666169,11356490,14049643,15177372,8077683,10834324,13528509,14589654].map(Mt),Sl=[3244733,7057110,10406625,13032431,15095053,16616764,16625259,16634018,3253076,7652470,10607003,13101504,7695281,10394312,12369372,14342891,6513507,9868950,12434877,14277081].map(Mt);ta.scale.quantile=function(){return no([],[])},ta.scale.quantize=function(){return to(0,1,[0,1])},ta.scale.threshold=function(){return eo([.5],[0,1])},ta.scale.identity=function(){return ro([0,1])},ta.svg={},ta.svg.arc=function(){function n(){var n=Math.max(0,+e.apply(this,arguments)),l=Math.max(0,+r.apply(this,arguments)),s=o.apply(this,arguments)-Ra,f=a.apply(this,arguments)-Ra,h=Math.abs(f-s),g=s>f?0:1;if(n>l&&(p=l,l=n,n=p),h>=Ta)return t(l,g)+(n?t(n,1-g):"")+"Z";var p,v,d,m,y,M,x,b,_,w,S,k,E=0,A=0,N=[];if((m=(+c.apply(this,arguments)||0)/2)&&(d=i===kl?Math.sqrt(n*n+l*l):+i.apply(this,arguments),g||(A*=-1),l&&(A=tt(d/l*Math.sin(m))),n&&(E=tt(d/n*Math.sin(m)))),l){y=l*Math.cos(s+A),M=l*Math.sin(s+A),x=l*Math.cos(f-A),b=l*Math.sin(f-A);var C=Math.abs(f-s-2*A)<=qa?0:1;if(A&&so(y,M,x,b)===g^C){var z=(s+f)/2;y=l*Math.cos(z),M=l*Math.sin(z),x=b=null}}else y=M=0;if(n){_=n*Math.cos(f-E),w=n*Math.sin(f-E),S=n*Math.cos(s+E),k=n*Math.sin(s+E);var q=Math.abs(s-f+2*E)<=qa?0:1;if(E&&so(_,w,S,k)===1-g^q){var L=(s+f)/2;_=n*Math.cos(L),w=n*Math.sin(L),S=k=null}}else _=w=0;if((p=Math.min(Math.abs(l-n)/2,+u.apply(this,arguments)))>.001){v=l>n^g?0:1;var T=null==S?[_,w]:null==x?[y,M]:Lr([y,M],[S,k],[x,b],[_,w]),R=y-T[0],D=M-T[1],P=x-T[0],U=b-T[1],j=1/Math.sin(Math.acos((R*P+D*U)/(Math.sqrt(R*R+D*D)*Math.sqrt(P*P+U*U)))/2),F=Math.sqrt(T[0]*T[0]+T[1]*T[1]);if(null!=x){var H=Math.min(p,(l-F)/(j+1)),O=fo(null==S?[_,w]:[S,k],[y,M],l,H,g),I=fo([x,b],[_,w],l,H,g);p===H?N.push("M",O[0],"A",H,",",H," 0 0,",v," ",O[1],"A",l,",",l," 0 ",1-g^so(O[1][0],O[1][1],I[1][0],I[1][1]),",",g," ",I[1],"A",H,",",H," 0 0,",v," ",I[0]):N.push("M",O[0],"A",H,",",H," 0 1,",v," ",I[0])}else N.push("M",y,",",M);if(null!=S){var Y=Math.min(p,(n-F)/(j-1)),Z=fo([y,M],[S,k],n,-Y,g),V=fo([_,w],null==x?[y,M]:[x,b],n,-Y,g);p===Y?N.push("L",V[0],"A",Y,",",Y," 0 0,",v," ",V[1],"A",n,",",n," 0 ",g^so(V[1][0],V[1][1],Z[1][0],Z[1][1]),",",1-g," ",Z[1],"A",Y,",",Y," 0 0,",v," ",Z[0]):N.push("L",V[0],"A",Y,",",Y," 0 0,",v," ",Z[0])}else N.push("L",_,",",w)}else N.push("M",y,",",M),null!=x&&N.push("A",l,",",l," 0 ",C,",",g," ",x,",",b),N.push("L",_,",",w),null!=S&&N.push("A",n,",",n," 0 ",q,",",1-g," ",S,",",k);return N.push("Z"),N.join("")}function t(n,t){return"M0,"+n+"A"+n+","+n+" 0 1,"+t+" 0,"+-n+"A"+n+","+n+" 0 1,"+t+" 0,"+n}var e=io,r=oo,u=uo,i=kl,o=ao,a=co,c=lo;return n.innerRadius=function(t){return arguments.length?(e=Et(t),n):e},n.outerRadius=function(t){return arguments.length?(r=Et(t),n):r},n.cornerRadius=function(t){return arguments.length?(u=Et(t),n):u},n.padRadius=function(t){return arguments.length?(i=t==kl?kl:Et(t),n):i},n.startAngle=function(t){return arguments.length?(o=Et(t),n):o},n.endAngle=function(t){return arguments.length?(a=Et(t),n):a},n.padAngle=function(t){return arguments.length?(c=Et(t),n):c},n.centroid=function(){var n=(+e.apply(this,arguments)+ +r.apply(this,arguments))/2,t=(+o.apply(this,arguments)+ +a.apply(this,arguments))/2-Ra;return[Math.cos(t)*n,Math.sin(t)*n]},n};var kl="auto";ta.svg.line=function(){return ho(y)};var El=ta.map({linear:go,"linear-closed":po,step:vo,"step-before":mo,"step-after":yo,basis:So,"basis-open":ko,"basis-closed":Eo,bundle:Ao,cardinal:bo,"cardinal-open":Mo,"cardinal-closed":xo,monotone:To});El.forEach(function(n,t){t.key=n,t.closed=/-closed$/.test(n)});var Al=[0,2/3,1/3,0],Nl=[0,1/3,2/3,0],Cl=[0,1/6,2/3,1/6];ta.svg.line.radial=function(){var n=ho(Ro);return n.radius=n.x,delete n.x,n.angle=n.y,delete n.y,n},mo.reverse=yo,yo.reverse=mo,ta.svg.area=function(){return Do(y)},ta.svg.area.radial=function(){var n=Do(Ro);return n.radius=n.x,delete n.x,n.innerRadius=n.x0,delete n.x0,n.outerRadius=n.x1,delete n.x1,n.angle=n.y,delete n.y,n.startAngle=n.y0,delete n.y0,n.endAngle=n.y1,delete n.y1,n},ta.svg.chord=function(){function n(n,a){var c=t(this,i,n,a),l=t(this,o,n,a);return"M"+c.p0+r(c.r,c.p1,c.a1-c.a0)+(e(c,l)?u(c.r,c.p1,c.r,c.p0):u(c.r,c.p1,l.r,l.p0)+r(l.r,l.p1,l.a1-l.a0)+u(l.r,l.p1,c.r,c.p0))+"Z"}function t(n,t,e,r){var u=t.call(n,e,r),i=a.call(n,u,r),o=c.call(n,u,r)-Ra,s=l.call(n,u,r)-Ra;return{r:i,a0:o,a1:s,p0:[i*Math.cos(o),i*Math.sin(o)],p1:[i*Math.cos(s),i*Math.sin(s)]}}function e(n,t){return n.a0==t.a0&&n.a1==t.a1}function r(n,t,e){return"A"+n+","+n+" 0 "+ +(e>qa)+",1 "+t}function u(n,t,e,r){return"Q 0,0 "+r}var i=mr,o=yr,a=Po,c=ao,l=co;return n.radius=function(t){return arguments.length?(a=Et(t),n):a},n.source=function(t){return arguments.length?(i=Et(t),n):i},n.target=function(t){return arguments.length?(o=Et(t),n):o},n.startAngle=function(t){return arguments.length?(c=Et(t),n):c},n.endAngle=function(t){return arguments.length?(l=Et(t),n):l},n},ta.svg.diagonal=function(){function n(n,u){var i=t.call(this,n,u),o=e.call(this,n,u),a=(i.y+o.y)/2,c=[i,{x:i.x,y:a},{x:o.x,y:a},o];return c=c.map(r),"M"+c[0]+"C"+c[1]+" "+c[2]+" "+c[3]}var t=mr,e=yr,r=Uo;return n.source=function(e){return arguments.length?(t=Et(e),n):t},n.target=function(t){return arguments.length?(e=Et(t),n):e},n.projection=function(t){return arguments.length?(r=t,n):r},n},ta.svg.diagonal.radial=function(){var n=ta.svg.diagonal(),t=Uo,e=n.projection;return n.projection=function(n){return arguments.length?e(jo(t=n)):t},n},ta.svg.symbol=function(){function n(n,r){return(zl.get(t.call(this,n,r))||Oo)(e.call(this,n,r))}var t=Ho,e=Fo;return n.type=function(e){return arguments.length?(t=Et(e),n):t},n.size=function(t){return arguments.length?(e=Et(t),n):e},n};var zl=ta.map({circle:Oo,cross:function(n){var t=Math.sqrt(n/5)/2;return"M"+-3*t+","+-t+"H"+-t+"V"+-3*t+"H"+t+"V"+-t+"H"+3*t+"V"+t+"H"+t+"V"+3*t+"H"+-t+"V"+t+"H"+-3*t+"Z"},diamond:function(n){var t=Math.sqrt(n/(2*Ll)),e=t*Ll;return"M0,"+-t+"L"+e+",0 0,"+t+" "+-e+",0Z"},square:function(n){var t=Math.sqrt(n)/2;return"M"+-t+","+-t+"L"+t+","+-t+" "+t+","+t+" "+-t+","+t+"Z"},"triangle-down":function(n){var t=Math.sqrt(n/ql),e=t*ql/2;return"M0,"+e+"L"+t+","+-e+" "+-t+","+-e+"Z"},"triangle-up":function(n){var t=Math.sqrt(n/ql),e=t*ql/2;return"M0,"+-e+"L"+t+","+e+" "+-t+","+e+"Z"}});ta.svg.symbolTypes=zl.keys();var ql=Math.sqrt(3),Ll=Math.tan(30*Da);_a.transition=function(n){for(var t,e,r=Tl||++Ul,u=Xo(n),i=[],o=Rl||{time:Date.now(),ease:Su,delay:0,duration:250},a=-1,c=this.length;++ai;i++){u.push(t=[]);for(var e=this[i],a=0,c=e.length;c>a;a++)(r=e[a])&&n.call(r,r.__data__,a,i)&&t.push(r)}return Yo(u,this.namespace,this.id)},Pl.tween=function(n,t){var e=this.id,r=this.namespace;return arguments.length<2?this.node()[r][e].tween.get(n):Y(this,null==t?function(t){t[r][e].tween.remove(n)}:function(u){u[r][e].tween.set(n,t)})},Pl.attr=function(n,t){function e(){this.removeAttribute(a)}function r(){this.removeAttributeNS(a.space,a.local)}function u(n){return null==n?e:(n+="",function(){var t,e=this.getAttribute(a);return e!==n&&(t=o(e,n),function(n){this.setAttribute(a,t(n))})})}function i(n){return null==n?r:(n+="",function(){var t,e=this.getAttributeNS(a.space,a.local);return e!==n&&(t=o(e,n),function(n){this.setAttributeNS(a.space,a.local,t(n))})})}if(arguments.length<2){for(t in n)this.attr(t,n[t]);return this}var o="transform"==n?Hu:mu,a=ta.ns.qualify(n);return Zo(this,"attr."+n,t,a.local?i:u)},Pl.attrTween=function(n,t){function e(n,e){var r=t.call(this,n,e,this.getAttribute(u));return r&&function(n){this.setAttribute(u,r(n))}}function r(n,e){var r=t.call(this,n,e,this.getAttributeNS(u.space,u.local));return r&&function(n){this.setAttributeNS(u.space,u.local,r(n))}}var u=ta.ns.qualify(n);return this.tween("attr."+n,u.local?r:e)},Pl.style=function(n,e,r){function u(){this.style.removeProperty(n)}function i(e){return null==e?u:(e+="",function(){var u,i=t(this).getComputedStyle(this,null).getPropertyValue(n);return i!==e&&(u=mu(i,e),function(t){this.style.setProperty(n,u(t),r)})})}var o=arguments.length;if(3>o){if("string"!=typeof n){2>o&&(e="");for(r in n)this.style(r,n[r],e);return this}r=""}return Zo(this,"style."+n,e,i)},Pl.styleTween=function(n,e,r){function u(u,i){var o=e.call(this,u,i,t(this).getComputedStyle(this,null).getPropertyValue(n));return o&&function(t){this.style.setProperty(n,o(t),r)}}return arguments.length<3&&(r=""),this.tween("style."+n,u)},Pl.text=function(n){return Zo(this,"text",n,Vo)},Pl.remove=function(){var n=this.namespace;return this.each("end.transition",function(){var t;this[n].count<2&&(t=this.parentNode)&&t.removeChild(this)})},Pl.ease=function(n){var t=this.id,e=this.namespace;return arguments.length<1?this.node()[e][t].ease:("function"!=typeof n&&(n=ta.ease.apply(ta,arguments)),Y(this,function(r){r[e][t].ease=n}))},Pl.delay=function(n){var t=this.id,e=this.namespace;return arguments.length<1?this.node()[e][t].delay:Y(this,"function"==typeof n?function(r,u,i){r[e][t].delay=+n.call(r,r.__data__,u,i)}:(n=+n,function(r){r[e][t].delay=n}))},Pl.duration=function(n){var t=this.id,e=this.namespace;return arguments.length<1?this.node()[e][t].duration:Y(this,"function"==typeof n?function(r,u,i){r[e][t].duration=Math.max(1,n.call(r,r.__data__,u,i))}:(n=Math.max(1,n),function(r){r[e][t].duration=n}))},Pl.each=function(n,t){var e=this.id,r=this.namespace;if(arguments.length<2){var u=Rl,i=Tl;try{Tl=e,Y(this,function(t,u,i){Rl=t[r][e],n.call(t,t.__data__,u,i)})}finally{Rl=u,Tl=i}}else Y(this,function(u){var i=u[r][e];(i.event||(i.event=ta.dispatch("start","end","interrupt"))).on(n,t)});return this},Pl.transition=function(){for(var n,t,e,r,u=this.id,i=++Ul,o=this.namespace,a=[],c=0,l=this.length;l>c;c++){a.push(n=[]);for(var t=this[c],s=0,f=t.length;f>s;s++)(e=t[s])&&(r=e[o][u],$o(e,s,o,i,{time:r.time,ease:r.ease,delay:r.delay+r.duration,duration:r.duration})),n.push(e)}return Yo(a,o,i)},ta.svg.axis=function(){function n(n){n.each(function(){var n,l=ta.select(this),s=this.__chart__||e,f=this.__chart__=e.copy(),h=null==c?f.ticks?f.ticks.apply(f,a):f.domain():c,g=null==t?f.tickFormat?f.tickFormat.apply(f,a):y:t,p=l.selectAll(".tick").data(h,f),v=p.enter().insert("g",".domain").attr("class","tick").style("opacity",Ca),d=ta.transition(p.exit()).style("opacity",Ca).remove(),m=ta.transition(p.order()).style("opacity",1),M=Math.max(u,0)+o,x=Ui(f),b=l.selectAll(".domain").data([0]),_=(b.enter().append("path").attr("class","domain"),ta.transition(b));v.append("line"),v.append("text");var w,S,k,E,A=v.select("line"),N=m.select("line"),C=p.select("text").text(g),z=v.select("text"),q=m.select("text"),L="top"===r||"left"===r?-1:1;if("bottom"===r||"top"===r?(n=Bo,w="x",k="y",S="x2",E="y2",C.attr("dy",0>L?"0em":".71em").style("text-anchor","middle"),_.attr("d","M"+x[0]+","+L*i+"V0H"+x[1]+"V"+L*i)):(n=Wo,w="y",k="x",S="y2",E="x2",C.attr("dy",".32em").style("text-anchor",0>L?"end":"start"),_.attr("d","M"+L*i+","+x[0]+"H0V"+x[1]+"H"+L*i)),A.attr(E,L*u),z.attr(k,L*M),N.attr(S,0).attr(E,L*u),q.attr(w,0).attr(k,L*M),f.rangeBand){var T=f,R=T.rangeBand()/2;s=f=function(n){return T(n)+R}}else s.rangeBand?s=f:d.call(n,f,s);v.call(n,s,f),m.call(n,f,f)})}var t,e=ta.scale.linear(),r=jl,u=6,i=6,o=3,a=[10],c=null;return n.scale=function(t){return arguments.length?(e=t,n):e},n.orient=function(t){return arguments.length?(r=t in Fl?t+"":jl,n):r},n.ticks=function(){return arguments.length?(a=arguments,n):a},n.tickValues=function(t){return arguments.length?(c=t,n):c},n.tickFormat=function(e){return arguments.length?(t=e,n):t},n.tickSize=function(t){var e=arguments.length;return e?(u=+t,i=+arguments[e-1],n):u},n.innerTickSize=function(t){return arguments.length?(u=+t,n):u},n.outerTickSize=function(t){return arguments.length?(i=+t,n):i},n.tickPadding=function(t){return arguments.length?(o=+t,n):o},n.tickSubdivide=function(){return arguments.length&&n},n};var jl="bottom",Fl={top:1,right:1,bottom:1,left:1};ta.svg.brush=function(){function n(t){t.each(function(){var t=ta.select(this).style("pointer-events","all").style("-webkit-tap-highlight-color","rgba(0,0,0,0)").on("mousedown.brush",i).on("touchstart.brush",i),o=t.selectAll(".background").data([0]);o.enter().append("rect").attr("class","background").style("visibility","hidden").style("cursor","crosshair"),t.selectAll(".extent").data([0]).enter().append("rect").attr("class","extent").style("cursor","move");var a=t.selectAll(".resize").data(v,y);a.exit().remove(),a.enter().append("g").attr("class",function(n){return"resize "+n}).style("cursor",function(n){return Hl[n]}).append("rect").attr("x",function(n){return/[ew]$/.test(n)?-3:null}).attr("y",function(n){return/^[ns]/.test(n)?-3:null}).attr("width",6).attr("height",6).style("visibility","hidden"),a.style("display",n.empty()?"none":null);var c,f=ta.transition(t),h=ta.transition(o);l&&(c=Ui(l),h.attr("x",c[0]).attr("width",c[1]-c[0]),r(f)),s&&(c=Ui(s),h.attr("y",c[0]).attr("height",c[1]-c[0]),u(f)),e(f)})}function e(n){n.selectAll(".resize").attr("transform",function(n){return"translate("+f[+/e$/.test(n)]+","+h[+/^s/.test(n)]+")"})}function r(n){n.select(".extent").attr("x",f[0]),n.selectAll(".extent,.n>rect,.s>rect").attr("width",f[1]-f[0])}function u(n){n.select(".extent").attr("y",h[0]),n.selectAll(".extent,.e>rect,.w>rect").attr("height",h[1]-h[0])}function i(){function i(){32==ta.event.keyCode&&(C||(M=null,q[0]-=f[1],q[1]-=h[1],C=2),S())}function v(){32==ta.event.keyCode&&2==C&&(q[0]+=f[1],q[1]+=h[1],C=0,S())}function d(){var n=ta.mouse(b),t=!1;x&&(n[0]+=x[0],n[1]+=x[1]),C||(ta.event.altKey?(M||(M=[(f[0]+f[1])/2,(h[0]+h[1])/2]),q[0]=f[+(n[0]s?(u=r,r=s):u=s),v[0]!=r||v[1]!=u?(e?a=null:o=null,v[0]=r,v[1]=u,!0):void 0}function y(){d(),k.style("pointer-events","all").selectAll(".resize").style("display",n.empty()?"none":null),ta.select("body").style("cursor",null),L.on("mousemove.brush",null).on("mouseup.brush",null).on("touchmove.brush",null).on("touchend.brush",null).on("keydown.brush",null).on("keyup.brush",null),z(),w({type:"brushend"})}var M,x,b=this,_=ta.select(ta.event.target),w=c.of(b,arguments),k=ta.select(b),E=_.datum(),A=!/^(n|s)$/.test(E)&&l,N=!/^(e|w)$/.test(E)&&s,C=_.classed("extent"),z=W(b),q=ta.mouse(b),L=ta.select(t(b)).on("keydown.brush",i).on("keyup.brush",v);if(ta.event.changedTouches?L.on("touchmove.brush",d).on("touchend.brush",y):L.on("mousemove.brush",d).on("mouseup.brush",y),k.interrupt().selectAll("*").interrupt(),C)q[0]=f[0]-q[0],q[1]=h[0]-q[1];else if(E){var T=+/w$/.test(E),R=+/^n/.test(E);x=[f[1-T]-q[0],h[1-R]-q[1]],q[0]=f[T],q[1]=h[R]}else ta.event.altKey&&(M=q.slice());k.style("pointer-events","none").selectAll(".resize").style("display",null),ta.select("body").style("cursor",_.style("cursor")),w({type:"brushstart"}),d()}var o,a,c=E(n,"brushstart","brush","brushend"),l=null,s=null,f=[0,0],h=[0,0],g=!0,p=!0,v=Ol[0];return n.event=function(n){n.each(function(){var n=c.of(this,arguments),t={x:f,y:h,i:o,j:a},e=this.__chart__||t;this.__chart__=t,Tl?ta.select(this).transition().each("start.brush",function(){o=e.i,a=e.j,f=e.x,h=e.y,n({type:"brushstart"})}).tween("brush:brush",function(){var e=yu(f,t.x),r=yu(h,t.y);return o=a=null,function(u){f=t.x=e(u),h=t.y=r(u),n({type:"brush",mode:"resize"})}}).each("end.brush",function(){o=t.i,a=t.j,n({type:"brush",mode:"resize"}),n({type:"brushend"})}):(n({type:"brushstart"}),n({type:"brush",mode:"resize"}),n({type:"brushend"}))})},n.x=function(t){return arguments.length?(l=t,v=Ol[!l<<1|!s],n):l},n.y=function(t){return arguments.length?(s=t,v=Ol[!l<<1|!s],n):s},n.clamp=function(t){return arguments.length?(l&&s?(g=!!t[0],p=!!t[1]):l?g=!!t:s&&(p=!!t),n):l&&s?[g,p]:l?g:s?p:null},n.extent=function(t){var e,r,u,i,c;return arguments.length?(l&&(e=t[0],r=t[1],s&&(e=e[0],r=r[0]),o=[e,r],l.invert&&(e=l(e),r=l(r)),e>r&&(c=e,e=r,r=c),(e!=f[0]||r!=f[1])&&(f=[e,r])),s&&(u=t[0],i=t[1],l&&(u=u[1],i=i[1]),a=[u,i],s.invert&&(u=s(u),i=s(i)),u>i&&(c=u,u=i,i=c),(u!=h[0]||i!=h[1])&&(h=[u,i])),n):(l&&(o?(e=o[0],r=o[1]):(e=f[0],r=f[1],l.invert&&(e=l.invert(e),r=l.invert(r)),e>r&&(c=e,e=r,r=c))),s&&(a?(u=a[0],i=a[1]):(u=h[0],i=h[1],s.invert&&(u=s.invert(u),i=s.invert(i)),u>i&&(c=u,u=i,i=c))),l&&s?[[e,u],[r,i]]:l?[e,r]:s&&[u,i])},n.clear=function(){return n.empty()||(f=[0,0],h=[0,0],o=a=null),n},n.empty=function(){return!!l&&f[0]==f[1]||!!s&&h[0]==h[1]},ta.rebind(n,c,"on")};var Hl={n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},Ol=[["n","e","s","w","nw","ne","se","sw"],["e","w"],["n","s"],[]],Il=ac.format=gc.timeFormat,Yl=Il.utc,Zl=Yl("%Y-%m-%dT%H:%M:%S.%LZ");Il.iso=Date.prototype.toISOString&&+new Date("2000-01-01T00:00:00.000Z")?Jo:Zl,Jo.parse=function(n){var t=new Date(n);return isNaN(t)?null:t},Jo.toString=Zl.toString,ac.second=Ft(function(n){return new cc(1e3*Math.floor(n/1e3))},function(n,t){n.setTime(n.getTime()+1e3*Math.floor(t))},function(n){return n.getSeconds()}),ac.seconds=ac.second.range,ac.seconds.utc=ac.second.utc.range,ac.minute=Ft(function(n){return new cc(6e4*Math.floor(n/6e4))},function(n,t){n.setTime(n.getTime()+6e4*Math.floor(t))},function(n){return n.getMinutes()}),ac.minutes=ac.minute.range,ac.minutes.utc=ac.minute.utc.range,ac.hour=Ft(function(n){var t=n.getTimezoneOffset()/60;return new cc(36e5*(Math.floor(n/36e5-t)+t))},function(n,t){n.setTime(n.getTime()+36e5*Math.floor(t))},function(n){return n.getHours()}),ac.hours=ac.hour.range,ac.hours.utc=ac.hour.utc.range,ac.month=Ft(function(n){return n=ac.day(n),n.setDate(1),n},function(n,t){n.setMonth(n.getMonth()+t)},function(n){return n.getMonth()}),ac.months=ac.month.range,ac.months.utc=ac.month.utc.range;var Vl=[1e3,5e3,15e3,3e4,6e4,3e5,9e5,18e5,36e5,108e5,216e5,432e5,864e5,1728e5,6048e5,2592e6,7776e6,31536e6],Xl=[[ac.second,1],[ac.second,5],[ac.second,15],[ac.second,30],[ac.minute,1],[ac.minute,5],[ac.minute,15],[ac.minute,30],[ac.hour,1],[ac.hour,3],[ac.hour,6],[ac.hour,12],[ac.day,1],[ac.day,2],[ac.week,1],[ac.month,1],[ac.month,3],[ac.year,1]],$l=Il.multi([[".%L",function(n){return n.getMilliseconds()}],[":%S",function(n){return n.getSeconds()}],["%I:%M",function(n){return n.getMinutes()}],["%I %p",function(n){return n.getHours()}],["%a %d",function(n){return n.getDay()&&1!=n.getDate()}],["%b %d",function(n){return 1!=n.getDate()}],["%B",function(n){return n.getMonth()}],["%Y",Ne]]),Bl={range:function(n,t,e){return ta.range(Math.ceil(n/e)*e,+t,e).map(Ko)},floor:y,ceil:y};Xl.year=ac.year,ac.scale=function(){return Go(ta.scale.linear(),Xl,$l)};var Wl=Xl.map(function(n){return[n[0].utc,n[1]]}),Jl=Yl.multi([[".%L",function(n){return n.getUTCMilliseconds()}],[":%S",function(n){return n.getUTCSeconds()}],["%I:%M",function(n){return n.getUTCMinutes()}],["%I %p",function(n){return n.getUTCHours()}],["%a %d",function(n){return n.getUTCDay()&&1!=n.getUTCDate()}],["%b %d",function(n){return 1!=n.getUTCDate()}],["%B",function(n){return n.getUTCMonth()}],["%Y",Ne]]);Wl.year=ac.year.utc,ac.scale.utc=function(){return Go(ta.scale.linear(),Wl,Jl)},ta.text=At(function(n){return n.responseText}),ta.json=function(n,t){return Nt(n,"application/json",Qo,t)},ta.html=function(n,t){return Nt(n,"text/html",na,t)},ta.xml=At(function(n){return n.responseXML}),"function"==typeof define&&define.amd?define(ta):"object"==typeof module&&module.exports&&(module.exports=ta),this.d3=ta}();
\ No newline at end of file
+return i.size=function(n){return arguments.length?(l=n,i):l},i.padding=function(n){function t(t){var e=n.call(i,t,t.depth);return null==e?Ri(t):Di(t,"number"==typeof e?[e,e,e,e]:e)}function e(t){return Di(t,n)}if(!arguments.length)return s;var r;return f=null==(s=n)?Ri:"function"==(r=typeof n)?t:"number"===r?(n=[n,n,n,n],e):e,i},i.round=function(n){return arguments.length?(c=n?Math.round:Number,i):c!=Number},i.sticky=function(n){return arguments.length?(h=n,o=null,i):h},i.ratio=function(n){return arguments.length?(p=n,i):p},i.mode=function(n){return arguments.length?(g=n+"",i):g},Gu(i,a)},ta.random={normal:function(n,t){var e=arguments.length;return 2>e&&(t=1),1>e&&(n=0),function(){var e,r,u;do e=2*Math.random()-1,r=2*Math.random()-1,u=e*e+r*r;while(!u||u>1);return n+t*e*Math.sqrt(-2*Math.log(u)/u)}},logNormal:function(){var n=ta.random.normal.apply(ta,arguments);return function(){return Math.exp(n())}},bates:function(n){var t=ta.random.irwinHall(n);return function(){return t()/n}},irwinHall:function(n){return function(){for(var t=0,e=0;n>e;e++)t+=Math.random();return t}}},ta.scale={};var ml={floor:y,ceil:y};ta.scale.linear=function(){return Ii([0,1],[0,1],mu,!1)};var yl={s:1,g:1,p:1,r:1,e:1};ta.scale.log=function(){return Ji(ta.scale.linear().domain([0,1]),10,!0,[1,10])};var Ml=ta.format(".0e"),xl={floor:function(n){return-Math.ceil(-n)},ceil:function(n){return-Math.floor(-n)}};ta.scale.pow=function(){return Gi(ta.scale.linear(),1,[0,1])},ta.scale.sqrt=function(){return ta.scale.pow().exponent(.5)},ta.scale.ordinal=function(){return Qi([],{t:"range",a:[[]]})},ta.scale.category10=function(){return ta.scale.ordinal().range(bl)},ta.scale.category20=function(){return ta.scale.ordinal().range(_l)},ta.scale.category20b=function(){return ta.scale.ordinal().range(wl)},ta.scale.category20c=function(){return ta.scale.ordinal().range(Sl)};var bl=[2062260,16744206,2924588,14034728,9725885,9197131,14907330,8355711,12369186,1556175].map(Mt),_l=[2062260,11454440,16744206,16759672,2924588,10018698,14034728,16750742,9725885,12955861,9197131,12885140,14907330,16234194,8355711,13092807,12369186,14408589,1556175,10410725].map(Mt),wl=[3750777,5395619,7040719,10264286,6519097,9216594,11915115,13556636,9202993,12426809,15186514,15190932,8666169,11356490,14049643,15177372,8077683,10834324,13528509,14589654].map(Mt),Sl=[3244733,7057110,10406625,13032431,15095053,16616764,16625259,16634018,3253076,7652470,10607003,13101504,7695281,10394312,12369372,14342891,6513507,9868950,12434877,14277081].map(Mt);ta.scale.quantile=function(){return no([],[])},ta.scale.quantize=function(){return to(0,1,[0,1])},ta.scale.threshold=function(){return eo([.5],[0,1])},ta.scale.identity=function(){return ro([0,1])},ta.svg={},ta.svg.arc=function(){function n(){var n=Math.max(0,+e.apply(this,arguments)),l=Math.max(0,+r.apply(this,arguments)),s=o.apply(this,arguments)-Ra,f=a.apply(this,arguments)-Ra,h=Math.abs(f-s),g=s>f?0:1;if(n>l&&(p=l,l=n,n=p),h>=Ta)return t(l,g)+(n?t(n,1-g):"")+"Z";var p,v,d,m,y,M,x,b,_,w,S,k,E=0,A=0,N=[];if((m=(+c.apply(this,arguments)||0)/2)&&(d=i===kl?Math.sqrt(n*n+l*l):+i.apply(this,arguments),g||(A*=-1),l&&(A=tt(d/l*Math.sin(m))),n&&(E=tt(d/n*Math.sin(m)))),l){y=l*Math.cos(s+A),M=l*Math.sin(s+A),x=l*Math.cos(f-A),b=l*Math.sin(f-A);var C=Math.abs(f-s-2*A)<=qa?0:1;if(A&&so(y,M,x,b)===g^C){var z=(s+f)/2;y=l*Math.cos(z),M=l*Math.sin(z),x=b=null}}else y=M=0;if(n){_=n*Math.cos(f-E),w=n*Math.sin(f-E),S=n*Math.cos(s+E),k=n*Math.sin(s+E);var q=Math.abs(s-f+2*E)<=qa?0:1;if(E&&so(_,w,S,k)===1-g^q){var L=(s+f)/2;_=n*Math.cos(L),w=n*Math.sin(L),S=k=null}}else _=w=0;if((p=Math.min(Math.abs(l-n)/2,+u.apply(this,arguments)))>.001){v=l>n^g?0:1;var T=null==S?[_,w]:null==x?[y,M]:Lr([y,M],[S,k],[x,b],[_,w]),R=y-T[0],D=M-T[1],P=x-T[0],U=b-T[1],j=1/Math.sin(Math.acos((R*P+D*U)/(Math.sqrt(R*R+D*D)*Math.sqrt(P*P+U*U)))/2),F=Math.sqrt(T[0]*T[0]+T[1]*T[1]);if(null!=x){var H=Math.min(p,(l-F)/(j+1)),O=fo(null==S?[_,w]:[S,k],[y,M],l,H,g),I=fo([x,b],[_,w],l,H,g);p===H?N.push("M",O[0],"A",H,",",H," 0 0,",v," ",O[1],"A",l,",",l," 0 ",1-g^so(O[1][0],O[1][1],I[1][0],I[1][1]),",",g," ",I[1],"A",H,",",H," 0 0,",v," ",I[0]):N.push("M",O[0],"A",H,",",H," 0 1,",v," ",I[0])}else N.push("M",y,",",M);if(null!=S){var Y=Math.min(p,(n-F)/(j-1)),Z=fo([y,M],[S,k],n,-Y,g),V=fo([_,w],null==x?[y,M]:[x,b],n,-Y,g);p===Y?N.push("L",V[0],"A",Y,",",Y," 0 0,",v," ",V[1],"A",n,",",n," 0 ",g^so(V[1][0],V[1][1],Z[1][0],Z[1][1]),",",1-g," ",Z[1],"A",Y,",",Y," 0 0,",v," ",Z[0]):N.push("L",V[0],"A",Y,",",Y," 0 0,",v," ",Z[0])}else N.push("L",_,",",w)}else N.push("M",y,",",M),null!=x&&N.push("A",l,",",l," 0 ",C,",",g," ",x,",",b),N.push("L",_,",",w),null!=S&&N.push("A",n,",",n," 0 ",q,",",1-g," ",S,",",k);return N.push("Z"),N.join("")}function t(n,t){return"M0,"+n+"A"+n+","+n+" 0 1,"+t+" 0,"+-n+"A"+n+","+n+" 0 1,"+t+" 0,"+n}var e=io,r=oo,u=uo,i=kl,o=ao,a=co,c=lo;return n.innerRadius=function(t){return arguments.length?(e=Et(t),n):e},n.outerRadius=function(t){return arguments.length?(r=Et(t),n):r},n.cornerRadius=function(t){return arguments.length?(u=Et(t),n):u},n.padRadius=function(t){return arguments.length?(i=t==kl?kl:Et(t),n):i},n.startAngle=function(t){return arguments.length?(o=Et(t),n):o},n.endAngle=function(t){return arguments.length?(a=Et(t),n):a},n.padAngle=function(t){return arguments.length?(c=Et(t),n):c},n.centroid=function(){var n=(+e.apply(this,arguments)+ +r.apply(this,arguments))/2,t=(+o.apply(this,arguments)+ +a.apply(this,arguments))/2-Ra;return[Math.cos(t)*n,Math.sin(t)*n]},n};var kl="auto";ta.svg.line=function(){return ho(y)};var El=ta.map({linear:go,"linear-closed":po,step:vo,"step-before":mo,"step-after":yo,basis:So,"basis-open":ko,"basis-closed":Eo,bundle:Ao,cardinal:bo,"cardinal-open":Mo,"cardinal-closed":xo,monotone:To});El.forEach(function(n,t){t.key=n,t.closed=/-closed$/.test(n)});var Al=[0,2/3,1/3,0],Nl=[0,1/3,2/3,0],Cl=[0,1/6,2/3,1/6];ta.svg.line.radial=function(){var n=ho(Ro);return n.radius=n.x,delete n.x,n.angle=n.y,delete n.y,n},mo.reverse=yo,yo.reverse=mo,ta.svg.area=function(){return Do(y)},ta.svg.area.radial=function(){var n=Do(Ro);return n.radius=n.x,delete n.x,n.innerRadius=n.x0,delete n.x0,n.outerRadius=n.x1,delete n.x1,n.angle=n.y,delete n.y,n.startAngle=n.y0,delete n.y0,n.endAngle=n.y1,delete n.y1,n},ta.svg.chord=function(){function n(n,a){var c=t(this,i,n,a),l=t(this,o,n,a);return"M"+c.p0+r(c.r,c.p1,c.a1-c.a0)+(e(c,l)?u(c.r,c.p1,c.r,c.p0):u(c.r,c.p1,l.r,l.p0)+r(l.r,l.p1,l.a1-l.a0)+u(l.r,l.p1,c.r,c.p0))+"Z"}function t(n,t,e,r){var u=t.call(n,e,r),i=a.call(n,u,r),o=c.call(n,u,r)-Ra,s=l.call(n,u,r)-Ra;return{r:i,a0:o,a1:s,p0:[i*Math.cos(o),i*Math.sin(o)],p1:[i*Math.cos(s),i*Math.sin(s)]}}function e(n,t){return n.a0==t.a0&&n.a1==t.a1}function r(n,t,e){return"A"+n+","+n+" 0 "+ +(e>qa)+",1 "+t}function u(n,t,e,r){return"Q 0,0 "+r}var i=mr,o=yr,a=Po,c=ao,l=co;return n.radius=function(t){return arguments.length?(a=Et(t),n):a},n.source=function(t){return arguments.length?(i=Et(t),n):i},n.target=function(t){return arguments.length?(o=Et(t),n):o},n.startAngle=function(t){return arguments.length?(c=Et(t),n):c},n.endAngle=function(t){return arguments.length?(l=Et(t),n):l},n},ta.svg.diagonal=function(){function n(n,u){var i=t.call(this,n,u),o=e.call(this,n,u),a=(i.y+o.y)/2,c=[i,{x:i.x,y:a},{x:o.x,y:a},o];return c=c.map(r),"M"+c[0]+"C"+c[1]+" "+c[2]+" "+c[3]}var t=mr,e=yr,r=Uo;return n.source=function(e){return arguments.length?(t=Et(e),n):t},n.target=function(t){return arguments.length?(e=Et(t),n):e},n.projection=function(t){return arguments.length?(r=t,n):r},n},ta.svg.diagonal.radial=function(){var n=ta.svg.diagonal(),t=Uo,e=n.projection;return n.projection=function(n){return arguments.length?e(jo(t=n)):t},n},ta.svg.symbol=function(){function n(n,r){return(zl.get(t.call(this,n,r))||Oo)(e.call(this,n,r))}var t=Ho,e=Fo;return n.type=function(e){return arguments.length?(t=Et(e),n):t},n.size=function(t){return arguments.length?(e=Et(t),n):e},n};var zl=ta.map({circle:Oo,cross:function(n){var t=Math.sqrt(n/5)/2;return"M"+-3*t+","+-t+"H"+-t+"V"+-3*t+"H"+t+"V"+-t+"H"+3*t+"V"+t+"H"+t+"V"+3*t+"H"+-t+"V"+t+"H"+-3*t+"Z"},diamond:function(n){var t=Math.sqrt(n/(2*Ll)),e=t*Ll;return"M0,"+-t+"L"+e+",0 0,"+t+" "+-e+",0Z"},square:function(n){var t=Math.sqrt(n)/2;return"M"+-t+","+-t+"L"+t+","+-t+" "+t+","+t+" "+-t+","+t+"Z"},"triangle-down":function(n){var t=Math.sqrt(n/ql),e=t*ql/2;return"M0,"+e+"L"+t+","+-e+" "+-t+","+-e+"Z"},"triangle-up":function(n){var t=Math.sqrt(n/ql),e=t*ql/2;return"M0,"+-e+"L"+t+","+e+" "+-t+","+e+"Z"}});ta.svg.symbolTypes=zl.keys();var ql=Math.sqrt(3),Ll=Math.tan(30*Da);_a.transition=function(n){for(var t,e,r=Tl||++Ul,u=Xo(n),i=[],o=Rl||{time:Date.now(),ease:Su,delay:0,duration:250},a=-1,c=this.length;++ai;i++){u.push(t=[]);for(var e=this[i],a=0,c=e.length;c>a;a++)(r=e[a])&&n.call(r,r.__data__,a,i)&&t.push(r)}return Yo(u,this.namespace,this.id)},Pl.tween=function(n,t){var e=this.id,r=this.namespace;return arguments.length<2?this.node()[r][e].tween.get(n):Y(this,null==t?function(t){t[r][e].tween.remove(n)}:function(u){u[r][e].tween.set(n,t)})},Pl.attr=function(n,t){function e(){this.removeAttribute(a)}function r(){this.removeAttributeNS(a.space,a.local)}function u(n){return null==n?e:(n+="",function(){var t,e=this.getAttribute(a);return e!==n&&(t=o(e,n),function(n){this.setAttribute(a,t(n))})})}function i(n){return null==n?r:(n+="",function(){var t,e=this.getAttributeNS(a.space,a.local);return e!==n&&(t=o(e,n),function(n){this.setAttributeNS(a.space,a.local,t(n))})})}if(arguments.length<2){for(t in n)this.attr(t,n[t]);return this}var o="transform"==n?Hu:mu,a=ta.ns.qualify(n);return Zo(this,"attr."+n,t,a.local?i:u)},Pl.attrTween=function(n,t){function e(n,e){var r=t.call(this,n,e,this.getAttribute(u));return r&&function(n){this.setAttribute(u,r(n))}}function r(n,e){var r=t.call(this,n,e,this.getAttributeNS(u.space,u.local));return r&&function(n){this.setAttributeNS(u.space,u.local,r(n))}}var u=ta.ns.qualify(n);return this.tween("attr."+n,u.local?r:e)},Pl.style=function(n,e,r){function u(){this.style.removeProperty(n)}function i(e){return null==e?u:(e+="",function(){var u,i=t(this).getComputedStyle(this,null).getPropertyValue(n);return i!==e&&(u=mu(i,e),function(t){this.style.setProperty(n,u(t),r)})})}var o=arguments.length;if(3>o){if("string"!=typeof n){2>o&&(e="");for(r in n)this.style(r,n[r],e);return this}r=""}return Zo(this,"style."+n,e,i)},Pl.styleTween=function(n,e,r){function u(u,i){var o=e.call(this,u,i,t(this).getComputedStyle(this,null).getPropertyValue(n));return o&&function(t){this.style.setProperty(n,o(t),r)}}return arguments.length<3&&(r=""),this.tween("style."+n,u)},Pl.text=function(n){return Zo(this,"text",n,Vo)},Pl.remove=function(){var n=this.namespace;return this.each("end.transition",function(){var t;this[n].count<2&&(t=this.parentNode)&&t.removeChild(this)})},Pl.ease=function(n){var t=this.id,e=this.namespace;return arguments.length<1?this.node()[e][t].ease:("function"!=typeof n&&(n=ta.ease.apply(ta,arguments)),Y(this,function(r){r[e][t].ease=n}))},Pl.delay=function(n){var t=this.id,e=this.namespace;return arguments.length<1?this.node()[e][t].delay:Y(this,"function"==typeof n?function(r,u,i){r[e][t].delay=+n.call(r,r.__data__,u,i)}:(n=+n,function(r){r[e][t].delay=n}))},Pl.duration=function(n){var t=this.id,e=this.namespace;return arguments.length<1?this.node()[e][t].duration:Y(this,"function"==typeof n?function(r,u,i){r[e][t].duration=Math.max(1,n.call(r,r.__data__,u,i))}:(n=Math.max(1,n),function(r){r[e][t].duration=n}))},Pl.each=function(n,t){var e=this.id,r=this.namespace;if(arguments.length<2){var u=Rl,i=Tl;try{Tl=e,Y(this,function(t,u,i){Rl=t[r][e],n.call(t,t.__data__,u,i)})}finally{Rl=u,Tl=i}}else Y(this,function(u){var i=u[r][e];(i.event||(i.event=ta.dispatch("start","end","interrupt"))).on(n,t)});return this},Pl.transition=function(){for(var n,t,e,r,u=this.id,i=++Ul,o=this.namespace,a=[],c=0,l=this.length;l>c;c++){a.push(n=[]);for(var t=this[c],s=0,f=t.length;f>s;s++)(e=t[s])&&(r=e[o][u],$o(e,s,o,i,{time:r.time,ease:r.ease,delay:r.delay+r.duration,duration:r.duration})),n.push(e)}return Yo(a,o,i)},ta.svg.axis=function(){function n(n){n.each(function(){var n,l=ta.select(this),s=this.__chart__||e,f=this.__chart__=e.copy(),h=null==c?f.ticks?f.ticks.apply(f,a):f.domain():c,g=null==t?f.tickFormat?f.tickFormat.apply(f,a):y:t,p=l.selectAll(".tick").data(h,f),v=p.enter().insert("g",".domain").attr("class","tick").style("opacity",Ca),d=ta.transition(p.exit()).style("opacity",Ca).remove(),m=ta.transition(p.order()).style("opacity",1),M=Math.max(u,0)+o,x=Ui(f),b=l.selectAll(".domain").data([0]),_=(b.enter().append("path").attr("class","domain"),ta.transition(b));v.append("line"),v.append("text");var w,S,k,E,A=v.select("line"),N=m.select("line"),C=p.select("text").text(g),z=v.select("text"),q=m.select("text"),L="top"===r||"left"===r?-1:1;if("bottom"===r||"top"===r?(n=Bo,w="x",k="y",S="x2",E="y2",C.attr("dy",0>L?"0em":".71em").style("text-anchor","middle"),_.attr("d","M"+x[0]+","+L*i+"V0H"+x[1]+"V"+L*i)):(n=Wo,w="y",k="x",S="y2",E="x2",C.attr("dy",".32em").style("text-anchor",0>L?"end":"start"),_.attr("d","M"+L*i+","+x[0]+"H0V"+x[1]+"H"+L*i)),A.attr(E,L*u),z.attr(k,L*M),N.attr(S,0).attr(E,L*u),q.attr(w,0).attr(k,L*M),f.rangeBand){var T=f,R=T.rangeBand()/2;s=f=function(n){return T(n)+R}}else s.rangeBand?s=f:d.call(n,f,s);v.call(n,s,f),m.call(n,f,f)})}var t,e=ta.scale.linear(),r=jl,u=6,i=6,o=3,a=[10],c=null;return n.scale=function(t){return arguments.length?(e=t,n):e},n.orient=function(t){return arguments.length?(r=t in Fl?t+"":jl,n):r},n.ticks=function(){return arguments.length?(a=arguments,n):a},n.tickValues=function(t){return arguments.length?(c=t,n):c},n.tickFormat=function(e){return arguments.length?(t=e,n):t},n.tickSize=function(t){var e=arguments.length;return e?(u=+t,i=+arguments[e-1],n):u},n.innerTickSize=function(t){return arguments.length?(u=+t,n):u},n.outerTickSize=function(t){return arguments.length?(i=+t,n):i},n.tickPadding=function(t){return arguments.length?(o=+t,n):o},n.tickSubdivide=function(){return arguments.length&&n},n};var jl="bottom",Fl={top:1,right:1,bottom:1,left:1};ta.svg.brush=function(){function n(t){t.each(function(){var t=ta.select(this).style("pointer-events.scala","all").style("-webkit-tap-highlight-color","rgba(0,0,0,0)").on("mousedown.brush",i).on("touchstart.brush",i),o=t.selectAll(".background").data([0]);o.enter().append("rect").attr("class","background").style("visibility","hidden").style("cursor","crosshair"),t.selectAll(".extent").data([0]).enter().append("rect").attr("class","extent").style("cursor","move");var a=t.selectAll(".resize").data(v,y);a.exit().remove(),a.enter().append("g").attr("class",function(n){return"resize "+n}).style("cursor",function(n){return Hl[n]}).append("rect").attr("x",function(n){return/[ew]$/.test(n)?-3:null}).attr("y",function(n){return/^[ns]/.test(n)?-3:null}).attr("width",6).attr("height",6).style("visibility","hidden"),a.style("display",n.empty()?"none":null);var c,f=ta.transition(t),h=ta.transition(o);l&&(c=Ui(l),h.attr("x",c[0]).attr("width",c[1]-c[0]),r(f)),s&&(c=Ui(s),h.attr("y",c[0]).attr("height",c[1]-c[0]),u(f)),e(f)})}function e(n){n.selectAll(".resize").attr("transform",function(n){return"translate("+f[+/e$/.test(n)]+","+h[+/^s/.test(n)]+")"})}function r(n){n.select(".extent").attr("x",f[0]),n.selectAll(".extent,.n>rect,.s>rect").attr("width",f[1]-f[0])}function u(n){n.select(".extent").attr("y",h[0]),n.selectAll(".extent,.e>rect,.w>rect").attr("height",h[1]-h[0])}function i(){function i(){32==ta.event.keyCode&&(C||(M=null,q[0]-=f[1],q[1]-=h[1],C=2),S())}function v(){32==ta.event.keyCode&&2==C&&(q[0]+=f[1],q[1]+=h[1],C=0,S())}function d(){var n=ta.mouse(b),t=!1;x&&(n[0]+=x[0],n[1]+=x[1]),C||(ta.event.altKey?(M||(M=[(f[0]+f[1])/2,(h[0]+h[1])/2]),q[0]=f[+(n[0]s?(u=r,r=s):u=s),v[0]!=r||v[1]!=u?(e?a=null:o=null,v[0]=r,v[1]=u,!0):void 0}function y(){d(),k.style("pointer-events.scala","all").selectAll(".resize").style("display",n.empty()?"none":null),ta.select("body").style("cursor",null),L.on("mousemove.brush",null).on("mouseup.brush",null).on("touchmove.brush",null).on("touchend.brush",null).on("keydown.brush",null).on("keyup.brush",null),z(),w({type:"brushend"})}var M,x,b=this,_=ta.select(ta.event.target),w=c.of(b,arguments),k=ta.select(b),E=_.datum(),A=!/^(n|s)$/.test(E)&&l,N=!/^(e|w)$/.test(E)&&s,C=_.classed("extent"),z=W(b),q=ta.mouse(b),L=ta.select(t(b)).on("keydown.brush",i).on("keyup.brush",v);if(ta.event.changedTouches?L.on("touchmove.brush",d).on("touchend.brush",y):L.on("mousemove.brush",d).on("mouseup.brush",y),k.interrupt().selectAll("*").interrupt(),C)q[0]=f[0]-q[0],q[1]=h[0]-q[1];else if(E){var T=+/w$/.test(E),R=+/^n/.test(E);x=[f[1-T]-q[0],h[1-R]-q[1]],q[0]=f[T],q[1]=h[R]}else ta.event.altKey&&(M=q.slice());k.style("pointer-events.scala","none").selectAll(".resize").style("display",null),ta.select("body").style("cursor",_.style("cursor")),w({type:"brushstart"}),d()}var o,a,c=E(n,"brushstart","brush","brushend"),l=null,s=null,f=[0,0],h=[0,0],g=!0,p=!0,v=Ol[0];return n.event=function(n){n.each(function(){var n=c.of(this,arguments),t={x:f,y:h,i:o,j:a},e=this.__chart__||t;this.__chart__=t,Tl?ta.select(this).transition().each("start.brush",function(){o=e.i,a=e.j,f=e.x,h=e.y,n({type:"brushstart"})}).tween("brush:brush",function(){var e=yu(f,t.x),r=yu(h,t.y);return o=a=null,function(u){f=t.x=e(u),h=t.y=r(u),n({type:"brush",mode:"resize"})}}).each("end.brush",function(){o=t.i,a=t.j,n({type:"brush",mode:"resize"}),n({type:"brushend"})}):(n({type:"brushstart"}),n({type:"brush",mode:"resize"}),n({type:"brushend"}))})},n.x=function(t){return arguments.length?(l=t,v=Ol[!l<<1|!s],n):l},n.y=function(t){return arguments.length?(s=t,v=Ol[!l<<1|!s],n):s},n.clamp=function(t){return arguments.length?(l&&s?(g=!!t[0],p=!!t[1]):l?g=!!t:s&&(p=!!t),n):l&&s?[g,p]:l?g:s?p:null},n.extent=function(t){var e,r,u,i,c;return arguments.length?(l&&(e=t[0],r=t[1],s&&(e=e[0],r=r[0]),o=[e,r],l.invert&&(e=l(e),r=l(r)),e>r&&(c=e,e=r,r=c),(e!=f[0]||r!=f[1])&&(f=[e,r])),s&&(u=t[0],i=t[1],l&&(u=u[1],i=i[1]),a=[u,i],s.invert&&(u=s(u),i=s(i)),u>i&&(c=u,u=i,i=c),(u!=h[0]||i!=h[1])&&(h=[u,i])),n):(l&&(o?(e=o[0],r=o[1]):(e=f[0],r=f[1],l.invert&&(e=l.invert(e),r=l.invert(r)),e>r&&(c=e,e=r,r=c))),s&&(a?(u=a[0],i=a[1]):(u=h[0],i=h[1],s.invert&&(u=s.invert(u),i=s.invert(i)),u>i&&(c=u,u=i,i=c))),l&&s?[[e,u],[r,i]]:l?[e,r]:s&&[u,i])},n.clear=function(){return n.empty()||(f=[0,0],h=[0,0],o=a=null),n},n.empty=function(){return!!l&&f[0]==f[1]||!!s&&h[0]==h[1]},ta.rebind(n,c,"on")};var Hl={n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},Ol=[["n","e","s","w","nw","ne","se","sw"],["e","w"],["n","s"],[]],Il=ac.format=gc.timeFormat,Yl=Il.utc,Zl=Yl("%Y-%m-%dT%H:%M:%S.%LZ");Il.iso=Date.prototype.toISOString&&+new Date("2000-01-01T00:00:00.000Z")?Jo:Zl,Jo.parse=function(n){var t=new Date(n);return isNaN(t)?null:t},Jo.toString=Zl.toString,ac.second=Ft(function(n){return new cc(1e3*Math.floor(n/1e3))},function(n,t){n.setTime(n.getTime()+1e3*Math.floor(t))},function(n){return n.getSeconds()}),ac.seconds=ac.second.range,ac.seconds.utc=ac.second.utc.range,ac.minute=Ft(function(n){return new cc(6e4*Math.floor(n/6e4))},function(n,t){n.setTime(n.getTime()+6e4*Math.floor(t))},function(n){return n.getMinutes()}),ac.minutes=ac.minute.range,ac.minutes.utc=ac.minute.utc.range,ac.hour=Ft(function(n){var t=n.getTimezoneOffset()/60;return new cc(36e5*(Math.floor(n/36e5-t)+t))},function(n,t){n.setTime(n.getTime()+36e5*Math.floor(t))},function(n){return n.getHours()}),ac.hours=ac.hour.range,ac.hours.utc=ac.hour.utc.range,ac.month=Ft(function(n){return n=ac.day(n),n.setDate(1),n},function(n,t){n.setMonth(n.getMonth()+t)},function(n){return n.getMonth()}),ac.months=ac.month.range,ac.months.utc=ac.month.utc.range;var Vl=[1e3,5e3,15e3,3e4,6e4,3e5,9e5,18e5,36e5,108e5,216e5,432e5,864e5,1728e5,6048e5,2592e6,7776e6,31536e6],Xl=[[ac.second,1],[ac.second,5],[ac.second,15],[ac.second,30],[ac.minute,1],[ac.minute,5],[ac.minute,15],[ac.minute,30],[ac.hour,1],[ac.hour,3],[ac.hour,6],[ac.hour,12],[ac.day,1],[ac.day,2],[ac.week,1],[ac.month,1],[ac.month,3],[ac.year,1]],$l=Il.multi([[".%L",function(n){return n.getMilliseconds()}],[":%S",function(n){return n.getSeconds()}],["%I:%M",function(n){return n.getMinutes()}],["%I %p",function(n){return n.getHours()}],["%a %d",function(n){return n.getDay()&&1!=n.getDate()}],["%b %d",function(n){return 1!=n.getDate()}],["%B",function(n){return n.getMonth()}],["%Y",Ne]]),Bl={range:function(n,t,e){return ta.range(Math.ceil(n/e)*e,+t,e).map(Ko)},floor:y,ceil:y};Xl.year=ac.year,ac.scale=function(){return Go(ta.scale.linear(),Xl,$l)};var Wl=Xl.map(function(n){return[n[0].utc,n[1]]}),Jl=Yl.multi([[".%L",function(n){return n.getUTCMilliseconds()}],[":%S",function(n){return n.getUTCSeconds()}],["%I:%M",function(n){return n.getUTCMinutes()}],["%I %p",function(n){return n.getUTCHours()}],["%a %d",function(n){return n.getUTCDay()&&1!=n.getUTCDate()}],["%b %d",function(n){return 1!=n.getUTCDate()}],["%B",function(n){return n.getUTCMonth()}],["%Y",Ne]]);Wl.year=ac.year.utc,ac.scale.utc=function(){return Go(ta.scale.linear(),Wl,Jl)},ta.text=At(function(n){return n.responseText}),ta.json=function(n,t){return Nt(n,"application/json",Qo,t)},ta.html=function(n,t){return Nt(n,"text/html",na,t)},ta.xml=At(function(n){return n.responseXML}),"function"==typeof define&&define.amd?define(ta):"object"==typeof module&&module.exports&&(module.exports=ta),this.d3=ta}();
\ No newline at end of file
diff --git a/test/com/linkedin/drelephant/BackfillTest.java b/test/com/linkedin/drelephant/BackfillTest.java
deleted file mode 100644
index a67fb602e..000000000
--- a/test/com/linkedin/drelephant/BackfillTest.java
+++ /dev/null
@@ -1,681 +0,0 @@
-/*
- * Copyright 2016 LinkedIn Corp.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.linkedin.drelephant;
-
-import com.google.common.collect.Lists;
-import com.linkedin.drelephant.analysis.AnalyticJob;
-import com.linkedin.drelephant.analysis.AnalyticJobGenerator;
-import com.linkedin.drelephant.analysis.ApplicationType;
-import com.linkedin.drelephant.analysis.ElephantBackfillFetcher;
-import com.linkedin.drelephant.analysis.JobType;
-import com.linkedin.drelephant.analysis.Severity;
-import com.linkedin.drelephant.priorityexecutor.Priority;
-import com.linkedin.drelephant.util.Utils;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.Future;
-import models.AppResult;
-import models.BackfillInfo;
-import org.apache.hadoop.conf.Configuration;
-import org.apache.hadoop.security.authentication.client.AuthenticationException;
-import org.junit.Before;
-import org.junit.Test;
-import play.test.FakeApplication;
-
-import static common.DBTestUtil.initDB;
-import static common.TestConstants.APPLY_EVOLUTIONS_DEFAULT_KEY;
-import static common.TestConstants.APPLY_EVOLUTIONS_DEFAULT_VALUE;
-import static common.TestConstants.DB_DEFAULT_DRIVER_KEY;
-import static common.TestConstants.DB_DEFAULT_DRIVER_VALUE;
-import static common.TestConstants.DB_DEFAULT_URL_KEY;
-import static common.TestConstants.DB_DEFAULT_URL_VALUE;
-import static common.TestConstants.EVOLUTION_PLUGIN_KEY;
-import static common.TestConstants.EVOLUTION_PLUGIN_VALUE;
-import static common.TestConstants.TEST_SERVER_PORT;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.*;
-import static play.test.Helpers.fakeApplication;
-import static play.test.Helpers.running;
-import static play.test.Helpers.testServer;
-
-/**
- * Tests backfilling of jobs when Dr.Elephant comes up.
- */
-public class BackfillTest {
-
- private static FakeApplication fakeApp;
-
- @Before
- public void setup() {
- Map dbConn = new HashMap();
- dbConn.put(DB_DEFAULT_DRIVER_KEY, DB_DEFAULT_DRIVER_VALUE);
- dbConn.put(DB_DEFAULT_URL_KEY, DB_DEFAULT_URL_VALUE);
- dbConn.put(EVOLUTION_PLUGIN_KEY, EVOLUTION_PLUGIN_VALUE);
- dbConn.put(APPLY_EVOLUTIONS_DEFAULT_KEY, APPLY_EVOLUTIONS_DEFAULT_VALUE);
-
- fakeApp = fakeApplication(dbConn);
- }
-
- private void populateTestData() {
- try {
- initDB();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- @Test
- public void testGetBackfillData() {
- running(testServer(TEST_SERVER_PORT, fakeApp), new Runnable() {
- public void run() {
- populateTestData();
- List infos = BackfillInfo.find.select("*").findList();
- assertEquals(2, infos.size());
- for (BackfillInfo info : infos) {
- if (info.appType.equals("MAPREDUCE")) {
- assertEquals(123456789, info.backfillTs);
- } else if (info.appType.equals("SPARK")) {
- assertEquals(123456779, info.backfillTs);
- } else {
- fail("Unexpected app type retrieved from backfill_info table");
- }
- }
-
- // Update backfill info.
- BackfillInfo info = BackfillInfo.find.byId("MAPREDUCE");
- long ts = System.currentTimeMillis();
- info.appType = "MAPREDUCE";
- info.backfillTs = ts;
- info.save();
- BackfillInfo infoAfterUpdate = BackfillInfo.find.select("*").
- where().eq("app_type", "MAPREDUCE").findUnique();
- assertEquals(ts, infoAfterUpdate.backfillTs);
-
- // Insert in backfill info.
- info = BackfillInfo.find.byId("TEZ");
- assertNull(info);
- info = new BackfillInfo();
- info.appType = "TEZ";
- info.backfillTs = ts;
- info.save();
- BackfillInfo infoAfterInsert = BackfillInfo.find.select("*").
- where().eq("app_type", "TEZ").findUnique();
- assertEquals(ts, infoAfterInsert.backfillTs);
- }
- });
- }
-
- private static void assertAppResultEntry(String appId, long startTime, long finishTime, String appName) {
- AppResult result = AppResult.find.byId(appId);
- assertNotNull(appId + " should have been found in yarn_app_result_table", result);
- assertEquals(startTime, result.startTime);
- assertEquals(finishTime, result.finishTime);
- assertEquals("default", result.queueName);
- assertEquals("user", result.username);
- assertEquals(appName, result.name);
- assertEquals(Utils.getJobIdFromApplicationId(appId), result.jobExecId);
- assertEquals("flow_123", result.flowExecId);
- assertEquals("Azkaban", result.scheduler);
- assertEquals(Severity.LOW, result.severity);
- assertEquals(1, result.workflowDepth);
- assertEquals(100, result.score);
- }
-
- @Test
- public void testBackfillWithNoDataInDB() {
- running(testServer(TEST_SERVER_PORT, fakeApp), new Runnable() {
- public void run() {
- List infos = BackfillInfo.find.findList();
- assertEquals(0, infos.size());
-
- // Start runner with 2 threads.
- ElephantContext.instance().getGeneralConf().setInt("drelephant.analysis.thread.count", 2);
- final ElephantRunner runner = spy(new ElephantRunner());
- Map appsToPriorityMap = Collections.synchronizedMap(new LinkedHashMap());
- // 4 jobs to be returned.
- List jobs = new ArrayList();
- jobs.add(new DummyAnalyticJobGenerator.DummyAnalyticJob().setAppId("application_1526555215992_0001").
- setAppType(new ApplicationType("MAPREDUCE")).setName("mapreduce_job").setQueueName("default").
- setStartTime(1526520000000L).setFinishTime(1526520000050L).setUser("user"));
- jobs.add(new DummyAnalyticJobGenerator.DummyAnalyticJob().setAppId("application_1526555215992_0002").
- setAppType(new ApplicationType("SPARK")).setName("spark_job").setQueueName("default").
- setStartTime(1526600000000L).setFinishTime(1526600000050L).setUser("user"));
- jobs.add(new DummyAnalyticJobGenerator.DummyAnalyticJob().setAppId("application_1526555215992_0003").
- setAppType(new ApplicationType("SPARK")).setName("spark_job").setQueueName("default").
- setStartTime(1526700000000L).setFinishTime(1526700000050L).setUser("user"));
- jobs.add(new DummyAnalyticJobGenerator.DummyAnalyticJob().setAppId("application_1526555215992_0004").
- setAppType(new ApplicationType("MAPREDUCE")).setName("mapreduce_job").setQueueName("default").
- setStartTime(1526800000000L).setFinishTime(1526800000050L).setUser("user"));
- doReturn(new DummyAnalyticJobGenerator(appsToPriorityMap, jobs)).when(runner).getAnalyticJobGenerator();
- Thread runnerThread = new Thread(new Runnable() {
- @Override
- public void run() {
- runner.run();
- }
- });
- runnerThread.start();
-
- // Wait till results have been updated in DB.
- List results = AppResult.find.findList();
- int resultCount = results.size();
- int loopCount = 400;
- while (resultCount < 4 && loopCount > 0) {
- try {
- Thread.sleep(50);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- results = AppResult.find.findList();
- resultCount = results.size();
- loopCount--;
- }
-
- // Check yarn_app_result.
- assertEquals(4, resultCount);
- assertAppResultEntry("application_1526555215992_0001", 1526520000000L, 1526520000050L,
- "mapreduce_job");
- assertAppResultEntry("application_1526555215992_0002", 1526600000000L, 1526600000050L,
- "spark_job");
- assertAppResultEntry("application_1526555215992_0003", 1526700000000L, 1526700000050L,
- "spark_job");
- assertAppResultEntry("application_1526555215992_0004", 1526800000000L, 1526800000050L,
- "mapreduce_job");
-
- // Check backfill_info.
- assertEquals(2, BackfillInfo.find.findList().size());
- BackfillInfo mapReduceInfo = BackfillInfo.find.byId("MAPREDUCE");
- assertEquals(1526800000050L, mapReduceInfo.backfillTs);
- BackfillInfo sparkInfo = BackfillInfo.find.byId("SPARK");
- assertEquals(1526700000050L, sparkInfo.backfillTs);
-
- // Verify if apps were submitted with NORMAL priority.
- assertEquals(4, appsToPriorityMap.size());
- for (Priority priority : appsToPriorityMap.values()) {
- assertEquals(Priority.NORMAL, priority);
- }
-
- // Ensure cleanup is performed.
- assertTrue("App to analytic map should have been empty", runner.getAppToAnalyticJobMap().isEmpty());
- assertNotNull("MAPREDUCE app type should have final info", runner.getFinishTimeInfo("MAPREDUCE"));
- assertTrue("Finish times map should be cleaned up for MAPREDUCE app type",
- runner.getFinishTimeInfo("MAPREDUCE")._appFinishTimesMap.isEmpty());
- assertNotNull("SPARK app type should have final info", runner.getFinishTimeInfo("SPARK"));
- assertTrue("Finish times map should be cleaned up for SPARK app type",
- runner.getFinishTimeInfo("SPARK")._appFinishTimesMap.isEmpty());
-
- // Stop the runner and do cleanup before exiting.
- runner.kill();
- runnerThread.interrupt();
- try {
- runnerThread.join();
- } catch (InterruptedException e) {
- // Ignore the exception.
- }
- }
- });
- }
-
- private static void assertBackfillInfo(String appType, long expectedBackfillTs) {
- int loopCount = 800;
- BackfillInfo info = BackfillInfo.find.byId(appType);
- while ((info == null || info.backfillTs != expectedBackfillTs) && loopCount > 0) {
- try {
- Thread.sleep(50);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- info = BackfillInfo.find.byId(appType);
- loopCount--;
- }
- assertEquals(expectedBackfillTs, info.backfillTs);
- }
-
- @Test
- public void testBackfillWithDataInDB() {
- running(testServer(TEST_SERVER_PORT, fakeApp), new Runnable() {
- public void run() {
- populateTestData();
- long backfillTs = 1526400000000L;
- List results = AppResult.find.findList();
- int initialResultCount = results.size();
- BackfillInfo mapReduceBackfillInfo = BackfillInfo.find.byId("MAPREDUCE");
- assertNotNull(mapReduceBackfillInfo);
- mapReduceBackfillInfo.backfillTs = backfillTs;
- mapReduceBackfillInfo.save();
- BackfillInfo sparkBackfillInfo = BackfillInfo.find.byId("SPARK");
- assertNotNull(sparkBackfillInfo);
- sparkBackfillInfo.backfillTs = backfillTs;
- sparkBackfillInfo.save();
- BackfillInfo tezBackfillInfo = new BackfillInfo();
- tezBackfillInfo.appType = "TEZ";
- tezBackfillInfo.backfillTs = backfillTs;
- tezBackfillInfo.save();
- List infos = BackfillInfo.find.findList();
- assertEquals(3, infos.size());
-
- // Enable backfill and start runner with 1 thread.
- ElephantContext.instance().getGeneralConf().setInt("drelephant.analysis.thread.count", 1);
- ElephantContext.instance().getGeneralConf().setBoolean("drelephant.analysis.backfill.enabled", true);
- final ElephantRunner runner = spy(new ElephantRunner());
- Map appsToPriorityMap = Collections.synchronizedMap(new LinkedHashMap());
- // 2 jobs to be returned by job generator.
- // For each job, set job execution priority as MIN_PRIORITY. This acts as a sentinel value and we will wait
- // during analysis till the value changes to avoid race while adding to appsToPriorityMap.
- List jobs = new ArrayList();
- jobs.add(new DummyAnalyticJobGenerator.DummyAnalyticJob().setAppId("application_1526555215992_0007").
- setAppType(new ApplicationType("MAPREDUCE")).setName("mapreduce_job_3").setQueueName("default").
- setStartTime(1526800000000L).setFinishTime(1526800000050L).setUser("user"));
- jobs.add(new DummyAnalyticJobGenerator.DummyAnalyticJob().setAppId("application_1526555215992_0008").
- setAppType(new ApplicationType("SPARK")).setName("spark_job_3").setQueueName("default").
- setStartTime(1526900000000L).setFinishTime(1526900000050L).setUser("user"));
- long lowestTsFromRM = 1526800000050L;
- AnalyticJobGenerator jobGenerator = new DummyAnalyticJobGenerator(appsToPriorityMap, jobs);
- doReturn(jobGenerator).when(runner).getAnalyticJobGenerator();
-
- // 6 jobs to be backfilled.
- List mapReduceBackfillJobs = new ArrayList();
- mapReduceBackfillJobs.add(new DummyAnalyticJobGenerator.DummyAnalyticJob().
- setAppId("application_1526555215992_0001").setAppType(new ApplicationType("MAPREDUCE")).
- setName("mapreduce_job_1").setQueueName("default").setStartTime(1526510000000L).
- setFinishTime(1526520000150L).setUser("user").setJobExecutionPriority(Priority.MIN_PRIORITY));
- mapReduceBackfillJobs.add(new DummyAnalyticJobGenerator.DummyAnalyticJob().
- setAppId("application_1526555215992_0003").setAppType(new ApplicationType("MAPREDUCE")).
- setName("mapreduce_job_2").setQueueName("default").setStartTime(1526520000000L).
- setFinishTime(1526520000050L).setUser("user").setJobExecutionPriority(Priority.MIN_PRIORITY));
- DummyElephantBackfillFetcher mapreduceBackfillFetcher =
- new DummyElephantBackfillFetcher(mapReduceBackfillJobs, "MAPREDUCE", backfillTs, lowestTsFromRM);
- when(runner.getBackfillFetcher(eq(new ApplicationType("MAPREDUCE")))).thenReturn(mapreduceBackfillFetcher);
-
- List sparkBackfillJobs = new ArrayList();
- sparkBackfillJobs.add(new DummyAnalyticJobGenerator.DummyAnalyticJob().setAppId("application_1526555215992_0002").
- setAppType(new ApplicationType("SPARK")).setName("spark_job_1").setQueueName("default").
- setStartTime(1526510050000L).setFinishTime(1526700000060L).setUser("user").
- setJobExecutionPriority(Priority.MIN_PRIORITY));
- sparkBackfillJobs.add(new DummyAnalyticJobGenerator.DummyAnalyticJob().setAppId("application_1526555215992_0006").
- setAppType(new ApplicationType("SPARK")).setName("spark_job_2").setQueueName("default").
- setStartTime(1526700000000L).setFinishTime(1526700000050L).setUser("user").
- setJobExecutionPriority(Priority.MIN_PRIORITY));
- DummyElephantBackfillFetcher sparkBackfillFetcher =
- new DummyElephantBackfillFetcher(sparkBackfillJobs, "SPARK", backfillTs, lowestTsFromRM);
- when(runner.getBackfillFetcher(eq(new ApplicationType("SPARK")))).thenReturn(sparkBackfillFetcher);
-
- // 2 jobs below will not have finish time at the time of backfill.
- List tezBackfillJobs = new ArrayList();
- tezBackfillJobs.add(
- ((DummyAnalyticJobGenerator.DummyAnalyticJob) new DummyAnalyticJobGenerator.DummyAnalyticJob().
- setAppId("application_1526555215992_0004").setAppType(new ApplicationType("TEZ")).
- setName("tez_job_1").setQueueName("default").setUser("user").setStartTime(1526600000000L)).
- setFinishTimeAfterAnalysis(1526600000050L).setJobExecutionPriority(Priority.MIN_PRIORITY));
- tezBackfillJobs.add(
- ((DummyAnalyticJobGenerator.DummyAnalyticJob) new DummyAnalyticJobGenerator.DummyAnalyticJob().
- setAppId("application_1526555215992_0005").setAppType(new ApplicationType("TEZ")).
- setName("tez_job_2").setQueueName("default").setUser("user").setStartTime(1526600000020L)).
- setFinishTimeAfterAnalysis(1526600000040L).setJobExecutionPriority(Priority.MIN_PRIORITY));
- ApplicationType tezAppType = new ApplicationType("TEZ");
- doReturn(tezAppType).when(runner).getAppTypeForName("TEZ");
- DummyElephantBackfillFetcher tezBackfillFetcher = new DummyElephantBackfillFetcher(
- tezBackfillJobs, "TEZ", backfillTs, lowestTsFromRM);
- when(runner.getBackfillFetcher(eq(tezAppType))).thenReturn(tezBackfillFetcher);
-
- Thread runnerThread = new Thread(new Runnable() {
- @Override
- public void run() {
- runner.run();
- }
- });
- runnerThread.start();
-
- // Wait till results have been updated in DB.
- results = AppResult.find.findList();
- int resultCount = results.size();
- int loopCount = 400;
- while (resultCount < 8 + initialResultCount && loopCount > 0) {
- try {
- Thread.sleep(50);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- results = AppResult.find.findList();
- resultCount = results.size();
- loopCount--;
- }
-
- // Check yarn_app_result.
- assertEquals(8 + initialResultCount, resultCount);
- assertAppResultEntry("application_1526555215992_0001", 1526510000000L, 1526520000150L,
- "mapreduce_job_1");
- assertAppResultEntry("application_1526555215992_0002", 1526510050000L, 1526700000060L,
- "spark_job_1");
- assertAppResultEntry("application_1526555215992_0003", 1526520000000L, 1526520000050L,
- "mapreduce_job_2");
- assertAppResultEntry("application_1526555215992_0004", 1526600000000L, 1526600000050L,
- "tez_job_1");
- assertAppResultEntry("application_1526555215992_0005", 1526600000020L, 1526600000040L,
- "tez_job_2");
- assertAppResultEntry("application_1526555215992_0006", 1526700000000L, 1526700000050L,
- "spark_job_2");
- assertAppResultEntry("application_1526555215992_0007", 1526800000000L, 1526800000050L,
- "mapreduce_job_3");
- assertAppResultEntry("application_1526555215992_0008", 1526900000000L, 1526900000050L,
- "spark_job_3");
- DummyElephantBackfillFetcher[] backfillFetchers =
- new DummyElephantBackfillFetcher[] {mapreduceBackfillFetcher, sparkBackfillFetcher, tezBackfillFetcher};
- for (DummyElephantBackfillFetcher backfillFetcher : backfillFetchers) {
- try {
- assertTrue("Jobs for backfill (of type " + backfillFetcher.getFetcherName() + ") should have been "
- + "fetched based on lowest ts of apps retrieved from RM and backfill ts in DB",
- backfillFetcher.getJobsFetchedFlag());
- } catch (Exception e) {
- fail("Unexpected exception.");
- }
- }
-
- // Verify apps submitted.
- assertEquals(8, appsToPriorityMap.size());
- assertEquals(Lists.newArrayList(Priority.NORMAL, Priority.NORMAL, Priority.LOW, Priority.LOW, Priority.LOW,
- Priority.LOW, Priority.LOW, Priority.LOW), new ArrayList(appsToPriorityMap.values()));
-
- String[] appTypes = new String[] {"MAPREDUCE", "SPARK", "TEZ"};
- for (String appType : appTypes) {
- ElephantRunner.FinishTimeInfo finishTimeInfo = runner.getFinishTimeInfo(appType);
- loopCount = 400;
- while ((finishTimeInfo == null || !finishTimeInfo._appFinishTimesMap.isEmpty()) && loopCount > 0) {
- try {
- Thread.sleep(50);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- loopCount--;
- }
- }
-
- // Ensure cleanup is performed.
- assertTrue("App to analytic map should have been empty", runner.getAppToAnalyticJobMap().isEmpty());
- assertNotNull("MAPREDUCE app type should have final info", runner.getFinishTimeInfo("MAPREDUCE"));
- assertTrue("Finish times map should be cleaned up for MAPREDUCE app type",
- runner.getFinishTimeInfo("MAPREDUCE")._appFinishTimesMap.isEmpty());
- assertNotNull("SPARK app type should have final info", runner.getFinishTimeInfo("SPARK"));
- assertTrue("Finish times map should be cleaned up for SPARK app type",
- runner.getFinishTimeInfo("SPARK")._appFinishTimesMap.isEmpty());
- assertNotNull("TEZ app type should have final info", runner.getFinishTimeInfo("TEZ"));
- assertTrue("Finish times map should be cleaned up for TEZ app type",
- runner.getFinishTimeInfo("TEZ")._appFinishTimesMap.isEmpty());
-
- // Check backfill_info.
- assertEquals(3, BackfillInfo.find.findList().size());
- assertBackfillInfo("MAPREDUCE", 1526800000050L);
- assertBackfillInfo("SPARK", 1526900000050L);
-
- // Stop the runner and do cleanup before exiting.
- runner.kill();
- runnerThread.interrupt();
- try {
- runnerThread.join();
- } catch (InterruptedException e) {
- // Ignore the exception.
- }
- }
- });
- }
-
- @Test
- public void testPrioritizeExecution() {
- running(testServer(TEST_SERVER_PORT, fakeApp), new Runnable() {
- public void run() {
- List infos = BackfillInfo.find.findList();
- assertEquals(0, infos.size());
-
- // Start runner with 1 thread.
- ElephantContext.instance().getGeneralConf().setInt("drelephant.analysis.thread.count", 1);
- final ElephantRunner runner = spy(new ElephantRunner());
- Map appsToPriorityMap = Collections.synchronizedMap(new LinkedHashMap());
- // 3 jobs to be returned.
- List jobs = new ArrayList();
- // First job will sleep for 5 seconds before analysis, if not interrupted.
- jobs.add(((DummyAnalyticJobGenerator.DummyAnalyticJob) new DummyAnalyticJobGenerator.DummyAnalyticJob().
- setAppId("application_1526555215992_0001").setAppType(new ApplicationType("MAPREDUCE")).
- setName("mapreduce_job").setQueueName("default").setStartTime(1526520000000L).setFinishTime(1526520000050L).
- setUser("user")).setSleepBeforeAnalysis());
- jobs.add(new DummyAnalyticJobGenerator.DummyAnalyticJob().setAppId("application_1526555215992_0002").
- setAppType(new ApplicationType("SPARK")).setName("spark_job").setQueueName("default").
- setStartTime(1526600000000L).setFinishTime(1526600000050L).setUser("user"));
- jobs.add(new DummyAnalyticJobGenerator.DummyAnalyticJob().setAppId("application_1526555215992_0003").
- setAppType(new ApplicationType("SPARK")).setName("spark_job").setQueueName("default").
- setStartTime(1526700000000L).setFinishTime(1526700000050L).setUser("user"));
- doReturn(new DummyAnalyticJobGenerator(appsToPriorityMap, jobs)).when(runner).getAnalyticJobGenerator();
- Thread runnerThread = new Thread(new Runnable() {
- @Override
- public void run() {
- runner.run();
- }
- });
- runnerThread.start();
-
- // Wait till first app has been picked up by executor.
- int loopCount = 400;
- while (!runner.getAppToAnalyticJobMap().containsKey("application_1526555215992_0001") && loopCount > 0) {
- try {
- Thread.sleep(50);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- loopCount--;
- }
- assertTrue("Executor should have picked up application_1526555215992_0001 for execution",
- runner.getAppToAnalyticJobMap().containsKey("application_1526555215992_0001"));
-
- // Prioritize application_1526555215992_0003.
- Future> future = runner.prioritizeExecutionAndReturnFuture("application_1526555215992_0003");
- assertNotNull("Priortization was not successful", future);
- // Ensure first job proceeds ahead from sleep by interrupting it.
- runner.getAppToAnalyticJobMap().get("application_1526555215992_0001").getJobFuture().cancel(true);
- runner.waitTillPrioritizedJobAnalysisFinishes(future);
- assertTrue("Prioritized job should have finished.", future.isDone());
-
- // Wait till results have been updated in DB.
- List results = AppResult.find.findList();
- int resultCount = results.size();
- loopCount = 400;
- while (resultCount < 3 && loopCount > 0) {
- try {
- Thread.sleep(50);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- results = AppResult.find.findList();
- resultCount = results.size();
- loopCount--;
- }
-
- // Check yarn_app_result.
- assertEquals("yarn_app_result table should have 3 rows", 3, resultCount);
- assertAppResultEntry("application_1526555215992_0001", 1526520000000L, 1526520000050L,
- "mapreduce_job");
- assertAppResultEntry("application_1526555215992_0002", 1526600000000L, 1526600000050L,
- "spark_job");
- assertAppResultEntry("application_1526555215992_0003", 1526700000000L, 1526700000050L,
- "spark_job");
-
- // Check backfill_info.
- assertEquals("backfill_info table should have 2 rows", 2, BackfillInfo.find.findList().size());
- BackfillInfo mapReduceInfo = BackfillInfo.find.byId("MAPREDUCE");
- assertEquals(1526520000050L, mapReduceInfo.backfillTs);
- BackfillInfo sparkInfo = BackfillInfo.find.byId("SPARK");
- assertEquals(1526700000050L, sparkInfo.backfillTs);
-
- // Verify if apps were submitted in correct order based on prioritization.
- assertEquals(3, appsToPriorityMap.size());
- assertEquals(Lists.newArrayList("application_1526555215992_0001", "application_1526555215992_0003",
- "application_1526555215992_0002"), new ArrayList(appsToPriorityMap.keySet()));
- assertEquals(Lists.newArrayList(Priority.NORMAL, Priority.HIGH, Priority.NORMAL),
- new ArrayList(appsToPriorityMap.values()));
-
- // Stop the runner and do cleanup before exiting.
- runner.kill();
- runnerThread.interrupt();
- try {
- runnerThread.join();
- } catch (InterruptedException e) {
- // Ignore the exception.
- }
- }
- });
- }
-
- private static class DummyAnalyticJobGenerator implements AnalyticJobGenerator {
- private static Map _appsToPriorityMap;
- private List _analyticJobs;
-
- private DummyAnalyticJobGenerator(Map appsMap, List jobs) {
- _appsToPriorityMap = appsMap;
- _analyticJobs = jobs;
- }
-
- @Override
- public void configure(Configuration configuration) throws IOException {
- }
-
- @Override
- public void updateResourceManagerAddresses() {
- }
-
- @Override
- public List fetchAnalyticJobs() throws IOException, AuthenticationException {
- return _analyticJobs;
- }
-
- @Override
- public void addIntoRetries(AnalyticJob job) {
- }
-
- @Override
- public void addIntoSecondRetryQueue(AnalyticJob job) {
- }
-
- @Override
- public String getEffectiveResourceManagerAddress() {
- return "localhost:8188";
- }
-
- @Override
- public long getFetchStartTime() {
- return 0;
- }
-
- private static class DummyAnalyticJob extends AnalyticJob {
- private long _finishTimeAfterAnalysis = -1;
- // For prioritization tests, sleep for 5 seconds before analysis.
- // Interruption is caught and ignored.
- private boolean _sleepBeforeAnalysis = false;
- @Override
- public AppResult getAnalysis() throws Exception {
- if (_sleepBeforeAnalysis) {
- try {
- Thread.sleep(5000L);
- } catch (InterruptedException e) {
- // Ignore and continue with analysis.
- }
- }
- AppResult result = new AppResult();
- result.id = getAppId();
- result.finishTime = getFinishTime() <= 0 ? _finishTimeAfterAnalysis : getFinishTime();
- result.jobName = getName();
- result.queueName = getQueueName();
- result.trackingUrl = getTrackingUrl() == null ? "" : getTrackingUrl();
- result.name = getName();
- result.username = getUser();
- result.startTime = getStartTime();
- List jobTypes = ElephantContext.instance().getAppTypeToJobTypes().get(getAppType());
- result.jobType = ((jobTypes == null) ? "" : jobTypes.get(0).getName());
- result.severity = Severity.LOW;
- result.score = 100;
- result.workflowDepth = 1;
- result.scheduler = "Azkaban";
- result.jobExecId = Utils.getJobIdFromApplicationId(getAppId());
- result.flowExecId = "flow_123";
- result.jobDefId = "job_def_123";
- result.flowDefId = "flow_def_123";
- result.jobExecUrl = "job_url";
- result.flowExecUrl = "flow_url";
- result.jobDefUrl = "job_def_url";
- result.flowDefUrl = "flow_def_url";
- // Wait for execution priority to be set, if not already set, to avoid race.
- int loopCount = 400;
- while (getJobExecutionPriority() == Priority.MIN_PRIORITY && loopCount > 0) {
- try {
- Thread.sleep(50);
- } catch (InterruptedException e) {
- // Ignore.
- }
- loopCount--;
- }
- _appsToPriorityMap.put(getAppId(), getJobExecutionPriority());
- return result;
- }
-
- DummyAnalyticJob setFinishTimeAfterAnalysis(long finishTime) {
- _finishTimeAfterAnalysis = finishTime;
- return this;
- }
-
- DummyAnalyticJob setSleepBeforeAnalysis() {
- _sleepBeforeAnalysis = true;
- return this;
- }
- }
- }
-
- private static class DummyElephantBackfillFetcher implements ElephantBackfillFetcher {
- private List _backfillJobs;
- private long _backfillTs;
- private long _lowestTsFromRM;
- private volatile boolean _jobsFetchedFlag = false;
- private String _fetcherName;
- private DummyElephantBackfillFetcher(List jobs, String fetcherName, long backfillTs, long lowestTsFromRM) {
- _backfillJobs = jobs;
- _backfillTs = backfillTs;
- _lowestTsFromRM = lowestTsFromRM;
- _fetcherName = fetcherName;
- }
-
- @Override
- public List fetchJobsForBackfill(long startTime, long endTime) throws Exception {
- // Verify whether jobs were backfilled based on lowest ts of apps retrieved from RM and backfill ts in DB.
- if ((startTime == _backfillTs - ElephantRunner.BACKFILL_BUFFER_TIME) && (endTime == _lowestTsFromRM)) {
- _jobsFetchedFlag = true;
- }
- return _backfillJobs;
- }
-
- private boolean getJobsFetchedFlag() {
- return _jobsFetchedFlag;
- }
-
- private String getFetcherName() {
- return _fetcherName;
- }
- }
-}
diff --git a/test/com/linkedin/drelephant/analysis/AnalyticJobGeneratorHadoop2Test.java b/test/com/linkedin/drelephant/analysis/AnalyticJobGeneratorHadoop2Test.java
deleted file mode 100644
index e0bebbfb2..000000000
--- a/test/com/linkedin/drelephant/analysis/AnalyticJobGeneratorHadoop2Test.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright 2016 LinkedIn Corp.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.linkedin.drelephant.analysis;
-
-import java.util.ArrayList;
-import java.util.ConcurrentModificationException;
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-import org.junit.Test;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
-
-
-/**
- * Unit tests for class {@link AnalyticJobGeneratorHadoop2}.
- */
-public class AnalyticJobGeneratorHadoop2Test {
- /**
- * Tests concurrent operations (fetch and add) on second retry queue.
- */
- @Test
- public void testSecondRetryQueueConcurrentOperations() {
- final AnalyticJobGeneratorHadoop2 analyticJobGenerator =
- new AnalyticJobGeneratorHadoop2();
-
- // Latch to ensure operations on second retry queue from multiple threads
- // run in parallel
- final CountDownLatch latch = new CountDownLatch(1);
-
- // Add a job into second retry queue.
- AnalyticJob job1 = spy(new AnalyticJob());
- // Custom answer on call to readyForSecondRetry for this job.
- doAnswer(new Answer() {
- @Override
- public Boolean answer(final InvocationOnMock invocation) throws Throwable {
- // Wait for additions to second retry queue from add jobs thread to
- // begin. In case of synchronized access, wait will be for 5 sec.
- // In case of unsynchronized access, this would lead to
- // ConcurrentModificationException.
- latch.await(5000L, TimeUnit.MILLISECONDS);
- return true ;
- }
- }).when(job1).readyForSecondRetry();
- analyticJobGenerator.addIntoSecondRetryQueue(job1);
-
- // Add couple of other jobs to second retry queue.
- AnalyticJob job2 = spy(new AnalyticJob());
- when(job2.readyForSecondRetry()).thenReturn(false);
- analyticJobGenerator.addIntoSecondRetryQueue(job2);
-
- AnalyticJob job3 = spy(new AnalyticJob());
- when(job3.readyForSecondRetry()).thenReturn(true);
- analyticJobGenerator.addIntoSecondRetryQueue(job3);
-
- final List appList = new ArrayList();
- // Flag to indicate if ConcurrentModificationException has been thrown.
- final AtomicBoolean cmExceptionFlag = new AtomicBoolean(false);
- // Start a fetch jobs thread which calls fetchJobsFromSecondRetryQueue
- // method.
- Thread fetchJobsThread = new Thread(new Runnable() {
- @Override
- public void run() {
- try {
- analyticJobGenerator.fetchJobsFromSecondRetryQueue(appList);
- } catch (ConcurrentModificationException e) {
- cmExceptionFlag.set(true);
- }
- }
- });
- fetchJobsThread.start();
-
- // Start a add jobs jobs thread which adds a couple of jobs into second
- // retry queue while fetch jobs thread is running in parallel.
- Thread addJobsThread = new Thread(new Runnable() {
- @Override
- public void run() {
- AnalyticJob job4 = spy(new AnalyticJob());
- when(job4.readyForSecondRetry()).thenReturn(false);
- analyticJobGenerator.addIntoSecondRetryQueue(job4);
-
- // Latch countdown to ensure fetch jobs thread can continue.
- latch.countDown();
-
- AnalyticJob job5 = spy(new AnalyticJob());
- when(job5.readyForSecondRetry()).thenReturn(true);
- analyticJobGenerator.addIntoSecondRetryQueue(job5);
- }
- });
- addJobsThread.start();
-
- // Wait for both the threads to finish.
- try {
- fetchJobsThread.join();
- addJobsThread.join();
- } catch (InterruptedException e) {
- // Ignore the exception.
- }
-
- // Concurrent operations from multiple threads should not lead to
- // ConcurrentModificationException as accesses to second retry queue are
- // synchronized.
- assertFalse("ConcurrentModificationException should not have been thrown " +
- "while fetching jobs", cmExceptionFlag.get());
- // Checking for apps >= 2 as the exact number can be 2 or 3 depending on
- // order of invocation of threads.
- assertTrue("Apps fetched from second retry queue should be >= 2.",
- appList.size() >= 2);
-
- // Drain the second retry queue by fetching jobs from it.
- analyticJobGenerator.fetchJobsFromSecondRetryQueue(appList);
- assertEquals("Apps fetched from second retry queue should be 3.", 3,
- appList.size());
- }
-}
diff --git a/test/com/linkedin/drelephant/analysis/AnalyticJobTest.java b/test/com/linkedin/drelephant/analysis/AnalyticJobTest.java
deleted file mode 100644
index 06b5dae36..000000000
--- a/test/com/linkedin/drelephant/analysis/AnalyticJobTest.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright 2016 LinkedIn Corp.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.linkedin.drelephant.analysis;
-
-import com.linkedin.drelephant.ElephantContext;
-import com.linkedin.drelephant.configurations.heuristic.HeuristicConfigurationData;
-import com.linkedin.drelephant.mapreduce.fetchers.MapReduceFetcherHadoop2;
-import com.linkedin.drelephant.mapreduce.data.MapReduceApplicationData;
-import com.linkedin.drelephant.mapreduce.data.MapReduceCounterData;
-import com.linkedin.drelephant.mapreduce.data.MapReduceTaskData;
-import com.linkedin.drelephant.mapreduce.heuristics.MapperSkewHeuristic;
-import common.TestUtil;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import mockit.Expectations;
-import mockit.Mocked;
-import models.AppResult;
-import org.junit.Ignore;
-import org.junit.Test;
-
-import static common.TestConstants.*;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-
-/**
- * Test aims to exercise {@code getAnalysis()} method in {@code AnalyticJob}.
- * Dependencies to {@code ElephantContext, ElephantFetcher and Heuristics} are mocked
- * out with JMockit.
- */
-@Ignore
-public class AnalyticJobTest {
- @Mocked(stubOutClassInitialization = true)
- ElephantContext elephantContext = null;
- @Mocked
- MapReduceFetcherHadoop2 fetcher;
-
- @Test
- public void testGetAnalysis()
- throws Exception {
- try {
- // Setup analytic job
- final AnalyticJob analyticJob = new AnalyticJob().
- setAppId(TEST_JOB_ID1).setAppType(new ApplicationType(TEST_APP_TYPE)).
- setFinishTime(1462178403).setStartTime(1462178412).setName(TEST_JOB_NAME).
- setQueueName(TEST_DEFAULT_QUEUE_NAME).setUser(TEST_USERNAME).setTrackingUrl(TEST_TRACKING_URL);
-
- // Setup job counter data
- String filePath = FILENAME_JOBCOUNTER;
- MapReduceCounterData jobCounter = new MapReduceCounterData();
- setCounterData(jobCounter, filePath);
-
- // Setup mapper data
- long[][] mapperTasksTime = {{2563, 0, 0, 0, 0}, {2562, 0, 0, 0, 0}, {2567, 0, 0, 0, 0}};
- MapReduceTaskData[] mappers = new MapReduceTaskData[3];
- for (int i = 1; i <= mappers.length; i++) {
- MapReduceCounterData taskCounter = new MapReduceCounterData();
- setCounterData(taskCounter, FILENAME_MAPPERTASK.replaceFirst("\\$", Integer.toString(i)));
- mappers[i - 1 ] = new MapReduceTaskData("task-id-"+(i-1), "task-attempt-id-"+(i-1));
- mappers[i - 1].setTimeAndCounter(mapperTasksTime[i - 1], taskCounter);
- }
-
- // Setup reducer data
- long[][] reducerTasksTime = {{1870, 1665, 14, 0, 0}};
- MapReduceTaskData[] reducers = new MapReduceTaskData[1];
- for (int i = 1; i <= reducers.length; i++) {
- MapReduceCounterData taskCounter = new MapReduceCounterData();
- setCounterData(taskCounter, FILENAME_REDUCERTASK.replaceFirst("\\$", Integer.toString(i)));
- reducers[i - 1] = new MapReduceTaskData("task-id-"+(i-1), "task-attempt-id-"+(i-1));
- reducers[i - 1].setTimeAndCounter(reducerTasksTime[i - 1], taskCounter);
- }
-
- // Setup job configuration data
- filePath = FILENAME_JOBCONF;
- Properties jobConf = TestUtil.loadProperties(filePath);
-
- // Setup application data
- final MapReduceApplicationData data = new MapReduceApplicationData().setCounters(jobCounter).
- setMapperData(mappers).setReducerData(reducers).setJobConf(jobConf).setSucceeded(true).
- setDiagnosticInfo("").setUsername(TEST_USERNAME).setUrl("").setJobName(TEST_JOB_NAME).
- setStartTime(1462178412).setFinishTime(1462178403).setRetry(false).setAppId(TEST_JOB_ID1);
-
- // Setup heuristics
- final List heuristics = loadHeuristics();
-
- // Setup job type
- final JobType jobType = new JobType(TEST_JOB_TYPE, TEST_JOBCONF_NAME, TEST_JOBCONF_PATTERN);
-
- // Set expectations in JMockit
- new Expectations() {{
- fetcher.fetchData(analyticJob);
- result = data;
-
- elephantContext.getHeuristicsForApplicationType(analyticJob.getAppType());
- result = heuristics;
-
- elephantContext.matchJobType(data);
- result = jobType;
- }};
-
- // Call the method under test
- AppResult result = analyticJob.getAnalysis();
-
- // Make assertions on result
- assertTrue("Result is null", result != null);
- assertTrue("Score did not match", result.score == TEST_SCORE);
- assertTrue("Severity did not match", result.severity.toString().equals(TEST_SEVERITY));
- assertTrue("APP ID did not match", result.id.equals(TEST_JOB_ID1));
- assertTrue("Scheduler did not match", result.scheduler.equals(TEST_SCHEDULER));
- } catch (Exception e) {
- e.printStackTrace();
- assertFalse("Test failed with exception", true);
- }
- }
-
- private void setCounterData(MapReduceCounterData counter, String filePath)
- throws IOException {
- Properties counterData = TestUtil.loadProperties(filePath);
-
- for (Object groupName : counterData.keySet()) {
- String counterValueString = (String) counterData.get(groupName);
- counterValueString = counterValueString.replaceAll("\\{|\\}", "");
-
- StringBuilder stringBuilder = new StringBuilder();
-
- for (String counterKeyValue : counterValueString.split(",")) {
- stringBuilder.append(counterKeyValue.trim()).append('\n');
- }
- ByteArrayInputStream inputStream = new ByteArrayInputStream(stringBuilder.toString().getBytes(DEFAULT_ENCODING));
- Properties counterProperties = new Properties();
- counterProperties.load(inputStream);
-
- for (Object counterKey : counterProperties.keySet()) {
- long counterValue = Long.parseLong(counterProperties.get(counterKey).toString());
- counter.set(groupName.toString(), counterKey.toString(), counterValue);
- }
- }
- }
-
- private List loadHeuristics() {
- List heuristics = new ArrayList();
- // dummy hash map
- Map paramsMap = new HashMap();
- heuristics.add(new MapperSkewHeuristic(new HeuristicConfigurationData("Mapper Skew",
- "com.linkedin.drelephant.mapreduce.heuristics.MapperSkewHeuristic",
- "views.html.help.mapreduce.helpMapperSkew", new ApplicationType("mapreduce"), paramsMap)));
- heuristics.add(new MapperSkewHeuristic(
- new HeuristicConfigurationData("Mapper GC", "com.linkedin.drelephant.mapreduce.heuristics.MapperGCHeuristic",
- "views.html.help.mapreduce.helpGC", new ApplicationType("mapreduce"), paramsMap)));
- heuristics.add(new MapperSkewHeuristic(new HeuristicConfigurationData("Mapper Time",
- "com.linkedin.drelephant.mapreduce.heuristics.MapperTimeHeuristic", "views.html.help.mapreduce.helpMapperTime",
- new ApplicationType("mapreduce"), paramsMap)));
- heuristics.add(new MapperSkewHeuristic(new HeuristicConfigurationData("Mapper Speed",
- "com.linkedin.drelephant.mapreduce.heuristics.MapperSpeedHeuristic",
- "views.html.help.mapreduce.helpMapperSpeed", new ApplicationType("mapreduce"), paramsMap)));
- heuristics.add(new MapperSkewHeuristic(new HeuristicConfigurationData("Mapper Spill",
- "com.linkedin.drelephant.mapreduce.heuristics.MapperSpillHeuristic",
- "views.html.help.mapreduce.helpMapperSpill", new ApplicationType("mapreduce"), paramsMap)));
- heuristics.add(new MapperSkewHeuristic(new HeuristicConfigurationData("Mapper Memory",
- "com.linkedin.drelephant.mapreduce.heuristics.MapperMemoryHeuristic",
- "views.html.help.mapreduce.helpMapperMemory", new ApplicationType("mapreduce"), paramsMap)));
- heuristics.add(new MapperSkewHeuristic(new HeuristicConfigurationData("Reducer Skew",
- "com.linkedin.drelephant.mapreduce.heuristics.ReducerSkewHeuristic",
- "views.html.help.mapreduce.helpReducerSkew", new ApplicationType("mapreduce"), paramsMap)));
- heuristics.add(new MapperSkewHeuristic(
- new HeuristicConfigurationData("Reducer GC", "com.linkedin.drelephant.mapreduce.heuristics.ReducerGCHeuristic",
- "views.html.help.mapreduce.helpGC", new ApplicationType("mapreduce"), paramsMap)));
- heuristics.add(new MapperSkewHeuristic(new HeuristicConfigurationData("Reducer Time",
- "com.linkedin.drelephant.mapreduce.heuristics.ReducerTimeHeuristic",
- "views.html.help.mapreduce.helpReducerTime", new ApplicationType("mapreduce"), paramsMap)));
- heuristics.add(new MapperSkewHeuristic(new HeuristicConfigurationData("Reducer Memory",
- "com.linkedin.drelephant.mapreduce.heuristics.ReducerMemoryHeuristic",
- "views.html.help.mapreduce.helpReducerMemory", new ApplicationType("mapreduce"), paramsMap)));
- heuristics.add(new MapperSkewHeuristic(new HeuristicConfigurationData("Shuffle & Sort",
- "com.linkedin.drelephant.mapreduce.heuristics.ShuffleSortHeuristic",
- "views.html.help.mapreduce.helpShuffleSort", new ApplicationType("mapreduce"), paramsMap)));
- heuristics.add(new MapperSkewHeuristic(
- new HeuristicConfigurationData("Exception", "com.linkedin.drelephant.mapreduce.heuristics.ExceptionHeuristic",
- "views.html.help.mapreduce.helpException", new ApplicationType("mapreduce"), paramsMap)));
-
- return heuristics;
- }
-}
diff --git a/test/com/linkedin/drelephant/analysis/SeverityTest.java b/test/com/linkedin/drelephant/analysis/SeverityTest.java
deleted file mode 100644
index 7f54accfc..000000000
--- a/test/com/linkedin/drelephant/analysis/SeverityTest.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2016 LinkedIn Corp.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.linkedin.drelephant.analysis;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-
-
-public class SeverityTest {
-
- @Test
- public void testSeverityMax() {
- assertEquals(Severity.CRITICAL, Severity.max(Severity.CRITICAL));
- assertEquals(Severity.CRITICAL, Severity.max(Severity.CRITICAL, Severity.SEVERE));
- assertEquals(Severity.CRITICAL, Severity.max(Severity.LOW, Severity.LOW, Severity.CRITICAL));
- }
-
- @Test
- public void testSeverityMin() {
- assertEquals(Severity.NONE, Severity.min(Severity.NONE, Severity.LOW));
- assertEquals(Severity.LOW, Severity.min(Severity.LOW, Severity.LOW));
- }
-
- @Test
- public void testSeverityAscending() {
- assertEquals(Severity.CRITICAL, Severity.getSeverityAscending(8, 2, 4, 6, 8));
- assertEquals(Severity.SEVERE, Severity.getSeverityAscending(10, 2, 4, 6, 12));
- }
-
- @Test
- public void testSeverityDescending() {
- assertEquals(Severity.CRITICAL, Severity.getSeverityDescending(2, 10, 8, 4, 2));
- assertEquals(Severity.MODERATE, Severity.getSeverityDescending(5, 10, 8, 4, 2));
- }
-}
diff --git a/test/com/linkedin/drelephant/analysis/SeverityThresholdsTest.scala b/test/com/linkedin/drelephant/analysis/SeverityThresholdsTest.scala
deleted file mode 100644
index 488118e01..000000000
--- a/test/com/linkedin/drelephant/analysis/SeverityThresholdsTest.scala
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright 2016 LinkedIn Corp.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.linkedin.drelephant.analysis
-
-import org.scalatest.{FunSpec, Matchers}
-
-class SeverityThresholdsTest extends FunSpec with Matchers {
- describe("SeverityThresholds") {
- it("can be used to represent thresholds considered in ascending order") {
- val thresholds = SeverityThresholds(low = 0.2D, moderate = 0.4D, severe = 0.6D, critical = 0.8D, ascending = true)
- thresholds.severityOf(0.1D) should be(Severity.NONE)
- thresholds.severityOf(0.2D) should be(Severity.LOW)
- thresholds.severityOf(0.3D) should be(Severity.LOW)
- thresholds.severityOf(0.4D) should be(Severity.MODERATE)
- thresholds.severityOf(0.5D) should be(Severity.MODERATE)
- thresholds.severityOf(0.6D) should be(Severity.SEVERE)
- thresholds.severityOf(0.7D) should be(Severity.SEVERE)
- thresholds.severityOf(0.8D) should be(Severity.CRITICAL)
- thresholds.severityOf(0.9D) should be(Severity.CRITICAL)
- }
-
- it("can be used to represent thresholds considered in descending order") {
- val thresholds = SeverityThresholds(low = 0.8D, moderate = 0.6D, severe = 0.4D, critical = 0.2D, ascending = false)
- thresholds.severityOf(0.1D) should be(Severity.CRITICAL)
- thresholds.severityOf(0.2D) should be(Severity.CRITICAL)
- thresholds.severityOf(0.3D) should be(Severity.SEVERE)
- thresholds.severityOf(0.4D) should be(Severity.SEVERE)
- thresholds.severityOf(0.5D) should be(Severity.MODERATE)
- thresholds.severityOf(0.6D) should be(Severity.MODERATE)
- thresholds.severityOf(0.7D) should be(Severity.LOW)
- thresholds.severityOf(0.8D) should be(Severity.LOW)
- thresholds.severityOf(0.9D) should be(Severity.NONE)
- }
-
- it("can be parsed as ascending thresholds from a string that can be processed by Utils.getParam") {
- SeverityThresholds.parse("0.2,0.4,0.6,0.8", ascending = true) should be(
- Some(SeverityThresholds(low = 0.2D, moderate = 0.4D, severe = 0.6D, critical = 0.8D, ascending = true))
- )
- }
-
- it("can be parsed as descending thresholds from a string that can be processed by Utils.getParam") {
- SeverityThresholds.parse("0.8,0.6,0.4,0.2", ascending = false) should be(
- Some(SeverityThresholds(low = 0.8D, moderate = 0.6D, severe = 0.4D, critical = 0.2D, ascending = false))
- )
- }
-
- it("cannot be created as ascending thresholds with unordered values") {
- an[IllegalArgumentException] should be thrownBy(
- SeverityThresholds(low = 0.8D, moderate = 0.6D, severe = 0.4D, critical = 0.2D, ascending = true)
- )
- }
-
- it("cannot be created as descending thresholds with unordered values") {
- an[IllegalArgumentException] should be thrownBy(
- SeverityThresholds(low = 0.2D, moderate = 0.4D, severe = 0.6D, critical = 0.8D, ascending = false)
- )
- }
- }
-}
diff --git a/test/com/linkedin/drelephant/configurations/fetcher/FetcherConfigurationTest.java b/test/com/linkedin/drelephant/configurations/fetcher/FetcherConfigurationTest.java
deleted file mode 100644
index 2db6431c4..000000000
--- a/test/com/linkedin/drelephant/configurations/fetcher/FetcherConfigurationTest.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright 2016 LinkedIn Corp.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.linkedin.drelephant.configurations.fetcher;
-
-import java.io.IOException;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-
-
-import org.junit.BeforeClass;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.w3c.dom.Document;
-import org.xml.sax.SAXException;
-
-import static org.junit.Assert.assertEquals;
-
-
-public class FetcherConfigurationTest {
-
- private static Document document1 = null;
- private static Document document2 = null;
- private static Document document3 = null;
- private static Document document4 = null;
- private static Document document5 = null;
-
- private static final String spark = "SPARK";
- private static final String logDirField = "event_log_dir";
- private static final String logDirValue = "/custom/configured";
- private static final String logSizeField = "event_log_size_limit_in_mb";
- private static final String logSizeValue = "50";
-
-
- @BeforeClass
- public static void runBeforeClass() {
- try {
- DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
- DocumentBuilder builder = factory.newDocumentBuilder();
- document1 = builder.parse(
- FetcherConfigurationTest.class.getClassLoader().getResourceAsStream(
- "configurations/fetcher/FetcherConfTest1.xml"));
- document2 = builder.parse(
- FetcherConfigurationTest.class.getClassLoader().getResourceAsStream(
- "configurations/fetcher/FetcherConfTest2.xml"));
- document3 = builder.parse(
- FetcherConfigurationTest.class.getClassLoader().getResourceAsStream(
- "configurations/fetcher/FetcherConfTest3.xml"));
- document4 = builder.parse(
- FetcherConfigurationTest.class.getClassLoader().getResourceAsStream(
- "configurations/fetcher/FetcherConfTest4.xml"));
- document5 = builder.parse(
- FetcherConfigurationTest.class.getClassLoader().getResourceAsStream(
- "configurations/fetcher/FetcherConfTest5.xml"));
- } catch (ParserConfigurationException e) {
- throw new RuntimeException("XML Parser could not be created.", e);
- } catch (SAXException e) {
- throw new RuntimeException("Test files are not properly formed", e);
- } catch (IOException e) {
- throw new RuntimeException("Unable to read test files ", e);
- }
- }
-
- @Rule
- public ExpectedException expectedEx = ExpectedException.none();
-
- /**
- * Correctly configured fetcher
- */
- @Test
- public void testParseFetcherConf1() {
- FetcherConfiguration fetcherConf = new FetcherConfiguration(document1.getDocumentElement());
- assertEquals(fetcherConf.getFetchersConfigurationData().size(), 2);
- }
-
- /**
- * No classname field
- */
- @Test
- public void testParseFetcherConf2() {
- expectedEx.expect(RuntimeException.class);
- expectedEx.expectMessage("No tag 'classname' in fetcher 2");
- FetcherConfiguration fetcherConf = new FetcherConfiguration(document2.getDocumentElement());
- }
-
- /**
- * Empty classname field
- */
- @Test
- public void testParseFetcherConf3() {
- expectedEx.expect(RuntimeException.class);
- expectedEx.expectMessage("Empty tag 'classname' in fetcher 1");
- FetcherConfiguration fetcherConf = new FetcherConfiguration(document3.getDocumentElement());
- }
-
- /**
- * No applicationtype tag
- */
- @Test
- public void testParseFetcherConf4() {
- expectedEx.expect(RuntimeException.class);
- expectedEx.expectMessage("No tag or invalid tag 'applicationtype' in fetcher 1"
- + " classname com.linkedin.drelephant.mapreduce.fetchers.MapReduceFetcherHadoop2");
- FetcherConfiguration fetcherConf = new FetcherConfiguration(document4.getDocumentElement());
- }
-
- /**
- * Test Spark fetcher params, Event log size and log directory
- */
- @Test
- public void testParseFetcherConf5() {
- FetcherConfiguration fetcherConf = new FetcherConfiguration(document5.getDocumentElement());
- assertEquals(fetcherConf.getFetchersConfigurationData().size(), 1);
- assertEquals(fetcherConf.getFetchersConfigurationData().get(0).getAppType().getName(), spark);
- }
-
-}
diff --git a/test/com/linkedin/drelephant/configurations/heuristic/HeuristicConfigurationTest.java b/test/com/linkedin/drelephant/configurations/heuristic/HeuristicConfigurationTest.java
deleted file mode 100644
index 16c3c8a6f..000000000
--- a/test/com/linkedin/drelephant/configurations/heuristic/HeuristicConfigurationTest.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright 2016 LinkedIn Corp.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.linkedin.drelephant.configurations.heuristic;
-
-import java.io.IOException;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-import org.junit.BeforeClass;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.w3c.dom.Document;
-import org.xml.sax.SAXException;
-
-import static org.junit.Assert.assertEquals;
-
-
-public class HeuristicConfigurationTest {
-
- private static Document document1 = null;
- private static Document document2 = null;
- private static Document document3 = null;
- private static Document document4 = null;
- private static Document document5 = null;
-
- @BeforeClass
- public static void runBeforeClass() {
- try {
- DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
- DocumentBuilder builder = factory.newDocumentBuilder();
- document1 = builder.parse(HeuristicConfigurationTest.class.getClassLoader()
- .getResourceAsStream("configurations/heuristic/HeuristicConfTest1.xml"));
- document2 = builder.parse(
- HeuristicConfigurationTest.class.getClassLoader().getResourceAsStream(
- "configurations/heuristic/HeuristicConfTest2.xml"));
- document3 = builder.parse(
- HeuristicConfigurationTest.class.getClassLoader().getResourceAsStream(
- "configurations/heuristic/HeuristicConfTest3.xml"));
- document4 = builder.parse(
- HeuristicConfigurationTest.class.getClassLoader().getResourceAsStream(
- "configurations/heuristic/HeuristicConfTest4.xml"));
- document5 = builder.parse(
- HeuristicConfigurationTest.class.getClassLoader().getResourceAsStream(
- "configurations/heuristic/HeuristicConfTest5.xml"));
- } catch (ParserConfigurationException e) {
- throw new RuntimeException("XML Parser could not be created.", e);
- } catch (SAXException e) {
- throw new RuntimeException("Test files are not properly formed", e);
- } catch (IOException e) {
- throw new RuntimeException("Unable to read test files ", e);
- }
- }
-
- @Rule
- public ExpectedException expectedEx = ExpectedException.none();
-
- /**
- * Correctly configured fetcher
- */
- @Test
- public void testParseFetcherConf1() {
- HeuristicConfiguration heuristicConf = new HeuristicConfiguration(document1.getDocumentElement());
- assertEquals(heuristicConf.getHeuristicsConfigurationData().size(), 3);
- }
-
- /**
- * No classname tag
- */
- @Test
- public void testParseFetcherConf2() {
- expectedEx.expect(RuntimeException.class);
- expectedEx.expectMessage("No tag 'classname' in heuristic 1");
- HeuristicConfiguration heuristicConf = new HeuristicConfiguration(document2.getDocumentElement());
- }
-
- /**
- * No heuristic name tag
- */
- @Test
- public void testParseFetcherConf3() {
- expectedEx.expect(RuntimeException.class);
- expectedEx.expectMessage("No tag 'heuristicname' in heuristic 1 classname"
- + " com.linkedin.drelephant.mapreduce.heuristics.MapperSkewHeuristic");
- HeuristicConfiguration heuristicConf = new HeuristicConfiguration(document3.getDocumentElement());
- }
-
- /**
- * No view name tag
- */
- @Test
- public void testParseFetcherConf4() {
- expectedEx.expect(RuntimeException.class);
- expectedEx.expectMessage("No tag 'viewname' in heuristic 1 classname"
- + " com.linkedin.drelephant.mapreduce.heuristics.MapperSkewHeuristic");
- HeuristicConfiguration heuristicConf = new HeuristicConfiguration(document4.getDocumentElement());
- }
-
- /**
- * No application type tag
- */
- @Test
- public void testParseFetcherConf5() {
- expectedEx.expect(RuntimeException.class);
- expectedEx.expectMessage("No tag or invalid tag 'applicationtype' in heuristic 2 classname"
- + " com.linkedin.drelephant.mapreduce.heuristics.MapperGCHeuristic");
- HeuristicConfiguration heuristicConf = new HeuristicConfiguration(document5.getDocumentElement());
- }
-}
-
diff --git a/test/com/linkedin/drelephant/configurations/jobtype/JobTypeConfigurationTest.java b/test/com/linkedin/drelephant/configurations/jobtype/JobTypeConfigurationTest.java
deleted file mode 100644
index a99ebd9f2..000000000
--- a/test/com/linkedin/drelephant/configurations/jobtype/JobTypeConfigurationTest.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright 2016 LinkedIn Corp.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.linkedin.drelephant.configurations.jobtype;
-
-import java.io.IOException;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-import org.junit.BeforeClass;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.w3c.dom.Document;
-import org.xml.sax.SAXException;
-
-import static org.junit.Assert.assertEquals;
-
-
-public class JobTypeConfigurationTest {
-
- private static Document document1 = null;
- private static Document document2 = null;
- private static Document document3 = null;
- private static Document document4 = null;
- private static Document document5 = null;
- private static Document document6 = null;
-
- @BeforeClass
- public static void runBeforeClass() {
- try {
- DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
- DocumentBuilder builder = factory.newDocumentBuilder();
- document1 = builder.parse(JobTypeConfigurationTest.class.getClassLoader()
- .getResourceAsStream("configurations/jobtype/JobTypeConfTest1.xml"));
- document2 = builder.parse(JobTypeConfigurationTest.class.getClassLoader()
- .getResourceAsStream("configurations/jobtype/JobTypeConfTest2.xml"));
- document3 = builder.parse(JobTypeConfigurationTest.class.getClassLoader()
- .getResourceAsStream("configurations/jobtype/JobTypeConfTest3.xml"));
- document4 = builder.parse(JobTypeConfigurationTest.class.getClassLoader()
- .getResourceAsStream("configurations/jobtype/JobTypeConfTest4.xml"));
- document5 = builder.parse(JobTypeConfigurationTest.class.getClassLoader()
- .getResourceAsStream("configurations/jobtype/JobTypeConfTest5.xml"));
- document6 = builder.parse(JobTypeConfigurationTest.class.getClassLoader()
- .getResourceAsStream("configurations/jobtype/JobTypeConfTest6.xml"));
- } catch (ParserConfigurationException e) {
- throw new RuntimeException("XML Parser could not be created.", e);
- } catch (SAXException e) {
- throw new RuntimeException("Test files are not properly formed", e);
- } catch (IOException e) {
- throw new RuntimeException("Unable to read test files ", e);
- }
- }
-
- @Rule
- public ExpectedException expectedEx = ExpectedException.none();
-
- /**
- * Correctly configured fetcher
- */
- @Test
- public void testParseFetcherConf1() {
- JobTypeConfiguration jobTypeConf = new JobTypeConfiguration(document1.getDocumentElement());
- assertEquals(jobTypeConf.getAppTypeToJobTypeList().size(), 2);
- }
-
- /**
- * No name tag
- */
- @Test
- public void testParseFetcherConf2() {
- expectedEx.expect(RuntimeException.class);
- expectedEx.expectMessage("No tag 'jobtype' in jobtype 3");
- JobTypeConfiguration jobTypeConf = new JobTypeConfiguration(document2.getDocumentElement());
- }
-
- /**
- * No conf tag
- */
- @Test
- public void testParseFetcherConf3() {
- expectedEx.expect(RuntimeException.class);
- expectedEx.expectMessage("No tag 'conf' in jobtype Spark");
- JobTypeConfiguration jobTypeConf = new JobTypeConfiguration(document3.getDocumentElement());
- }
-
- /**
- * No applicationtype tag
- */
- @Test
- public void testParseFetcherConf4() {
- expectedEx.expect(RuntimeException.class);
- expectedEx.expectMessage("No tag 'applicationtype' in jobtype Pig");
- JobTypeConfiguration jobTypeConf = new JobTypeConfiguration(document4.getDocumentElement());
- }
-
- /**
- * Wrong pattern for job type
- */
- @Test
- public void testParseFetcherConf5() {
- expectedEx.expect(RuntimeException.class);
- expectedEx.expectMessage("Error processing this pattern. Pattern:[(voldemort) jobtype:Voldemort");
- JobTypeConfiguration jobTypeConf = new JobTypeConfiguration(document5.getDocumentElement());
- }
-
- /**
- * Multiple default types
- */
- @Test
- public void testParseFetcherConf6() {
- expectedEx.expect(RuntimeException.class);
- expectedEx.expectMessage("Each application type should have one and only one default job type. Duplicate default"
- + " job type: jobType:Hive, for application type:mapreduce, isDefault:true, confName:hive.mapred.mode,"
- + " confValue:.*. for application type: MAPREDUCE");
- JobTypeConfiguration jobTypeConf = new JobTypeConfiguration(document6.getDocumentElement());
- }
-}
diff --git a/test/com/linkedin/drelephant/configurations/scheduler/SchedulerConfigurationTest.java b/test/com/linkedin/drelephant/configurations/scheduler/SchedulerConfigurationTest.java
deleted file mode 100644
index 2c86ec561..000000000
--- a/test/com/linkedin/drelephant/configurations/scheduler/SchedulerConfigurationTest.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright 2016 LinkedIn Corp.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.linkedin.drelephant.configurations.scheduler;
-
-import com.linkedin.drelephant.configurations.scheduler.SchedulerConfiguration;
-import com.linkedin.drelephant.configurations.scheduler.SchedulerConfigurationData;
-
-import java.io.IOException;
-import java.util.List;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-import org.junit.BeforeClass;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.w3c.dom.Document;
-import org.xml.sax.SAXException;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-
-public class SchedulerConfigurationTest {
-
- private static Document document1;
- private static Document document2;
- private static Document document3;
-
- @BeforeClass
- public static void runBeforeClass() {
- try {
- DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
- DocumentBuilder builder = factory.newDocumentBuilder();
- document1 = builder.parse(SchedulerConfigurationTest.class.getClassLoader()
- .getResourceAsStream("configurations/scheduler/SchedulerConfTest1.xml"));
- document2 = builder.parse(SchedulerConfigurationTest.class.getClassLoader()
- .getResourceAsStream("configurations/scheduler/SchedulerConfTest2.xml"));
- document3 = builder.parse(SchedulerConfigurationTest.class.getClassLoader()
- .getResourceAsStream("configurations/scheduler/SchedulerConfTest3.xml"));
- } catch (ParserConfigurationException e) {
- throw new RuntimeException("XML Parser could not be created.", e);
- } catch (SAXException e) {
- throw new RuntimeException("Test files are not properly formed", e);
- } catch (IOException e) {
- throw new RuntimeException("Unable to read test files ", e);
- }
- }
-
- @Rule
- public ExpectedException expectedEx = ExpectedException.none();
-
- /**
- * Correctly configured scheduler
- */
- @Test
- public void testParseSchedulerConf1() {
- SchedulerConfiguration schedulerConf = new SchedulerConfiguration(document1.getDocumentElement());
- List schedulerConfData = schedulerConf.getSchedulerConfigurationData();
- assertEquals(schedulerConfData.size(), 2);
- for (SchedulerConfigurationData data : schedulerConfData) {
- if (data.getSchedulerName().equals("airflow")) {
- assertEquals("com.linkedin.drelephant.schedulers.AirflowScheduler", data.getClassName());
- assertEquals("http://localhost:8000", data.getParamMap().get("airflowbaseurl"));
- } else {
- assertEquals("azkaban", data.getSchedulerName());
- assertEquals("com.linkedin.drelephant.schedulers.AzkabanScheduler", data.getClassName());
- }
- }
- }
-
- /**
- * No classname tag
- */
- @Test
- public void testParseSchedulerConf2() {
- expectedEx.expect(RuntimeException.class);
- expectedEx.expectMessage("No tag 'classname' in scheduler 1");
- new SchedulerConfiguration(document2.getDocumentElement());
- }
-
- /**
- * No name tag
- */
- @Test
- public void testParseSchedulerConf3() {
- expectedEx.expect(RuntimeException.class);
- expectedEx.expectMessage("No tag 'name' in scheduler 2 classname com.linkedin.drelephant.schedulers.AzkabanScheduler");
- new SchedulerConfiguration(document3.getDocumentElement());
- }
-
-}
diff --git a/test/com/linkedin/drelephant/exceptions/EventExceptionTest.java b/test/com/linkedin/drelephant/exceptions/EventExceptionTest.java
deleted file mode 100644
index e0086e1be..000000000
--- a/test/com/linkedin/drelephant/exceptions/EventExceptionTest.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 2016 LinkedIn Corp.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.linkedin.drelephant.exceptions;
-
-import org.apache.log4j.Logger;
-import org.junit.Test;
-
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.assertFalse;
-
-
-public class EventExceptionTest {
- private static final Logger logger = Logger.getLogger(EventExceptionTest.class);
-
- @Test
- public void getMessageTest() {
-
- String rawEventException =
- "java.io.FileNotFoundException: Path is not a file: /data/sample/Sample/Sample/1466675602538-PT-472724050\n"
- + "24-06-2016 03:12:40 PDT help_center_sessions INFO - \tat org.apache.hadoop.hdfs.server.namenode.INodeFile.valueOf(INodeFile.java:70)\n"
- + "24-06-2016 03:12:40 PDT help_center_sessions INFO - \tat org.apache.hadoop.hdfs.server.namenode.INodeFile.valueOf(INodeFile.java:56)\n"
- + "24-06-2016 03:12:40 PDT help_center_sessions INFO - \tat org.apache.hadoop.hdfs.server.namenode.FSNamesystem.getBlockLocationsUpdateTimes(FSNamesystem.java:1914)\n"
- + "24-06-2016 03:12:40 PDT help_center_sessions INFO - \tat org.apache.hadoop.hdfs.server.namenode.FSNamesystem.getBlockLocationsInt(FSNamesystem.java:1855)\n"
- + "24-06-2016 03:12:40 PDT help_center_sessions INFO - \tat org.apache.hadoop.hdfs.server.namenode.FSNamesystem.getBlockLocations(FSNamesystem.java:1835)\n"
- + "24-06-2016 03:12:40 PDT help_center_sessions INFO - \tat org.apache.hadoop.hdfs.server.namenode.FSNamesystem.getBlockLocations(FSNamesystem.java:1807)\n"
- + "24-06-2016 03:12:40 PDT help_center_sessions INFO - \tat org.apache.hadoop.hdfs.server.namenode.NameNodeRpcServer.getBlockLocations(NameNodeRpcServer.java:552)\n"
- + "24-06-2016 03:12:40 PDT help_center_sessions INFO - \tat org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolServerSideTranslatorPB.getBlockLocations(ClientNamenodeProtocolServerSideTranslatorPB.java:362)\n"
- + "24-06-2016 03:12:40 PDT help_center_sessions INFO - \tat org.apache.hadoop.hdfs.protocol.proto.ClientNamenodeProtocolProtos$ClientNamenodeProtocol$2.callBlockingMethod(ClientNamenodeProtocolProtos.java)\n"
- + "24-06-2016 03:12:40 PDT help_center_sessions INFO - \tat org.apache.hadoop.ipc.ProtobufRpcEngine$Server$ProtoBufRpcInvoker.call(ProtobufRpcEngine.java:619)\n"
- + "24-06-2016 03:12:40 PDT help_center_sessions INFO - \tat org.apache.hadoop.ipc.RPC$Server.call(RPC.java:962)\n"
- + "24-06-2016 03:12:40 PDT help_center_sessions INFO - \tat org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:2044)\n"
- + "24-06-2016 03:12:40 PDT help_center_sessions INFO - \tat org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:2040)\n"
- + "24-06-2016 03:12:40 PDT help_center_sessions INFO - \tat java.security.AccessController.doPrivileged(Native Method)\n"
- + "24-06-2016 03:12:40 PDT help_center_sessions INFO - \tat javax.security.auth.Subject.doAs(Subject.java:422)\n"
- + "24-06-2016 03:12:40 PDT help_center_sessions INFO - \tat org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1671)\n"
- + "24-06-2016 03:12:40 PDT help_center_sessions INFO - \tat org.apache.hadoop.ipc.Server$Handler.run(Server.java:2038)";
-
- EventException eventException = new EventException(0, rawEventException);
- assertTrue("getMessageTest failed", eventException.getMessage()
- .equals("Path is not a file: /data/sample/Sample/Sample/1466675602538-PT-472724050"));
- logger.info("correct message" + eventException.getMessage());
- }
-}
\ No newline at end of file
diff --git a/test/com/linkedin/drelephant/exceptions/MRJobLogAnalyzerTest.java b/test/com/linkedin/drelephant/exceptions/MRJobLogAnalyzerTest.java
deleted file mode 100644
index 8942c0b6a..000000000
--- a/test/com/linkedin/drelephant/exceptions/MRJobLogAnalyzerTest.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2016 LinkedIn Corp.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.linkedin.drelephant.exceptions;
-
-import org.junit.Test;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertEquals;
-
-public class MRJobLogAnalyzerTest {
-
- private String failedMRJobDiagnostic = "Task failed task_1466048666726_979739_r_000000\n"
- + "Job failed as tasks failed. failedMaps:0 failedReduces:1";
-
- private String killedMRJobDiagnostic = "Kill job job_1466048666726_978316 received from zfu@LINKEDIN.BIZ (auth:TOKEN) at 10.150.4.50\n"
- + "Job received Kill while in RUNNING state.";
-
- private MRJobLogAnalyzer analyzedFailedJobDiagnostic;
- private MRJobLogAnalyzer analyzedKilledJobDiagnostic;
-
- public MRJobLogAnalyzerTest(){
- analyzedFailedJobDiagnostic = new MRJobLogAnalyzer(failedMRJobDiagnostic);
- analyzedKilledJobDiagnostic = new MRJobLogAnalyzer(killedMRJobDiagnostic);
- }
-
- @Test
- public void getFailedSubEventsTest(){
- assertEquals(analyzedFailedJobDiagnostic.getFailedSubEvents().size(),1 );
- assertTrue(analyzedKilledJobDiagnostic.getFailedSubEvents().isEmpty());
- }
-
- @Test
- public void getExceptionTest(){
-
- }
-}
\ No newline at end of file
diff --git a/test/com/linkedin/drelephant/exceptions/azkaban/AzkabanJobLogAnalyzerTest.java b/test/com/linkedin/drelephant/exceptions/azkaban/AzkabanJobLogAnalyzerTest.java
deleted file mode 100644
index b26478a95..000000000
--- a/test/com/linkedin/drelephant/exceptions/azkaban/AzkabanJobLogAnalyzerTest.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright 2016 LinkedIn Corp.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.linkedin.drelephant.exceptions.azkaban;
-
-import com.linkedin.drelephant.exceptions.JobState;
-import org.junit.Test;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.assertFalse;
-
-
-public class AzkabanJobLogAnalyzerTest {
-
- private String succeededAzkabanJobLog = "24-06-2016 03:12:53 PDT extractCrawlCompanyIndustryClassificationFlow_extractionFinalizer INFO - Starting job sample_sample at 1466763173873\n"
- + "24-06-2016 03:12:53 PDT extractCrawlCompanyIndustryClassificationFlow_extractionFinalizer INFO - job JVM args: -Dazkaban.flowid=sampleFlow -Dazkaban.execid=557260 -Dazkaban.jobid=sample_jobr\n"
- + "24-06-2016 03:12:55 PDT extractCrawlCompanyIndustryClassificationFlow_extractionFinalizer INFO - Finishing job sample_job attempt: 0 at 1466763175040 with status SUCCEEDED";
-
- private String killedAzkabanJobLog = "28-06-2016 16:58:20 PDT feature-exploration_create-index-map INFO - Starting job sample at 1467158300703\n"
- + "28-06-2016 17:58:05 PDT feature-exploration_create-index-map ERROR - Kill has been called.\n"
- + "28-06-2016 17:58:05 PDT feature-exploration_create-index-map INFO - 16/06/29 00:58:05 INFO util.Utils: Shutdown hook called\n"
- + "28-06-2016 17:58:06 PDT feature-exploration_create-index-map ERROR - caught error running the job\n"
- + "28-06-2016 17:58:06 PDT feature-exploration_create-index-map INFO - Token service: sample-localhostrm01.grid.linkedin.com:8032\n"
- + "28-06-2016 17:58:06 PDT feature-exploration_create-index-map INFO - Cancelling mr job tracker token \n"
- + "28-06-2016 17:58:06 PDT feature-exploration_create-index-map ERROR - Job run failed!\n"
- + "28-06-2016 17:58:06 PDT feature-exploration_create-index-map ERROR - java.lang.RuntimeException: azkaban.jobExecutor.utils.process.ProcessFailureException cause: java.lang.RuntimeException: azkaban.jobExecutor.utils.process.ProcessFailureException\n"
- + "28-06-2016 17:58:06 PDT feature-exploration_create-index-map INFO - Finishing job feature-exploration_create-index-map attempt: 0 at 1467161886022 with status KILLED\n"
- + "28-06-2016 17:58:06 PDT feature-exploration_create-index-map INFO - applicationIds to kill: [application_1466048666726_642278]\n"
- + "28-06-2016 17:58:06 PDT feature-exploration_create-index-map INFO - start klling application: application_1466048666726_642278\n"
- + "28-06-2016 17:58:06 PDT feature-exploration_create-index-map INFO - successfully killed application: application_1466048666726_642278";
-
- private String mrLevelFailedAzkabanJobLog = "24-06-2016 03:12:19 PDT help_center_sessions INFO - Starting job help_center_sessions at 1466763139993\n"
- + "24-06-2016 03:12:25 PDT help_center_sessions INFO - INFO Kind: HDFS_DELEGATION_TOKEN, Service: sample-localhostnn01.grid.linkedin.com:9000, Ident: (HDFS_DELEGATION_TOKEN token 5017233 for username)\n"
- + "24-06-2016 03:12:26 PDT help_center_sessions INFO - INFO Submitted application application_1466048666726_410150\n"
- + "24-06-2016 03:12:26 PDT help_center_sessions INFO - INFO Running job: job_1466048666726_410150\n"
- + "24-06-2016 03:12:33 PDT help_center_sessions INFO - INFO Job job_1466048666726_410150 running in uber mode : false\n"
- + "24-06-2016 03:12:40 PDT help_center_sessions INFO - Error: java.io.FileNotFoundException: Path is not a file: /data/databases/sample/Sample/1466675602538-PT-472724050\n"
- + "24-06-2016 03:12:40 PDT help_center_sessions INFO - \tat org.apache.hadoop.hdfs.server.namenode.INodeFile.valueOf(INodeFile.java:70)\n"
- + "24-06-2016 03:12:40 PDT help_center_sessions INFO - \tat org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1671)\n"
- + "24-06-2016 03:12:40 PDT help_center_sessions INFO - \tat org.apache.hadoop.ipc.Server$Handler.run(Server.java:2038\n"
- + "24-06-2016 03:13:00 PDT help_center_sessions ERROR - Job run failed!\n"
- + "24-06-2016 03:13:00 PDT help_center_sessions ERROR - java.lang.RuntimeException: azkaban.jobExecutor.utils.process.ProcessFailureException cause: java.lang.RuntimeException: azkaban.jobExecutor.utils.process.ProcessFailureException\n"
- + "24-06-2016 03:13:00 PDT help_center_sessions INFO - Finishing job help_center_sessions attempt: 0 at 1466763180242 with status FAILED";
-
- private String scriptLevelFailedAzkabanJobLog="28-06-2016 16:23:10 PDT job_search_trigger INFO - Starting job job_search_trigger at 1467156190329\n"
- + "28-06-2016 16:23:12 PDT job_search_trigger INFO - INFO Last attempt: false\n"
- + "28-06-2016 16:23:12 PDT job_search_trigger INFO - Exception in thread \"main\" java.lang.reflect.UndeclaredThrowableException\n"
- + "28-06-2016 16:23:12 PDT job_search_trigger INFO - \tat org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1686)\n"
- + "28-06-2016 16:23:12 PDT job_search_trigger INFO - \t... 3 more\n"
- + "28-06-2016 16:23:12 PDT job_search_trigger INFO - Caused by: java.lang.RuntimeException: Backfill requires start and end date\n"
- + "28-06-2016 16:23:12 PDT job_search_trigger INFO - \tat com.linkedin.metrics.feeder.TriggerJob.generateDaily(TriggerJob.java:143)\n"
- + "28-06-2016 16:23:12 PDT job_search_trigger INFO - \tat com.linkedin.metrics.feeder.TriggerJob.run(TriggerJob.java:135)\n"
- + "28-06-2016 16:23:12 PDT job_search_trigger INFO - \t... 14 more\n"
- + "28-06-2016 16:23:12 PDT job_search_trigger INFO - Process completed unsuccessfully in 1 seconds.\n"
- + "28-06-2016 16:23:12 PDT job_search_trigger ERROR - Job run failed!\n"
- + "28-06-2016 16:23:12 PDT job_search_trigger ERROR - java.lang.RuntimeException: azkaban.jobExecutor.utils.process.ProcessFailureException cause: java.lang.RuntimeException: azkaban.jobExecutor.utils.process.ProcessFailureException\n"
- + "28-06-2016 16:23:12 PDT job_search_trigger INFO - Finishing job job_search_trigger attempt: 0 at 1467156192215 with status FAILED";
-
- private String azkabanLevelFailedAzkabanJobLog = "28-06-2016 13:45:27 PDT feature-exploration_create-index-map INFO - Starting job feature-exploration_create-index-map at 1467146727699\n"
- + "28-06-2016 13:45:27 PDT feature-exploration_create-index-map INFO - job JVM args: -Dazkaban.flowid=feature-exploration -Dazkaban.execid=593197 -Dazkaban.jobid=feature-exploration_create-index-map\n"
- + "28-06-2016 13:45:27 PDT feature-exploration_create-index-map INFO - Building spark job executor. \n"
- + "28-06-2016 13:45:27 PDT feature-exploration_create-index-map ERROR - Failed to build job executor for job feature-exploration_create-index-mapCould not find variable substitution for variable(s) [global.jvm.args->user.to.proxy]\n"
- + "28-06-2016 13:45:27 PDT feature-exploration_create-index-map ERROR - Failed to build job type\n"
- + "azkaban.jobtype.JobTypeManagerException: Failed to build job executor for job feature-exploration_create-index-map\n"
- + "28-06-2016 13:45:27 PDT feature-exploration_create-index-map ERROR - Job run failed preparing the job.\n"
- + "28-06-2016 13:45:27 PDT feature-exploration_create-index-map INFO - Finishing job feature-exploration_create-index-map attempt: 0 at 1467146727702 with status FAILED";
-
- private AzkabanJobLogAnalyzer analyzedSucceededLog;
- private AzkabanJobLogAnalyzer analyzedKilledLog;
- private AzkabanJobLogAnalyzer analyzedMRLevelFailedLog;
- private AzkabanJobLogAnalyzer analyzedScriptLevelFailedLog;
- private AzkabanJobLogAnalyzer analyzedAzkabanLevelFailedLog;
-
- public AzkabanJobLogAnalyzerTest(){
- analyzedSucceededLog = new AzkabanJobLogAnalyzer(succeededAzkabanJobLog);
- analyzedKilledLog = new AzkabanJobLogAnalyzer(killedAzkabanJobLog);
- analyzedMRLevelFailedLog = new AzkabanJobLogAnalyzer(mrLevelFailedAzkabanJobLog);
- analyzedScriptLevelFailedLog = new AzkabanJobLogAnalyzer(scriptLevelFailedAzkabanJobLog);
- analyzedAzkabanLevelFailedLog = new AzkabanJobLogAnalyzer(azkabanLevelFailedAzkabanJobLog);
- }
- @Test
- public void getStateTest(){
- assertTrue(analyzedSucceededLog.getState() == JobState.SUCCEEDED);
- assertTrue(analyzedKilledLog.getState() == JobState.KILLED);
- assertTrue(analyzedMRLevelFailedLog.getState() == JobState.MRFAIL);
- assertTrue(analyzedScriptLevelFailedLog.getState() == JobState.SCRIPTFAIL);
- assertTrue(analyzedAzkabanLevelFailedLog.getState() == JobState.SCHEDULERFAIL);
- }
-
- @Test
- public void getSubEventsTest(){
- assertTrue("Succeeded sub events test failed",analyzedSucceededLog.getSubEvents().isEmpty());
- assertTrue("Script level failed sub events test failed",analyzedScriptLevelFailedLog.getSubEvents().isEmpty());
- assertTrue("Azkaban level failed sub events test failed",analyzedAzkabanLevelFailedLog.getSubEvents().isEmpty());
- assertTrue(analyzedMRLevelFailedLog.getSubEvents().size() == 1);
- assertTrue(analyzedMRLevelFailedLog.getSubEvents().iterator().next().equals("job_1466048666726_410150"));
- assertTrue("Killed sub events test failed",analyzedKilledLog.getSubEvents().isEmpty());
- }
-
- @Test
- public void getExceptionsTest(){
- assertTrue(analyzedSucceededLog.getException() == null);
- assertTrue(analyzedKilledLog.getException() == null);
- }
-}
\ No newline at end of file
diff --git a/test/com/linkedin/drelephant/mapreduce/TestTaskLevelAggregatedMetrics.java b/test/com/linkedin/drelephant/mapreduce/TestTaskLevelAggregatedMetrics.java
deleted file mode 100644
index 93208e8b5..000000000
--- a/test/com/linkedin/drelephant/mapreduce/TestTaskLevelAggregatedMetrics.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright 2016 LinkedIn Corp.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.linkedin.drelephant.mapreduce;
-
-import com.linkedin.drelephant.mapreduce.data.MapReduceCounterData;
-import com.linkedin.drelephant.mapreduce.data.MapReduceTaskData;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class TestTaskLevelAggregatedMetrics {
-
- @Test
- public void testZeroTasks() {
- MapReduceTaskData taskData[] = {};
- TaskLevelAggregatedMetrics taskMetrics = new TaskLevelAggregatedMetrics(taskData, 0, 0);
- Assert.assertEquals(taskMetrics.getDelay(), 0);
- Assert.assertEquals(taskMetrics.getResourceUsed(), 0);
- Assert.assertEquals(taskMetrics.getResourceWasted(), 0);
- }
-
- @Test
- public void testNullTaskArray() {
- TaskLevelAggregatedMetrics taskMetrics = new TaskLevelAggregatedMetrics(null, 0, 0);
- Assert.assertEquals(taskMetrics.getDelay(), 0);
- Assert.assertEquals(taskMetrics.getResourceUsed(), 0);
- Assert.assertEquals(taskMetrics.getResourceWasted(), 0);
- }
-
- @Test
- public void testTaskLevelData() {
- MapReduceTaskData taskData[] = new MapReduceTaskData[3];
- MapReduceCounterData counterData = new MapReduceCounterData();
- counterData.set(MapReduceCounterData.CounterName.PHYSICAL_MEMORY_BYTES, 655577088L);
- counterData.set(MapReduceCounterData.CounterName.VIRTUAL_MEMORY_BYTES, 3051589632L);
- long time[] = {0,0,0,1464218501117L, 1464218534148L};
- taskData[0] = new MapReduceTaskData("task", "id");
- taskData[0].setTimeAndCounter(time, counterData);
- taskData[1] = new MapReduceTaskData("task", "id");
- taskData[1].setTimeAndCounter(new long[5], counterData);
- // Non-sampled task, which does not contain time and counter data
- taskData[2] = new MapReduceTaskData("task", "id");
- TaskLevelAggregatedMetrics taskMetrics = new TaskLevelAggregatedMetrics(taskData, 4096L, 1463218501117L);
- Assert.assertEquals(taskMetrics.getDelay(), 1000000000L);
- Assert.assertEquals(taskMetrics.getResourceUsed(), 135168L);
- Assert.assertEquals(taskMetrics.getResourceWasted(), 66627L);
- }
-}
diff --git a/test/com/linkedin/drelephant/mapreduce/fetchers/MapReduceFSFetcherHadoop2Test.java b/test/com/linkedin/drelephant/mapreduce/fetchers/MapReduceFSFetcherHadoop2Test.java
deleted file mode 100644
index 16f3ffb8f..000000000
--- a/test/com/linkedin/drelephant/mapreduce/fetchers/MapReduceFSFetcherHadoop2Test.java
+++ /dev/null
@@ -1,322 +0,0 @@
-/*
- * Copyright 2016 LinkedIn Corp.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.linkedin.drelephant.mapreduce.fetchers;
-
-import com.google.common.collect.ImmutableMap;
-import com.linkedin.drelephant.analysis.AnalyticJob;
-import com.linkedin.drelephant.analysis.ApplicationType;
-import com.linkedin.drelephant.configurations.fetcher.FetcherConfiguration;
-import com.linkedin.drelephant.configurations.fetcher.FetcherConfigurationData;
-import com.linkedin.drelephant.mapreduce.data.MapReduceApplicationData;
-import com.linkedin.drelephant.mapreduce.data.MapReduceCounterData;
-import com.linkedin.drelephant.mapreduce.data.MapReduceTaskData;
-import java.io.FileNotFoundException;
-import org.apache.commons.lang.StringUtils;
-import org.apache.hadoop.mapreduce.Counters;
-import org.apache.hadoop.mapreduce.TaskAttemptID;
-import org.apache.hadoop.mapreduce.TaskID;
-import org.apache.hadoop.mapreduce.TaskType;
-import org.apache.hadoop.mapreduce.jobhistory.JobHistoryParser;
-import org.junit.Assert;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.w3c.dom.Document;
-import org.xml.sax.SAXException;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.List;
-import java.util.Map;
-import java.util.HashMap;
-import java.util.TimeZone;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-
-public class MapReduceFSFetcherHadoop2Test {
-
- private static Document document9 = null;
- private static Document document10 = null;
- private static Document document11 = null;
-
- @BeforeClass
- public static void before() {
- try {
- DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
- DocumentBuilder builder = factory.newDocumentBuilder();
- ClassLoader classLoader = MapReduceFSFetcherHadoop2Test.class.getClassLoader();
- document9 = builder.parse(classLoader.getResourceAsStream(
- "configurations/fetcher/FetcherConfTest9.xml"));
- document10 = builder.parse(classLoader.getResourceAsStream(
- "configurations/fetcher/FetcherConfTest10.xml"));
- document11 = builder.parse(classLoader.getResourceAsStream(
- "configurations/fetcher/FetcherConfTest11.xml"));
- } catch (ParserConfigurationException e) {
- throw new RuntimeException("XML Parser could not be created.", e);
- } catch (SAXException e) {
- throw new RuntimeException("Test files are not properly formed", e);
- } catch (IOException e) {
- throw new RuntimeException("Unable to read test files ", e);
- }
- }
-
- @Test
- public void testFetcherDefaultConfig() {
- FetcherConfiguration fetcherConf = new FetcherConfiguration(document9.getDocumentElement());
- try {
- MapReduceFSFetcherHadoop2 fetcher = new MapReduceFSFetcherHadoop2(
- fetcherConf.getFetchersConfigurationData().get(0));
- Assert.assertFalse("Sampling should be disabled in default", fetcher.isSamplingEnabled());
- Assert.assertEquals(fetcher.DEFALUT_MAX_LOG_SIZE_IN_MB, fetcher.getMaxLogSizeInMB(), 0.0001);
- Assert.assertEquals(TimeZone.getDefault(), fetcher.getTimeZone());
-
- List