/* AngularJS v1.3.4 (c) 2010-2014 Google, Inc. http://angularjs.org License: MIT */ (function(U,V,u){'use strict';function z(b){return function(){var a=arguments[0],c;c="["+(b?b+":":"")+a+"] http://errors.angularjs.org/1.3.4/"+(b?b+"/":"")+a;for(a=1;a").append(b).html();try{return b[0].nodeType===mb?R(c):c.match(/^(<[^>]+>)/)[1].replace(/^<([\w\-]+)/,function(a,b){return"<"+R(b)})}catch(d){return R(c)}}function pc(b){try{return decodeURIComponent(b)}catch(a){}}function qc(b){var a={},c,d;r((b||"").split("&"),function(b){b&&(c=b.replace(/\+/g, "%20").split("="),d=pc(c[0]),y(d)&&(b=y(c[1])?pc(c[1]):!0,Jb.call(a,d)?D(a[d])?a[d].push(b):a[d]=[a[d],b]:a[d]=b))});return a}function Kb(b){var a=[];r(b,function(b,d){D(b)?r(b,function(b){a.push(Da(d,!0)+(!0===b?"":"="+Da(b,!0)))}):a.push(Da(d,!0)+(!0===b?"":"="+Da(b,!0)))});return a.length?a.join("&"):""}function nb(b){return Da(b,!0).replace(/%26/gi,"&").replace(/%3D/gi,"=").replace(/%2B/gi,"+")}function Da(b,a){return encodeURIComponent(b).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g, "$").replace(/%2C/gi,",").replace(/%3B/gi,";").replace(/%20/g,a?"%20":"+")}function Fd(b,a){var c,d,e=ob.length;b=A(b);for(d=0;d/,">"));}a=a||[];a.unshift(["$provide",function(a){a.value("$rootElement",b)}]);c.debugInfoEnabled&&a.push(["$compileProvider",function(a){a.debugInfoEnabled(!0)}]);a.unshift("ng");d=Lb(a,c.strictDi);d.invoke(["$rootScope","$rootElement","$compile","$injector",function(a,b,c,d){a.$apply(function(){b.data("$injector",d);c(b)(a)})}]);return d},e= /^NG_ENABLE_DEBUG_INFO!/,f=/^NG_DEFER_BOOTSTRAP!/;U&&e.test(U.name)&&(c.debugInfoEnabled=!0,U.name=U.name.replace(e,""));if(U&&!f.test(U.name))return d();U.name=U.name.replace(f,"");ha.resumeBootstrap=function(b){r(b,function(b){a.push(b)});d()}}function Hd(){U.name="NG_ENABLE_DEBUG_INFO!"+U.name;U.location.reload()}function Id(b){return ha.element(b).injector().get("$$testability")}function Mb(b,a){a=a||"_";return b.replace(Jd,function(b,d){return(d?a:"")+b.toLowerCase()})}function Kd(){var b;sc|| ((qa=U.jQuery)&&qa.fn.on?(A=qa,C(qa.fn,{scope:Ka.scope,isolateScope:Ka.isolateScope,controller:Ka.controller,injector:Ka.injector,inheritedData:Ka.inheritedData}),b=qa.cleanData,qa.cleanData=function(a){var c;if(Nb)Nb=!1;else for(var d=0,e;null!=(e=a[d]);d++)(c=qa._data(e,"events"))&&c.$destroy&&qa(e).triggerHandler("$destroy");b(a)}):A=S,ha.element=A,sc=!0)}function Ob(b,a,c){if(!b)throw Wa("areq",a||"?",c||"required");return b}function pb(b,a,c){c&&D(b)&&(b=b[b.length-1]);Ob(F(b),a,"not a function, got "+ (b&&"object"===typeof b?b.constructor.name||"Object":typeof b));return b}function La(b,a){if("hasOwnProperty"===b)throw Wa("badname",a);}function tc(b,a,c){if(!a)return b;a=a.split(".");for(var d,e=b,f=a.length,g=0;g")+d[2];for(d=d[0];d--;)c=c.lastChild;f=Xa(f,c.childNodes);c=e.firstChild;c.textContent=""}else f.push(a.createTextNode(b));e.textContent="";e.innerHTML="";r(f,function(a){e.appendChild(a)});return e}function S(b){if(b instanceof S)return b;var a;I(b)&&(b=P(b),a=!0);if(!(this instanceof S)){if(a&&"<"!=b.charAt(0))throw Qb("nosel");return new S(b)}if(a){a=V;var c;b=(c=cf.exec(b))?[a.createElement(c[1])]:(c=Dc(b,a))?c.childNodes:[]}Ec(this,b)}function Rb(b){return b.cloneNode(!0)}function tb(b,a){a||ub(b);if(b.querySelectorAll)for(var c=b.querySelectorAll("*"),d=0,e=c.length;d 4096 bytes)!"));else{if(p.cookie!==y)for(y=p.cookie,d=y.split("; "),aa={},f=0;fl&&this.remove(s.key),b},get:function(a){if(l").parent()[0])});var f=ea(a,b,a,c,d,e);B.$$addScopeClass(a);var g=null;return function(b, c,d){Ob(b,"scope");d=d||{};var e=d.parentBoundTranscludeFn,h=d.transcludeControllers;d=d.futureParentElement;e&&e.$$boundTransclude&&(e=e.$$boundTransclude);g||(g=(d=d&&d[0])?"foreignobject"!==ta(d)&&d.toString().match(/SVG/)?"svg":"html":"html");d="html"!==g?A(U(g,A("
").append(a).html())):c?Ka.clone.call(a):a;if(h)for(var k in h)d.data("$"+k+"Controller",h[k].instance);B.$$addScopeInfo(d,b);c&&c(d,b);f&&f(b,d,d,e);return d}}function ea(a,b,c,d,e,f){function g(a,c,d,e){var f,k,l,q,s,n,w;if(p)for(w= Array(c.length),q=0;qJ.priority)break;if(z=J.scope)J.templateUrl||(K(z)?(ya("new/isolated scope",L||M,J,T),L=J):ya("new/isolated scope",L,J,T)),M=M||J;ga=J.name;!J.templateUrl&&J.controller&&(z=J.controller,E=E||{},ya("'"+ga+"' controller",E[ga],J,T),E[ga]=J);if(z=J.transclude)x=!0,J.$$tlb||(ya("transclusion",da,J,T),da=J),"element"==z?(C=!0,v=J.priority,z=T,T=e.$$element=A(V.createComment(" "+ga+": "+ e[ga]+" ")),d=T[0],Ab(g,Ya.call(z,0),d),Ga=B(z,f,v,k&&k.name,{nonTlbTranscludeDirective:da})):(z=A(Rb(d)).contents(),T.empty(),Ga=B(z,f));if(J.template)if(Na=!0,ya("template",aa,J,T),aa=J,z=F(J.template)?J.template(T,e):J.template,z=Pc(z),J.replace){k=J;z=Pb.test(z)?Qc(U(J.templateNamespace,P(z))):[];d=z[0];if(1!=z.length||d.nodeType!==na)throw ka("tplrt",ga,"");Ab(g,T,d);za={$attr:{}};z=W(d,[],za);var mf=a.splice(S+1,a.length-(S+1));L&&y(z);a=a.concat(z).concat(mf);Oc(e,za);za=a.length}else T.html(z); if(J.templateUrl)Na=!0,ya("template",aa,J,T),aa=J,J.replace&&(k=J),H=G(a.splice(S,a.length-S),T,e,g,x&&Ga,l,q,{controllerDirectives:E,newIsolateScopeDirective:L,templateDirective:aa,nonTlbTranscludeDirective:da}),za=a.length;else if(J.compile)try{R=J.compile(T,e,Ga),F(R)?w(null,R,zb,$):R&&w(R.pre,R.post,zb,$)}catch(ca){c(ca,va(T))}J.terminal&&(H.terminal=!0,v=Math.max(v,J.priority))}H.scope=M&&!0===M.scope;H.transcludeOnThisElement=x;H.elementTranscludeOnThisElement=C;H.templateOnThisElement=Na;H.transclude= Ga;p.hasElementTranscludeDirective=C;return H}function y(a){for(var b=0,c=a.length;bq.priority)&&-1!=q.restrict.indexOf(f)){if(k){var w={$$start:k,$$end:l};q=C(Object.create(q),w)}b.push(q);h=q}}catch(N){c(N)}}return h}function Oc(a,b){var c=b.$attr,d=a.$attr,e=a.$$element; r(a,function(d,e){"$"!=e.charAt(0)&&(b[e]&&b[e]!==d&&(d+=("style"===e?";":" ")+b[e]),a.$set(e,d,!0,c[e]))});r(b,function(b,f){"class"==f?(M(e,b),a["class"]=(a["class"]?a["class"]+" ":"")+b):"style"==f?(e.attr("style",e.attr("style")+";"+b),a.style=(a.style?a.style+";":"")+b):"$"==f.charAt(0)||a.hasOwnProperty(f)||(a[f]=b,d[f]=c[f])})}function G(a,b,c,d,e,f,g,h){var k=[],l,s,p=b[0],n=a.shift(),w=C({},n,{templateUrl:null,transclude:null,replace:null,$$originalDirective:n}),N=F(n.templateUrl)?n.templateUrl(b, c):n.templateUrl,t=n.templateNamespace;b.empty();q(O.getTrustedResourceUrl(N)).then(function(q){var v,O;q=Pc(q);if(n.replace){q=Pb.test(q)?Qc(U(t,P(q))):[];v=q[0];if(1!=q.length||v.nodeType!==na)throw ka("tplrt",n.name,N);q={$attr:{}};Ab(d,b,v);var H=W(v,[],q);K(n.scope)&&y(H);a=H.concat(a);Oc(c,q)}else v=p,b.html(q);a.unshift(w);l=aa(a,v,c,e,b,n,f,g,h);r(d,function(a,c){a==v&&(d[c]=b[0])});for(s=ea(b[0].childNodes,e);k.length;){q=k.shift();O=k.shift();var E=k.shift(),B=k.shift(),H=b[0];if(!q.$$destroyed){if(O!== p){var Q=O.className;h.hasElementTranscludeDirective&&n.replace||(H=Rb(v));Ab(E,A(O),H);M(A(H),Q)}O=l.transcludeOnThisElement?L(q,l.transclude,B):B;l(s,q,H,d,O)}}k=null});return function(a,b,c,d,e){a=e;b.$$destroyed||(k?k.push(b,c,d,a):(l.transcludeOnThisElement&&(a=L(b,l.transclude,e)),l(s,b,c,d,a)))}}function z(a,b){var c=b.priority-a.priority;return 0!==c?c:a.name!==b.name?a.name"+b+"";return c.childNodes[0].childNodes;default:return b}}function Ga(a,b){if("srcdoc"==b)return O.HTML;var c=ta(a);if("xlinkHref"== b||"form"==c&&"action"==b||"img"!=c&&("src"==b||"ngSrc"==b))return O.RESOURCE_URL}function S(a,c,d,e,f){var h=b(d,!0);if(h){if("multiple"===e&&"select"===ta(a))throw ka("selmulti",va(a));c.push({priority:100,compile:function(){return{pre:function(c,d,l){d=l.$$observers||(l.$$observers={});if(k.test(e))throw ka("nodomevents");l[e]&&(h=b(l[e],!0,Ga(a,e),g[e]||f))&&(l[e]=h(c),(d[e]||(d[e]=[])).$$inter=!0,(l.$$observers&&l.$$observers[e].$$scope||c).$watch(h,function(a,b){"class"===e&&a!=b?l.$updateClass(a, b):l.$set(e,a)}))}}}})}}function Ab(a,b,c){var d=b[0],e=b.length,f=d.parentNode,g,h;if(a)for(g=0,h=a.length;g=a)return b;for(;a--;)8===b[a].nodeType&&of.call(b,a,1);return b}function Ce(){var b={},a=!1,c=/^(\S+)(\s+as\s+(\w+))?$/;this.register=function(a,c){La(a,"controller");K(a)?C(b,a):b[a]=c};this.allowGlobals=function(){a=!0};this.$get=["$injector","$window",function(d,e){function f(a, b,c,d){if(!a||!K(a.$scope))throw z("$controller")("noscp",d,b);a.$scope[b]=c}return function(g,h,k,l){var m,p,s;k=!0===k;l&&I(l)&&(s=l);I(g)&&(l=g.match(c),p=l[1],s=s||l[3],g=b.hasOwnProperty(p)?b[p]:tc(h.$scope,p,!0)||(a?tc(e,p,!0):u),pb(g,p,!0));if(k)return k=(D(g)?g[g.length-1]:g).prototype,m=Object.create(k),s&&f(h,s,m,p||g.name),C(function(){d.invoke(g,m,h,p);return m},{instance:m,identifier:s});m=d.instantiate(g,h,p);s&&f(h,s,m,p||g.name);return m}}]}function De(){this.$get=["$window",function(b){return A(b.document)}]} function Ee(){this.$get=["$log",function(b){return function(a,c){b.error.apply(b,arguments)}}]}function Yb(b,a){if(I(b)){b=b.replace(pf,"");var c=a("Content-Type");if(c&&0===c.indexOf(Sc)&&b.trim()||qf.test(b)&&rf.test(b))b=oc(b)}return b}function Tc(b){var a=ia(),c,d,e;if(!b)return a;r(b.split("\n"),function(b){e=b.indexOf(":");c=R(P(b.substr(0,e)));d=P(b.substr(e+1));c&&(a[c]=a[c]?a[c]+", "+d:d)});return a}function Uc(b){var a=K(b)?b:u;return function(c){a||(a=Tc(b));return c?(c=a[R(c)],void 0=== c&&(c=null),c):a}}function Vc(b,a,c){if(F(c))return c(b,a);r(c,function(c){b=c(b,a)});return b}function He(){var b=this.defaults={transformResponse:[Yb],transformRequest:[function(a){return K(a)&&"[object File]"!==Ja.call(a)&&"[object Blob]"!==Ja.call(a)?Za(a):a}],headers:{common:{Accept:"application/json, text/plain, */*"},post:ua(Zb),put:ua(Zb),patch:ua(Zb)},xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN"},a=!1;this.useApplyAsync=function(b){return y(b)?(a=!!b,this):a};var c=this.interceptors= [];this.$get=["$httpBackend","$browser","$cacheFactory","$rootScope","$q","$injector",function(d,e,f,g,h,k){function l(a){function c(a){var b=C({},a);b.data=a.data?Vc(a.data,a.headers,d.transformResponse):a.data;a=a.status;return 200<=a&&300>a?b:h.reject(b)}var d={method:"get",transformRequest:b.transformRequest,transformResponse:b.transformResponse},e=function(a){var c=b.headers,d=C({},a.headers),e,f,c=C({},c.common,c[R(a.method)]);a:for(e in c){a=R(e);for(f in d)if(R(f)===a)continue a;d[e]=c[e]}(function(a){var b; r(a,function(c,d){F(c)&&(b=c(),null!=b?a[d]=b:delete a[d])})})(d);return d}(a);if(!ha.isObject(a))throw z("$http")("badreq",a);C(d,a);d.headers=e;d.method=rb(d.method);var f=[function(a){e=a.headers;var d=Vc(a.data,Uc(e),a.transformRequest);G(d)&&r(e,function(a,b){"content-type"===R(b)&&delete e[b]});G(a.withCredentials)&&!G(b.withCredentials)&&(a.withCredentials=b.withCredentials);return m(a,d,e).then(c,c)},u],g=h.when(d);for(r(t,function(a){(a.request||a.requestError)&&f.unshift(a.request,a.requestError); (a.response||a.responseError)&&f.push(a.response,a.responseError)});f.length;){a=f.shift();var k=f.shift(),g=g.then(a,k)}g.success=function(a){g.then(function(b){a(b.data,b.status,b.headers,d)});return g};g.error=function(a){g.then(null,function(b){a(b.data,b.status,b.headers,d)});return g};return g}function m(c,f,k){function m(b,c,d,e){function f(){w(c,b,d,e)}M&&(200<=b&&300>b?M.put(r,[b,c,Tc(d),e]):M.remove(r));a?g.$applyAsync(f):(f(),g.$$phase||g.$apply())}function w(a,b,d,e){b=Math.max(b,0);(200<= b&&300>b?E.resolve:E.reject)({data:a,status:b,headers:Uc(d),config:c,statusText:e})}function t(){var a=l.pendingRequests.indexOf(c);-1!==a&&l.pendingRequests.splice(a,1)}var E=h.defer(),H=E.promise,M,B,r=p(c.url,c.params);l.pendingRequests.push(c);H.then(t,t);!c.cache&&!b.cache||!1===c.cache||"GET"!==c.method&&"JSONP"!==c.method||(M=K(c.cache)?c.cache:K(b.cache)?b.cache:s);if(M)if(B=M.get(r),y(B)){if(B&&F(B.then))return B.then(t,t),B;D(B)?w(B[1],B[0],ua(B[2]),B[3]):w(B,200,{},"OK")}else M.put(r,H); G(B)&&((B=Wc(c.url)?e.cookies()[c.xsrfCookieName||b.xsrfCookieName]:u)&&(k[c.xsrfHeaderName||b.xsrfHeaderName]=B),d(c.method,r,f,m,k,c.timeout,c.withCredentials,c.responseType));return H}function p(a,b){if(!b)return a;var c=[];Bd(b,function(a,b){null===a||G(a)||(D(a)||(a=[a]),r(a,function(a){K(a)&&(a=fa(a)?a.toISOString():Za(a));c.push(Da(b)+"="+Da(a))}))});0=k&&(q.resolve(s), p(N.$$intervalId),delete f[N.$$intervalId]);t||b.$apply()},h);f[N.$$intervalId]=q;return N}var f={};e.cancel=function(b){return b&&b.$$intervalId in f?(f[b.$$intervalId].reject("canceled"),a.clearInterval(b.$$intervalId),delete f[b.$$intervalId],!0):!1};return e}]}function Od(){this.$get=function(){return{id:"en-us",NUMBER_FORMATS:{DECIMAL_SEP:".",GROUP_SEP:",",PATTERNS:[{minInt:1,minFrac:0,maxFrac:3,posPre:"",posSuf:"",negPre:"-",negSuf:"",gSize:3,lgSize:3},{minInt:1,minFrac:2,maxFrac:2,posPre:"\u00a4", posSuf:"",negPre:"(\u00a4",negSuf:")",gSize:3,lgSize:3}],CURRENCY_SYM:"$"},DATETIME_FORMATS:{MONTH:"January February March April May June July August September October November December".split(" "),SHORTMONTH:"Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" "),DAY:"Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "),SHORTDAY:"Sun Mon Tue Wed Thu Fri Sat".split(" "),AMPMS:["AM","PM"],medium:"MMM d, y h:mm:ss a","short":"M/d/yy h:mm a",fullDate:"EEEE, MMMM d, y",longDate:"MMMM d, y", mediumDate:"MMM d, y",shortDate:"M/d/yy",mediumTime:"h:mm:ss a",shortTime:"h:mm a"},pluralCat:function(b){return 1===b?"one":"other"}}}}function ac(b){b=b.split("/");for(var a=b.length;a--;)b[a]=nb(b[a]);return b.join("/")}function Xc(b,a){var c=Aa(b);a.$$protocol=c.protocol;a.$$host=c.hostname;a.$$port=$(c.port)||uf[c.protocol]||null}function Yc(b,a){var c="/"!==b.charAt(0);c&&(b="/"+b);var d=Aa(b);a.$$path=decodeURIComponent(c&&"/"===d.pathname.charAt(0)?d.pathname.substring(1):d.pathname);a.$$search= qc(d.search);a.$$hash=decodeURIComponent(d.hash);a.$$path&&"/"!=a.$$path.charAt(0)&&(a.$$path="/"+a.$$path)}function xa(b,a){if(0===a.indexOf(b))return a.substr(b.length)}function Fa(b){var a=b.indexOf("#");return-1==a?b:b.substr(0,a)}function bc(b){return b.substr(0,Fa(b).lastIndexOf("/")+1)}function cc(b,a){this.$$html5=!0;a=a||"";var c=bc(b);Xc(b,this);this.$$parse=function(a){var b=xa(c,a);if(!I(b))throw eb("ipthprfx",a,c);Yc(b,this);this.$$path||(this.$$path="/");this.$$compose()};this.$$compose= function(){var a=Kb(this.$$search),b=this.$$hash?"#"+nb(this.$$hash):"";this.$$url=ac(this.$$path)+(a?"?"+a:"")+b;this.$$absUrl=c+this.$$url.substr(1)};this.$$parseLinkUrl=function(d,e){if(e&&"#"===e[0])return this.hash(e.slice(1)),!0;var f,g;(f=xa(b,d))!==u?(g=f,g=(f=xa(a,f))!==u?c+(xa("/",f)||f):b+g):(f=xa(c,d))!==u?g=c+f:c==d+"/"&&(g=c);g&&this.$$parse(g);return!!g}}function dc(b,a){var c=bc(b);Xc(b,this);this.$$parse=function(d){var e=xa(b,d)||xa(c,d),e="#"==e.charAt(0)?xa(a,e):this.$$html5?e: "";if(!I(e))throw eb("ihshprfx",d,a);Yc(e,this);d=this.$$path;var f=/^\/[A-Z]:(\/.*)/;0===e.indexOf(b)&&(e=e.replace(b,""));f.exec(e)||(d=(e=f.exec(d))?e[1]:d);this.$$path=d;this.$$compose()};this.$$compose=function(){var c=Kb(this.$$search),e=this.$$hash?"#"+nb(this.$$hash):"";this.$$url=ac(this.$$path)+(c?"?"+c:"")+e;this.$$absUrl=b+(this.$$url?a+this.$$url:"")};this.$$parseLinkUrl=function(a,c){return Fa(b)==Fa(a)?(this.$$parse(a),!0):!1}}function Zc(b,a){this.$$html5=!0;dc.apply(this,arguments); var c=bc(b);this.$$parseLinkUrl=function(d,e){if(e&&"#"===e[0])return this.hash(e.slice(1)),!0;var f,g;b==Fa(d)?f=d:(g=xa(c,d))?f=b+a+g:c===d+"/"&&(f=c);f&&this.$$parse(f);return!!f};this.$$compose=function(){var c=Kb(this.$$search),e=this.$$hash?"#"+nb(this.$$hash):"";this.$$url=ac(this.$$path)+(c?"?"+c:"")+e;this.$$absUrl=b+a+this.$$url}}function Bb(b){return function(){return this[b]}}function $c(b,a){return function(c){if(G(c))return this[b];this[b]=a(c);this.$$compose();return this}}function Je(){var b= "",a={enabled:!1,requireBase:!0,rewriteLinks:!0};this.hashPrefix=function(a){return y(a)?(b=a,this):b};this.html5Mode=function(b){return Ua(b)?(a.enabled=b,this):K(b)?(Ua(b.enabled)&&(a.enabled=b.enabled),Ua(b.requireBase)&&(a.requireBase=b.requireBase),Ua(b.rewriteLinks)&&(a.rewriteLinks=b.rewriteLinks),this):a};this.$get=["$rootScope","$browser","$sniffer","$rootElement",function(c,d,e,f){function g(a,b,c){var e=k.url(),f=k.$$state;try{d.url(a,b,c),k.$$state=d.state()}catch(g){throw k.url(e),k.$$state= f,g;}}function h(a,b){c.$broadcast("$locationChangeSuccess",k.absUrl(),a,k.$$state,b)}var k,l;l=d.baseHref();var m=d.url(),p;if(a.enabled){if(!l&&a.requireBase)throw eb("nobase");p=m.substring(0,m.indexOf("/",m.indexOf("//")+2))+(l||"/");l=e.history?cc:Zc}else p=Fa(m),l=dc;k=new l(p,"#"+b);k.$$parseLinkUrl(m,m);k.$$state=d.state();var s=/^\s*(javascript|mailto):/i;f.on("click",function(b){if(a.rewriteLinks&&!b.ctrlKey&&!b.metaKey&&2!=b.which){for(var e=A(b.target);"a"!==ta(e[0]);)if(e[0]===f[0]|| !(e=e.parent())[0])return;var g=e.prop("href"),h=e.attr("href")||e.attr("xlink:href");K(g)&&"[object SVGAnimatedString]"===g.toString()&&(g=Aa(g.animVal).href);s.test(g)||!g||e.attr("target")||b.isDefaultPrevented()||!k.$$parseLinkUrl(g,h)||(b.preventDefault(),k.absUrl()!=d.url()&&(c.$apply(),U.angular["ff-684208-preventDefault"]=!0))}});k.absUrl()!=m&&d.url(k.absUrl(),!0);var t=!0;d.onUrlChange(function(a,b){c.$evalAsync(function(){var d=k.absUrl(),e=k.$$state,f;k.$$parse(a);k.$$state=b;f=c.$broadcast("$locationChangeStart", a,d,b,e).defaultPrevented;k.absUrl()===a&&(f?(k.$$parse(d),k.$$state=e,g(d,!1,e)):(t=!1,h(d,e)))});c.$$phase||c.$digest()});c.$watch(function(){var a=d.url(),b=d.state(),f=k.$$replace,l=a!==k.absUrl()||k.$$html5&&e.history&&b!==k.$$state;if(t||l)t=!1,c.$evalAsync(function(){var d=k.absUrl(),e=c.$broadcast("$locationChangeStart",d,a,k.$$state,b).defaultPrevented;k.absUrl()===d&&(e?(k.$$parse(a),k.$$state=b):(l&&g(d,f,b===k.$$state?null:k.$$state),h(a,b)))});k.$$replace=!1});return k}]}function Ke(){var b= !0,a=this;this.debugEnabled=function(a){return y(a)?(b=a,this):b};this.$get=["$window",function(c){function d(a){a instanceof Error&&(a.stack?a=a.message&&-1===a.stack.indexOf(a.message)?"Error: "+a.message+"\n"+a.stack:a.stack:a.sourceURL&&(a=a.message+"\n"+a.sourceURL+":"+a.line));return a}function e(a){var b=c.console||{},e=b[a]||b.log||x;a=!1;try{a=!!e.apply}catch(k){}return a?function(){var a=[];r(arguments,function(b){a.push(d(b))});return e.apply(b,a)}:function(a,b){e(a,null==b?"":b)}}return{log:e("log"), info:e("info"),warn:e("warn"),error:e("error"),debug:function(){var c=e("debug");return function(){b&&c.apply(a,arguments)}}()}}]}function ra(b,a){if("__defineGetter__"===b||"__defineSetter__"===b||"__lookupGetter__"===b||"__lookupSetter__"===b||"__proto__"===b)throw la("isecfld",a);return b}function sa(b,a){if(b){if(b.constructor===b)throw la("isecfn",a);if(b.window===b)throw la("isecwindow",a);if(b.children&&(b.nodeName||b.prop&&b.attr&&b.find))throw la("isecdom",a);if(b===Object)throw la("isecobj", a);}return b}function ec(b){return b.constant}function Oa(b,a,c,d){sa(b,d);a=a.split(".");for(var e,f=0;1h?ad(g[0],g[1],g[2],g[3],g[4],c,d):function(a,b){var e=0,f;do f=ad(g[e++],g[e++],g[e++],g[e++],g[e++],c,d)(a,b),b=u,a=f;while(e=this.promise.$$state.status&&d&&d.length&&b(function(){for(var b,e,f=0,g=d.length;fa)for(b in l++,f)e.hasOwnProperty(b)||(n--,delete f[b])}else f!==e&&(f=e,l++);return l}}c.$stateful=!0;var d=this,e,f,h,k=1r&&(y=4-r,u[y]||(u[y]=[]),u[y].push({msg:F(e.exp)?"fn: "+(e.exp.name||e.exp.toString()):e.exp,newVal:g,oldVal:k})); else if(e===c){v=!1;break a}}catch(A){f(A)}if(!(m=L.$$childHead||L!==this&&L.$$nextSibling))for(;L!==this&&!(m=L.$$nextSibling);)L=L.$parent}while(L=m);if((v||N.length)&&!r--)throw q.$$phase=null,a("infdig",b,u);}while(v||N.length);for(q.$$phase=null;n.length;)try{n.shift()()}catch(da){f(da)}},$destroy:function(){if(!this.$$destroyed){var a=this.$parent;this.$broadcast("$destroy");this.$$destroyed=!0;if(this!==q){for(var b in this.$$listenerCount)m(this,this.$$listenerCount[b],b);a.$$childHead==this&& (a.$$childHead=this.$$nextSibling);a.$$childTail==this&&(a.$$childTail=this.$$prevSibling);this.$$prevSibling&&(this.$$prevSibling.$$nextSibling=this.$$nextSibling);this.$$nextSibling&&(this.$$nextSibling.$$prevSibling=this.$$prevSibling);this.$destroy=this.$digest=this.$apply=this.$evalAsync=this.$applyAsync=x;this.$on=this.$watch=this.$watchGroup=function(){return x};this.$$listeners={};this.$parent=this.$$nextSibling=this.$$prevSibling=this.$$childHead=this.$$childTail=this.$root=this.$$watchers= null}}},$eval:function(a,b){return g(a)(this,b)},$evalAsync:function(a){q.$$phase||N.length||h.defer(function(){N.length&&q.$digest()});N.push({scope:this,expression:a})},$$postDigest:function(a){n.push(a)},$apply:function(a){try{return l("$apply"),this.$eval(a)}catch(b){f(b)}finally{q.$$phase=null;try{q.$digest()}catch(c){throw f(c),c;}}},$applyAsync:function(a){function b(){c.$eval(a)}var c=this;a&&v.push(b);t()},$on:function(a,b){var c=this.$$listeners[a];c||(this.$$listeners[a]=c=[]);c.push(b); var d=this;do d.$$listenerCount[a]||(d.$$listenerCount[a]=0),d.$$listenerCount[a]++;while(d=d.$parent);var e=this;return function(){var d=c.indexOf(b);-1!==d&&(c[d]=null,m(e,1,a))}},$emit:function(a,b){var c=[],d,e=this,g=!1,h={name:a,targetScope:e,stopPropagation:function(){g=!0},preventDefault:function(){h.defaultPrevented=!0},defaultPrevented:!1},k=Xa([h],arguments,1),l,m;do{d=e.$$listeners[a]||c;h.currentScope=e;l=0;for(m=d.length;lHa)throw Ba("iequirks");var d=ua(ma);d.isEnabled=function(){return b};d.trustAs=c.trustAs;d.getTrusted=c.getTrusted;d.valueOf= c.valueOf;b||(d.trustAs=d.getTrusted=function(a,b){return b},d.valueOf=oa);d.parseAs=function(b,c){var e=a(c);return e.literal&&e.constant?e:a(c,function(a){return d.getTrusted(b,a)})};var e=d.parseAs,f=d.getTrusted,g=d.trustAs;r(ma,function(a,b){var c=R(b);d[bb("parse_as_"+c)]=function(b){return e(a,b)};d[bb("get_trusted_"+c)]=function(b){return f(a,b)};d[bb("trust_as_"+c)]=function(b){return g(a,b)}});return d}]}function Re(){this.$get=["$window","$document",function(b,a){var c={},d=$((/android (\d+)/.exec(R((b.navigator|| {}).userAgent))||[])[1]),e=/Boxee/i.test((b.navigator||{}).userAgent),f=a[0]||{},g,h=/^(Moz|webkit|ms)(?=[A-Z])/,k=f.body&&f.body.style,l=!1,m=!1;if(k){for(var p in k)if(l=h.exec(p)){g=l[0];g=g.substr(0,1).toUpperCase()+g.substr(1);break}g||(g="WebkitOpacity"in k&&"webkit");l=!!("transition"in k||g+"Transition"in k);m=!!("animation"in k||g+"Animation"in k);!d||l&&m||(l=I(f.body.style.webkitTransition),m=I(f.body.style.webkitAnimation))}return{history:!(!b.history||!b.history.pushState||4>d||e),hasEvent:function(a){if("input"== a&&9==Ha)return!1;if(G(c[a])){var b=f.createElement("div");c[a]="on"+a in b}return c[a]},csp:$a(),vendorPrefix:g,transitions:l,animations:m,android:d}}]}function Te(){this.$get=["$templateCache","$http","$q",function(b,a,c){function d(e,f){d.totalPendingRequests++;var g=a.defaults&&a.defaults.transformResponse;if(D(g))for(var h=g,g=[],k=0;kb;b=Math.abs(b);var g=b+"",h="",k=[],l=!1;if(-1!==g.indexOf("e")){var m=g.match(/([\d\.]+)e(-?)(\d+)/);m&&"-"==m[2]&&m[3]>e+1?(g="0",b=0):(h=g,l=!0)}if(l)0b&&(h=b.toFixed(e));else{g=(g.split(ld)[1]||"").length;G(e)&&(e=Math.min(Math.max(a.minFrac,g),a.maxFrac));b=+(Math.round(+(b.toString()+"e"+e)).toString()+"e"+-e);0===b&&(f=!1);b=(""+b).split(ld);g=b[0];b=b[1]||"";var m=0,p=a.lgSize,s=a.gSize;if(g.length>=p+s)for(m=g.length-p,l=0;lb&&(d="-",b=-b);for(b=""+b;b.length-c)e+=c;0===e&&-12==c&&(e=12);return Cb(e,a,d)}}function Db(b,a){return function(c, d){var e=c["get"+b](),f=rb(a?"SHORT"+b:b);return d[f][e]}}function md(b){var a=(new Date(b,0,1)).getDay();return new Date(b,0,(4>=a?5:12)-a)}function nd(b){return function(a){var c=md(a.getFullYear());a=+new Date(a.getFullYear(),a.getMonth(),a.getDate()+(4-a.getDay()))-+c;a=1+Math.round(a/6048E5);return Cb(a,b)}}function hd(b){function a(a){var b;if(b=a.match(c)){a=new Date(0);var f=0,g=0,h=b[8]?a.setUTCFullYear:a.setFullYear,k=b[8]?a.setUTCHours:a.setHours;b[9]&&(f=$(b[9]+b[10]),g=$(b[9]+b[11])); h.call(a,$(b[1]),$(b[2])-1,$(b[3]));f=$(b[4]||0)-f;g=$(b[5]||0)-g;h=$(b[6]||0);b=Math.round(1E3*parseFloat("0."+(b[7]||0)));k.call(a,f,g,h,b)}return a}var c=/^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;return function(c,e,f){var g="",h=[],k,l;e=e||"mediumDate";e=b.DATETIME_FORMATS[e]||e;I(c)&&(c=Ff.test(c)?$(c):a(c));X(c)&&(c=new Date(c));if(!fa(c))return c;for(;e;)(l=Gf.exec(e))?(h=Xa(h,l,1),e=h.pop()):(h.push(e),e=null);f&&"UTC"===f&&(c= new Date(c.getTime()),c.setMinutes(c.getMinutes()+c.getTimezoneOffset()));r(h,function(a){k=Hf[a];g+=k?k(c,b.DATETIME_FORMATS):a.replace(/(^'|'$)/g,"").replace(/''/g,"'")});return g}}function Bf(){return function(b){return Za(b,!0)}}function Cf(){return function(b,a){X(b)&&(b=b.toString());if(!D(b)&&!I(b))return b;a=Infinity===Math.abs(Number(a))?Number(a):$(a);if(I(b))return a?0<=a?b.slice(0,a):b.slice(a,b.length):"";var c=[],d,e;a>b.length?a=b.length:a<-b.length&&(a=-b.length);0b||37<=b&&40>=b||s(a)});if(e.hasEvent("paste"))a.on("paste cut",s)}a.on("change",m);d.$render=function(){a.val(d.$isEmpty(d.$viewValue)? "":d.$viewValue)}}function Gb(b,a){return function(c,d){var e,f;if(fa(c))return c;if(I(c)){'"'==c.charAt(0)&&'"'==c.charAt(c.length-1)&&(c=c.substring(1,c.length-1));if(If.test(c))return new Date(c);b.lastIndex=0;if(e=b.exec(c))return e.shift(),f=d?{yyyy:d.getFullYear(),MM:d.getMonth()+1,dd:d.getDate(),HH:d.getHours(),mm:d.getMinutes(),ss:d.getSeconds(),sss:d.getMilliseconds()/1E3}:{yyyy:1970,MM:1,dd:1,HH:0,mm:0,ss:0,sss:0},r(e,function(b,c){c=r};g.$observe("min",function(a){r=s(a);h.$validate()})}if(y(g.max)||g.ngMax){var n;h.$validators.max=function(a){return!p(a)||G(n)||c(a)<=n};g.$observe("max",function(a){n=s(a);h.$validate()})}}}function qd(b,a,c,d){(d.$$hasNativeValidators=K(a[0].validity))&&d.$parsers.push(function(b){var c=a.prop("validity")|| {};return c.badInput&&!c.typeMismatch?u:b})}function rd(b,a,c,d,e){if(y(d)){b=b(d);if(!b.constant)throw z("ngModel")("constexpr",c,d);return b(a)}return e}function pd(b){function a(a,b){b&&!f[a]?(l.addClass(e,a),f[a]=!0):!b&&f[a]&&(l.removeClass(e,a),f[a]=!1)}function c(b,c){b=b?"-"+Mb(b,"-"):"";a(ib+b,!0===c);a(sd+b,!1===c)}var d=b.ctrl,e=b.$element,f={},g=b.set,h=b.unset,k=b.parentForm,l=b.$animate;f[sd]=!(f[ib]=e.hasClass(ib));d.$setValidity=function(b,e,f){e===u?(d.$pending||(d.$pending={}),g(d.$pending, b,f)):(d.$pending&&h(d.$pending,b,f),td(d.$pending)&&(d.$pending=u));Ua(e)?e?(h(d.$error,b,f),g(d.$$success,b,f)):(g(d.$error,b,f),h(d.$$success,b,f)):(h(d.$error,b,f),h(d.$$success,b,f));d.$pending?(a(ud,!0),d.$valid=d.$invalid=u,c("",null)):(a(ud,!1),d.$valid=td(d.$error),d.$invalid=!d.$valid,c("",d.$valid));e=d.$pending&&d.$pending[b]?u:d.$error[b]?!1:d.$$success[b]?!0:null;c(b,e);k.$setValidity(b,e,d)}}function td(b){if(b)for(var a in b)return!1;return!0}function ic(b,a){b="ngClass"+b;return["$animate", function(c){function d(a,b){var c=[],d=0;a:for(;d(?:<\/\1>|)$/,Pb=/<|&#?\w+;/,af=/<([\w:]+)/,bf=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, ja={option:[1,'"],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};ja.optgroup=ja.option;ja.tbody=ja.tfoot=ja.colgroup=ja.caption=ja.thead;ja.th=ja.td;var Ka=S.prototype={ready:function(b){function a(){c||(c=!0,b())}var c=!1;"complete"===V.readyState?setTimeout(a):(this.on("DOMContentLoaded",a),S(U).on("load",a))}, toString:function(){var b=[];r(this,function(a){b.push(""+a)});return"["+b.join(", ")+"]"},eq:function(b){return 0<=b?A(this[b]):A(this[this.length+b])},length:0,push:Kf,sort:[].sort,splice:[].splice},yb={};r("multiple selected checked disabled readOnly required open".split(" "),function(b){yb[R(b)]=b});var Kc={};r("input select option textarea button form details".split(" "),function(b){Kc[b]=!0});var Lc={ngMinlength:"minlength",ngMaxlength:"maxlength",ngMin:"min",ngMax:"max",ngPattern:"pattern"}; r({data:Sb,removeData:ub},function(b,a){S[a]=b});r({data:Sb,inheritedData:xb,scope:function(b){return A.data(b,"$scope")||xb(b.parentNode||b,["$isolateScope","$scope"])},isolateScope:function(b){return A.data(b,"$isolateScope")||A.data(b,"$isolateScopeNoTemplate")},controller:Gc,injector:function(b){return xb(b,"$injector")},removeAttr:function(b,a){b.removeAttribute(a)},hasClass:Tb,css:function(b,a,c){a=bb(a);if(y(c))b.style[a]=c;else return b.style[a]},attr:function(b,a,c){var d=R(a);if(yb[d])if(y(c))c? (b[a]=!0,b.setAttribute(a,d)):(b[a]=!1,b.removeAttribute(d));else return b[a]||(b.attributes.getNamedItem(a)||x).specified?d:u;else if(y(c))b.setAttribute(a,c);else if(b.getAttribute)return b=b.getAttribute(a,2),null===b?u:b},prop:function(b,a,c){if(y(c))b[a]=c;else return b[a]},text:function(){function b(a,b){if(G(b)){var d=a.nodeType;return d===na||d===mb?a.textContent:""}a.textContent=b}b.$dv="";return b}(),val:function(b,a){if(G(a)){if(b.multiple&&"select"===ta(b)){var c=[];r(b.options,function(a){a.selected&& c.push(a.value||a.text)});return 0===c.length?null:c}return b.value}b.value=a},html:function(b,a){if(G(a))return b.innerHTML;tb(b,!0);b.innerHTML=a},empty:Hc},function(b,a){S.prototype[a]=function(a,d){var e,f,g=this.length;if(b!==Hc&&(2==b.length&&b!==Tb&&b!==Gc?a:d)===u){if(K(a)){for(e=0;e":function(a,c,d,e){return d(a,c)>e(a,c)},"<=":function(a,c,d,e){return d(a,c)<=e(a,c)},">=":function(a,c,d,e){return d(a,c)>=e(a,c)},"&&":function(a,c,d,e){return d(a,c)&&e(a,c)},"||":function(a,c,d,e){return d(a,c)||e(a,c)},"!":function(a,c,d){return!d(a,c)},"=":!0,"|":!0}),Sf={n:"\n",f:"\f",r:"\r",t:"\t",v:"\v","'":"'",'"':'"'},gc=function(a){this.options=a};gc.prototype={constructor:gc,lex:function(a){this.text=a;this.index=0;for(this.tokens= [];this.index=a&&"string"===typeof a},isWhitespace:function(a){return" "===a||"\r"===a||"\t"===a||"\n"===a||"\v"===a||"\u00a0"===a},isIdent:function(a){return"a"<=a&&"z">=a||"A"<=a&&"Z">=a||"_"===a||"$"===a},isExpOperator:function(a){return"-"=== a||"+"===a||this.isNumber(a)},throwError:function(a,c,d){d=d||this.index;c=y(c)?"s "+c+"-"+this.index+" ["+this.text.substring(c,d)+"]":" "+d;throw la("lexerr",a,c,this.text);},readNumber:function(){for(var a="",c=this.index;this.indexa){a=this.tokens[a];var g=a.text;if(g===c||g===d||g===e||g===f||!(c||d||e||f))return a}return!1},expect:function(a,c,d,e){return(a=this.peek(a,c,d,e))?(this.tokens.shift(),a):!1},consume:function(a){if(0===this.tokens.length)throw la("ueoe",this.text);var c=this.expect(a);c||this.throwError("is unexpected, expecting ["+a+"]",this.peek());return c},unaryFn:function(a,c){var d=jb[a];return C(function(a,f){return d(a, f,c)},{constant:c.constant,inputs:[c]})},binaryFn:function(a,c,d,e){var f=jb[c];return C(function(c,e){return f(c,e,a,d)},{constant:a.constant&&d.constant,inputs:!e&&[a,d]})},identifier:function(){for(var a=this.consume().text;this.peek(".")&&this.peekAhead(1).identifier&&!this.peekAhead(2,"(");)a+=this.consume().text+this.consume().text;return Ib[a]||bd(a,this.options,this.text)},constant:function(){var a=this.consume().value;return C(function(){return a},{constant:!0,literal:!0})},statements:function(){for(var a= [];;)if(0","<=",">="))a=this.binaryFn(a,c.text,this.relational());return a},additive:function(){for(var a=this.multiplicative(),c;c=this.expect("+","-");)a=this.binaryFn(a,c.text,this.multiplicative());return a},multiplicative:function(){for(var a=this.unary(),c;c=this.expect("*","/","%");)a=this.binaryFn(a,c.text,this.unary());return a},unary:function(){var a;return this.expect("+")? this.primary():(a=this.expect("-"))?this.binaryFn(fb.ZERO,a.text,this.unary()):(a=this.expect("!"))?this.unaryFn(a.text,this.unary()):this.primary()},fieldAccess:function(a){var c=this.text,d=this.consume().text,e=bd(d,this.options,c);return C(function(c,d,h){return e(h||a(c,d))},{assign:function(e,g,h){(h=a(e,h))||a.assign(e,h={});return Oa(h,d,g,c)}})},objectIndex:function(a){var c=this.text,d=this.expression();this.consume("]");return C(function(e,f){var g=a(e,f),h=d(e,f);ra(h,c);return g?sa(g[h], c):u},{assign:function(e,f,g){var h=ra(d(e,g),c);(g=sa(a(e,g),c))||a.assign(e,g={});return g[h]=f}})},functionCall:function(a,c){var d=[];if(")"!==this.peekToken().text){do d.push(this.expression());while(this.expect(","))}this.consume(")");var e=this.text,f=d.length?[]:null;return function(g,h){var k=c?c(g,h):g,l=a(g,h,k)||x;if(f)for(var m=d.length;m--;)f[m]=sa(d[m](g,h),e);sa(k,e);if(l){if(l.constructor===l)throw la("isecfn",e);if(l===Pf||l===Qf||l===Rf)throw la("isecff",e);}k=l.apply?l.apply(k, f):l(f[0],f[1],f[2],f[3],f[4]);return sa(k,e)}},arrayDeclaration:function(){var a=[];if("]"!==this.peekToken().text){do{if(this.peek("]"))break;a.push(this.expression())}while(this.expect(","))}this.consume("]");return C(function(c,d){for(var e=[],f=0,g=a.length;fa.getHours()?c.AMPMS[0]:c.AMPMS[1]},Z:function(a){a=-1*a.getTimezoneOffset();return a=(0<= a?"+":"")+(Cb(Math[0=h};d.$observe("min",function(a){y(a)&&!X(a)&&(a=parseFloat(a,10));h=X(a)&&!isNaN(a)?a:u;e.$validate()})}if(d.max||d.ngMax){var k;e.$validators.max=function(a){return e.$isEmpty(a)||G(k)||a<=k};d.$observe("max",function(a){y(a)&&!X(a)&&(a=parseFloat(a,10));k=X(a)&&!isNaN(a)?a:u;e.$validate()})}},url:function(a,c,d,e,f,g){gb(a,c,d,e,f,g);hc(e);e.$$parserName="url";e.$validators.url=function(a, c){var d=a||c;return e.$isEmpty(d)||Tf.test(d)}},email:function(a,c,d,e,f,g){gb(a,c,d,e,f,g);hc(e);e.$$parserName="email";e.$validators.email=function(a,c){var d=a||c;return e.$isEmpty(d)||Uf.test(d)}},radio:function(a,c,d,e){G(d.name)&&c.attr("name",++kb);c.on("click",function(a){c[0].checked&&e.$setViewValue(d.value,a&&a.type)});e.$render=function(){c[0].checked=d.value==e.$viewValue};d.$observe("value",e.$render)},checkbox:function(a,c,d,e,f,g,h,k){var l=rd(k,a,"ngTrueValue",d.ngTrueValue,!0), m=rd(k,a,"ngFalseValue",d.ngFalseValue,!1);c.on("click",function(a){e.$setViewValue(c[0].checked,a&&a.type)});e.$render=function(){c[0].checked=e.$viewValue};e.$isEmpty=function(a){return!1===a};e.$formatters.push(function(a){return pa(a,l)});e.$parsers.push(function(a){return a?l:m})},hidden:x,button:x,submit:x,reset:x,file:x},vc=["$browser","$sniffer","$filter","$parse",function(a,c,d,e){return{restrict:"E",require:["?ngModel"],link:{pre:function(f,g,h,k){k[0]&&(Ad[R(h.type)]||Ad.text)(f,g,h,k[0], c,a,d,e)}}}}],ib="ng-valid",sd="ng-invalid",Qa="ng-pristine",Fb="ng-dirty",ud="ng-pending",Xf=["$scope","$exceptionHandler","$attrs","$element","$parse","$animate","$timeout","$rootScope","$q","$interpolate",function(a,c,d,e,f,g,h,k,l,m){this.$modelValue=this.$viewValue=Number.NaN;this.$$rawModelValue=u;this.$validators={};this.$asyncValidators={};this.$parsers=[];this.$formatters=[];this.$viewChangeListeners=[];this.$untouched=!0;this.$touched=!1;this.$pristine=!0;this.$dirty=!1;this.$valid=!0;this.$invalid= !1;this.$error={};this.$$success={};this.$pending=u;this.$name=m(d.name||"",!1)(a);var p=f(d.ngModel),s=p.assign,t=p,q=s,N=null,n=this;this.$$setOptions=function(a){if((n.$options=a)&&a.getterSetter){var c=f(d.ngModel+"()"),g=f(d.ngModel+"($$$p)");t=function(a){var d=p(a);F(d)&&(d=c(a));return d};q=function(a,c){F(p(a))?g(a,{$$$p:n.$modelValue}):s(a,n.$modelValue)}}else if(!p.assign)throw Hb("nonassign",d.ngModel,va(e));};this.$render=x;this.$isEmpty=function(a){return G(a)||""===a||null===a||a!== a};var v=e.inheritedData("$formController")||Eb,w=0;pd({ctrl:this,$element:e,set:function(a,c){a[c]=!0},unset:function(a,c){delete a[c]},parentForm:v,$animate:g});this.$setPristine=function(){n.$dirty=!1;n.$pristine=!0;g.removeClass(e,Fb);g.addClass(e,Qa)};this.$setDirty=function(){n.$dirty=!0;n.$pristine=!1;g.removeClass(e,Qa);g.addClass(e,Fb);v.$setDirty()};this.$setUntouched=function(){n.$touched=!1;n.$untouched=!0;g.setClass(e,"ng-untouched","ng-touched")};this.$setTouched=function(){n.$touched= !0;n.$untouched=!1;g.setClass(e,"ng-touched","ng-untouched")};this.$rollbackViewValue=function(){h.cancel(N);n.$viewValue=n.$$lastCommittedViewValue;n.$render()};this.$validate=function(){if(!X(n.$modelValue)||!isNaN(n.$modelValue)){var a=n.$$rawModelValue,c=n.$valid,d=n.$modelValue,e=n.$options&&n.$options.allowInvalid;n.$$runValidators(n.$error[n.$$parserName||"parse"]?!1:u,a,n.$$lastCommittedViewValue,function(f){e||c===f||(n.$modelValue=f?a:u,n.$modelValue!==d&&n.$$writeModelToScope())})}};this.$$runValidators= function(a,c,d,e){function f(){var a=!0;r(n.$validators,function(e,f){var g=e(c,d);a=a&&g;h(f,g)});return a?!0:(r(n.$asyncValidators,function(a,c){h(c,null)}),!1)}function g(){var a=[],e=!0;r(n.$asyncValidators,function(f,g){var k=f(c,d);if(!k||!F(k.then))throw Hb("$asyncValidators",k);h(g,u);a.push(k.then(function(){h(g,!0)},function(a){e=!1;h(g,!1)}))});a.length?l.all(a).then(function(){k(e)},x):k(!0)}function h(a,c){m===w&&n.$setValidity(a,c)}function k(a){m===w&&e(a)}w++;var m=w;(function(a){var c= n.$$parserName||"parse";if(a===u)h(c,null);else if(h(c,a),!a)return r(n.$validators,function(a,c){h(c,null)}),r(n.$asyncValidators,function(a,c){h(c,null)}),!1;return!0})(a)?f()?g():k(!1):k(!1)};this.$commitViewValue=function(){var a=n.$viewValue;h.cancel(N);if(n.$$lastCommittedViewValue!==a||""===a&&n.$$hasNativeValidators)n.$$lastCommittedViewValue=a,n.$pristine&&this.$setDirty(),this.$$parseAndValidate()};this.$$parseAndValidate=function(){var c=n.$$lastCommittedViewValue,d=c,e=G(d)?u:!0;if(e)for(var f= 0;ff||e.$isEmpty(a)||c.length<=f}}}}},yc=function(){return{restrict:"A",require:"?ngModel",link:function(a,c,d,e){if(e){var f=0;d.$observe("minlength",function(a){f=$(a)||0;e.$validate()});e.$validators.minlength=function(a,c){return e.$isEmpty(c)||c.length>=f}}}}},te=function(){return{restrict:"A",priority:100,require:"ngModel", link:function(a,c,d,e){var f=c.attr(d.$attr.ngList)||", ",g="false"!==d.ngTrim,h=g?P(f):f;e.$parsers.push(function(a){if(!G(a)){var c=[];a&&r(a.split(h),function(a){a&&c.push(g?P(a):a)});return c}});e.$formatters.push(function(a){return D(a)?a.join(f):u});e.$isEmpty=function(a){return!a||!a.length}}}},Yf=/^(true|false|\d+)$/,ve=function(){return{restrict:"A",priority:100,compile:function(a,c){return Yf.test(c.ngValue)?function(a,c,f){f.$set("value",a.$eval(f.ngValue))}:function(a,c,f){a.$watch(f.ngValue, function(a){f.$set("value",a)})}}}},we=function(){return{restrict:"A",controller:["$scope","$attrs",function(a,c){var d=this;this.$options=a.$eval(c.ngModelOptions);this.$options.updateOn!==u?(this.$options.updateOnDefault=!1,this.$options.updateOn=P(this.$options.updateOn.replace(Wf,function(){d.$options.updateOnDefault=!0;return" "}))):this.$options.updateOnDefault=!0}]}},Wd=["$compile",function(a){return{restrict:"AC",compile:function(c){a.$$addBindingClass(c);return function(c,e,f){a.$$addBindingInfo(e, f.ngBind);e=e[0];c.$watch(f.ngBind,function(a){e.textContent=a===u?"":a})}}}}],Yd=["$interpolate","$compile",function(a,c){return{compile:function(d){c.$$addBindingClass(d);return function(d,f,g){d=a(f.attr(g.$attr.ngBindTemplate));c.$$addBindingInfo(f,d.expressions);f=f[0];g.$observe("ngBindTemplate",function(a){f.textContent=a===u?"":a})}}}}],Xd=["$sce","$parse","$compile",function(a,c,d){return{restrict:"A",compile:function(e,f){var g=c(f.ngBindHtml),h=c(f.ngBindHtml,function(a){return(a||"").toString()}); d.$$addBindingClass(e);return function(c,e,f){d.$$addBindingInfo(e,f.ngBindHtml);c.$watch(h,function(){e.html(a.getTrustedHtml(g(c))||"")})}}}}],Zd=ic("",!0),ae=ic("Odd",0),$d=ic("Even",1),be=Ia({compile:function(a,c){c.$set("ngCloak",u);a.removeClass("ng-cloak")}}),ce=[function(){return{restrict:"A",scope:!0,controller:"@",priority:500}}],Ac={},Zf={blur:!0,focus:!0};r("click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste".split(" "), function(a){var c=wa("ng-"+a);Ac[c]=["$parse","$rootScope",function(d,e){return{restrict:"A",compile:function(f,g){var h=d(g[c],null,!0);return function(c,d){d.on(a,function(d){var f=function(){h(c,{$event:d})};Zf[a]&&e.$$phase?c.$evalAsync(f):c.$apply(f)})}}}}]});var fe=["$animate",function(a){return{multiElement:!0,transclude:"element",priority:600,terminal:!0,restrict:"A",$$tlb:!0,link:function(c,d,e,f,g){var h,k,l;c.$watch(e.ngIf,function(c){c?k||g(function(c,f){k=f;c[c.length++]=V.createComment(" end ngIf: "+ e.ngIf+" ");h={clone:c};a.enter(c,d.parent(),d)}):(l&&(l.remove(),l=null),k&&(k.$destroy(),k=null),h&&(l=qb(h.clone),a.leave(l).then(function(){l=null}),h=null))})}}}],ge=["$templateRequest","$anchorScroll","$animate","$sce",function(a,c,d,e){return{restrict:"ECA",priority:400,terminal:!0,transclude:"element",controller:ha.noop,compile:function(f,g){var h=g.ngInclude||g.src,k=g.onload||"",l=g.autoscroll;return function(f,g,s,r,q){var u=0,n,v,w,O=function(){v&&(v.remove(),v=null);n&&(n.$destroy(), n=null);w&&(d.leave(w).then(function(){v=null}),v=w,w=null)};f.$watch(e.parseAsResourceUrl(h),function(e){var h=function(){!y(l)||l&&!f.$eval(l)||c()},s=++u;e?(a(e,!0).then(function(a){if(s===u){var c=f.$new();r.template=a;a=q(c,function(a){O();d.enter(a,null,g).then(h)});n=c;w=a;n.$emit("$includeContentLoaded",e);f.$eval(k)}},function(){s===u&&(O(),f.$emit("$includeContentError",e))}),f.$emit("$includeContentRequested",e)):(O(),r.template=null)})}}}}],xe=["$compile",function(a){return{restrict:"ECA", priority:-400,require:"ngInclude",link:function(c,d,e,f){/SVG/.test(d[0].toString())?(d.empty(),a(Dc(f.template,V).childNodes)(c,function(a){d.append(a)},{futureParentElement:d})):(d.html(f.template),a(d.contents())(c))}}}],he=Ia({priority:450,compile:function(){return{pre:function(a,c,d){a.$eval(d.ngInit)}}}}),ie=Ia({terminal:!0,priority:1E3}),je=["$locale","$interpolate",function(a,c){var d=/{}/g,e=/^when(Minus)?(.+)$/;return{restrict:"EA",link:function(f,g,h){function k(a){g.text(a||"")}var l= h.count,m=h.$attr.when&&g.attr(h.$attr.when),p=h.offset||0,s=f.$eval(m)||{},t={},m=c.startSymbol(),q=c.endSymbol(),u=m+l+"-"+p+q,n=ha.noop,v;r(h,function(a,c){var d=e.exec(c);d&&(d=(d[1]?"-":"")+R(d[2]),s[d]=g.attr(h.$attr[c]))});r(s,function(a,e){t[e]=c(a.replace(d,u))});f.$watch(l,function(c){c=parseFloat(c);var d=isNaN(c);d||c in s||(c=a.pluralCat(c-p));c===v||d&&isNaN(v)||(n(),n=f.$watch(t[c],k),v=c)})}}}],ke=["$parse","$animate",function(a,c){var d=z("ngRepeat"),e=function(a,c,d,e,l,m,p){a[d]= e;l&&(a[l]=m);a.$index=c;a.$first=0===c;a.$last=c===p-1;a.$middle=!(a.$first||a.$last);a.$odd=!(a.$even=0===(c&1))};return{restrict:"A",multiElement:!0,transclude:"element",priority:1E3,terminal:!0,$$tlb:!0,compile:function(f,g){var h=g.ngRepeat,k=V.createComment(" end ngRepeat: "+h+" "),l=h.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+track\s+by\s+([\s\S]+?))?\s*$/);if(!l)throw d("iexp",h);var m=l[1],p=l[2],s=l[3],t=l[4],l=m.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/); if(!l)throw d("iidexp",m);var q=l[3]||l[1],y=l[2];if(s&&(!/^[$a-zA-Z_][$a-zA-Z0-9_]*$/.test(s)||/^(null|undefined|this|\$index|\$first|\$middle|\$last|\$even|\$odd|\$parent)$/.test(s)))throw d("badident",s);var n,v,w,z,E={$id:Ma};t?n=a(t):(w=function(a,c){return Ma(c)},z=function(a){return a});return function(a,f,g,l,m){n&&(v=function(c,d,e){y&&(E[y]=c);E[q]=d;E.$index=e;return n(a,E)});var t=ia();a.$watchCollection(p,function(g){var l,n,p=f[0],B,E=ia(),C,x,G,T,D,F,I;s&&(a[s]=g);if(Ra(g))D=g,n=v|| w;else{n=v||z;D=[];for(I in g)g.hasOwnProperty(I)&&"$"!=I.charAt(0)&&D.push(I);D.sort()}C=D.length;I=Array(C);for(l=0;lD;)d=q.pop(),m(Q,d.label,!1),d.element.remove();r(Q,function(a,c){0a&&s.removeOption(c)})}for(;R.length>x;)R.pop()[0].element.remove()}var p;if(!(p=q.match(d)))throw $f("iexp",q,va(f));var E=c(p[2]|| p[1]),x=p[4]||p[6],A=/ as /.test(p[0])&&p[1],C=A?c(A):null,G=p[5],I=c(p[3]||""),H=c(p[2]?p[1]:x),M=c(p[7]),K=p[8]?c(p[8]):null,S={},R=[[{element:f,label:""}]],U={};z&&(a(z)(e),z.removeClass("ng-scope"),z.remove());f.empty();f.on("change",function(){e.$apply(function(){var a=M(e)||[],c;if(t)c=[],r(f.val(),function(d){d=K?S[d]:d;c.push("?"===d?u:""===d?null:h(C?C:H,d,a[d]))});else{var d=K?S[f.val()]:f.val();c="?"===d?u:""===d?null:h(C?C:H,d,a[d])}g.$setViewValue(c);n()})});g.$render=n;e.$watchCollection(M, l);e.$watchCollection(function(){var a=M(e),c;if(a&&D(a)){c=Array(a.length);for(var d=0,f=a.length;d@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide:not(.ng-hide-animate){display:none !important;}ng\\:form{display:block;}'); //# sourceMappingURL=angular.min.js.map /* AngularJS v1.3.4 (c) 2010-2014 Google, Inc. http://angularjs.org License: MIT */ (function(p,d,C){'use strict';function v(r,h,g){return{restrict:"ECA",terminal:!0,priority:400,transclude:"element",link:function(a,c,b,f,y){function z(){k&&(g.cancel(k),k=null);l&&(l.$destroy(),l=null);m&&(k=g.leave(m),k.then(function(){k=null}),m=null)}function x(){var b=r.current&&r.current.locals;if(d.isDefined(b&&b.$template)){var b=a.$new(),f=r.current;m=y(b,function(b){g.enter(b,null,m||c).then(function(){!d.isDefined(t)||t&&!a.$eval(t)||h()});z()});l=f.scope=b;l.$emit("$viewContentLoaded"); l.$eval(w)}else z()}var l,m,k,t=b.autoscroll,w=b.onload||"";a.$on("$routeChangeSuccess",x);x()}}}function A(d,h,g){return{restrict:"ECA",priority:-400,link:function(a,c){var b=g.current,f=b.locals;c.html(f.$template);var y=d(c.contents());b.controller&&(f.$scope=a,f=h(b.controller,f),b.controllerAs&&(a[b.controllerAs]=f),c.data("$ngControllerController",f),c.children().data("$ngControllerController",f));y(a)}}}p=d.module("ngRoute",["ng"]).provider("$route",function(){function r(a,c){return d.extend(Object.create(a), c)}function h(a,d){var b=d.caseInsensitiveMatch,f={originalPath:a,regexp:a},g=f.keys=[];a=a.replace(/([().])/g,"\\$1").replace(/(\/)?:(\w+)([\?\*])?/g,function(a,d,b,c){a="?"===c?c:null;c="*"===c?c:null;g.push({name:b,optional:!!a});d=d||"";return""+(a?"":d)+"(?:"+(a?d:"")+(c&&"(.+?)"||"([^/]+)")+(a||"")+")"+(a||"")}).replace(/([\/$\*])/g,"\\$1");f.regexp=new RegExp("^"+a+"$",b?"i":"");return f}var g={};this.when=function(a,c){var b=d.copy(c);d.isUndefined(b.reloadOnSearch)&&(b.reloadOnSearch=!0); d.isUndefined(b.caseInsensitiveMatch)&&(b.caseInsensitiveMatch=this.caseInsensitiveMatch);g[a]=d.extend(b,a&&h(a,b));if(a){var f="/"==a[a.length-1]?a.substr(0,a.length-1):a+"/";g[f]=d.extend({redirectTo:a},h(f,b))}return this};this.caseInsensitiveMatch=!1;this.otherwise=function(a){"string"===typeof a&&(a={redirectTo:a});this.when(null,a);return this};this.$get=["$rootScope","$location","$routeParams","$q","$injector","$templateRequest","$sce",function(a,c,b,f,h,p,x){function l(b){var e=s.current; (v=(n=k())&&e&&n.$$route===e.$$route&&d.equals(n.pathParams,e.pathParams)&&!n.reloadOnSearch&&!w)||!e&&!n||a.$broadcast("$routeChangeStart",n,e).defaultPrevented&&b&&b.preventDefault()}function m(){var u=s.current,e=n;if(v)u.params=e.params,d.copy(u.params,b),a.$broadcast("$routeUpdate",u);else if(e||u)w=!1,(s.current=e)&&e.redirectTo&&(d.isString(e.redirectTo)?c.path(t(e.redirectTo,e.params)).search(e.params).replace():c.url(e.redirectTo(e.pathParams,c.path(),c.search())).replace()),f.when(e).then(function(){if(e){var a= d.extend({},e.resolve),b,c;d.forEach(a,function(b,e){a[e]=d.isString(b)?h.get(b):h.invoke(b,null,null,e)});d.isDefined(b=e.template)?d.isFunction(b)&&(b=b(e.params)):d.isDefined(c=e.templateUrl)&&(d.isFunction(c)&&(c=c(e.params)),c=x.getTrustedResourceUrl(c),d.isDefined(c)&&(e.loadedTemplateUrl=c,b=p(c)));d.isDefined(b)&&(a.$template=b);return f.all(a)}}).then(function(c){e==s.current&&(e&&(e.locals=c,d.copy(e.params,b)),a.$broadcast("$routeChangeSuccess",e,u))},function(b){e==s.current&&a.$broadcast("$routeChangeError", e,u,b)})}function k(){var a,b;d.forEach(g,function(f,g){var q;if(q=!b){var h=c.path();q=f.keys;var l={};if(f.regexp)if(h=f.regexp.exec(h)){for(var k=1,m=h.length;k> 1; if (value < data[mid][0]) high = mid; else low = mid + 1; } return low; } }; /** * Initialises a new TimeSeries with optional data options. * * Options are of the form (defaults shown): * *
   * {
   *   resetBounds: true,        // enables/disables automatic scaling of the y-axis
   *   resetBoundsInterval: 3000 // the period between scaling calculations, in millis
   * }
   * 
* * Presentation options for TimeSeries are specified as an argument to SmoothieChart.addTimeSeries. * * @constructor */ function TimeSeries(options) { this.options = Util.extend({}, TimeSeries.defaultOptions, options); this.clear(); } TimeSeries.defaultOptions = { resetBoundsInterval: 3000, resetBounds: true }; /** * Clears all data and state from this TimeSeries object. */ TimeSeries.prototype.clear = function() { this.data = []; this.maxValue = Number.NaN; // The maximum value ever seen in this TimeSeries. this.minValue = Number.NaN; // The minimum value ever seen in this TimeSeries. }; /** * Recalculate the min/max values for this TimeSeries object. * * This causes the graph to scale itself in the y-axis. */ TimeSeries.prototype.resetBounds = function() { if (this.data.length) { // Walk through all data points, finding the min/max value this.maxValue = this.data[0][1]; this.minValue = this.data[0][1]; for (var i = 1; i < this.data.length; i++) { var value = this.data[i][1]; if (value > this.maxValue) { this.maxValue = value; } if (value < this.minValue) { this.minValue = value; } } } else { // No data exists, so set min/max to NaN this.maxValue = Number.NaN; this.minValue = Number.NaN; } }; /** * Adds a new data point to the TimeSeries, preserving chronological order. * * @param timestamp the position, in time, of this data point * @param value the value of this data point * @param sumRepeatedTimeStampValues if timestamp has an exact match in the series, this flag controls * whether it is replaced, or the values summed (defaults to false.) */ TimeSeries.prototype.append = function(timestamp, value, sumRepeatedTimeStampValues) { // Rewind until we hit an older timestamp var i = this.data.length - 1; while (i >= 0 && this.data[i][0] > timestamp) { i--; } if (i === -1) { // This new item is the oldest data this.data.splice(0, 0, [timestamp, value]); } else if (this.data.length > 0 && this.data[i][0] === timestamp) { // Update existing values in the array if (sumRepeatedTimeStampValues) { // Sum this value into the existing 'bucket' this.data[i][1] += value; value = this.data[i][1]; } else { // Replace the previous value this.data[i][1] = value; } } else if (i < this.data.length - 1) { // Splice into the correct position to keep timestamps in order this.data.splice(i + 1, 0, [timestamp, value]); } else { // Add to the end of the array this.data.push([timestamp, value]); } this.maxValue = isNaN(this.maxValue) ? value : Math.max(this.maxValue, value); this.minValue = isNaN(this.minValue) ? value : Math.min(this.minValue, value); }; TimeSeries.prototype.dropOldData = function(oldestValidTime, maxDataSetLength) { // We must always keep one expired data point as we need this to draw the // line that comes into the chart from the left, but any points prior to that can be removed. var removeCount = 0; while (this.data.length - removeCount >= maxDataSetLength && this.data[removeCount + 1][0] < oldestValidTime) { removeCount++; } if (removeCount !== 0) { this.data.splice(0, removeCount); } }; /** * Initialises a new SmoothieChart. * * Options are optional, and should be of the form below. Just specify the values you * need and the rest will be given sensible defaults as shown: * *
   * {
   *   minValue: undefined,                      // specify to clamp the lower y-axis to a given value
   *   maxValue: undefined,                      // specify to clamp the upper y-axis to a given value
   *   maxValueScale: 1,                         // allows proportional padding to be added above the chart. for 10% padding, specify 1.1.
   *   minValueScale: 1,                         // allows proportional padding to be added below the chart. for 10% padding, specify 1.1.
   *   yRangeFunction: undefined,                // function({min: , max: }) { return {min: , max: }; }
   *   scaleSmoothing: 0.125,                    // controls the rate at which y-value zoom animation occurs
   *   millisPerPixel: 20,                       // sets the speed at which the chart pans by
   *   enableDpiScaling: true,                   // support rendering at different DPI depending on the device
   *   yMinFormatter: function(min, precision) { // callback function that formats the min y value label
   *     return parseFloat(min).toFixed(precision);
   *   },
   *   yMaxFormatter: function(max, precision) { // callback function that formats the max y value label
   *     return parseFloat(max).toFixed(precision);
   *   },
   *   maxDataSetLength: 2,
   *   interpolation: 'bezier'                   // one of 'bezier', 'linear', or 'step'
   *   timestampFormatter: null,                 // optional function to format time stamps for bottom of chart
   *                                             // you may use SmoothieChart.timeFormatter, or your own: function(date) { return ''; }
   *   scrollBackwards: false,                   // reverse the scroll direction of the chart
   *   horizontalLines: [],                      // [ { value: 0, color: '#ffffff', lineWidth: 1 } ]
   *   grid:
   *   {
   *     fillStyle: '#000000',                   // the background colour of the chart
   *     lineWidth: 1,                           // the pixel width of grid lines
   *     strokeStyle: '#777777',                 // colour of grid lines
   *     millisPerLine: 1000,                    // distance between vertical grid lines
   *     sharpLines: false,                      // controls whether grid lines are 1px sharp, or softened
   *     verticalSections: 2,                    // number of vertical sections marked out by horizontal grid lines
   *     borderVisible: true                     // whether the grid lines trace the border of the chart or not
   *   },
   *   labels
   *   {
   *     disabled: false,                        // enables/disables labels showing the min/max values
   *     fillStyle: '#ffffff',                   // colour for text of labels,
   *     fontSize: 15,
   *     fontFamily: 'sans-serif',
   *     precision: 2
   *   },
   *   tooltip: false                            // show tooltip when mouse is over the chart
   *   tooltipLine: {                            // properties for a vertical line at the cursor position
   *     lineWidth: 1,
   *     strokeStyle: '#BBBBBB'
   *   },
   *   tooltipFormatter: SmoothieChart.tooltipFormatter, // formatter function for tooltip text
   *   responsive: false,                        // whether the chart should adapt to the size of the canvas
   *   limitFPS: 0                         // maximum frame rate the chart will render at, in FPS (zero means no limit)
   * }
   * 
* * @constructor */ function SmoothieChart(options) { this.options = Util.extend({}, SmoothieChart.defaultChartOptions, options); this.seriesSet = []; this.currentValueRange = 1; this.currentVisMinValue = 0; this.lastRenderTimeMillis = 0; this.mousemove = this.mousemove.bind(this); this.mouseout = this.mouseout.bind(this); } /** Formats the HTML string content of the tooltip. */ SmoothieChart.tooltipFormatter = function (timestamp, data) { var timestampFormatter = this.options.timestampFormatter || SmoothieChart.timeFormatter, lines = [timestampFormatter(new Date(timestamp))]; for (var i = 0; i < data.length; ++i) { lines.push('' + this.options.yMaxFormatter(data[i].value, this.options.labels.precision) + ''); } return lines.join('
'); }; SmoothieChart.defaultChartOptions = { millisPerPixel: 20, enableDpiScaling: true, yMinFormatter: function(min, precision) { return parseFloat(min).toFixed(precision); }, yMaxFormatter: function(max, precision) { return parseFloat(max).toFixed(precision); }, maxValueScale: 1, minValueScale: 1, interpolation: 'bezier', scaleSmoothing: 0.125, maxDataSetLength: 2, scrollBackwards: false, grid: { fillStyle: '#000000', strokeStyle: '#777777', lineWidth: 1, sharpLines: false, millisPerLine: 1000, verticalSections: 2, borderVisible: true }, labels: { fillStyle: '#ffffff', disabled: false, fontSize: 10, fontFamily: 'monospace', precision: 2 }, horizontalLines: [], tooltip: false, tooltipLine: { lineWidth: 1, strokeStyle: '#BBBBBB' }, tooltipFormatter: SmoothieChart.tooltipFormatter, responsive: false, limitFPS: 0 }; // Based on http://inspirit.github.com/jsfeat/js/compatibility.js SmoothieChart.AnimateCompatibility = (function() { var requestAnimationFrame = function(callback, element) { var requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback) { return window.setTimeout(function() { callback(Date.now()); }, 16); }; return requestAnimationFrame.call(window, callback, element); }, cancelAnimationFrame = function(id) { var cancelAnimationFrame = window.cancelAnimationFrame || function(id) { clearTimeout(id); }; return cancelAnimationFrame.call(window, id); }; return { requestAnimationFrame: requestAnimationFrame, cancelAnimationFrame: cancelAnimationFrame }; })(); SmoothieChart.defaultSeriesPresentationOptions = { lineWidth: 1, strokeStyle: '#ffffff' }; /** * Adds a TimeSeries to this chart, with optional presentation options. * * Presentation options should be of the form (defaults shown): * *
   * {
   *   lineWidth: 1,
   *   strokeStyle: '#ffffff',
   *   fillStyle: undefined
   * }
   * 
*/ SmoothieChart.prototype.addTimeSeries = function(timeSeries, options) { this.seriesSet.push({timeSeries: timeSeries, options: Util.extend({}, SmoothieChart.defaultSeriesPresentationOptions, options)}); if (timeSeries.options.resetBounds && timeSeries.options.resetBoundsInterval > 0) { timeSeries.resetBoundsTimerId = setInterval( function() { timeSeries.resetBounds(); }, timeSeries.options.resetBoundsInterval ); } }; /** * Removes the specified TimeSeries from the chart. */ SmoothieChart.prototype.removeTimeSeries = function(timeSeries) { // Find the correct timeseries to remove, and remove it var numSeries = this.seriesSet.length; for (var i = 0; i < numSeries; i++) { if (this.seriesSet[i].timeSeries === timeSeries) { this.seriesSet.splice(i, 1); break; } } // If a timer was operating for that timeseries, remove it if (timeSeries.resetBoundsTimerId) { // Stop resetting the bounds, if we were clearInterval(timeSeries.resetBoundsTimerId); } }; /** * Gets render options for the specified TimeSeries. * * As you may use a single TimeSeries in multiple charts with different formatting in each usage, * these settings are stored in the chart. */ SmoothieChart.prototype.getTimeSeriesOptions = function(timeSeries) { // Find the correct timeseries to remove, and remove it var numSeries = this.seriesSet.length; for (var i = 0; i < numSeries; i++) { if (this.seriesSet[i].timeSeries === timeSeries) { return this.seriesSet[i].options; } } }; /** * Brings the specified TimeSeries to the top of the chart. It will be rendered last. */ SmoothieChart.prototype.bringToFront = function(timeSeries) { // Find the correct timeseries to remove, and remove it var numSeries = this.seriesSet.length; for (var i = 0; i < numSeries; i++) { if (this.seriesSet[i].timeSeries === timeSeries) { var set = this.seriesSet.splice(i, 1); this.seriesSet.push(set[0]); break; } } }; /** * Instructs the SmoothieChart to start rendering to the provided canvas, with specified delay. * * @param canvas the target canvas element * @param delayMillis an amount of time to wait before a data point is shown. This can prevent the end of the series * from appearing on screen, with new values flashing into view, at the expense of some latency. */ SmoothieChart.prototype.streamTo = function(canvas, delayMillis) { this.canvas = canvas; this.delay = delayMillis; this.start(); }; SmoothieChart.prototype.getTooltipEl = function () { // Create the tool tip element lazily if (!this.tooltipEl) { this.tooltipEl = document.createElement('div'); this.tooltipEl.className = 'smoothie-chart-tooltip'; this.tooltipEl.style.position = 'absolute'; this.tooltipEl.style.display = 'none'; document.body.appendChild(this.tooltipEl); } return this.tooltipEl; }; SmoothieChart.prototype.updateTooltip = function () { var el = this.getTooltipEl(); if (!this.mouseover || !this.options.tooltip) { el.style.display = 'none'; return; } var time = this.lastRenderTimeMillis - (this.delay || 0); // Round time down to pixel granularity, so motion appears smoother. time -= time % this.options.millisPerPixel; // x pixel to time var t = this.options.scrollBackwards ? time - this.mouseX * this.options.millisPerPixel : time - (this.canvas.offsetWidth - this.mouseX) * this.options.millisPerPixel; var data = []; // For each data set... for (var d = 0; d < this.seriesSet.length; d++) { var timeSeries = this.seriesSet[d].timeSeries, // find datapoint closest to time 't' closeIdx = Util.binarySearch(timeSeries.data, t); if (closeIdx > 0 && closeIdx < timeSeries.data.length) { data.push({ series: this.seriesSet[d], index: closeIdx, value: timeSeries.data[closeIdx][1] }); } } if (data.length) { el.innerHTML = this.options.tooltipFormatter.call(this, t, data); el.style.display = 'block'; } else { el.style.display = 'none'; } }; SmoothieChart.prototype.mousemove = function (evt) { this.mouseover = true; this.mouseX = evt.offsetX; this.mouseY = evt.offsetY; this.mousePageX = evt.pageX; this.mousePageY = evt.pageY; var el = this.getTooltipEl(); el.style.top = Math.round(this.mousePageY) + 'px'; el.style.left = Math.round(this.mousePageX) + 'px'; this.updateTooltip(); }; SmoothieChart.prototype.mouseout = function () { this.mouseover = false; this.mouseX = this.mouseY = -1; if (SmoothieChart.tooltipEl) SmoothieChart.tooltipEl.style.display = 'none'; }; /** * Make sure the canvas has the optimal resolution for the device's pixel ratio. */ SmoothieChart.prototype.resize = function () { var dpr = !this.options.enableDpiScaling || !window ? 1 : window.devicePixelRatio, width, height; if (this.options.responsive) { // Newer behaviour: Use the canvas's size in the layout, and set the internal // resolution according to that size and the device pixel ratio (eg: high DPI) width = this.canvas.offsetWidth; height = this.canvas.offsetHeight; if (width !== this.lastWidth) { this.lastWidth = width; this.canvas.setAttribute('width', (Math.floor(width * dpr)).toString()); } if (height !== this.lastHeight) { this.lastHeight = height; this.canvas.setAttribute('height', (Math.floor(height * dpr)).toString()); } } else if (dpr !== 1) { // Older behaviour: use the canvas's inner dimensions and scale the element's size // according to that size and the device pixel ratio (eg: high DPI) width = parseInt(this.canvas.getAttribute('width')); height = parseInt(this.canvas.getAttribute('height')); if (!this.originalWidth || (Math.floor(this.originalWidth * dpr) !== width)) { this.originalWidth = width; this.canvas.setAttribute('width', (Math.floor(width * dpr)).toString()); this.canvas.style.width = width + 'px'; this.canvas.getContext('2d').scale(dpr, dpr); } if (!this.originalHeight || (Math.floor(this.originalHeight * dpr) !== height)) { this.originalHeight = height; this.canvas.setAttribute('height', (Math.floor(height * dpr)).toString()); this.canvas.style.height = height + 'px'; this.canvas.getContext('2d').scale(dpr, dpr); } } }; /** * Starts the animation of this chart. */ SmoothieChart.prototype.start = function() { if (this.frame) { // We're already running, so just return return; } this.canvas.addEventListener('mousemove', this.mousemove); this.canvas.addEventListener('mouseout', this.mouseout); // Renders a frame, and queues the next frame for later rendering var animate = function() { this.frame = SmoothieChart.AnimateCompatibility.requestAnimationFrame(function() { this.render(); animate(); }.bind(this)); }.bind(this); animate(); }; /** * Stops the animation of this chart. */ SmoothieChart.prototype.stop = function() { if (this.frame) { SmoothieChart.AnimateCompatibility.cancelAnimationFrame(this.frame); delete this.frame; this.canvas.removeEventListener('mousemove', this.mousemove); this.canvas.removeEventListener('mouseout', this.mouseout); } }; SmoothieChart.prototype.updateValueRange = function() { // Calculate the current scale of the chart, from all time series. var chartOptions = this.options, chartMaxValue = Number.NaN, chartMinValue = Number.NaN; for (var d = 0; d < this.seriesSet.length; d++) { // TODO(ndunn): We could calculate / track these values as they stream in. var timeSeries = this.seriesSet[d].timeSeries; if (!isNaN(timeSeries.maxValue)) { chartMaxValue = !isNaN(chartMaxValue) ? Math.max(chartMaxValue, timeSeries.maxValue) : timeSeries.maxValue; } if (!isNaN(timeSeries.minValue)) { chartMinValue = !isNaN(chartMinValue) ? Math.min(chartMinValue, timeSeries.minValue) : timeSeries.minValue; } } // Scale the chartMaxValue to add padding at the top if required if (chartOptions.maxValue != null) { chartMaxValue = chartOptions.maxValue; } else { chartMaxValue *= chartOptions.maxValueScale; } // Set the minimum if we've specified one if (chartOptions.minValue != null) { chartMinValue = chartOptions.minValue; } else { chartMinValue -= Math.abs(chartMinValue * chartOptions.minValueScale - chartMinValue); } // If a custom range function is set, call it if (this.options.yRangeFunction) { var range = this.options.yRangeFunction({min: chartMinValue, max: chartMaxValue}); chartMinValue = range.min; chartMaxValue = range.max; } if (!isNaN(chartMaxValue) && !isNaN(chartMinValue)) { var targetValueRange = chartMaxValue - chartMinValue; var valueRangeDiff = (targetValueRange - this.currentValueRange); var minValueDiff = (chartMinValue - this.currentVisMinValue); this.isAnimatingScale = Math.abs(valueRangeDiff) > 0.1 || Math.abs(minValueDiff) > 0.1; this.currentValueRange += chartOptions.scaleSmoothing * valueRangeDiff; this.currentVisMinValue += chartOptions.scaleSmoothing * minValueDiff; } this.valueRange = { min: chartMinValue, max: chartMaxValue }; }; SmoothieChart.prototype.render = function(canvas, time) { var nowMillis = Date.now(); // Respect any frame rate limit. if (this.options.limitFPS > 0 && nowMillis - this.lastRenderTimeMillis < (1000/this.options.limitFPS)) return; if (!this.isAnimatingScale) { // We're not animating. We can use the last render time and the scroll speed to work out whether // we actually need to paint anything yet. If not, we can return immediately. // Render at least every 1/6th of a second. The canvas may be resized, which there is // no reliable way to detect. var maxIdleMillis = Math.min(1000/6, this.options.millisPerPixel); if (nowMillis - this.lastRenderTimeMillis < maxIdleMillis) { return; } } this.resize(); this.updateTooltip(); this.lastRenderTimeMillis = nowMillis; canvas = canvas || this.canvas; time = time || nowMillis - (this.delay || 0); // Round time down to pixel granularity, so motion appears smoother. time -= time % this.options.millisPerPixel; var context = canvas.getContext('2d'), chartOptions = this.options, dimensions = { top: 0, left: 0, width: canvas.clientWidth, height: canvas.clientHeight }, // Calculate the threshold time for the oldest data points. oldestValidTime = time - (dimensions.width * chartOptions.millisPerPixel), valueToYPixel = function(value) { var offset = value - this.currentVisMinValue; return this.currentValueRange === 0 ? dimensions.height : dimensions.height - (Math.round((offset / this.currentValueRange) * dimensions.height)); }.bind(this), timeToXPixel = function(t) { if(chartOptions.scrollBackwards) { return Math.round((time - t) / chartOptions.millisPerPixel); } return Math.round(dimensions.width - ((time - t) / chartOptions.millisPerPixel)); }; this.updateValueRange(); context.font = chartOptions.labels.fontSize + 'px ' + chartOptions.labels.fontFamily; // Save the state of the canvas context, any transformations applied in this method // will get removed from the stack at the end of this method when .restore() is called. context.save(); // Move the origin. context.translate(dimensions.left, dimensions.top); // Create a clipped rectangle - anything we draw will be constrained to this rectangle. // This prevents the occasional pixels from curves near the edges overrunning and creating // screen cheese (that phrase should need no explanation). context.beginPath(); context.rect(0, 0, dimensions.width, dimensions.height); context.clip(); // Clear the working area. context.save(); context.fillStyle = chartOptions.grid.fillStyle; context.clearRect(0, 0, dimensions.width, dimensions.height); context.fillRect(0, 0, dimensions.width, dimensions.height); context.restore(); // Grid lines... context.save(); context.lineWidth = chartOptions.grid.lineWidth; context.strokeStyle = chartOptions.grid.strokeStyle; // Vertical (time) dividers. if (chartOptions.grid.millisPerLine > 0) { context.beginPath(); for (var t = time - (time % chartOptions.grid.millisPerLine); t >= oldestValidTime; t -= chartOptions.grid.millisPerLine) { var gx = timeToXPixel(t); if (chartOptions.grid.sharpLines) { gx -= 0.5; } context.moveTo(gx, 0); context.lineTo(gx, dimensions.height); } context.stroke(); context.closePath(); } // Horizontal (value) dividers. for (var v = 1; v < chartOptions.grid.verticalSections; v++) { var gy = Math.round(v * dimensions.height / chartOptions.grid.verticalSections); if (chartOptions.grid.sharpLines) { gy -= 0.5; } context.beginPath(); context.moveTo(0, gy); context.lineTo(dimensions.width, gy); context.stroke(); context.closePath(); } // Bounding rectangle. if (chartOptions.grid.borderVisible) { context.beginPath(); context.strokeRect(0, 0, dimensions.width, dimensions.height); context.closePath(); } context.restore(); // Draw any horizontal lines... if (chartOptions.horizontalLines && chartOptions.horizontalLines.length) { for (var hl = 0; hl < chartOptions.horizontalLines.length; hl++) { var line = chartOptions.horizontalLines[hl], hly = Math.round(valueToYPixel(line.value)) - 0.5; context.strokeStyle = line.color || '#ffffff'; context.lineWidth = line.lineWidth || 1; context.beginPath(); context.moveTo(0, hly); context.lineTo(dimensions.width, hly); context.stroke(); context.closePath(); } } // For each data set... for (var d = 0; d < this.seriesSet.length; d++) { context.save(); var timeSeries = this.seriesSet[d].timeSeries, dataSet = timeSeries.data, seriesOptions = this.seriesSet[d].options; // Delete old data that's moved off the left of the chart. timeSeries.dropOldData(oldestValidTime, chartOptions.maxDataSetLength); // Set style for this dataSet. context.lineWidth = seriesOptions.lineWidth; context.strokeStyle = seriesOptions.strokeStyle; // Draw the line... context.beginPath(); // Retain lastX, lastY for calculating the control points of bezier curves. var firstX = 0, lastX = 0, lastY = 0; for (var i = 0; i < dataSet.length && dataSet.length !== 1; i++) { var x = timeToXPixel(dataSet[i][0]), y = valueToYPixel(dataSet[i][1]); if (i === 0) { firstX = x; context.moveTo(x, y); } else { switch (chartOptions.interpolation) { case "linear": case "line": { context.lineTo(x,y); break; } case "bezier": default: { // Great explanation of Bezier curves: http://en.wikipedia.org/wiki/Bezier_curve#Quadratic_curves // // Assuming A was the last point in the line plotted and B is the new point, // we draw a curve with control points P and Q as below. // // A---P // | // | // | // Q---B // // Importantly, A and P are at the same y coordinate, as are B and Q. This is // so adjacent curves appear to flow as one. // context.bezierCurveTo( // startPoint (A) is implicit from last iteration of loop Math.round((lastX + x) / 2), lastY, // controlPoint1 (P) Math.round((lastX + x)) / 2, y, // controlPoint2 (Q) x, y); // endPoint (B) break; } case "step": { context.lineTo(x,lastY); context.lineTo(x,y); break; } } } lastX = x; lastY = y; } if (dataSet.length > 1) { if (seriesOptions.fillStyle) { // Close up the fill region. context.lineTo(dimensions.width + seriesOptions.lineWidth + 1, lastY); context.lineTo(dimensions.width + seriesOptions.lineWidth + 1, dimensions.height + seriesOptions.lineWidth + 1); context.lineTo(firstX, dimensions.height + seriesOptions.lineWidth); context.fillStyle = seriesOptions.fillStyle; context.fill(); } if (seriesOptions.strokeStyle && seriesOptions.strokeStyle !== 'none') { context.stroke(); } context.closePath(); } context.restore(); } if (chartOptions.tooltip && this.mouseX >= 0) { // Draw vertical bar to show tooltip position context.lineWidth = chartOptions.tooltipLine.lineWidth; context.strokeStyle = chartOptions.tooltipLine.strokeStyle; context.beginPath(); context.moveTo(this.mouseX, 0); context.lineTo(this.mouseX, dimensions.height); context.closePath(); context.stroke(); this.updateTooltip(); } // Draw the axis values on the chart. if (!chartOptions.labels.disabled && !isNaN(this.valueRange.min) && !isNaN(this.valueRange.max)) { var maxValueString = chartOptions.yMaxFormatter(this.valueRange.max, chartOptions.labels.precision), minValueString = chartOptions.yMinFormatter(this.valueRange.min, chartOptions.labels.precision), maxLabelPos = chartOptions.scrollBackwards ? 0 : dimensions.width - context.measureText(maxValueString).width - 2, minLabelPos = chartOptions.scrollBackwards ? 0 : dimensions.width - context.measureText(minValueString).width - 2; context.fillStyle = chartOptions.labels.fillStyle; context.fillText(maxValueString, maxLabelPos, chartOptions.labels.fontSize); context.fillText(minValueString, minLabelPos, dimensions.height - 2); } // Display timestamps along x-axis at the bottom of the chart. if (chartOptions.timestampFormatter && chartOptions.grid.millisPerLine > 0) { var textUntilX = chartOptions.scrollBackwards ? context.measureText(minValueString).width : dimensions.width - context.measureText(minValueString).width + 4; for (var t = time - (time % chartOptions.grid.millisPerLine); t >= oldestValidTime; t -= chartOptions.grid.millisPerLine) { var gx = timeToXPixel(t); // Only draw the timestamp if it won't overlap with the previously drawn one. if ((!chartOptions.scrollBackwards && gx < textUntilX) || (chartOptions.scrollBackwards && gx > textUntilX)) { // Formats the timestamp based on user specified formatting function // SmoothieChart.timeFormatter function above is one such formatting option var tx = new Date(t), ts = chartOptions.timestampFormatter(tx), tsWidth = context.measureText(ts).width; textUntilX = chartOptions.scrollBackwards ? gx + tsWidth + 2 : gx - tsWidth - 2; context.fillStyle = chartOptions.labels.fillStyle; if(chartOptions.scrollBackwards) { context.fillText(ts, gx, dimensions.height - 2); } else { context.fillText(ts, gx - tsWidth, dimensions.height - 2); } } } } context.restore(); // See .save() above. }; // Sample timestamp formatting function SmoothieChart.timeFormatter = function(date) { function pad2(number) { return (number < 10 ? '0' : '') + number } return pad2(date.getHours()) + ':' + pad2(date.getMinutes()) + ':' + pad2(date.getSeconds()); }; exports.TimeSeries = TimeSeries; exports.SmoothieChart = SmoothieChart; })(typeof exports === 'undefined' ? this : exports); /*! Sortable 1.7.0 - MIT | git://github.com/rubaxa/Sortable.git */ !function(a){"use strict";"function"==typeof define&&define.amd?define(a):"undefined"!=typeof module&&"undefined"!=typeof module.exports?module.exports=a():window.Sortable=a()}(function(){"use strict";function a(b,c){if(!b||!b.nodeType||1!==b.nodeType)throw"Sortable: `el` must be HTMLElement, and not "+{}.toString.call(b);this.el=b,this.options=c=t({},c),b[V]=this;var d={group:Math.random(),sort:!0,disabled:!1,store:null,handle:null,scroll:!0,scrollSensitivity:30,scrollSpeed:10,draggable:/[uo]l/i.test(b.nodeName)?"li":">*",ghostClass:"sortable-ghost",chosenClass:"sortable-chosen",dragClass:"sortable-drag",ignore:"a, img",filter:null,preventOnFilter:!0,animation:0,setData:function(a,b){a.setData("Text",b.textContent)},dropBubble:!1,dragoverBubble:!1,dataIdAttr:"data-id",delay:0,forceFallback:!1,fallbackClass:"sortable-fallback",fallbackOnBody:!1,fallbackTolerance:0,fallbackOffset:{x:0,y:0},supportPointer:a.supportPointer!==!1};for(var e in d)!(e in c)&&(c[e]=d[e]);ka(c);for(var g in this)"_"===g.charAt(0)&&"function"==typeof this[g]&&(this[g]=this[g].bind(this));this.nativeDraggable=!c.forceFallback&&ca,f(b,"mousedown",this._onTapStart),f(b,"touchstart",this._onTapStart),c.supportPointer&&f(b,"pointerdown",this._onTapStart),this.nativeDraggable&&(f(b,"dragover",this),f(b,"dragenter",this)),ia.push(this._onDragOver),c.store&&this.sort(c.store.get(this))}function b(a,b){"clone"!==a.lastPullMode&&(b=!0),B&&B.state!==b&&(i(B,"display",b?"none":""),b||B.state&&(a.options.group.revertClone?(C.insertBefore(B,D),a._animate(y,B)):C.insertBefore(B,y)),B.state=b)}function c(a,b,c){if(a){c=c||X;do if(">*"===b&&a.parentNode===c||r(a,b))return a;while(a=d(a))}return null}function d(a){var b=a.host;return b&&b.nodeType?b:a.parentNode}function e(a){a.dataTransfer&&(a.dataTransfer.dropEffect="move"),a.preventDefault()}function f(a,b,c){a.addEventListener(b,c,aa)}function g(a,b,c){a.removeEventListener(b,c,aa)}function h(a,b,c){if(a)if(a.classList)a.classList[c?"add":"remove"](b);else{var d=(" "+a.className+" ").replace(T," ").replace(" "+b+" "," ");a.className=(d+(c?" "+b:"")).replace(T," ")}}function i(a,b,c){var d=a&&a.style;if(d){if(void 0===c)return X.defaultView&&X.defaultView.getComputedStyle?c=X.defaultView.getComputedStyle(a,""):a.currentStyle&&(c=a.currentStyle),void 0===b?c:c[b];b in d||(b="-webkit-"+b),d[b]=c+("string"==typeof c?"":"px")}}function j(a,b,c){if(a){var d=a.getElementsByTagName(b),e=0,f=d.length;if(c)for(;e5||b.clientX-(d.left+d.width)>5}function p(a){for(var b=a.tagName+a.className+a.src+a.href+a.textContent,c=b.length,d=0;c--;)d+=b.charCodeAt(c);return d.toString(36)}function q(a,b){var c=0;if(!a||!a.parentNode)return-1;for(;a&&(a=a.previousElementSibling);)"TEMPLATE"===a.nodeName.toUpperCase()||">*"!==b&&!r(a,b)||c++;return c}function r(a,b){if(a){b=b.split(".");var c=b.shift().toUpperCase(),d=new RegExp("\\s("+b.join("|")+")(?=\\s)","g");return!(""!==c&&a.nodeName.toUpperCase()!=c||b.length&&((" "+a.className+" ").match(d)||[]).length!=b.length)}return!1}function s(a,b){var c,d;return function(){void 0===c&&(c=arguments,d=this,Z(function(){1===c.length?a.call(d,c[0]):a.apply(d,c),c=void 0},b))}}function t(a,b){if(a&&b)for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c]);return a}function u(a){return _&&_.dom?_.dom(a).cloneNode(!0):$?$(a).clone(!0)[0]:a.cloneNode(!0)}function v(a){for(var b=a.getElementsByTagName("input"),c=b.length;c--;){var d=b[c];d.checked&&ha.push(d)}}function w(a){return Z(a,0)}function x(a){return clearTimeout(a)}if("undefined"==typeof window||!window.document)return function(){throw new Error("Sortable.js requires a window with a document")};var y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S={},T=/\s+/g,U=/left|right|inline/,V="Sortable"+(new Date).getTime(),W=window,X=W.document,Y=W.parseInt,Z=W.setTimeout,$=W.jQuery||W.Zepto,_=W.Polymer,aa=!1,ba=!1,ca="draggable"in X.createElement("div"),da=function(a){return!navigator.userAgent.match(/(?:Trident.*rv[ :]?11\.|msie)/i)&&(a=X.createElement("x"),a.style.cssText="pointer-events:auto","auto"===a.style.pointerEvents)}(),ea=!1,fa=Math.abs,ga=Math.min,ha=[],ia=[],ja=s(function(a,b,c){if(c&&b.scroll){var d,e,f,g,h,i,j=c[V],k=b.scrollSensitivity,l=b.scrollSpeed,m=a.clientX,n=a.clientY,o=window.innerWidth,p=window.innerHeight;if(G!==c&&(F=b.scroll,G=c,H=b.scrollFn,F===!0)){F=c;do if(F.offsetWidth-1:e==a)}}var c={},d=a.group;d&&"object"==typeof d||(d={name:d}),c.name=d.name,c.checkPull=b(d.pull,!0),c.checkPut=b(d.put),c.revertClone=d.revertClone,a.group=c};try{window.addEventListener("test",null,Object.defineProperty({},"passive",{get:function(){ba=!1,aa={capture:!1,passive:ba}}}))}catch(a){}return a.prototype={constructor:a,_onTapStart:function(a){var b,d=this,e=this.el,f=this.options,g=f.preventOnFilter,h=a.type,i=a.touches&&a.touches[0],j=(i||a).target,l=a.target.shadowRoot&&a.path&&a.path[0]||j,m=f.filter;if(v(e),!y&&!(/mousedown|pointerdown/.test(h)&&0!==a.button||f.disabled)&&!l.isContentEditable&&(j=c(j,f.draggable,e),j&&E!==j)){if(b=q(j,f.draggable),"function"==typeof m){if(m.call(this,a,j,this))return k(d,l,"filter",j,e,e,b),void(g&&a.preventDefault())}else if(m&&(m=m.split(",").some(function(a){if(a=c(l,a.trim(),e))return k(d,a,"filter",j,e,e,b),!0})))return void(g&&a.preventDefault());f.handle&&!c(l,f.handle,e)||this._prepareDragStart(a,i,j,b)}},_prepareDragStart:function(a,b,c,d){var e,g=this,i=g.el,l=g.options,n=i.ownerDocument;c&&!y&&c.parentNode===i&&(P=a,C=i,y=c,z=y.parentNode,D=y.nextSibling,E=c,N=l.group,L=d,this._lastX=(b||a).clientX,this._lastY=(b||a).clientY,y.style["will-change"]="all",e=function(){g._disableDelayedDrag(),y.draggable=g.nativeDraggable,h(y,l.chosenClass,!0),g._triggerDragStart(a,b),k(g,C,"choose",y,C,C,L)},l.ignore.split(",").forEach(function(a){j(y,a.trim(),m)}),f(n,"mouseup",g._onDrop),f(n,"touchend",g._onDrop),f(n,"touchcancel",g._onDrop),f(n,"selectstart",g),l.supportPointer&&f(n,"pointercancel",g._onDrop),l.delay?(f(n,"mouseup",g._disableDelayedDrag),f(n,"touchend",g._disableDelayedDrag),f(n,"touchcancel",g._disableDelayedDrag),f(n,"mousemove",g._disableDelayedDrag),f(n,"touchmove",g._disableDelayedDrag),l.supportPointer&&f(n,"pointermove",g._disableDelayedDrag),g._dragStartTimer=Z(e,l.delay)):e())},_disableDelayedDrag:function(){var a=this.el.ownerDocument;clearTimeout(this._dragStartTimer),g(a,"mouseup",this._disableDelayedDrag),g(a,"touchend",this._disableDelayedDrag),g(a,"touchcancel",this._disableDelayedDrag),g(a,"mousemove",this._disableDelayedDrag),g(a,"touchmove",this._disableDelayedDrag),g(a,"pointermove",this._disableDelayedDrag)},_triggerDragStart:function(a,b){b=b||("touch"==a.pointerType?a:null),b?(P={target:y,clientX:b.clientX,clientY:b.clientY},this._onDragStart(P,"touch")):this.nativeDraggable?(f(y,"dragend",this),f(C,"dragstart",this._onDragStart)):this._onDragStart(P,!0);try{X.selection?w(function(){X.selection.empty()}):window.getSelection().removeAllRanges()}catch(a){}},_dragStarted:function(){if(C&&y){var b=this.options;h(y,b.ghostClass,!0),h(y,b.dragClass,!1),a.active=this,k(this,C,"start",y,C,C,L)}else this._nulling()},_emulateDragOver:function(){if(Q){if(this._lastX===Q.clientX&&this._lastY===Q.clientY)return;this._lastX=Q.clientX,this._lastY=Q.clientY,da||i(A,"display","none");var a=X.elementFromPoint(Q.clientX,Q.clientY),b=a,c=ia.length;if(a&&a.shadowRoot&&(a=a.shadowRoot.elementFromPoint(Q.clientX,Q.clientY),b=a),b)do{if(b[V]){for(;c--;)ia[c]({clientX:Q.clientX,clientY:Q.clientY,target:a,rootEl:b});break}a=b}while(b=b.parentNode);da||i(A,"display","")}},_onTouchMove:function(b){if(P){var c=this.options,d=c.fallbackTolerance,e=c.fallbackOffset,f=b.touches?b.touches[0]:b,g=f.clientX-P.clientX+e.x,h=f.clientY-P.clientY+e.y,j=b.touches?"translate3d("+g+"px,"+h+"px,0)":"translate("+g+"px,"+h+"px)";if(!a.active){if(d&&ga(fa(f.clientX-this._lastX),fa(f.clientY-this._lastY))y.offsetWidth,x=e.offsetHeight>y.offsetHeight,E=(v?(d.clientX-g.left)/t:(d.clientY-g.top)/u)>.5,F=e.nextElementSibling,G=!1;if(v){var H=y.offsetTop,L=e.offsetTop;G=H===L?e.previousElementSibling===y&&!w||E&&w:e.previousElementSibling===y||y.previousElementSibling===e?(d.clientY-g.top)/u>.5:L>H}else r||(G=F!==y&&!x||E&&x);var M=l(C,j,y,f,e,g,d,G);M!==!1&&(1!==M&&M!==-1||(G=1===M),ea=!0,Z(n,30),b(p,q),y.contains(j)||(G&&!F?j.appendChild(y):e.parentNode.insertBefore(y,G?F:e)),z=y.parentNode,this._animate(f,y),this._animate(g,e))}}},_animate:function(a,b){var c=this.options.animation;if(c){var d=b.getBoundingClientRect();1===a.nodeType&&(a=a.getBoundingClientRect()),i(b,"transition","none"),i(b,"transform","translate3d("+(a.left-d.left)+"px,"+(a.top-d.top)+"px,0)"),b.offsetWidth,i(b,"transition","all "+c+"ms"),i(b,"transform","translate3d(0,0,0)"),clearTimeout(b.animated),b.animated=Z(function(){i(b,"transition",""),i(b,"transform",""),b.animated=!1},c)}},_offUpEvents:function(){var a=this.el.ownerDocument;g(X,"touchmove",this._onTouchMove),g(X,"pointermove",this._onTouchMove),g(a,"mouseup",this._onDrop),g(a,"touchend",this._onDrop),g(a,"pointerup",this._onDrop),g(a,"touchcancel",this._onDrop),g(a,"pointercancel",this._onDrop),g(a,"selectstart",this)},_onDrop:function(b){var c=this.el,d=this.options;clearInterval(this._loopId),clearInterval(S.pid),clearTimeout(this._dragStartTimer),x(this._cloneId),x(this._dragStartId),g(X,"mouseover",this),g(X,"mousemove",this._onTouchMove),this.nativeDraggable&&(g(X,"drop",this),g(c,"dragstart",this._onDragStart)),this._offUpEvents(),b&&(R&&(b.preventDefault(),!d.dropBubble&&b.stopPropagation()),A&&A.parentNode&&A.parentNode.removeChild(A),C!==z&&"clone"===a.active.lastPullMode||B&&B.parentNode&&B.parentNode.removeChild(B),y&&(this.nativeDraggable&&g(y,"dragend",this),m(y),y.style["will-change"]="",h(y,this.options.ghostClass,!1),h(y,this.options.chosenClass,!1),k(this,C,"unchoose",y,z,C,L),C!==z?(M=q(y,d.draggable),M>=0&&(k(null,z,"add",y,z,C,L,M),k(this,C,"remove",y,z,C,L,M),k(null,z,"sort",y,z,C,L,M),k(this,C,"sort",y,z,C,L,M))):y.nextSibling!==D&&(M=q(y,d.draggable),M>=0&&(k(this,C,"update",y,z,C,L,M),k(this,C,"sort",y,z,C,L,M))),a.active&&(null!=M&&M!==-1||(M=L),k(this,C,"end",y,z,C,L,M),this.save()))),this._nulling()},_nulling:function(){C=y=z=A=D=B=E=F=G=P=Q=R=M=I=J=O=N=a.active=null,ha.forEach(function(a){a.checked=!0}),ha.length=0},handleEvent:function(a){switch(a.type){case"drop":case"dragend":this._onDrop(a);break;case"dragover":case"dragenter":y&&(this._onDragOver(a),e(a));break;case"mouseover":this._onDrop(a);break;case"selectstart":a.preventDefault()}},toArray:function(){for(var a,b=[],d=this.el.children,e=0,f=d.length,g=this.options;e', '', 'Loading...', '
', ].join(''), controller: ['$scope', '$location', '$rootScope', appLoadController], }) .when('/system-status', { template: [ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ].join(''), }) .when('/basic-info', { template: [ '', '', '', '', '', '', ].join(''), }) .when('/network', { template: [ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ].join(''), }) .when('/accounts', { template: [ ' ', ' ', ' ', ].join(''), }) .when('/apps', { template: [ '', '', '', '', ].join(''), }) .otherwise({ redirectTo: '/loading' }) } angular.module('linuxDash').config(['$routeProvider', routesFn]) angular .module('linuxDash') .service('server', [ '$http', '$rootScope', '$location', function($http, $rootScope, $location) { var websocket = { connection: null, onMessageEventHandlers: {} }; /** * @description: * Establish a websocket connection with server * * @return Null */ var establishWebsocketConnection = function() { var websocketUrl = (location.protocol === 'https:' ? 'wss://' : 'ws://') + window.location.hostname + ':' + window.location.port; if (websocket.connection === null) { websocket.connection = new WebSocket(websocketUrl); websocket.connection.onopen = function() { $rootScope.$broadcast("start-linux-dash", {}); $rootScope.$apply(); console.info('Websocket connection is open'); }; websocket.connection.onmessage = function(event) { var response = JSON.parse(event.data); var moduleName = response.moduleName; var moduleData = JSON.parse(response.output); if (!!websocket.onMessageEventHandlers[moduleName]) { websocket.onMessageEventHandlers[moduleName](moduleData); } else { console.info("Websocket could not find module", moduleName, "in:", websocket.onMessageEventHandlers); } }; websocket.connection.onclose = function() { websocket.connection = null; } } }; /** * @description: * Check if websockets are supported * If so, call establishWebsocketConnection() * * @return Null */ this.checkIfWebsocketsAreSupported = function() { var websocketSupport = { browser: null, server: null, }; // does browser support websockets? if (window.WebSocket) { websocketSupport.browser = true; // does backend support websockets? $http.get("/websocket").then(function(response) { // if websocket_support property exists and is trurthy // websocketSupport.server will equal true. websocketSupport.server = !!response.data["websocket_support"]; }).catch(function websocketNotSupportedByServer() { websocketSupport.server = false; $rootScope.$broadcast("start-linux-dash", {}); }).then(function finalDecisionOnWebsocket() { if (websocketSupport.browser && websocketSupport.server) { establishWebsocketConnection(); } else { $rootScope.$broadcast("start-linux-dash", {}); } }); } }; /** * Handles requests from modules for data from server * * @param {String} moduleName * @param {Function} callback * @return {[ Null || callback(server response) ]} */ this.get = function(moduleName, callback) { // if we have a websocket connection if (websocket.connection) { // and the connection is ready if (websocket.connection.readyState === 1) { // set the callback as the event handler // for server response. // // Callback instance needs to be overwritten // each time for this to work. Not sure why. websocket.onMessageEventHandlers[moduleName] = callback; // websocket.connection.send(moduleName); } else { console.log("Websocket not ready yet.", moduleName); } } // otherwise else { var moduleAddress = 'server/?module=' + moduleName; return $http.get(moduleAddress).then(function(response) { return callback(response.data); }); } }; } ]) angular.module('linuxDash').directive('cpuAvgLoadChart', ['server', function(server) { return { restrict: 'E', scope: {}, template: '\ \ \ ', link: function(scope) { scope.units = '%' } } }]) angular.module('linuxDash').directive('cpuTemp', ['server', function(server) { return { restrict: 'E', scope: {}, template: ' \ \ \ ', link: function(scope) { scope.min = 0 scope.max = 100 scope.displayValue = function (serverResponseData) { return serverResponseData } scope.utilMetrics = [{ name: 'Temprature', generate: function (serverResponseData) { return serverResponseData + ' °C' } }] } } }]) angular.module('linuxDash').directive('cpuUtilizationChart', ['server', function(server) { return { restrict: 'E', scope: {}, template: ' \ \ \ ', link: function(scope) { scope.min = 0 scope.max = 100 scope.displayValue = function(serverResponseData) { return serverResponseData } scope.utilMetrics = [{ name: 'Usage', generate: function(serverResponseData) { return serverResponseData + ' %' } }] } } }]) angular.module('linuxDash').directive('downloadTransferRateChart', ['server', function(server) { return { restrict: 'E', scope: {}, template: ' \ \ \ ', link: function(scope) { scope.delay = 2000 scope.units = 'KB/s' } } }]) angular.module('linuxDash').directive('ramChart', ['server', function (server) { return { restrict: 'E', scope: {}, template: '\ \ \ ', link: function(scope) { // get max ram available on machine before we // can start charting server.get('current_ram', function(resp) { scope.maxRam = resp.total scope.minRam = 0 }) scope.ramToDisplay = function(serverResponseData) { return serverResponseData.used } var humanizeRam = function (ramInMB) { var ram = { value: parseInt(ramInMB, 10), unit: 'MB', } // if ram > 1,000 MB, use GB if (ram.value > 1000) { ram = { value: (ramInMB/1024).toFixed(2), unit: 'GB', } } return ram.value + ' ' + ram.unit } scope.ramMetrics = [{ name: 'Used', generate: function(serverResponseData) { var ratio = serverResponseData.used / serverResponseData.total var percentage = parseInt(ratio * 100) var usedRam = humanizeRam(serverResponseData.used) return usedRam + ' (' + percentage.toString() + '%)' } }, { name: 'Available', generate: function(serverResponseData) { var availableRam = humanizeRam(serverResponseData.available) var totalRam = humanizeRam(serverResponseData.total) return availableRam + ' of ' + totalRam } }] } } }]) var simpleTableModules = [ { name: 'machineInfo', template: '' }, { name: 'ipAddresses', template: '' }, { name: 'ramIntensiveProcesses', template: '' }, { name: 'cpuIntensiveProcesses', template: '' }, { name: 'dockerProcesses', template: '' }, { name: 'networkConnections', template: '' }, { name: 'serverAccounts', template: '' }, { name: 'loggedInAccounts', template: '' }, { name: 'recentLogins', template: '' }, { name: 'arpCacheTable', template: '' }, { name: 'commonApplications', template: '' }, { name: 'pingSpeeds', template: '' }, { name: 'bandwidth', template: '' }, { name: 'swapUsage', template: '' }, { name: 'internetSpeed', template: '' }, { name: 'memcached', template: '' }, { name: 'redis', template: '' }, { name: 'pm2', template: '' }, { name: 'memoryInfo', template: '' }, { name: 'cpuInfo', template: '' }, { name: 'ioStats', template: '' }, { name: 'scheduledCrons', template: '' }, { name: 'cronHistory', template: '' } ] simpleTableModules.forEach(function(module, key) { angular.module('linuxDash').directive(module.name, ['server', function(server) { var moduleDirective = { restrict: 'E', scope: {} } moduleDirective['template'] = module.template return moduleDirective }]) }) angular.module('linuxDash').directive('uploadTransferRateChart', ['server', function(server) { return { restrict: 'E', scope: {}, template: ' \ \ \ ', link: function(scope) { scope.delay = 2000 scope.units = 'KB/s' } } }]) angular .module('linuxDash') .run(['$rootScope', '$location', function ($rootScope, $location) { var key = 'hiddenPlugins' var getHiddenPlugins = function () { var hiddenPluginsCSV = localStorage.getItem(key) || '' return hiddenPluginsCSV.split(',') } var updateHiddenPlugins = function (hiddenPlugins) { localStorage.setItem(key, hiddenPlugins.join(',')) } $rootScope.$on('hide-plugin', function (e, m) { var hiddenPlugins = getHiddenPlugins() if(hiddenPlugins.indexOf(m) < 0) hiddenPlugins.push(m) updateHiddenPlugins(hiddenPlugins) }) $rootScope.$on('show-plugin', function (e, m) { var hiddenPlugins = getHiddenPlugins() var indexOfPlugin = hiddenPlugins.indexOf(m) if(indexOfPlugin > -1) hiddenPlugins.splice(indexOfPlugin, 1) updateHiddenPlugins(hiddenPlugins) }) $rootScope.hiddenPlugins = getHiddenPlugins() }]) angular .module('linuxDash') .run(['$rootScope', '$location', function ($rootScope, $location) { $rootScope.$on('$routeChangeSuccess', function () { var intervalId = setInterval(function () { var el = document.getElementById('plugins') if (el) { var sortable = Sortable.create(el, { group: 'plugin-order-' + $location.path().replace('/', ''), handle: '.heading', ghostClass: 'ld-ghost', chosenClass: 'ld-chosen', dataIdAttr: 'sortablejs-id', animation: 1050, store: { get: function (sortable) { var order = localStorage.getItem(sortable.options.group.name); return order ? order.split('|') : []; }, set: function (sortable) { var order = sortable.toArray(); localStorage.setItem(sortable.options.group.name, order.join('|')); } } }) clearInterval(intervalId) } }) }) }]) angular.module('linuxDash').directive('diskSpace', ['server', function(server) { return { restrict: 'E', scope: {}, templateUrl: 'src/js/plugins/disk-space/disk-space.html', link: function(scope) { var getKBMultiplierFn = function (size, power) { return function () { return size * Math.pow(1024, power) } } var kbDictionary = { 'M': function () { return getKBMultiplierFn(size, 1) }, 'G': function () { return getKBMultiplierFn(size, 2) }, 'T': function () { return getKBMultiplierFn(size, 3) }, 'P': function () { return getKBMultiplierFn(size, 4) }, 'E': function () { return getKBMultiplierFn(size, 5) }, 'Z': function () { return getKBMultiplierFn(size, 6) }, 'Y': function () { return getKBMultiplierFn(size, 7) }, } scope.heading = "Disk Partitions" scope.moduleName = 'disk_partitions' scope.getData = function() { server.get(scope.moduleName, function(serverResponseData) { scope.diskSpaceData = serverResponseData }) scope.lastGet = new Date().getTime() } scope.getData() scope.getKB = function(stringSize) { var lastChar = stringSize.slice(-1) var size = parseFloat(stringSize.replace(",", ".")) try { return kbDictionary[lastChar](size) } catch (err) { return size } } } } }]) angular.module('linuxDash').directive('keyValueList', ['server', '$rootScope', function (server, $rootScope) { return { scope: { heading: '@', info: '@', moduleName: '@', }, templateUrl: 'src/js/core/features/key-value-list/key-value-list.html', link: function(scope, element) { scope.getData = function() { delete scope.tableRows server.get(scope.moduleName, function(serverResponseData) { scope.tableRows = serverResponseData scope.lastGet = new Date().getTime() if (Object.keys(serverResponseData).length === 0) { scope.emptyResult = true } if (!scope.$$phase && !$rootScope.$$phase) scope.$digest() }) } scope.getData() } } }]) angular.module('linuxDash').directive('lineChartPlugin', [ '$interval', '$compile', 'server', '$window', function ($interval, $compile, server, $window) { return { scope: { heading: '@', moduleName: '@', refreshRate: '=', maxValue: '=', minValue: '=', getDisplayValue: '=', metrics: '=', color: '@' }, templateUrl: 'src/js/core/features/line-chart/line-chart-plugin.html', link: function(scope, element) { scope.initializing = true // wrap the entire plugin into an initializing function var start_rendering_line_chart = function () { if (!scope.color) scope.color = '0, 255, 0' var series, w, h, canvas angular.element($window).bind('resize', function() { canvas.width = w canvas.height = h }) // smoothieJS - Create new chart var chart = new SmoothieChart({ borderVisible: false, sharpLines: true, grid: { fillStyle: '#ffffff', strokeStyle: 'rgba(232,230,230,0.93)', sharpLines: true, millisPerLine: 3000, borderVisible: false }, labels: { fontSize: 11, precision: 0, fillStyle: '#0f0e0e' }, maxValue: parseInt(scope.maxValue), minValue: parseInt(scope.minValue), horizontalLines: [{ value: 5, color: '#eff', lineWidth: 1 }] }) var initializeChart = function () { // smoothieJS - set up canvas element for chart var checkForCanvasReadyState = $interval(function () { if (element.find('canvas')[0]) { canvas = element.find('canvas')[0] series = series || new TimeSeries() w = canvas.width h = canvas.height if (chart.seriesSet.length > 0) chart.removeTimeSeries(chart.seriesSet[0].timeSeries) chart.addTimeSeries(series, { strokeStyle: 'rgba(' + scope.color + ', 1)', fillStyle: 'rgba(' + scope.color + ', 0.2)', lineWidth: 2 }) chart.streamTo(canvas, 1000) $interval.cancel(checkForCanvasReadyState) } }, 100) } scope.reInitializeChart = function () { initializeChart() } if (!scope.isHidden) initializeChart() var dataCallInProgress = false // update data on chart scope.getData = function() { if(scope.initializing) scope.initializing = false if (dataCallInProgress || !element.find('canvas')[0]) return dataCallInProgress = true server.get(scope.moduleName, function(serverResponseData) { if (serverResponseData.length < 1) { scope.emptyResult = true return } dataCallInProgress = false scope.lastGet = new Date().getTime() // change graph colour depending on usage if (scope.maxValue / 4 * 3 < scope.getDisplayValue(serverResponseData)) { chart.seriesSet[0].options.strokeStyle = 'rgba(255, 89, 0, 1)' chart.seriesSet[0].options.fillStyle = 'rgba(255, 89, 0, 0.2)' } else if (scope.maxValue / 3 < scope.getDisplayValue(serverResponseData)) { chart.seriesSet[0].options.strokeStyle = 'rgba(255, 238, 0, 1)' chart.seriesSet[0].options.fillStyle = 'rgba(255, 238, 0, 0.2)' } else { chart.seriesSet[0].options.strokeStyle = 'rgba(' + scope.color + ', 1)' chart.seriesSet[0].options.fillStyle = 'rgba(' + scope.color + ', 0.2)' } scope.newData = scope.getDisplayValue(serverResponseData) // update chart with this response series.append(scope.lastGet, scope.newData) // update the metrics for this chart scope.metrics.forEach(function(metricObj) { metricObj.data = metricObj.generate(serverResponseData) }) }) } // set the directive-provided interval // at which to run the chart update var intervalRef = $interval(scope.getData, scope.refreshRate) var removeInterval = function() { $interval.cancel(intervalRef) } element.on("$destroy", removeInterval) } // only start rendering plugin when we know the scale of max/min for the canvas chart (smoothie) var stopWatching = scope.$watch('maxValue', function (n, o) { if (n) { start_rendering_line_chart() stopWatching() } }) } } } ]) angular.module('linuxDash').directive('loader', function() { return { scope: { width: '@' }, template: '\
\
\
\
\
\
\
\ ' } }) angular.module('linuxDash').directive('multiLineChartPlugin', [ '$interval', '$compile', 'server', '$window', function ($interval, $compile, server, $window) { return { scope: { heading: '@', moduleName: '@', refreshRate: '=', getDisplayValue: '=', units: '=', delay: '=' }, templateUrl: 'src/js/core/features/multi-line-chart/multi-line-chart-plugin.html', link: function(scope, element) { var w, h, canvas angular.element($window).bind('resize', function() { canvas.width = w canvas.height = h }) // smoothieJS - Create new chart var chart = new SmoothieChart({ borderVisible: false, sharpLines: true, grid: { fillStyle: '#ffffff', strokeStyle: 'rgba(232,230,230,0.93)', sharpLines: true, borderVisible: false }, labels: { fontSize: 12, precision: 0, fillStyle: '#0f0e0e' }, maxValue: 100, minValue: 0, horizontalLines: [{ value: 1, color: '#ecc', lineWidth: 1 }] }) var seriesOptions = [ { strokeStyle: 'rgba(255, 0, 0, 1)', lineWidth: 2 }, { strokeStyle: 'rgba(0, 255, 0, 1)', lineWidth: 2 }, { strokeStyle: 'rgba(0, 0, 255, 1)', lineWidth: 2 }, { strokeStyle: 'rgba(255, 255, 0, 1)', lineWidth: 1 } ] // smoothieJS - set up canvas element for chart scope.seriesArray = [] scope.metricsArray = [] var delay = 1000 if (angular.isDefined(scope.delay)) delay = scope.delay var initializeChart = function () { // smoothieJS - set up canvas element for chart var checkForCanvasReadyState = $interval(function () { if (element.find('canvas')[0]) { canvas = element.find('canvas')[0] w = canvas.width h = canvas.height // get the data once to set up # of lines on chart server.get(scope.moduleName, function(serverResponseData) { var numberOfLines = Object.keys(serverResponseData).length for (var x = 0; x < numberOfLines; x++) { var keyForThisLine = Object.keys(serverResponseData)[x]; scope.seriesArray[x] = new TimeSeries(); chart.addTimeSeries(scope.seriesArray[x], seriesOptions[x]); scope.metricsArray[x] = { name: keyForThisLine, color: seriesOptions[x].strokeStyle, } } }) chart.streamTo(canvas, delay) $interval.cancel(checkForCanvasReadyState) } }, 100) } scope.reInitializeChart = function () { chart.seriesSet.forEach(function (ts) { chart.removeTimeSeries(ts.timeSeries) }) initializeChart() } if (!scope.isHidden) initializeChart() var dataCallInProgress = false // update data on chart scope.getData = function() { if (dataCallInProgress) return if (!scope.seriesArray.length) return dataCallInProgress = true server.get(scope.moduleName, function(serverResponseData) { dataCallInProgress = false scope.lastGet = new Date().getTime() var keyCount = 0 var maxAvg = 100 // update chart with current response for (var key in serverResponseData) { scope.seriesArray[keyCount].append(scope.lastGet, serverResponseData[key]) keyCount++ maxAvg = Math.max(maxAvg, serverResponseData[key]) } // update the metrics for this chart scope.metricsArray.forEach(function(metricObj) { metricObj.data = serverResponseData[metricObj.name].toString() + ' ' + scope.units }) // round up the average and set the maximum scale var len = parseInt(Math.log(maxAvg) / Math.log(10)) var div = Math.pow(10, len) chart.options.maxValue = Math.ceil(maxAvg / div) * div }) } var refreshRate = (angular.isDefined(scope.refreshRate)) ? scope.refreshRate : 1000 var intervalRef = $interval(scope.getData, refreshRate) var removeInterval = function() { $interval.cancel(intervalRef) } element.on("$destroy", removeInterval) } } }]) angular.module('linuxDash').directive('navBar', ['$location', function($location) { return { template: '\ \ Linux Dash\ \
    \
  • \ \
  • \
\ \ Resources:\ GitHub | \ Gitter Chat Room | \ Docs \ \ ', link: function(scope) { scope.items = [ 'system-status', 'basic-info', 'network', 'accounts', 'apps' ] scope.getNavItemName = function(url) { return url.replace('-', ' ') } scope.isActive = function(route) { return '/' + route === $location.path() } } } }]) angular.module('linuxDash').directive('plugin', ['$rootScope', function($rootScope) { return { transclude: true, templateUrl: 'src/js/core/features/plugin/plugin.html', link: function (s, el, attr) { if (attr.hasOwnProperty('chartPlugin')) s.isChartPlugin = true if ($rootScope.hiddenPlugins.indexOf(s.moduleName) > -1) s.isHidden = true s.toggleWidth = function () { el.find('div')[0].removeAttribute('style') s.enlarged = !s.enlarged } var setPluginVisibility = function (shouldShow) { s.isHidden = !shouldShow if (shouldShow) { $rootScope.$emit('show-plugin', s.moduleName) if (s.isChartPlugin) s.reInitializeChart() } else { $rootScope.$emit('hide-plugin', s.moduleName) } } s.toggleVisibility = function () { setPluginVisibility(s.isHidden) } s.$watch('emptyResult', function (n, o) { if (n) { setPluginVisibility(false) } }) } } }]) angular.module('linuxDash').directive('progressBarPlugin', function() { return { scope: { width: '@', moduleName: '@', name: '@', value: '@', max: '@' }, template: '\
\
\
\
\
\ ' } }) angular.module('linuxDash').directive('topBar', ['$rootScope', function($rootScope) { return { scope: { heading: '=', refresh: '&', lastUpdated: '=', toggleVisibility: '&', isHidden: '=', toggleWidth: '&', isChart: '=', info: '=', // not being used; needs a good ui solution }, template: '\
\ ☰ {{ heading }} \ \ \ \ \ \ \
\ ', } }]) angular.module('linuxDash').directive('tableData', ['server', '$rootScope', function (server, $rootScope) { return { scope: { heading: '@', info: '@', moduleName: '@', width: '@', height: '@' }, templateUrl: 'src/js/core/features/table-data/table-data.html', link: function(scope, element) { scope.sortByColumn = null scope.sortReverse = null // set the column to sort by scope.setSortColumn = function(column) { // if the column is already being sorted // reverse the order if (column === scope.sortByColumn) { scope.sortReverse = !scope.sortReverse } else { scope.sortByColumn = column } scope.sortTableRows() } scope.sortTableRows = function() { scope.tableRows.sort(function(currentRow, nextRow) { var sortResult = 0 if (currentRow[scope.sortByColumn] < nextRow[scope.sortByColumn]) { sortResult = -1 } else if (currentRow[scope.sortByColumn] === nextRow[scope.sortByColumn]) { sortResult = 0 } else { sortResult = 1 } if (scope.sortReverse) { sortResult = -1 * sortResult } return sortResult }) } scope.getData = function() { delete scope.tableRows server.get(scope.moduleName, function(serverResponseData) { if (serverResponseData.length > 0) { scope.tableHeaders = Object.keys(serverResponseData[0]) } scope.tableRows = serverResponseData if (scope.sortByColumn) { scope.sortTableRows() } scope.lastGet = new Date().getTime() if (serverResponseData.length < 1) { scope.emptyResult = true } if (!scope.$$phase && !$rootScope.$$phase) scope.$digest() }) } scope.getData() } } }]) angular.module("linuxDash").run(["$templateCache", function($templateCache) {$templateCache.put("src/js/plugins/disk-space/disk-space.html","\n\n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
NameStatsUsedMount
{{partition[\'file_system\']}}\n \n \n \n {{ partition[\'used\'] }} / {{ partition[\'size\'] }}\n \n {{ partition[\'used%\'] }}\n {{ partition[\'mounted\'] }}
\n\n\n"); $templateCache.put("src/js/core/features/key-value-list/key-value-list.html","\n\n \n\n
\n \n \n \n \n \n \n \n
{{ name }}{{ value }}
\n\n
\n\n No data\n\n"); $templateCache.put("src/js/core/features/line-chart/line-chart-plugin.html","\n\n \n\n \n \n\n \n \n \n \n \n \n \n
{{ metric.name }}{{ metric.data }}
\n\n No data\n\n
\n"); $templateCache.put("src/js/core/features/multi-line-chart/multi-line-chart-plugin.html","\n\n \n\n \n \n \n \n \n \n \n \n
\n \n \n {{ metric.name }}{{ metric.data }}
\n\n
\n"); $templateCache.put("src/js/core/features/plugin/plugin.html","\n\n \n \n\n \n \n\n\n"); $templateCache.put("src/js/core/features/table-data/table-data.html","\n\n \n\n
\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n \n
\n {{ header }}\n \n {{ (header === sortByColumn && !sortReverse) ? \'▲\': \'\'; }}\n {{ (header === sortByColumn && sortReverse) ? \'▼\': \'\'; }}\n \n
\n {{ row[header] }}\n
\n\n
\n\n No data\n\n");}]);