Drawing a basic mCord Topology
diff --git a/views/ngXosViews/mcordTopology/src/css/dev.css b/views/ngXosViews/mcordTopology/src/css/dev.css
new file mode 100644
index 0000000..32d915d
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/src/css/dev.css
@@ -0,0 +1,7 @@
+#xosMcordTopology{
+  position: absolute;
+  /*top: 100px;
+  left: 200px;*/
+  width: 100%;
+  height: 100%;
+}
\ No newline at end of file
diff --git a/views/ngXosViews/mcordTopology/src/css/mcord.css b/views/ngXosViews/mcordTopology/src/css/mcord.css
new file mode 100644
index 0000000..54854ef
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/src/css/mcord.css
@@ -0,0 +1,46 @@
+[ui-view],
+m-cord-topology{
+  width: 100%;
+  height: 100%;
+  display: block;
+}
+
+line {
+  stroke: red;
+  stroke-width: 1;
+}
+
+circle,
+rect {
+  fill: #fff;
+  stroke-width: 1; 
+}
+
+.fabric {
+  stroke: green;
+}
+
+.bbu {
+  stroke: blue;
+}
+
+.bbu text {
+  font-size: 10px;
+}
+
+.rru {
+  stroke: blue;
+  fill: blue;
+}
+
+.rru-shadow {
+  fill: lightblue;
+}
+
+.MME, .SGW, .PGW {
+  stroke: purple;
+}
+
+.MME text, .SGW text, .PGW text {
+  font-size: 10px;
+}
\ No newline at end of file
diff --git a/views/ngXosViews/mcordTopology/src/index.html b/views/ngXosViews/mcordTopology/src/index.html
new file mode 100644
index 0000000..84baae5
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/src/index.html
@@ -0,0 +1,36 @@
+<!-- browserSync -->
+<!-- bower:css -->
+<link rel="stylesheet" href="vendor/bootstrap-css/css/bootstrap.css" />
+<!-- endbower --><!-- endcss -->
+<!-- inject:css -->
+<link rel="stylesheet" href="/css/dev.css">
+<link rel="stylesheet" href="/css/mcord.css">
+<!-- endinject -->
+
+<div ng-app="xos.mcordTopology" id="xosMcordTopology">
+    <div ui-view></div>
+</div>
+
+<!-- bower:js -->
+<script src="vendor/d3/d3.js"></script>
+<script src="vendor/jquery/dist/jquery.js"></script>
+<script src="vendor/angular/angular.js"></script>
+<script src="vendor/angular-mocks/angular-mocks.js"></script>
+<script src="vendor/angular-ui-router/release/angular-ui-router.js"></script>
+<script src="vendor/angular-cookies/angular-cookies.js"></script>
+<script src="vendor/angular-resource/angular-resource.js"></script>
+<script src="vendor/ng-lodash/build/ng-lodash.js"></script>
+<script src="vendor/bootstrap-css/js/bootstrap.js"></script>
+<!-- endbower --><!-- endjs -->
+<!-- inject:js -->
+<script src="/xosHelpers/src/xosHelpers.module.js"></script>
+<script src="/xosHelpers/src/services/noHyperlinks.interceptor.js"></script>
+<script src="/xosHelpers/src/services/csrfToken.interceptor.js"></script>
+<script src="/xosHelpers/src/services/api.services.js"></script>
+<script src="/api/ng-xoslib.js"></script>
+<script src="/api/ng-xos.js"></script>
+<script src="/api/ng-hpcapi.js"></script>
+<script src="/.tmp/main.js"></script>
+<script src="/.tmp/static.data.js"></script>
+<script src="/.tmp/bbu.js"></script>
+<!-- endinject -->
diff --git a/views/ngXosViews/mcordTopology/src/js/bbu.js b/views/ngXosViews/mcordTopology/src/js/bbu.js
new file mode 100644
index 0000000..1192c1d
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/src/js/bbu.js
@@ -0,0 +1,60 @@
+'use strict';
+
+angular.module('xos.mcordTopology')
+.service('NodeDrawer', function(){
+  this.drawBbus = (nodes) => {
+    nodes.append('circle')
+      .attr({
+        class: d => d.type,
+        r: 15
+      });
+
+    nodes.append('text')
+    .attr({
+      'text-anchor': 'middle',
+      y: 4
+    })
+    .text('BBU')
+  };
+
+  this.drawRrus = (nodes) => {
+
+    nodes.append('circle')
+      .attr({
+        class: d => `${d.type}-shadow`,
+        r: 30
+      });
+    
+    nodes.append('circle')
+      .attr({
+        class: d => d.type,
+        r: 10
+      });
+  };
+
+  this.drawFabric = (nodes) => {
+    nodes.append('rect')
+      .attr({
+        class: d => d.type,
+        width: 20,
+        height: 20,
+        x: -10,
+        y: -10
+      });
+  };
+
+  this.drawOthers = (nodes) => {
+    nodes.append('circle')
+      .attr({
+        class: d => d.type,
+        r: 15
+      });
+
+    nodes.append('text')
+    .attr({
+      'text-anchor': 'middle',
+      y: 4
+    })
+    .text(d => d.type)
+  };
+});
\ No newline at end of file
diff --git a/views/ngXosViews/mcordTopology/src/js/main.js b/views/ngXosViews/mcordTopology/src/js/main.js
new file mode 100644
index 0000000..f0605c3
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/src/js/main.js
@@ -0,0 +1,237 @@
+'use strict';
+
+angular.module('xos.mcordTopology', [
+  'ngResource',
+  'ngCookies',
+  'ngLodash',
+  'ui.router',
+  'xos.helpers'
+])
+.config(($stateProvider) => {
+  $stateProvider
+  .state('topology', {
+    url: '/',
+    template: '<m-cord-topology></m-cord-topology>'
+  });
+})
+.config(function($httpProvider){
+  $httpProvider.interceptors.push('NoHyperlinks');
+})
+.directive('mCordTopology', function(){
+  return {
+    restrict: 'E',
+    scope: {},
+    bindToController: true,
+    controllerAs: 'vm',
+    template: '',
+    controller: function($element, $window, XosApi, lodash, TopologyElements, NodeDrawer){
+
+      const el = $element[0];
+
+      let nodes = TopologyElements.nodes;
+      let links = TopologyElements.links;
+
+      const filterBBU = (instances) => {
+        return lodash.filter(instances, i => i.name.indexOf('BBU') >= 0);
+      };
+
+      const filterOthers = (instances) => {
+        return lodash.filter(instances, i => {
+          return (i.name.indexOf('MME') >= 0)
+          || (i.name.indexOf('SGW') >= 0)
+          || (i.name.indexOf('PGW') >= 0)
+        });
+      };
+
+      // retrieving instances list
+      XosApi.Instance_List_GET()
+      .then((instances) => {
+        addBbuNodes(filterBBU(instances));
+        addOtherNodes(filterOthers(instances));
+        draw(svg, nodes, links);
+      })
+      .catch((e) => {
+        throw new Error(e);
+      });
+
+      const force = d3.layout.force();
+
+      // create svg elements
+      const svg = d3.select(el)
+        .append('svg')
+        .style('width', `${el.clientWidth}px`)
+        .style('height', `${el.clientHeight}px`);
+
+
+      let hStep = el.clientWidth / 3;
+      let vStep = el.clientHeight / 5;
+
+      // replace human readable ids with d3 ids
+      const buildLinks = (links, nodes) => {
+        return links.map((l) => {
+          let source = lodash.findIndex(nodes, {id: l.source});
+          let target = lodash.findIndex(nodes, {id: l.target});
+          return {
+            source: source,
+            target: target,
+            value: 1
+          };
+
+        });
+      };
+
+      // find fabric nodes and center horizontally
+      const positionFabricNodes = (nodes) => {
+        return lodash.map(nodes, n => {
+          if(n.type !== 'fabric'){
+            return n;
+          }
+
+          n.x = n.x * hStep;
+          n.y = n.y * vStep;
+
+          return n;
+        });
+      };
+
+      const addBbuNodes = (instances) => {
+
+        // calculate bbu hStep
+        let bbuHStep = ((el.clientWidth / 2) / (instances.length + 1));
+
+        // create nodes
+        let bbuNodes = instances.map((n, i) => {
+          return {
+            type: 'bbu',
+            name: n.name,
+            id: `bbu-${n.id}`,
+            fixed: true,
+            y: vStep * 3,
+            x: bbuHStep * (i + 1)
+          };
+        });
+
+        // create links
+        let bbuLinks = bbuNodes.map(n => {
+          return {
+            source: n.id,
+            target: 'fabric2'
+          };
+        });
+
+        // fake RRU nodes and links
+        instances.forEach((n, i) => {
+          bbuNodes.push({
+            type: 'rru',
+            name: 'rru',
+            id: `rru-${n.id}`,
+            fixed: true,
+            y: vStep * 4,
+            x: bbuHStep * (i + 1)
+          });
+
+          bbuLinks.push({
+            source: `rru-${n.id}`,
+            target: `bbu-${n.id}`
+          });
+        })
+
+        nodes = nodes.concat(bbuNodes);
+        links = links.concat(bbuLinks);
+      };
+
+      // add MME, PGW, SGW nodes
+      const addOtherNodes = (instances) => {
+        let hStep = ((el.clientWidth / 2) / (instances.length + 1));
+
+        // create nodes
+        let otherNodes = instances.map((n, i) => {
+          return {
+            type: n.name.substring(0, 3),
+            name: n.name,
+            id: `${n.name.substring(0, 3)}-${n.id}`,
+            fixed: true,
+            y: vStep * 3,
+            x: (el.clientWidth / 2) + (hStep * (i + 1))
+          };
+        });
+
+        // create links
+        let otherLinks = otherNodes.map(n => {
+          return {
+            source: n.id,
+            target: 'fabric4'
+          };
+        });
+
+        nodes = nodes.concat(otherNodes);
+        links = links.concat(otherLinks);
+      }
+
+      // NOTE nodes get dublicated
+      const draw = (svg, nodes, links) => {
+
+        links = buildLinks(links, nodes);
+
+        nodes = positionFabricNodes(nodes);
+
+        // start force layout
+        force
+          .nodes(nodes)
+          .links(links)
+          .size([el.clientWidth, el.clientHeight])
+          .charge(-20)
+          .chargeDistance(200)
+          .linkDistance(80)
+          .linkStrength(0.1)
+          .start();
+
+        // draw links
+        var link = svg.selectAll('.link')
+          .data(links)
+          .enter().append('line')
+          .attr({
+            class: 'link',
+          });
+
+        //draw nodes
+        var node = svg.selectAll('.node')
+          .data(nodes, d => {
+            return d.id
+          });
+        
+        // append a group for any new node
+        var enter = node.enter()
+          .append('g', d => d.interfaceCfgIdentifier)
+          .attr({
+            class: d => d.type,
+            transform: d => `translate(${d.x}, ${d.y})`
+          });
+
+        // draw nodes
+        NodeDrawer.drawBbus(node.filter('.bbu'))
+        NodeDrawer.drawRrus(node.filter('.rru'))
+        NodeDrawer.drawFabric(node.filter('.fabric'))
+        NodeDrawer.drawOthers(node.filter(d => {
+          return (
+            d.type  === 'MME' ||
+            d.type === 'SGW' ||
+            d.type === 'PGW'
+          )
+        }));
+
+        force.on('tick', function() {
+          link
+            .attr('x1', d => d.source.x )
+            .attr('y1', d => d.source.y )
+            .attr('x2', d => d.target.x )
+            .attr('y2', d => d.target.y );
+
+          node.attr('transform', (d) => `translate(${d.x},${d.y})`);
+        });
+      };
+      
+      // draw(svg, TopologyElements.nodes, TopologyElements.links);
+    }
+  };
+});
\ No newline at end of file
diff --git a/views/ngXosViews/mcordTopology/src/js/static.data.js b/views/ngXosViews/mcordTopology/src/js/static.data.js
new file mode 100644
index 0000000..8dbca46
--- /dev/null
+++ b/views/ngXosViews/mcordTopology/src/js/static.data.js
@@ -0,0 +1,57 @@
+'use strict';
+
+angular.module('xos.mcordTopology')
+.constant('TopologyElements', {
+  nodes: [
+    {
+      id: 'fabric1',
+      type: 'fabric',
+      name: 'fabric1',
+      fixed: true,
+      x: 1,
+      y: 1
+    },
+    {
+      id: 'fabric2',
+      type: 'fabric',
+      name: 'fabric2',
+      fixed: true,
+      x: 1,
+      y: 2
+    },
+    {
+      id: 'fabric3',
+      type: 'fabric',
+      name: 'fabric3',
+      fixed: true,
+      x: 2,
+      y: 1
+    },
+    {
+      id: 'fabric4',
+      type: 'fabric',
+      name: 'fabric4',
+      fixed: true,
+      x: 2,
+      y: 2
+    }
+  ],
+  links: [
+    {
+      source: 'fabric1',
+      target: 'fabric2'
+    },
+    {
+      source: 'fabric1',
+      target: 'fabric4'
+    },
+    {
+      source: 'fabric3',
+      target: 'fabric4'
+    },
+    {
+      source: 'fabric3',
+      target: 'fabric2'
+    }
+  ]
+})
\ No newline at end of file