Renamed serviceTopology in diagnostic
diff --git a/views/ngXosViews/diagnostic/gulp/build.js b/views/ngXosViews/diagnostic/gulp/build.js
index ecf9ed3..8544187 100644
--- a/views/ngXosViews/diagnostic/gulp/build.js
+++ b/views/ngXosViews/diagnostic/gulp/build.js
@@ -25,14 +25,14 @@
 
 var TEMPLATE_FOOTER = `}]);
 angular.module('xos.serviceTopology').run(function($location){$location.path('/')});
-angular.bootstrap(angular.element('#xosServiceTopology'), ['xos.serviceTopology']);`;
+angular.bootstrap(angular.element('#xosDiagnostic'), ['xos.serviceTopology']);`;
 
 module.exports = function(options){
   
   // delete previous builded file
   gulp.task('clean', function(){
     return del(
-      [options.dashboards + 'xosServiceTopology.html'],
+      [options.dashboards + 'xosDiagnostic.html'],
       {force: true}
     );
   });
@@ -44,7 +44,7 @@
     ])
     .pipe(ngAnnotate())
     .pipe(angularFilesort())
-    .pipe(concat('xosServiceTopology.js'))
+    .pipe(concat('xosDiagnostic.js'))
     .pipe(uglify())
     .pipe(gulp.dest(options.static + 'js/'));
   });
@@ -71,12 +71,12 @@
       .pipe(
         inject(
           gulp.src([
-            options.static + 'js/vendor/xosServiceTopologyVendor.js',
-            options.static + 'js/xosServiceTopology.js'
+            options.static + 'js/vendor/xosDiagnosticVendor.js',
+            options.static + 'js/xosDiagnostic.js'
           ])
         )
       )
-      .pipe(rename('xosServiceTopology.html'))
+      .pipe(rename('xosDiagnostic.html'))
       .pipe(gulp.dest(options.dashboards));
   });
 
@@ -93,7 +93,7 @@
     });
 
     return gulp.src(bowerDeps)
-      .pipe(concat('xosServiceTopologyVendor.js'))
+      .pipe(concat('xosDiagnosticVendor.js'))
       .pipe(uglify())
       .pipe(gulp.dest(options.static + 'js/vendor/'));
   });
diff --git a/views/ngXosViews/diagnostic/src/css/serviceTopology.css b/views/ngXosViews/diagnostic/src/css/diagnostic.css
similarity index 100%
rename from views/ngXosViews/diagnostic/src/css/serviceTopology.css
rename to views/ngXosViews/diagnostic/src/css/diagnostic.css
diff --git a/views/ngXosViews/diagnostic/src/index.html b/views/ngXosViews/diagnostic/src/index.html
index 5678816..dcba923 100644
--- a/views/ngXosViews/diagnostic/src/index.html
+++ b/views/ngXosViews/diagnostic/src/index.html
@@ -4,10 +4,10 @@
 <!-- endbower --><!-- endcss -->
 <!-- inject:css -->
 <link rel="stylesheet" href="/css/dev.css">
-<link rel="stylesheet" href="/css/serviceTopology.css">
+<link rel="stylesheet" href="/css/diagnostic.css">
 <!-- endinject -->
 
-<div ng-app="xos.serviceTopology" id="xosServiceTopology">
+<div ng-app="xos.diagnostic" id="xosDiagnostic">
     <div ui-view></div>
 </div>
 
diff --git a/views/ngXosViews/diagnostic/src/js/chart_data_service.js b/views/ngXosViews/diagnostic/src/js/chart_data_service.js
index 1fd093a..609b27b 100644
--- a/views/ngXosViews/diagnostic/src/js/chart_data_service.js
+++ b/views/ngXosViews/diagnostic/src/js/chart_data_service.js
@@ -1,7 +1,7 @@
 (function () {
   'use strict';
 
-  angular.module('xos.serviceTopology')
+  angular.module('xos.diagnostic')
   .service('ChartData', function($rootScope, $q, lodash, Tenant, Node, serviceTopologyConfig, Ceilometer, Instances) {
     this.currentSubscriber = null;
     this.currentServiceChain = null;
diff --git a/views/ngXosViews/diagnostic/src/js/config.js b/views/ngXosViews/diagnostic/src/js/config.js
index f8d6bbf..75b5fe7 100644
--- a/views/ngXosViews/diagnostic/src/js/config.js
+++ b/views/ngXosViews/diagnostic/src/js/config.js
@@ -1,7 +1,7 @@
 (function () {
   'use strict';
 
-  angular.module('xos.serviceTopology')
+  angular.module('xos.diagnostic')
   .constant('serviceTopologyConfig', {
     widthMargin: 20,
     heightMargin: 30,
diff --git a/views/ngXosViews/diagnostic/src/js/d3.js b/views/ngXosViews/diagnostic/src/js/d3.js
index d94a22e..b56ee8f 100644
--- a/views/ngXosViews/diagnostic/src/js/d3.js
+++ b/views/ngXosViews/diagnostic/src/js/d3.js
@@ -1,7 +1,7 @@
 (function () {
   'use strict';
 
-  angular.module('xos.serviceTopology')
+  angular.module('xos.diagnostic')
   .factory('d3', function($window){
     return $window.d3;
   })
diff --git a/views/ngXosViews/diagnostic/src/js/diagnostic.js b/views/ngXosViews/diagnostic/src/js/diagnostic.js
index f3c133a..356583d 100644
--- a/views/ngXosViews/diagnostic/src/js/diagnostic.js
+++ b/views/ngXosViews/diagnostic/src/js/diagnostic.js
@@ -1,7 +1,7 @@
 (function () {
   'use strict';
 
-  angular.module('xos.serviceTopology')
+  angular.module('xos.diagnostic')
   .directive('diagnostic', function(){
     return {
       restrict: 'E',
diff --git a/views/ngXosViews/diagnostic/src/js/logicTopology.js b/views/ngXosViews/diagnostic/src/js/logicTopology.js
index f6798c6..ce81bec 100644
--- a/views/ngXosViews/diagnostic/src/js/logicTopology.js
+++ b/views/ngXosViews/diagnostic/src/js/logicTopology.js
@@ -1,6 +1,6 @@
 (function () {
   'use strict';
-  angular.module('xos.serviceTopology')
+  angular.module('xos.diagnostic')
   .directive('logicTopology', function(){
     return {
       restrict: 'E',
diff --git a/views/ngXosViews/diagnostic/src/js/logicTopologyHelper.js b/views/ngXosViews/diagnostic/src/js/logicTopologyHelper.js
index b0184ef..51ac0f7 100644
--- a/views/ngXosViews/diagnostic/src/js/logicTopologyHelper.js
+++ b/views/ngXosViews/diagnostic/src/js/logicTopologyHelper.js
@@ -1,7 +1,7 @@
 (function () {
   'use strict';
 
-  angular.module('xos.serviceTopology')
+  angular.module('xos.diagnostic')
   .service('LogicTopologyHelper', function($window, $log, $rootScope, lodash, serviceTopologyConfig, NodeDrawer, ChartData){
 
     var diagonal, nodes, links, i = 0, svgWidth, svgHeight, layout;
diff --git a/views/ngXosViews/diagnostic/src/js/main.js b/views/ngXosViews/diagnostic/src/js/main.js
index a6e79c5..c3ea927 100644
--- a/views/ngXosViews/diagnostic/src/js/main.js
+++ b/views/ngXosViews/diagnostic/src/js/main.js
@@ -1,6 +1,6 @@
 'use strict';
 
-angular.module('xos.serviceTopology', [
+angular.module('xos.diagnostic', [
   'ngResource',
   'ngCookies',
   'ngLodash',
diff --git a/views/ngXosViews/diagnostic/src/js/nodeDrawer.js b/views/ngXosViews/diagnostic/src/js/nodeDrawer.js
index d172102..e875426 100644
--- a/views/ngXosViews/diagnostic/src/js/nodeDrawer.js
+++ b/views/ngXosViews/diagnostic/src/js/nodeDrawer.js
@@ -8,7 +8,7 @@
   var computeNodeId = 0;
   var instanceId = 0;
 
-  angular.module('xos.serviceTopology')
+  angular.module('xos.diagnostic')
   .service('NodeDrawer', function(d3, serviceTopologyConfig, RackHelper, lodash){
 
     var _this = this;
diff --git a/views/ngXosViews/diagnostic/src/js/rackHelper.js b/views/ngXosViews/diagnostic/src/js/rackHelper.js
index 40ca88d..17eb0db 100644
--- a/views/ngXosViews/diagnostic/src/js/rackHelper.js
+++ b/views/ngXosViews/diagnostic/src/js/rackHelper.js
@@ -1,5 +1,5 @@
 (function () {
-  angular.module('xos.serviceTopology')
+  angular.module('xos.diagnostic')
   .service('RackHelper', function(serviceTopologyConfig, lodash){
 
     this.getComputeNodeLabelSize = () => {
diff --git a/views/ngXosViews/diagnostic/src/js/rest_services.js b/views/ngXosViews/diagnostic/src/js/rest_services.js
index 311ea07..cb66c37 100644
--- a/views/ngXosViews/diagnostic/src/js/rest_services.js
+++ b/views/ngXosViews/diagnostic/src/js/rest_services.js
@@ -1,7 +1,7 @@
 (function () {
   'use strict';
 
-  angular.module('xos.serviceTopology')
+  angular.module('xos.diagnostic')
   .service('Services', function($resource){
     return $resource('/xos/services/:id', {id: '@id'});
   })
diff --git a/views/ngXosViews/diagnostic/src/js/serviceTopology.js b/views/ngXosViews/diagnostic/src/js/serviceTopology.js
index b358abf..f131dcf 100644
--- a/views/ngXosViews/diagnostic/src/js/serviceTopology.js
+++ b/views/ngXosViews/diagnostic/src/js/serviceTopology.js
@@ -1,7 +1,7 @@
 (function () {
   'use strict';
 
-  angular.module('xos.serviceTopology')
+  angular.module('xos.diagnostic')
   .directive('serviceTopology', function(){
     return {
       restrict: 'E',
diff --git a/views/ngXosViews/diagnostic/src/js/serviceTopologyHelper.js b/views/ngXosViews/diagnostic/src/js/serviceTopologyHelper.js
index d47bf24..1d53d72 100644
--- a/views/ngXosViews/diagnostic/src/js/serviceTopologyHelper.js
+++ b/views/ngXosViews/diagnostic/src/js/serviceTopologyHelper.js
@@ -1,7 +1,7 @@
 (function () {
   'use strict';
 
-  angular.module('xos.serviceTopology')
+  angular.module('xos.diagnostic')
   .service('ServiceTopologyHelper', function($rootScope, $window, $log, lodash, ServiceRelation, serviceTopologyConfig, d3){
 
     // NOTE not used anymore
diff --git a/views/ngXosViews/diagnostic/src/js/subscriber-modal.js b/views/ngXosViews/diagnostic/src/js/subscriber-modal.js
index f805c1a..0620277 100644
--- a/views/ngXosViews/diagnostic/src/js/subscriber-modal.js
+++ b/views/ngXosViews/diagnostic/src/js/subscriber-modal.js
@@ -1,6 +1,6 @@
 (function () {
   'use strict';
-  angular.module('xos.serviceTopology')
+  angular.module('xos.diagnostic')
   .directive('subscriberModal', function(){
     return {
       scope: {
diff --git a/xos/configurations/cord/ceilometer.yaml b/xos/configurations/cord/ceilometer.yaml
index 6fcd132..4747fed 100644
--- a/xos/configurations/cord/ceilometer.yaml
+++ b/xos/configurations/cord/ceilometer.yaml
@@ -223,6 +223,12 @@
       type: tosca.nodes.DashboardView
       properties:
           url: template:xosCeilometerDashboard
+
+    Diagnostic:
+      type: tosca.nodes.DashboardView
+      properties:
+          url: template:xosDiagnostic
+
     Tenant:
       type: tosca.nodes.DashboardView
       properties:
@@ -243,3 +249,6 @@
           - ceilometer_dashboard:
               node: Ceilometer
               relationship: tosca.relationships.UsesDashboard
+          - diagnostic_dashboard:
+              node: Diagnostic
+              relationship: tosca.relationships.UsesDashboard
diff --git a/xos/core/xoslib/dashboards/xosDiagnostic.html b/xos/core/xoslib/dashboards/xosDiagnostic.html
new file mode 100644
index 0000000..8090385
--- /dev/null
+++ b/xos/core/xoslib/dashboards/xosDiagnostic.html
@@ -0,0 +1,16 @@
+<!-- browserSync -->
+
+<!-- inject:css -->
+<link rel="stylesheet" href="/css/dev.css">
+<link rel="stylesheet" href="/css/diagnostic.css">
+<!-- endinject -->
+
+<div id="xosDiagnostic">
+    <div ui-view></div>
+</div>
+
+
+<!-- inject:js -->
+<script src="/../../../xos/core/xoslib/static/js/vendor/xosDiagnosticVendor.js"></script>
+<script src="/../../../xos/core/xoslib/static/js/xosDiagnostic.js"></script>
+<!-- endinject -->
diff --git a/xos/core/xoslib/dashboards/xosServiceTopology.html b/xos/core/xoslib/dashboards/xosServiceTopology.html
deleted file mode 100644
index 613f09d..0000000
--- a/xos/core/xoslib/dashboards/xosServiceTopology.html
+++ /dev/null
@@ -1,16 +0,0 @@
-<!-- browserSync -->
-
-<!-- inject:css -->
-<link rel="stylesheet" href="/css/dev.css">
-<link rel="stylesheet" href="/css/serviceTopology.css">
-<!-- endinject -->
-
-<div id="xosServiceTopology">
-    <div ui-view></div>
-</div>
-
-
-<!-- inject:js -->
-<script src="/../../../xos/core/xoslib/static/js/vendor/xosServiceTopologyVendor.js"></script>
-<script src="/../../../xos/core/xoslib/static/js/xosServiceTopology.js"></script>
-<!-- endinject -->
diff --git a/xos/core/xoslib/static/js/vendor/xosServiceTopologyVendor.js b/xos/core/xoslib/static/js/vendor/xosDiagnosticVendor.js
similarity index 100%
rename from xos/core/xoslib/static/js/vendor/xosServiceTopologyVendor.js
rename to xos/core/xoslib/static/js/vendor/xosDiagnosticVendor.js
diff --git a/xos/core/xoslib/static/js/xosDiagnostic.js b/xos/core/xoslib/static/js/xosDiagnostic.js
new file mode 100644
index 0000000..32f6814
--- /dev/null
+++ b/xos/core/xoslib/static/js/xosDiagnostic.js
@@ -0,0 +1 @@
+angular.module("xos.serviceTopology").run(["$templateCache",function(t){t.put("templates/diagnostic.tpl.html",'<div class="container-fluid">\n  <div ng-hide="vm.error && vm.loader">\n    <div class="onethird-height">\n      <service-topology service-chain="vm.serviceChain"></service-topology>\n    </div>\n    <div class="twothird-height">\n      <!-- <div class="panel panel-primary subscriber-select">\n        <div class="panel-heading">Select a subscriber:</div>\n        <div class="panel-body">\n          <select class="form-control" ng-options="s as s.name for s in vm.subscribers" ng-model="vm.selectedSubscriber">\n            <option value="">Select a subscriber...</option>\n          </select>\n        </div>\n      </div> -->\n      <logic-topology ng-if="vm.subscribers" subscribers="vm.subscribers" selected="vm.selectedSubscriber"></logic-topology>\n    </div>\n  </div>\n  <div class="row" ng-show="vm.error">\n    <div class="col-xs-12">\n      <div class="alert alert-danger">\n        {{vm.error}}\n      </div>\n    </div>\n  </div>\n  <div class="row" ng-show="vm.loader">\n    <div class="col-xs-12">\n      <div class="loader">Loading</div>\n    </div>\n  </div>\n</div>'),t.put("templates/logicTopology.tpl.html",'<subscriber-modal open="vm.subscriberModal" subscribers="vm.subscribers"></subscriber-modal>\n<div class="instances-stats animate" ng-hide="vm.hideInstanceStats">\n  <div class="row">\n    <div class="col-sm-3 col-sm-offset-8">\n      <div class="panel panel-primary" ng-repeat="instance in vm.selectedInstances">\n        <div class="panel-heading">\n          {{instance.humanReadableName}}\n        </div>\n          <ul class="list-group">\n            <li class="list-group-item">Backend Status: {{instance.backend_status}}</li>\n            <li class="list-group-item">IP Address: {{instance.ip}}</li>\n          </ul>\n          <ul class="list-group">\n            <li class="list-group-item" ng-repeat="stat in instance.stats">\n              <span class="badge">{{stat.value}}</span>\n              {{stat.meter}}\n            </li>\n          </ul>\n        </div>\n      </div>  \n    </div>\n  </div>\n</div>'),t.put("templates/subscriber-modal.tpl.html",'<div class="modal fade" ng-class="{in: vm.open}" tabindex="-1" role="dialog">\n  <div class="modal-dialog modal-sm">\n    <div class="modal-content">\n      <div class="modal-header">\n        <button ng-click="vm.close()"  type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>\n        <h4 class="modal-title">Select a subscriber:</h4>\n      </div>\n      <div class="modal-body">\n        <select class="form-control" ng-options="s as s.humanReadableName for s in vm.subscribers" ng-model="vm.selected"></select>\n      </div>\n      <div class="modal-footer">\n        <button ng-click="vm.close()" type="button" class="btn btn-default" data-dismiss="modal">Close</button>\n        <button ng-click="vm.select(vm.selected)" type="button" class="btn btn-primary">Select</button>\n      </div>\n    </div><!-- /.modal-content -->\n  </div><!-- /.modal-dialog -->\n</div><!-- /.modal -->')}]),angular.module("xos.serviceTopology").run(["$location",function(t){t.path("/")}]),angular.bootstrap(angular.element("#xosDiagnostic"),["xos.serviceTopology"]),angular.module("xos.diagnostic",["ngResource","ngCookies","ngLodash","ngAnimate","ui.router","xos.helpers"]).config(["$stateProvider",function(t){t.state("home",{url:"/",template:"<diagnostic></diagnostic>"})}]).config(["$httpProvider",function(t){t.interceptors.push("NoHyperlinks")}]),function(){"use strict";angular.module("xos.diagnostic").directive("subscriberModal",function(){return{scope:{subscribers:"=",open:"="},bindToController:!0,restrict:"E",templateUrl:"templates/subscriber-modal.tpl.html",controllerAs:"vm",controller:["$rootScope",function(t){var e=this;this.close=function(){e.open=!1},this.select=function(n){t.$emit("subscriber.selected",n),e.close()}}]}})}(),function(){"use strict";angular.module("xos.diagnostic").service("ServiceTopologyHelper",["$rootScope","$window","$log","lodash","ServiceRelation","serviceTopologyConfig","d3",function(t,e,n,r,i,a,o){var c,s,u,d=function(t){var e=t.append("g").attr({"class":"legend"});e.append("rect").attr({transform:function(t){return"translate(10, 80)"},width:100,height:100});var n=e.append("g").attr({"class":"node service"});n.append("circle").attr({r:a.circle.radius,transform:function(t){return"translate(30, 100)"}}),n.append("text").attr({transform:function(t){return"translate(45, 100)"},dy:".35em"}).text("Service").style("fill-opacity",1);var r=e.append("g").attr({"class":"node slice"});r.append("rect").attr({width:20,height:20,x:-10,y:-10,transform:function(t){return"translate(30, 130)"}}),r.append("text").attr({transform:function(t){return"translate(45, 130)"},dy:".35em"}).text("Slices").style("fill-opacity",1);var i=e.append("g").attr({"class":"node instance"});i.append("rect").attr({width:20,height:20,x:-10,y:-10,transform:function(t){return"translate(30, 160)"}}),i.append("text").attr({transform:function(t){return"translate(45, 160)"},dy:".35em"}).text("Instances").style("fill-opacity",1)},l=0,p=function(t,n,r){c=t,s=n,u=r;var d=i.depthOf(r),p=o.svg.diagonal().projection(function(t){return[t.y,t.x]}),f=n.nodes(r).reverse(),g=n.links(f);f.forEach(function(t){var n=(e.innerWidth-2*a.widthMargin)/d;t.y=t.depth*n});var v=t.selectAll("g.node").data(f,function(t){return t.id||(t.id=++l)}),m=v.enter().append("g").attr({"class":function(t){return"node "+t.type},transform:function(t){return t.x&&t.y?"translate("+t.y+", "+t.x+")":"translate("+r.y0+", "+r.x0+")"}}),b=m.filter(".subscriber"),y=m.filter(".router"),x=m.filter(".service");b.append("rect").attr(a.square),y.append("rect").attr(a.square),x.append("circle").attr("r",1e-6).style("fill",function(t){return t._children?"lightsteelblue":"#fff"}).on("click",h),m.append("text").attr({x:function(t){return t.children?-a.circle.selectedRadius-3:a.circle.selectedRadius+3},dy:".35em",transform:function(t){return t.children&&t.parent?t.parent.x<t.x?"rotate(-30)":"rotate(30)":void 0},"text-anchor":function(t){return t.children?"end":"start"}}).text(function(t){return t.name}).style("fill-opacity",1e-6);var S=v.transition().duration(a.duration).attr({transform:function(t){return"translate("+t.y+","+t.x+")"}});S.select("circle").attr("r",function(t){return t.selected?a.circle.selectedRadius:a.circle.radius}).style("fill",function(t){return t.selected?"lightsteelblue":"#fff"}),S.select("text").style("fill-opacity",1);var w=v.exit().transition().duration(a.duration).remove();w.select("circle").attr("r",1e-6),w.select("text").style("fill-opacity",1e-6);var T=t.selectAll("path.link").data(g,function(t){return t.target.id});T.enter().insert("path","g").attr("class",function(t){return"link "+t.target.type+" "+(t.target.active?"":"active")}).attr("d",function(t){var e={x:r.x0,y:r.y0};return p({source:e,target:e})}),T.transition().duration(a.duration).attr("d",p),T.exit().transition().duration(a.duration).attr("d",function(t){var e={x:r.x,y:r.y};return p({source:e,target:e})}).remove(),f.forEach(function(t){t.x0=t.x,t.y0=t.y})},h=function(e){return e.selected?(e.selected=!e.selected,t.$emit("instance.detail.hide",{}),p(c,s,u)):(t.$emit("instance.detail",{name:e.name,service:e.service,tenant:e.tenant}),c.selectAll("circle").each(function(t){return t.selected=!1}),e.selected=!e.selected,void p(c,s,u))};this.updateTree=p,this.drawLegend=d}])}(),function(){"use strict";angular.module("xos.diagnostic").directive("serviceTopology",function(){return{restrict:"E",scope:{serviceChain:"="},bindToController:!0,controllerAs:"vm",template:"",controller:["$element","$window","$scope","d3","serviceTopologyConfig","ServiceRelation","Slice","Instances","Subscribers","ServiceTopologyHelper",function(t,e,n,r,i,a,o,c,s,u){var d=this,l=t[0];r.select(window).on("resize",function(){f(d.serviceChain)});var p,h,f=function(e){r.select(t[0]).select("svg").remove();var n=l.clientWidth-2*i.widthMargin,a=l.clientHeight-2*i.heightMargin,o=r.layout.tree().size([a,n]);h=r.select(t[0]).append("svg").style("width",l.clientWidth+"px").style("height",l.clientHeight+"px");var c=h.append("g").attr("transform","translate("+4*i.widthMargin+","+i.heightMargin+")");p=e,p.x0=a/2,p.y0=n/2,u.updateTree(c,o,p)};this.getInstances=function(t){c.query({slice:t.id}).$promise.then(function(e){d.selectedSlice=t,d.instances=e})["catch"](function(t){throw d.errors=t,new Error(t)})},n.$watch(function(){return d.serviceChain},function(t){t&&f(t)})}]}})}(),function(){"use strict";angular.module("xos.diagnostic").service("Services",["$resource",function(t){return t("/xos/services/:id",{id:"@id"})}]).service("Tenant",["$resource",function(t){return t("/xos/tenants",{id:"@id"},{queryVsgInstances:{method:"GET",isArray:!0,interceptor:{response:function(t){var e=[];return angular.forEach(t.data,function(t){var n=JSON.parse(t.service_specific_attribute);n&&n.instance_id&&e.push(n.instance_id)}),e}}},getSubscriberTag:{method:"GET",isArray:!0,interceptor:{response:function(t){return JSON.parse(t.data[0].service_specific_attribute)}}}})}]).service("Ceilometer",["$http","$q","Instances",function(t,e,n){var r=this;this.getInstanceStats=function(n){var r=e.defer();return t.get("/xoslib/xos-instance-statistics",{params:{"instance-uuid":n}}).then(function(t){r.resolve(t.data)})["catch"](function(t){r.reject(t)}),r.promise},this.getInstancesStats=function(t){var i=e.defer(),a=[],o=[];return t.forEach(function(t){a.push(n.get({id:t}).$promise)}),e.all(a).then(function(t){o=t;var n=[];return o.forEach(function(t){n.push(r.getInstanceStats(t.instance_uuid))}),e.all(n)}).then(function(t){o.map(function(e,n){e.stats=t[n]}),i.resolve(o)})["catch"](i.reject),i.promise},this.getContainerStats=function(n){var r=e.defer(),i={};return t.get("/xoslib/meterstatistics",{params:{resource:n}}).then(function(e){return i.stats=e.data,t.get("/xoslib/meterstatistics",{params:{resource:n+"-eth0"}})}).then(function(e){return i.port={eth0:e.data},t.get("/xoslib/meterstatistics",{params:{resource:n+"-eth1"}})}).then(function(t){i.port.eth1=t.data,r.resolve(i)})["catch"](function(t){r.reject(t)}),r.promise}}]).service("Slice",["$resource",function(t){return t("/xos/slices",{id:"@id"})}]).service("Instances",["$resource",function(t){return t("/xos/instances/:id",{id:"@id"})}]).service("Node",["$resource","$q","Instances",function(t,e,n){return t("/xos/nodes",{id:"@id"},{queryWithInstances:{method:"GET",isArray:!0,interceptor:{response:function(t){var r=e.defer(),i=[];return angular.forEach(t.data,function(t){i.push(n.query({node:t.id}).$promise)}),e.all(i).then(function(e){t.data.map(function(t,n){return t.instances=e[n],t}),r.resolve(t.data)}),r.promise}}}})}]).service("Subscribers",["$resource","$q","SubscriberDevice",function(t,e,n){return t("/xos/subscribers/:id",{id:"@id"},{queryWithDevices:{method:"GET",isArray:!0,interceptor:{response:function(t){var r=e.defer(),i=[];return angular.forEach(t.data,function(t){i.push(n.query({id:t.id}).$promise)}),e.all(i).then(function(e){t.data.map(function(t,n){return t.devices=e[n],t.type="subscriber",t.devices.map(function(t){return t.type="device"}),t}),r.resolve(t.data)}),r.promise}}},getWithDevices:{method:"GET",isArray:!1,interceptor:{response:function(t){var r=e.defer();return n.query({id:t.data.id}).$promise.then(function(e){e.map(function(t){return t.type="device"}),t.data.devices=e,t.data.type="subscriber",r.resolve(t.data)})["catch"](function(t){r.reject(t)}),r.promise}}}})}]).service("SubscriberDevice",["$resource",function(t){return t("/xoslib/rs/subscriber/:id/users/",{id:"@id"})}]).service("ServiceRelation",["$q","lodash","Services","Tenant","Slice","Instances",function(t,e,n,r,i,a){var o=function g(t){var e=0;return t.children&&t.children.forEach(function(t){var n=g(t);n>e&&(e=n)}),1+e},c=function(t,n){return e.filter(t,function(t){return t.subscriber_service===n})},s=function(t,n){var r,t=e.filter(t,function(t){return t.provider_service===n&&t.subscriber_tenant});return t.forEach(function(t){t.service_specific_attribute&&(r=JSON.parse(t.service_specific_attribute))}),r},u=function(t,n){var r=[];return e.forEach(t,function(t){var i=e.find(n,{id:t.provider_service});r.push(i)}),r},d=function v(t,n,r,i){var a=arguments.length<=4||void 0===arguments[4]?null:arguments[4],o=e.difference(n,[r]),d=c(t,r.id),l=u(d,n);o=e.difference(o,l),r.service_specific_attribute=s(t,r.id);var p={name:r.humanReadableName,parent:a,type:"service",service:r,tenant:i,children:[]};return e.forEach(l,function(n){var a=e.find(t,{subscriber_tenant:i.id,provider_service:n.id});p.children.push(v(t,o,n,a,r.humanReadableName))}),0===p.children.length&&p.children.push({name:"Router",type:"router",children:[]}),p},l=function(t,n){var r=arguments.length<=2||void 0===arguments[2]?{id:1,name:"fakeSubs"}:arguments[2],i=e.find(n,{subscriber_root:r.id}),a=e.find(t,{id:i.provider_service}),o=d(n,t,a,i);return{name:r.name,parent:null,type:"subscriber",children:[o]}},p=function(t,n){var r=function o(t,n,r){var i={type:"service",name:r.humanReadableName,service:r},a=e.find(n,{subscriber_service:r.id});if(a){var c=e.find(t,{id:a.provider_service});i.children=[o(t,n,c)]}else i.children=[{name:"Router",type:"router",children:[]}];return delete r.id,i},i=e.find(t,{id:3}),a={name:"Subscriber",type:"subscriber",parent:null,children:[r(t,n,i)]};return a},h=function(e){var i,a,o=t.defer();return n.query().$promise.then(function(t){return i=t,r.query().$promise}).then(function(t){a=t,o.resolve(l(i,a,e))})["catch"](function(t){throw new Error(t)}),o.promise},f=function(){var e,i,a=t.defer();return n.query().$promise.then(function(t){return e=t,r.query({kind:"coarse"}).$promise}).then(function(t){i=t,a.resolve(p(e,i))})["catch"](function(t){throw new Error(t)}),a.promise};return{get:f,buildServiceTree:p,getBySubscriber:h,buildLevel:d,buildSubscriberServiceTree:l,findLevelRelation:c,findLevelServices:u,depthOf:o,findSpecificInformation:s}}])}();var _slicedToArray=function(){function t(t,e){var n=[],r=!0,i=!1,a=void 0;try{for(var o,c=t[Symbol.iterator]();!(r=(o=c.next()).done)&&(n.push(o.value),!e||n.length!==e);r=!0);}catch(s){i=!0,a=s}finally{try{!r&&c["return"]&&c["return"]()}finally{if(i)throw a}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}();!function(){angular.module("xos.diagnostic").service("RackHelper",["serviceTopologyConfig","lodash",function(t,e){var n=this;this.getComputeNodeLabelSize=function(){return t.computeNode.labelHeight+2*t.instance.margin},this.getComputeNodeSize=e.memoize(function(e){var r=3*t.instance.margin+2*t.instance.width,i=Math.round(e.length/2),a=n.getComputeNodeLabelSize(),o=t.instance.height*i+t.instance.margin*(i+1)+a;return[r,o]}),this.getRackSize=function(r){var i=0,a=t.computeNode.margin;return e.forEach(r,function(e){var r=n.getComputeNodeSize(e.instances),o=_slicedToArray(r,2),c=o[0],s=o[1];i=c+2*t.computeNode.margin,a+=s+t.computeNode.margin}),[i,a]},this.getInstancePosition=function(e){var r=Math.floor(e/2),i=e%2?1:0,a=n.getComputeNodeLabelSize(),o=t.instance.margin+t.instance.width*i+t.instance.margin*i,c=a+t.instance.margin+t.instance.height*r+t.instance.margin*r;return[o,c]},this.getComputeNodePosition=function(r,i){var a=t.computeNode.margin,o=e.reduce(r.slice(0,i),function(t,e){return t+n.getComputeNodeSize(e.instances)[1]},0),c=t.computeNode.margin+t.computeNode.margin*i+o;return[a,c]}}])}();var _slicedToArray=function(){function t(t,e){var n=[],r=!0,i=!1,a=void 0;try{for(var o,c=t[Symbol.iterator]();!(r=(o=c.next()).done)&&(n.push(o.value),!e||n.length!==e);r=!0);}catch(s){i=!0,a=s}finally{try{!r&&c["return"]&&c["return"]()}finally{if(i)throw a}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}();!function(){"use strict";var t={cloud:" M 79.72 49.60 C 86.00 37.29 98.57 29.01 111.96 26.42 C 124.27 24.11 137.53 26.15 148.18 32.90 C 158.08 38.78 165.39 48.87 167.65 60.20 C 176.20 57.90 185.14 56.01 194.00 57.73 C 206.08 59.59 217.92 66.01 224.37 76.66 C 227.51 81.54 228.85 87.33 229.23 93.06 C 237.59 93.33 246.22 95.10 253.04 100.19 C 256.69 103.13 259.87 107.67 258.91 112.59 C 257.95 118.43 252.78 122.38 247.78 124.82 C 235.27 130.43 220.23 130.09 207.98 123.93 C 199.33 127.88 189.76 129.43 180.30 128.57 C 173.70 139.92 161.70 147.65 148.86 149.93 C 133.10 153.26 116.06 148.15 104.42 137.08 C 92.98 143.04 78.96 143.87 66.97 139.04 C 57.75 135.41 49.70 128.00 46.60 118.43 C 43.87 109.95 45.81 100.29 51.30 93.32 C 57.38 85.18 67.10 80.44 76.99 78.89 C 74.38 69.20 74.87 58.52 79.72 49.60 Z"},e=0,n=0;angular.module("xos.diagnostic").service("NodeDrawer",["d3","serviceTopologyConfig","RackHelper","lodash",function(r,i,a,o){var c=this,s=this;this.addNetworks=function(e){e.append("path").attr({d:t.cloud,transform:"translate(-63, -52), scale(0.5)","class":"cloud"}),e.append("text").attr({"text-anchor":"middle"}).text(function(t){return t.name}),e.each(function(t){var e=r.select(this);"LAN"===t.name&&angular.isDefined(t.subscriberTag)&&(e.append("text").attr({"text-anchor":"middle",y:40}).text(function(){return"C-Tag: "+t.subscriberTag.cTag}),e.append("text").attr({"text-anchor":"middle",y:60}).text(function(){return"S-Tag: "+t.subscriberTag.sTag})),"WAN"===t.name&&angular.isDefined(t.subscriberIP)&&e.append("text").attr({"text-anchor":"middle",y:40}).text(function(){return"Public IP: "+t.subscriberIP})})},this.addRack=function(t){t.each(function(e){var n=a.getRackSize(e.computeNodes),r=_slicedToArray(n,2),o=r[0],s=r[1];t.select("g").remove();var u=t.append("g");u.attr({transform:"translate(0,0)"}).transition().duration(i.duration).attr({transform:function(){return"translate("+-(o/2)+", "+-(s/2)+")"}}),u.append("rect").attr({width:0,height:0}).transition().duration(i.duration).attr({width:o,height:s}),u.append("text").attr({"text-anchor":"middle",y:-10,x:o/2,opacity:0}).text(function(t){return t.name}).transition().duration(i.duration).attr({opacity:1}),c.drawComputeNodes(u,e.computeNodes)})},this.drawComputeNodes=function(t,n){var o=t.selectAll(".compute-nodes").data(n,function(t){return angular.isString(t.d3Id)||(t.d3Id="compute-node-"+ ++e),t.d3Id}),c=t.node().getBoundingClientRect(),u=c.width,d=c.height,l=o.enter().append("g");l.attr({transform:"translate("+u/2+", "+d/2+")","class":"compute-node"}).transition().duration(i.duration).attr({transform:function(t){return"translate("+a.getComputeNodePosition(n,t.d3Id.replace("compute-node-","")-1)+")"}}),l.append("rect").attr({width:0,height:0}).transition().duration(i.duration).attr({width:function(t){return a.getComputeNodeSize(t.instances)[0]},height:function(t){return a.getComputeNodeSize(t.instances)[1]}}),l.append("text").attr({"text-anchor":"start",y:15,x:10,opacity:0}).text(function(t){return t.humanReadableName.split(".")[0]}).transition().duration(i.duration).attr({opacity:1}),l.length>0&&l.each(function(t){s.drawInstances(r.select(this),t.instances)})};var u=function(t){return t.replace("app_","").replace("service_","").replace("mysite_","").replace("_instance","")},d=function(t){function e(t,e){return e.substring(0,t.length)===t}return e("0 - ",t.backend_status)?"provisioning":e("1 - ",t.backend_status)?"good":e("2 - ",t.backend_status)?"bad":""},l=function(t,e){var n=t.append("g").attr({"class":"container",transform:"translate("+i.instance.margin+", 115)"});n.append("rect").attr({width:250-2*i.container.margin,height:i.container.height}),n.append("text").attr({y:20,x:i.instance.margin,"class":"name"}).text(e.name);var r=["memory","memory.usage","cpu_util"];r.forEach(function(t,r){var a=o.find(e.stats,{meter:t});angular.isDefined(a)&&n.append("text").attr({y:40+15*r,x:i.instance.margin,opacity:0}).text(a.description+": "+Math.round(a.value)+" "+a.unit).transition().duration(i.duration).attr({opacity:1})});var a=["eth0","eth1"],c=[{meter:"network.incoming.bytes.rate",label:"Incoming"},{meter:"network.outgoing.bytes.rate",label:"Outgoing"}];a.forEach(function(t,r){0!==e.port[t].length&&(n.append("text").attr({y:90,x:i.instance.margin+120*r,"class":"name"}).text(e.name+"-"+t),c.forEach(function(a,c){var s=o.find(e.port[t],{meter:a.meter});angular.isDefined(s)&&n.append("text").attr({y:105+15*c,x:i.instance.margin+120*r,opacity:0}).text(a.label+": "+Math.round(s.value)+" "+s.unit).transition().duration(i.duration).attr({opacity:1})}))})},p=function(t,e){var n=t.append("g").attr({transform:"translate(200, -120)","class":"stats-container"});n.append("line").attr({x1:-160,y1:120,x2:0,y2:50,stroke:"black",opacity:0}).transition().duration(i.duration).attr({opacity:1});var r=110,a=250;e.container&&(r+=i.container.height+2*i.container.margin),n.append("rect").attr({width:a,height:r,opacity:0}).transition().duration(i.duration).attr({opacity:1}),n.append("text").attr({y:15,x:i.instance.margin,"class":"name",opacity:0}).text(e.humanReadableName).transition().duration(i.duration).attr({opacity:1}),n.append("text").attr({y:30,x:i.instance.margin,"class":"ip",opacity:0}).text(e.ip).transition().duration(i.duration).attr({opacity:1});var c=["memory","memory.usage","cpu","vcpus"];c.forEach(function(t,r){var a=o.find(e.stats,{meter:t});n.append("text").attr({y:55+15*r,x:i.instance.margin,opacity:0}).text(a.description+": "+Math.round(a.value)+" "+a.unit).transition().duration(i.duration).attr({opacity:1})}),e.container&&l(n,e.container)};this.drawInstances=function(t,e){var o=t.node().getBoundingClientRect(),c=o.width,s=o.height,l=t.selectAll(".instances").data(e,function(t){return angular.isString(t.d3Id)?t.d3Id:t.d3Id="instance-"+ ++n}),h=l.enter().append("g");h.attr({transform:"translate("+c/2+", "+s/2+")","class":function(t){return"instance "+(t.selected?"active":"")+" "+d(t)}}).transition().duration(i.duration).attr({transform:function(t,e){return"translate("+a.getInstancePosition(e)+")"}}),h.append("rect").attr({width:0,height:0}).transition().duration(i.duration).attr({width:i.instance.width,height:i.instance.height}),h.append("text").attr({"text-anchor":"middle",y:23,x:40,opacity:0}).text(function(t){return u(t.humanReadableName)}).transition().duration(i.duration).attr({opacity:1}),h.each(function(t,e){var n=r.select(this);angular.isDefined(t.stats)&&t.selected&&p(n,t,e)}),h.on("click",function(t){console.log("Draw vignette with stats for instance: "+t.name)})},this.addPhisical=function(t){t.append("rect").attr(i.square),t.append("text").attr({"text-anchor":"middle",y:i.square.y-10}).text(function(t){return t.name})},this.addDevice=function(t){t.append("circle").attr(i.circle),t.append("text").attr({"text-anchor":"end",x:-i.circle.r-10,y:i.circle.r/2}).text(function(t){return t.name||t.mac})}}])}();var _slicedToArray=function(){function t(t,e){var n=[],r=!0,i=!1,a=void 0;try{for(var o,c=t[Symbol.iterator]();!(r=(o=c.next()).done)&&(n.push(o.value),!e||n.length!==e);r=!0);}catch(s){i=!0,a=s}finally{try{!r&&c["return"]&&c["return"]()}finally{if(i)throw a}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}();!function(){"use strict";angular.module("xos.diagnostic").service("LogicTopologyHelper",["$window","$log","$rootScope","lodash","serviceTopologyConfig","NodeDrawer","ChartData",function(t,e,n,r,i,a,o){var c,s,u,d,l,p,h=this,f=0,g=o.logicTopologyData;this.computeElementPosition=function(t){var e=[],n=r.reduce(i.elWidths,function(t,e){return e+t},0),a=t-n-2*i.widthMargin,o=a/(i.elWidths.length-1);return r.forEach(i.elWidths,function(n,a){var c=0;0!==a&&(c=r.reduce(i.elWidths.slice(0,a),function(t,e){return e+t},0));var s=i.widthMargin+o*a+n/2+c;e.push(t-s)}),e};var v=function(t){var e=p.nodes(t);e.forEach(function(t){t.y=h.computeElementPosition(d)[t.depth]});var n=p.links(e);return[e,n]},m=function(t,e){var r=t.selectAll("g.node").data(e,function(t){return angular.isString(t.d3Id)||(t.d3Id="tree-"+ ++f),t.d3Id});r.enter().append("g").attr({"class":function(t){return"node "+t.type},transform:"translate("+d/2+", "+l/2+")"});a.addNetworks(r.filter(".network")),a.addRack(r.filter(".rack")),a.addPhisical(r.filter(".router")),a.addPhisical(r.filter(".subscriber")),a.addDevice(r.filter(".device")),r.filter(".subscriber").on("click",function(){n.$emit("subscriber.modal.open")});r.transition().duration(i.duration).attr({transform:function(t){return"translate("+t.y+","+t.x+")"}}),r.exit().remove()},b=function(t,e){c=d3.svg.diagonal().projection(function(t){return[t.y,t.x]});var n=t.selectAll("path.link").data(e,function(t){return t.target.d3Id});n.enter().insert("path","g").attr("class",function(t){return"link "+t.target.type}).attr("d",function(t){var e={x:l/2,y:d/2};return c({source:e,target:e})}),n.transition().duration(i.duration).attr("d",c),n.exit().remove()};this.setupTree=function(t){d=t.node().getBoundingClientRect().width,l=t.node().getBoundingClientRect().height;var e=d-2*i.widthMargin,n=l-2*i.heightMargin;p=d3.layout.tree().size([n,e])},this.updateTree=function(t){var e=v(g),n=_slicedToArray(e,2);s=n[0],u=n[1],m(t,s),b(t,u)}}])}(),function(){"use strict";angular.module("xos.diagnostic").directive("logicTopology",function(){return{restrict:"E",scope:{subscribers:"=",selected:"="},bindToController:!0,controllerAs:"vm",templateUrl:"templates/logicTopology.tpl.html",controller:["$element","$log","$scope","$rootScope","$timeout","d3","LogicTopologyHelper","Node","Tenant","Ceilometer","serviceTopologyConfig","ChartData",function(t,e,n,r,i,a,o,c,s,u,d,l){var p=this;e.info("Logic Plane");var h;this.selectedInstances=[],this.hideInstanceStats=!0;var f=function(t){h=a.select(t).append("svg").style("width",t.clientWidth+"px").style("height",t.clientHeight+"px")};l.getLogicTree().then(function(t){o.updateTree(h)}),n.$watch(function(){return p.selected},function(t){t&&(l.selectSubscriber(t),o.updateTree(h))}),r.$on("instance.detail.hide",function(){p.hideInstanceStats=!0,i(function(){p.selectedInstances=[],l.highlightInstances([]),o.updateTree(h)},500)}),r.$on("instance.detail",function(t,e){l.getInstanceStatus(e).then(function(t){o.updateTree(h)})}),f(t[0]),o.setupTree(h),this.openSubscriberModal=function(){p.subscriberModal=!0,n.$apply()},r.$on("subscriber.modal.open",function(){p.openSubscriberModal()})}]}})}(),function(){"use strict";angular.module("xos.diagnostic").directive("diagnostic",function(){return{restrict:"E",templateUrl:"templates/diagnostic.tpl.html",controllerAs:"vm",controller:["ChartData","Subscribers","ServiceRelation","$rootScope",function(t,e,n,r){var i=this;this.loader=!0,this.error=!1,e.query().$promise.then(function(t){return i.subscribers=t,n.get()}).then(function(t){i.serviceChain=t})["catch"](function(t){throw new Error(t)})["finally"](function(){i.loader=!1}),r.$on("subscriber.selected",function(r,a){n.getBySubscriber(a).then(function(n){return i.serviceChain=n,t.currentServiceChain=n,e.getWithDevices({id:a.id}).$promise}).then(function(e){i.selectedSubscriber=e,t.currentSubscriber=e})})}]}})}(),function(){"use strict";angular.module("xos.diagnostic").factory("d3",["$window",function(t){return t.d3}])}(),function(){"use strict";angular.module("xos.diagnostic").constant("serviceTopologyConfig",{widthMargin:20,heightMargin:30,duration:750,elWidths:[20,104,105,104,20],circle:{radius:10,r:10,selectedRadius:15},square:{width:20,height:20,x:-10,y:-10},rack:{width:105,height:50,x:-30,y:-25},computeNode:{width:50,height:20,margin:5,labelHeight:10,x:-25,y:-10},instance:{width:80,height:36,margin:5,x:-40,y:-18},container:{width:60,height:130,margin:5,x:-30,y:-15}})}(),function(){"use strict";angular.module("xos.diagnostic").service("ChartData",["$rootScope","$q","lodash","Tenant","Node","serviceTopologyConfig","Ceilometer","Instances",function(t,e,n,r,i,a,o,c){var s=this;this.currentSubscriber=null,this.currentServiceChain=null,this.logicTopologyData={name:"Router",type:"router",children:[{name:"WAN",type:"network",children:[{name:"Rack",type:"rack",computeNodes:[],children:[{name:"LAN",type:"network",children:[{name:"Subscriber",type:"subscriber"}]}]}]}]},this.getLogicTree=function(){var t=e.defer();return i.queryWithInstances().$promise.then(function(e){s.logicTopologyData.children[0].children[0].computeNodes=e,t.resolve(s.logicTopologyData)}),t.promise},this.addSubscriberTag=function(t){s.logicTopologyData.children[0].children[0].children[0].subscriberTag={cTag:t.c_tag,sTag:t.s_tag}},this.addSubscriber=function(t){return t.children=t.devices,s.logicTopologyData.children[0].children[0].children[0].children=[t],s.logicTopologyData},this.getSubscriberTag=function(){var t=JSON.parse(s.currentServiceChain.children[0].tenant.service_specific_attribute);delete t.creator_id,s.addSubscriberTag(t),s.currentSubscriber.tags={cTag:t.c_tag,sTag:t.s_tag}},this.getSubscriberIP=function(){var t=JSON.parse(s.currentServiceChain.children[0].children[0].tenant.service_specific_attribute).wan_container_ip;s.logicTopologyData.children[0].subscriberIP=t},this.selectSubscriber=function(t){a.elWidths.push(160),s.addSubscriber(angular.copy(t)),s.highlightInstances([]),s.getSubscriberTag(),s.getSubscriberIP()},this.highlightInstances=function(t){var e=s.logicTopologyData.children[0].children[0].computeNodes;e.map(function(t){t.instances.map(function(t){return t.selected=!1,t})}),n.forEach(t,function(t){e.map(function(e){e.instances.map(function(e){return e.id===t.id&&(e.selected=!0,e.stats=t.stats,e.container=t.container),e})})})},this.getInstanceStatus=function(t){var n=e.defer(),i=void 0;if(s.currentSubscriber){var a=void 0;try{a=JSON.parse(t.tenant.service_specific_attribute)}catch(u){a=null}if(a&&a.instance_id)!function(){var t={};i=c.get({id:a.instance_id}).$promise.then(function(e){return t=e,o.getInstanceStats(t.instance_uuid)}).then(function(e){t.stats=e;var n="vcpe-"+s.currentSubscriber.tags.sTag+"-"+s.currentSubscriber.tags.cTag;return t.container={name:n},o.getContainerStats(n)}).then(function(e){return t.container.stats=e.stats,t.container.port=e.port,[t]})}();else{var d=e.defer();d.resolve([]),i=d.promise}}else{var l={service_vsg:{kind:"vCPE"},service_vbng:{kind:"vBNG"},service_volt:{kind:"vOLT"}};i=r.queryVsgInstances(l[t.name]).$promise.then(function(t){return o.getInstancesStats(t)})}return i.then(function(t){s.highlightInstances(t),n.resolve(t)})["catch"](function(t){n.reject(t)}),n.promise}}])}();
\ No newline at end of file
diff --git a/xos/core/xoslib/static/js/xosServiceTopology.js b/xos/core/xoslib/static/js/xosServiceTopology.js
deleted file mode 100644
index 5521bbf..0000000
--- a/xos/core/xoslib/static/js/xosServiceTopology.js
+++ /dev/null
@@ -1 +0,0 @@
-"use strict";angular.module("xos.serviceTopology",["ngResource","ngCookies","ngLodash","ngAnimate","ui.router","xos.helpers"]).config(["$stateProvider",function(e){e.state("home",{url:"/",template:"<diagnostic></diagnostic>"})}]).config(["$httpProvider",function(e){e.interceptors.push("NoHyperlinks")}]),angular.module("xos.serviceTopology").run(["$templateCache",function(e){e.put("templates/diagnostic.tpl.html",'<div class="container-fluid">\n  <div ng-hide="vm.error && vm.loader">\n    <div class="onethird-height">\n      <service-topology service-chain="vm.serviceChain"></service-topology>\n    </div>\n    <div class="twothird-height">\n      <!-- <div class="panel panel-primary subscriber-select">\n        <div class="panel-heading">Select a subscriber:</div>\n        <div class="panel-body">\n          <select class="form-control" ng-options="s as s.name for s in vm.subscribers" ng-model="vm.selectedSubscriber">\n            <option value="">Select a subscriber...</option>\n          </select>\n        </div>\n      </div> -->\n      <logic-topology ng-if="vm.subscribers" subscribers="vm.subscribers" selected="vm.selectedSubscriber"></logic-topology>\n    </div>\n  </div>\n  <div class="row" ng-show="vm.error">\n    <div class="col-xs-12">\n      <div class="alert alert-danger">\n        {{vm.error}}\n      </div>\n    </div>\n  </div>\n  <div class="row" ng-show="vm.loader">\n    <div class="col-xs-12">\n      <div class="loader">Loading</div>\n    </div>\n  </div>\n</div>'),e.put("templates/logicTopology.tpl.html",'<subscriber-modal open="vm.subscriberModal" subscribers="vm.subscribers"></subscriber-modal>\n<div class="instances-stats animate" ng-hide="vm.hideInstanceStats">\n  <div class="row">\n    <div class="col-sm-3 col-sm-offset-8">\n      <div class="panel panel-primary" ng-repeat="instance in vm.selectedInstances">\n        <div class="panel-heading">\n          {{instance.humanReadableName}}\n        </div>\n          <ul class="list-group">\n            <li class="list-group-item">Backend Status: {{instance.backend_status}}</li>\n            <li class="list-group-item">IP Address: {{instance.ip}}</li>\n          </ul>\n          <ul class="list-group">\n            <li class="list-group-item" ng-repeat="stat in instance.stats">\n              <span class="badge">{{stat.value}}</span>\n              {{stat.meter}}\n            </li>\n          </ul>\n        </div>\n      </div>  \n    </div>\n  </div>\n</div>'),e.put("templates/subscriber-modal.tpl.html",'<div class="modal fade" ng-class="{in: vm.open}" tabindex="-1" role="dialog">\n  <div class="modal-dialog modal-sm">\n    <div class="modal-content">\n      <div class="modal-header">\n        <button ng-click="vm.close()"  type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>\n        <h4 class="modal-title">Select a subscriber:</h4>\n      </div>\n      <div class="modal-body">\n        <select class="form-control" ng-options="s as s.humanReadableName for s in vm.subscribers" ng-model="vm.selected"></select>\n      </div>\n      <div class="modal-footer">\n        <button ng-click="vm.close()" type="button" class="btn btn-default" data-dismiss="modal">Close</button>\n        <button ng-click="vm.select(vm.selected)" type="button" class="btn btn-primary">Select</button>\n      </div>\n    </div><!-- /.modal-content -->\n  </div><!-- /.modal-dialog -->\n</div><!-- /.modal -->')}]),angular.module("xos.serviceTopology").run(["$location",function(e){e.path("/")}]),angular.bootstrap(angular.element("#xosServiceTopology"),["xos.serviceTopology"]),function(){angular.module("xos.serviceTopology").directive("subscriberModal",function(){return{scope:{subscribers:"=",open:"="},bindToController:!0,restrict:"E",templateUrl:"templates/subscriber-modal.tpl.html",controllerAs:"vm",controller:["$rootScope",function(e){var t=this;this.close=function(){t.open=!1},this.select=function(n){e.$emit("subscriber.selected",n),t.close()}}]}})}(),function(){angular.module("xos.serviceTopology").service("ServiceTopologyHelper",["$rootScope","$window","$log","lodash","ServiceRelation","serviceTopologyConfig","d3",function(e,t,n,r,i,a,o){var c,s,u,l=function(e){var t=e.append("g").attr({"class":"legend"});t.append("rect").attr({transform:function(e){return"translate(10, 80)"},width:100,height:100});var n=t.append("g").attr({"class":"node service"});n.append("circle").attr({r:a.circle.radius,transform:function(e){return"translate(30, 100)"}}),n.append("text").attr({transform:function(e){return"translate(45, 100)"},dy:".35em"}).text("Service").style("fill-opacity",1);var r=t.append("g").attr({"class":"node slice"});r.append("rect").attr({width:20,height:20,x:-10,y:-10,transform:function(e){return"translate(30, 130)"}}),r.append("text").attr({transform:function(e){return"translate(45, 130)"},dy:".35em"}).text("Slices").style("fill-opacity",1);var i=t.append("g").attr({"class":"node instance"});i.append("rect").attr({width:20,height:20,x:-10,y:-10,transform:function(e){return"translate(30, 160)"}}),i.append("text").attr({transform:function(e){return"translate(45, 160)"},dy:".35em"}).text("Instances").style("fill-opacity",1)},d=0,p=function(e,n,r){c=e,s=n,u=r;var l=i.depthOf(r),p=o.svg.diagonal().projection(function(e){return[e.y,e.x]}),f=n.nodes(r).reverse(),g=n.links(f);f.forEach(function(e){var n=(t.innerWidth-2*a.widthMargin)/l;e.y=e.depth*n});var v=e.selectAll("g.node").data(f,function(e){return e.id||(e.id=++d)}),m=v.enter().append("g").attr({"class":function(e){return"node "+e.type},transform:function(e){return e.x&&e.y?"translate("+e.y+", "+e.x+")":"translate("+r.y0+", "+r.x0+")"}}),b=m.filter(".subscriber"),y=m.filter(".router"),x=m.filter(".service");b.append("rect").attr(a.square),y.append("rect").attr(a.square),x.append("circle").attr("r",1e-6).style("fill",function(e){return e._children?"lightsteelblue":"#fff"}).on("click",h),m.append("text").attr({x:function(e){return e.children?-a.circle.selectedRadius-3:a.circle.selectedRadius+3},dy:".35em",transform:function(e){return e.children&&e.parent?e.parent.x<e.x?"rotate(-30)":"rotate(30)":void 0},"text-anchor":function(e){return e.children?"end":"start"}}).text(function(e){return e.name}).style("fill-opacity",1e-6);var S=v.transition().duration(a.duration).attr({transform:function(e){return"translate("+e.y+","+e.x+")"}});S.select("circle").attr("r",function(e){return e.selected?a.circle.selectedRadius:a.circle.radius}).style("fill",function(e){return e.selected?"lightsteelblue":"#fff"}),S.select("text").style("fill-opacity",1);var T=v.exit().transition().duration(a.duration).remove();T.select("circle").attr("r",1e-6),T.select("text").style("fill-opacity",1e-6);var w=e.selectAll("path.link").data(g,function(e){return e.target.id});w.enter().insert("path","g").attr("class",function(e){return"link "+e.target.type+" "+(e.target.active?"":"active")}).attr("d",function(e){var t={x:r.x0,y:r.y0};return p({source:t,target:t})}),w.transition().duration(a.duration).attr("d",p),w.exit().transition().duration(a.duration).attr("d",function(e){var t={x:r.x,y:r.y};return p({source:t,target:t})}).remove(),f.forEach(function(e){e.x0=e.x,e.y0=e.y})},h=function(t){return t.selected?(t.selected=!t.selected,e.$emit("instance.detail.hide",{}),p(c,s,u)):(e.$emit("instance.detail",{name:t.name,service:t.service,tenant:t.tenant}),c.selectAll("circle").each(function(e){return e.selected=!1}),t.selected=!t.selected,void p(c,s,u))};this.updateTree=p,this.drawLegend=l}])}(),function(){angular.module("xos.serviceTopology").directive("serviceTopology",function(){return{restrict:"E",scope:{serviceChain:"="},bindToController:!0,controllerAs:"vm",template:"",controller:["$element","$window","$scope","d3","serviceTopologyConfig","ServiceRelation","Slice","Instances","Subscribers","ServiceTopologyHelper",function(e,t,n,r,i,a,o,c,s,u){var l=this,d=e[0];r.select(window).on("resize",function(){f(l.serviceChain)});var p,h,f=function(t){r.select(e[0]).select("svg").remove();var n=d.clientWidth-2*i.widthMargin,a=d.clientHeight-2*i.heightMargin,o=r.layout.tree().size([a,n]);h=r.select(e[0]).append("svg").style("width",d.clientWidth+"px").style("height",d.clientHeight+"px");var c=h.append("g").attr("transform","translate("+4*i.widthMargin+","+i.heightMargin+")");p=t,p.x0=a/2,p.y0=n/2,u.updateTree(c,o,p)};this.getInstances=function(e){c.query({slice:e.id}).$promise.then(function(t){l.selectedSlice=e,l.instances=t})["catch"](function(e){throw l.errors=e,new Error(e)})},n.$watch(function(){return l.serviceChain},function(e){e&&f(e)})}]}})}(),function(){angular.module("xos.serviceTopology").service("Services",["$resource",function(e){return e("/xos/services/:id",{id:"@id"})}]).service("Tenant",["$resource",function(e){return e("/xos/tenants",{id:"@id"},{queryVsgInstances:{method:"GET",isArray:!0,interceptor:{response:function(e){var t=[];return angular.forEach(e.data,function(e){var n=JSON.parse(e.service_specific_attribute);n&&n.instance_id&&t.push(n.instance_id)}),t}}},getSubscriberTag:{method:"GET",isArray:!0,interceptor:{response:function(e){return JSON.parse(e.data[0].service_specific_attribute)}}}})}]).service("Ceilometer",["$http","$q","Instances",function(e,t,n){var r=this;this.getInstanceStats=function(n){var r=t.defer();return e.get("/xoslib/xos-instance-statistics",{params:{"instance-uuid":n}}).then(function(e){r.resolve(e.data)})["catch"](function(e){r.reject(e)}),r.promise},this.getInstancesStats=function(e){var i=t.defer(),a=[],o=[];return e.forEach(function(e){a.push(n.get({id:e}).$promise)}),t.all(a).then(function(e){o=e;var n=[];return o.forEach(function(e){n.push(r.getInstanceStats(e.instance_uuid))}),t.all(n)}).then(function(e){o.map(function(t,n){t.stats=e[n]}),i.resolve(o)})["catch"](i.reject),i.promise},this.getContainerStats=function(n){var r=t.defer(),i={};return e.get("/xoslib/meterstatistics",{params:{resource:n}}).then(function(t){return i.stats=t.data,e.get("/xoslib/meterstatistics",{params:{resource:n+"-eth0"}})}).then(function(t){return i.port={eth0:t.data},e.get("/xoslib/meterstatistics",{params:{resource:n+"-eth1"}})}).then(function(e){i.port.eth1=e.data,r.resolve(i)})["catch"](function(e){r.reject(e)}),r.promise}}]).service("Slice",["$resource",function(e){return e("/xos/slices",{id:"@id"})}]).service("Instances",["$resource",function(e){return e("/xos/instances/:id",{id:"@id"})}]).service("Node",["$resource","$q","Instances",function(e,t,n){return e("/xos/nodes",{id:"@id"},{queryWithInstances:{method:"GET",isArray:!0,interceptor:{response:function(e){var r=t.defer(),i=[];return angular.forEach(e.data,function(e){i.push(n.query({node:e.id}).$promise)}),t.all(i).then(function(t){e.data.map(function(e,n){return e.instances=t[n],e}),r.resolve(e.data)}),r.promise}}}})}]).service("Subscribers",["$resource","$q","SubscriberDevice",function(e,t,n){return e("/xos/subscribers/:id",{id:"@id"},{queryWithDevices:{method:"GET",isArray:!0,interceptor:{response:function(e){var r=t.defer(),i=[];return angular.forEach(e.data,function(e){i.push(n.query({id:e.id}).$promise)}),t.all(i).then(function(t){e.data.map(function(e,n){return e.devices=t[n],e.type="subscriber",e.devices.map(function(e){return e.type="device"}),e}),r.resolve(e.data)}),r.promise}}},getWithDevices:{method:"GET",isArray:!1,interceptor:{response:function(e){var r=t.defer();return n.query({id:e.data.id}).$promise.then(function(t){t.map(function(e){return e.type="device"}),e.data.devices=t,e.data.type="subscriber",r.resolve(e.data)})["catch"](function(e){r.reject(e)}),r.promise}}}})}]).service("SubscriberDevice",["$resource",function(e){return e("/xoslib/rs/subscriber/:id/users/",{id:"@id"})}]).service("ServiceRelation",["$q","lodash","Services","Tenant","Slice","Instances",function(e,t,n,r,i,a){var o=function g(e){var t=0;return e.children&&e.children.forEach(function(e){var n=g(e);n>t&&(t=n)}),1+t},c=function(e,n){return t.filter(e,function(e){return e.subscriber_service===n})},s=function(e,n){var r,e=t.filter(e,function(e){return e.provider_service===n&&e.subscriber_tenant});return e.forEach(function(e){e.service_specific_attribute&&(r=JSON.parse(e.service_specific_attribute))}),r},u=function(e,n){var r=[];return t.forEach(e,function(e){var i=t.find(n,{id:e.provider_service});r.push(i)}),r},l=function v(e,n,r,i){var a=arguments.length<=4||void 0===arguments[4]?null:arguments[4],o=t.difference(n,[r]),l=c(e,r.id),d=u(l,n);o=t.difference(o,d),r.service_specific_attribute=s(e,r.id);var p={name:r.humanReadableName,parent:a,type:"service",service:r,tenant:i,children:[]};return t.forEach(d,function(n){var a=t.find(e,{subscriber_tenant:i.id,provider_service:n.id});p.children.push(v(e,o,n,a,r.humanReadableName))}),0===p.children.length&&p.children.push({name:"Router",type:"router",children:[]}),p},d=function(e,n){var r=arguments.length<=2||void 0===arguments[2]?{id:1,name:"fakeSubs"}:arguments[2],i=t.find(n,{subscriber_root:r.id}),a=t.find(e,{id:i.provider_service}),o=l(n,e,a,i);return{name:r.name,parent:null,type:"subscriber",children:[o]}},p=function(e,n){var r=function o(e,n,r){var i={type:"service",name:r.humanReadableName,service:r},a=t.find(n,{subscriber_service:r.id});if(a){var c=t.find(e,{id:a.provider_service});i.children=[o(e,n,c)]}else i.children=[{name:"Router",type:"router",children:[]}];return delete r.id,i},i=t.find(e,{id:3}),a={name:"Subscriber",type:"subscriber",parent:null,children:[r(e,n,i)]};return a},h=function(t){var i,a,o=e.defer();return n.query().$promise.then(function(e){return i=e,r.query().$promise}).then(function(e){a=e,o.resolve(d(i,a,t))})["catch"](function(e){throw new Error(e)}),o.promise},f=function(){var t,i,a=e.defer();return n.query().$promise.then(function(e){return t=e,r.query({kind:"coarse"}).$promise}).then(function(e){i=e,a.resolve(p(t,i))})["catch"](function(e){throw new Error(e)}),a.promise};return{get:f,buildServiceTree:p,getBySubscriber:h,buildLevel:l,buildSubscriberServiceTree:d,findLevelRelation:c,findLevelServices:u,depthOf:o,findSpecificInformation:s}}])}();var _slicedToArray=function(){function e(e,t){var n=[],r=!0,i=!1,a=void 0;try{for(var o,c=e[Symbol.iterator]();!(r=(o=c.next()).done)&&(n.push(o.value),!t||n.length!==t);r=!0);}catch(s){i=!0,a=s}finally{try{!r&&c["return"]&&c["return"]()}finally{if(i)throw a}}return n}return function(t,n){if(Array.isArray(t))return t;if(Symbol.iterator in Object(t))return e(t,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}();!function(){angular.module("xos.serviceTopology").service("RackHelper",["serviceTopologyConfig","lodash",function(e,t){var n=this;this.getComputeNodeLabelSize=function(){return e.computeNode.labelHeight+2*e.instance.margin},this.getComputeNodeSize=t.memoize(function(t){var r=3*e.instance.margin+2*e.instance.width,i=Math.round(t.length/2),a=n.getComputeNodeLabelSize(),o=e.instance.height*i+e.instance.margin*(i+1)+a;return[r,o]}),this.getRackSize=function(r){var i=0,a=e.computeNode.margin;return t.forEach(r,function(t){var r=n.getComputeNodeSize(t.instances),o=_slicedToArray(r,2),c=o[0],s=o[1];i=c+2*e.computeNode.margin,a+=s+e.computeNode.margin}),[i,a]},this.getInstancePosition=function(t){var r=Math.floor(t/2),i=t%2?1:0,a=n.getComputeNodeLabelSize(),o=e.instance.margin+e.instance.width*i+e.instance.margin*i,c=a+e.instance.margin+e.instance.height*r+e.instance.margin*r;return[o,c]},this.getComputeNodePosition=function(r,i){var a=e.computeNode.margin,o=t.reduce(r.slice(0,i),function(e,t){return e+n.getComputeNodeSize(t.instances)[1]},0),c=e.computeNode.margin+e.computeNode.margin*i+o;return[a,c]}}])}();var _slicedToArray=function(){function e(e,t){var n=[],r=!0,i=!1,a=void 0;try{for(var o,c=e[Symbol.iterator]();!(r=(o=c.next()).done)&&(n.push(o.value),!t||n.length!==t);r=!0);}catch(s){i=!0,a=s}finally{try{!r&&c["return"]&&c["return"]()}finally{if(i)throw a}}return n}return function(t,n){if(Array.isArray(t))return t;if(Symbol.iterator in Object(t))return e(t,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}();!function(){var e={cloud:" M 79.72 49.60 C 86.00 37.29 98.57 29.01 111.96 26.42 C 124.27 24.11 137.53 26.15 148.18 32.90 C 158.08 38.78 165.39 48.87 167.65 60.20 C 176.20 57.90 185.14 56.01 194.00 57.73 C 206.08 59.59 217.92 66.01 224.37 76.66 C 227.51 81.54 228.85 87.33 229.23 93.06 C 237.59 93.33 246.22 95.10 253.04 100.19 C 256.69 103.13 259.87 107.67 258.91 112.59 C 257.95 118.43 252.78 122.38 247.78 124.82 C 235.27 130.43 220.23 130.09 207.98 123.93 C 199.33 127.88 189.76 129.43 180.30 128.57 C 173.70 139.92 161.70 147.65 148.86 149.93 C 133.10 153.26 116.06 148.15 104.42 137.08 C 92.98 143.04 78.96 143.87 66.97 139.04 C 57.75 135.41 49.70 128.00 46.60 118.43 C 43.87 109.95 45.81 100.29 51.30 93.32 C 57.38 85.18 67.10 80.44 76.99 78.89 C 74.38 69.20 74.87 58.52 79.72 49.60 Z"},t=0,n=0;angular.module("xos.serviceTopology").service("NodeDrawer",["d3","serviceTopologyConfig","RackHelper","lodash",function(r,i,a,o){var c=this,s=this;this.addNetworks=function(t){t.append("path").attr({d:e.cloud,transform:"translate(-63, -52), scale(0.5)","class":"cloud"}),t.append("text").attr({"text-anchor":"middle"}).text(function(e){return e.name}),t.each(function(e){var t=r.select(this);"LAN"===e.name&&angular.isDefined(e.subscriberTag)&&(t.append("text").attr({"text-anchor":"middle",y:40}).text(function(){return"C-Tag: "+e.subscriberTag.cTag}),t.append("text").attr({"text-anchor":"middle",y:60}).text(function(){return"S-Tag: "+e.subscriberTag.sTag})),"WAN"===e.name&&angular.isDefined(e.subscriberIP)&&t.append("text").attr({"text-anchor":"middle",y:40}).text(function(){return"Public IP: "+e.subscriberIP})})},this.addRack=function(e){e.each(function(t){var n=a.getRackSize(t.computeNodes),r=_slicedToArray(n,2),o=r[0],s=r[1];e.select("g").remove();var u=e.append("g");u.attr({transform:"translate(0,0)"}).transition().duration(i.duration).attr({transform:function(){return"translate("+-(o/2)+", "+-(s/2)+")"}}),u.append("rect").attr({width:0,height:0}).transition().duration(i.duration).attr({width:o,height:s}),u.append("text").attr({"text-anchor":"middle",y:-10,x:o/2,opacity:0}).text(function(e){return e.name}).transition().duration(i.duration).attr({opacity:1}),c.drawComputeNodes(u,t.computeNodes)})},this.drawComputeNodes=function(e,n){var o=e.selectAll(".compute-nodes").data(n,function(e){return angular.isString(e.d3Id)||(e.d3Id="compute-node-"+ ++t),e.d3Id}),c=e.node().getBoundingClientRect(),u=c.width,l=c.height,d=o.enter().append("g");d.attr({transform:"translate("+u/2+", "+l/2+")","class":"compute-node"}).transition().duration(i.duration).attr({transform:function(e){return"translate("+a.getComputeNodePosition(n,e.d3Id.replace("compute-node-","")-1)+")"}}),d.append("rect").attr({width:0,height:0}).transition().duration(i.duration).attr({width:function(e){return a.getComputeNodeSize(e.instances)[0]},height:function(e){return a.getComputeNodeSize(e.instances)[1]}}),d.append("text").attr({"text-anchor":"start",y:15,x:10,opacity:0}).text(function(e){return e.humanReadableName.split(".")[0]}).transition().duration(i.duration).attr({opacity:1}),d.length>0&&d.each(function(e){s.drawInstances(r.select(this),e.instances)})};var u=function(e){return e.replace("app_","").replace("service_","").replace("mysite_","").replace("_instance","")},l=function(e){function t(e,t){return t.substring(0,e.length)===e}return t("0 - ",e.backend_status)?"provisioning":t("1 - ",e.backend_status)?"good":t("2 - ",e.backend_status)?"bad":""},d=function(e,t){var n=e.append("g").attr({"class":"container",transform:"translate("+i.instance.margin+", 115)"});n.append("rect").attr({width:250-2*i.container.margin,height:i.container.height}),n.append("text").attr({y:20,x:i.instance.margin,"class":"name"}).text(t.name);var r=["memory","memory.usage","cpu_util"];r.forEach(function(e,r){var a=o.find(t.stats,{meter:e});angular.isDefined(a)&&n.append("text").attr({y:40+15*r,x:i.instance.margin,opacity:0}).text(a.description+": "+Math.round(a.value)+" "+a.unit).transition().duration(i.duration).attr({opacity:1})});var a=["eth0","eth1"],c=[{meter:"network.incoming.bytes.rate",label:"Incoming"},{meter:"network.outgoing.bytes.rate",label:"Outgoing"}];a.forEach(function(e,r){0!==t.port[e].length&&(n.append("text").attr({y:90,x:i.instance.margin+120*r,"class":"name"}).text(t.name+"-"+e),c.forEach(function(a,c){var s=o.find(t.port[e],{meter:a.meter});angular.isDefined(s)&&n.append("text").attr({y:105+15*c,x:i.instance.margin+120*r,opacity:0}).text(a.label+": "+Math.round(s.value)+" "+s.unit).transition().duration(i.duration).attr({opacity:1})}))})},p=function(e,t){var n=e.append("g").attr({transform:"translate(200, -120)","class":"stats-container"});n.append("line").attr({x1:-160,y1:120,x2:0,y2:50,stroke:"black",opacity:0}).transition().duration(i.duration).attr({opacity:1});var r=110,a=250;t.container&&(r+=i.container.height+2*i.container.margin),n.append("rect").attr({width:a,height:r,opacity:0}).transition().duration(i.duration).attr({opacity:1}),n.append("text").attr({y:15,x:i.instance.margin,"class":"name",opacity:0}).text(t.humanReadableName).transition().duration(i.duration).attr({opacity:1}),n.append("text").attr({y:30,x:i.instance.margin,"class":"ip",opacity:0}).text(t.ip).transition().duration(i.duration).attr({opacity:1});var c=["memory","memory.usage","cpu","vcpus"];c.forEach(function(e,r){var a=o.find(t.stats,{meter:e});n.append("text").attr({y:55+15*r,x:i.instance.margin,opacity:0}).text(a.description+": "+Math.round(a.value)+" "+a.unit).transition().duration(i.duration).attr({opacity:1})}),t.container&&d(n,t.container)};this.drawInstances=function(e,t){var o=e.node().getBoundingClientRect(),c=o.width,s=o.height,d=e.selectAll(".instances").data(t,function(e){return angular.isString(e.d3Id)?e.d3Id:e.d3Id="instance-"+ ++n}),h=d.enter().append("g");h.attr({transform:"translate("+c/2+", "+s/2+")","class":function(e){return"instance "+(e.selected?"active":"")+" "+l(e)}}).transition().duration(i.duration).attr({transform:function(e,t){return"translate("+a.getInstancePosition(t)+")"}}),h.append("rect").attr({width:0,height:0}).transition().duration(i.duration).attr({width:i.instance.width,height:i.instance.height}),h.append("text").attr({"text-anchor":"middle",y:23,x:40,opacity:0}).text(function(e){return u(e.humanReadableName)}).transition().duration(i.duration).attr({opacity:1}),h.each(function(e,t){var n=r.select(this);angular.isDefined(e.stats)&&e.selected&&p(n,e,t)}),h.on("click",function(e){console.log("Draw vignette with stats for instance: "+e.name)})},this.addPhisical=function(e){e.append("rect").attr(i.square),e.append("text").attr({"text-anchor":"middle",y:i.square.y-10}).text(function(e){return e.name})},this.addDevice=function(e){e.append("circle").attr(i.circle),e.append("text").attr({"text-anchor":"end",x:-i.circle.r-10,y:i.circle.r/2}).text(function(e){return e.name||e.mac})}}])}();var _slicedToArray=function(){function e(e,t){var n=[],r=!0,i=!1,a=void 0;try{for(var o,c=e[Symbol.iterator]();!(r=(o=c.next()).done)&&(n.push(o.value),!t||n.length!==t);r=!0);}catch(s){i=!0,a=s}finally{try{!r&&c["return"]&&c["return"]()}finally{if(i)throw a}}return n}return function(t,n){if(Array.isArray(t))return t;if(Symbol.iterator in Object(t))return e(t,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}();!function(){angular.module("xos.serviceTopology").service("LogicTopologyHelper",["$window","$log","$rootScope","lodash","serviceTopologyConfig","NodeDrawer","ChartData",function(e,t,n,r,i,a,o){var c,s,u,l,d,p,h=this,f=0,g=o.logicTopologyData;this.computeElementPosition=function(e){var t=[],n=r.reduce(i.elWidths,function(e,t){return t+e},0),a=e-n-2*i.widthMargin,o=a/(i.elWidths.length-1);return r.forEach(i.elWidths,function(n,a){var c=0;0!==a&&(c=r.reduce(i.elWidths.slice(0,a),function(e,t){return t+e},0));var s=i.widthMargin+o*a+n/2+c;t.push(e-s)}),t};var v=function(e){var t=p.nodes(e);t.forEach(function(e){e.y=h.computeElementPosition(l)[e.depth]});var n=p.links(t);return[t,n]},m=function(e,t){var r=e.selectAll("g.node").data(t,function(e){return angular.isString(e.d3Id)||(e.d3Id="tree-"+ ++f),e.d3Id});r.enter().append("g").attr({"class":function(e){return"node "+e.type},transform:"translate("+l/2+", "+d/2+")"});a.addNetworks(r.filter(".network")),a.addRack(r.filter(".rack")),a.addPhisical(r.filter(".router")),a.addPhisical(r.filter(".subscriber")),a.addDevice(r.filter(".device")),r.filter(".subscriber").on("click",function(){n.$emit("subscriber.modal.open")});r.transition().duration(i.duration).attr({transform:function(e){return"translate("+e.y+","+e.x+")"}}),r.exit().remove()},b=function(e,t){c=d3.svg.diagonal().projection(function(e){return[e.y,e.x]});var n=e.selectAll("path.link").data(t,function(e){return e.target.d3Id});n.enter().insert("path","g").attr("class",function(e){return"link "+e.target.type}).attr("d",function(e){var t={x:d/2,y:l/2};return c({source:t,target:t})}),n.transition().duration(i.duration).attr("d",c),n.exit().remove()};this.setupTree=function(e){l=e.node().getBoundingClientRect().width,d=e.node().getBoundingClientRect().height;var t=l-2*i.widthMargin,n=d-2*i.heightMargin;p=d3.layout.tree().size([n,t])},this.updateTree=function(e){var t=v(g),n=_slicedToArray(t,2);s=n[0],u=n[1],m(e,s),b(e,u)}}])}(),function(){angular.module("xos.serviceTopology").directive("logicTopology",function(){return{restrict:"E",scope:{subscribers:"=",selected:"="},bindToController:!0,controllerAs:"vm",templateUrl:"templates/logicTopology.tpl.html",controller:["$element","$log","$scope","$rootScope","$timeout","d3","LogicTopologyHelper","Node","Tenant","Ceilometer","serviceTopologyConfig","ChartData",function(e,t,n,r,i,a,o,c,s,u,l,d){var p=this;t.info("Logic Plane");var h;this.selectedInstances=[],this.hideInstanceStats=!0;var f=function(e){h=a.select(e).append("svg").style("width",e.clientWidth+"px").style("height",e.clientHeight+"px")};d.getLogicTree().then(function(e){o.updateTree(h)}),n.$watch(function(){return p.selected},function(e){e&&(d.selectSubscriber(e),o.updateTree(h))}),r.$on("instance.detail.hide",function(){p.hideInstanceStats=!0,i(function(){p.selectedInstances=[],d.highlightInstances([]),o.updateTree(h)},500)}),r.$on("instance.detail",function(e,t){d.getInstanceStatus(t).then(function(e){o.updateTree(h)})}),f(e[0]),o.setupTree(h),this.openSubscriberModal=function(){p.subscriberModal=!0,n.$apply()},r.$on("subscriber.modal.open",function(){p.openSubscriberModal()})}]}})}(),function(){angular.module("xos.serviceTopology").directive("diagnostic",function(){return{restrict:"E",templateUrl:"templates/diagnostic.tpl.html",controllerAs:"vm",controller:["ChartData","Subscribers","ServiceRelation","$rootScope",function(e,t,n,r){var i=this;this.loader=!0,this.error=!1,t.query().$promise.then(function(e){return i.subscribers=e,n.get()}).then(function(e){i.serviceChain=e})["catch"](function(e){throw new Error(e)})["finally"](function(){i.loader=!1}),r.$on("subscriber.selected",function(r,a){n.getBySubscriber(a).then(function(n){return i.serviceChain=n,e.currentServiceChain=n,t.getWithDevices({id:a.id}).$promise}).then(function(t){i.selectedSubscriber=t,e.currentSubscriber=t})})}]}})}(),function(){angular.module("xos.serviceTopology").factory("d3",["$window",function(e){return e.d3}])}(),function(){angular.module("xos.serviceTopology").constant("serviceTopologyConfig",{widthMargin:20,heightMargin:30,duration:750,elWidths:[20,104,105,104,20],circle:{radius:10,r:10,selectedRadius:15},square:{width:20,height:20,x:-10,y:-10},rack:{width:105,height:50,x:-30,y:-25},computeNode:{width:50,height:20,margin:5,labelHeight:10,x:-25,y:-10},instance:{width:80,height:36,margin:5,x:-40,y:-18},container:{width:60,height:130,margin:5,x:-30,y:-15}})}(),function(){angular.module("xos.serviceTopology").service("ChartData",["$rootScope","$q","lodash","Tenant","Node","serviceTopologyConfig","Ceilometer","Instances",function(e,t,n,r,i,a,o,c){var s=this;this.currentSubscriber=null,this.currentServiceChain=null,this.logicTopologyData={name:"Router",type:"router",children:[{name:"WAN",type:"network",children:[{name:"Rack",type:"rack",computeNodes:[],children:[{name:"LAN",type:"network",children:[{name:"Subscriber",type:"subscriber"}]}]}]}]},this.getLogicTree=function(){var e=t.defer();return i.queryWithInstances().$promise.then(function(t){s.logicTopologyData.children[0].children[0].computeNodes=t,e.resolve(s.logicTopologyData)}),e.promise},this.addSubscriberTag=function(e){s.logicTopologyData.children[0].children[0].children[0].subscriberTag={cTag:e.c_tag,sTag:e.s_tag}},this.addSubscriber=function(e){return e.children=e.devices,s.logicTopologyData.children[0].children[0].children[0].children=[e],s.logicTopologyData},this.getSubscriberTag=function(){var e=JSON.parse(s.currentServiceChain.children[0].tenant.service_specific_attribute);delete e.creator_id,s.addSubscriberTag(e),s.currentSubscriber.tags={cTag:e.c_tag,sTag:e.s_tag}},this.getSubscriberIP=function(){var e=JSON.parse(s.currentServiceChain.children[0].children[0].tenant.service_specific_attribute).wan_container_ip;s.logicTopologyData.children[0].subscriberIP=e},this.selectSubscriber=function(e){a.elWidths.push(160),s.addSubscriber(angular.copy(e)),s.highlightInstances([]),s.getSubscriberTag(),s.getSubscriberIP()},this.highlightInstances=function(e){var t=s.logicTopologyData.children[0].children[0].computeNodes;t.map(function(e){e.instances.map(function(e){return e.selected=!1,e})}),n.forEach(e,function(e){t.map(function(t){t.instances.map(function(t){return t.id===e.id&&(t.selected=!0,t.stats=e.stats,t.container=e.container),t})})})},this.getInstanceStatus=function(e){var n=t.defer(),i=void 0;if(s.currentSubscriber){var a=void 0;try{a=JSON.parse(e.tenant.service_specific_attribute)}catch(u){a=null}if(a&&a.instance_id)!function(){var e={};i=c.get({id:a.instance_id}).$promise.then(function(t){return e=t,o.getInstanceStats(e.instance_uuid)}).then(function(t){e.stats=t;var n="vcpe-"+s.currentSubscriber.tags.sTag+"-"+s.currentSubscriber.tags.cTag;return e.container={name:n},o.getContainerStats(n)}).then(function(t){return e.container.stats=t.stats,e.container.port=t.port,[e]})}();else{var l=t.defer();l.resolve([]),i=l.promise}}else{var d={service_vsg:{kind:"vCPE"},service_vbng:{kind:"vBNG"},service_volt:{kind:"vOLT"}};i=r.queryVsgInstances(d[e.name]).$promise.then(function(e){return o.getInstancesStats(e)})}return i.then(function(e){s.highlightInstances(e),n.resolve(e)})["catch"](function(e){n.reject(e)}),n.promise}}])}();
\ No newline at end of file