Base tree layout
diff --git a/gui/ngXosViews/serviceTopology/src/css/dev.css b/gui/ngXosViews/serviceTopology/src/css/dev.css
new file mode 100644
index 0000000..7ff2305
--- /dev/null
+++ b/gui/ngXosViews/serviceTopology/src/css/dev.css
@@ -0,0 +1,15 @@
+
+html, body {
+  margin: 0;
+  padding: 0;
+  max-height: 100%;
+  height: 100%;
+}
+
+#xosServiceTopology{
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+}
\ No newline at end of file
diff --git a/gui/ngXosViews/serviceTopology/src/css/serviceTopology.css b/gui/ngXosViews/serviceTopology/src/css/serviceTopology.css
new file mode 100644
index 0000000..05b06ed
--- /dev/null
+++ b/gui/ngXosViews/serviceTopology/src/css/serviceTopology.css
@@ -0,0 +1,25 @@
+service-canvas {
+    height: 100%;
+    width: 100%;
+    display: block;
+}
+
+.node {
+    cursor: pointer;
+}
+
+.node circle {
+    fill: #fff;
+    stroke: steelblue;
+    stroke-width: 3px;
+}
+
+.node text {
+    font: 12px sans-serif;
+}
+
+.link {
+    fill: none;
+    stroke: #ccc;
+    stroke-width: 2px;
+}
\ No newline at end of file
diff --git a/gui/ngXosViews/serviceTopology/src/index.html b/gui/ngXosViews/serviceTopology/src/index.html
new file mode 100644
index 0000000..1627e38
--- /dev/null
+++ b/gui/ngXosViews/serviceTopology/src/index.html
@@ -0,0 +1,38 @@
+<!-- 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/serviceTopology.css">
+<!-- endinject -->
+
+<div ng-app="xos.serviceTopology" id="xosServiceTopology">
+    <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/topologyCanvas.js"></script>
+<script src="/.tmp/services.js"></script>
+<script src="/.tmp/d3.js"></script>
+<script src="/.tmp/config.js"></script>
+<!-- endinject -->
diff --git a/gui/ngXosViews/serviceTopology/src/js/config.js b/gui/ngXosViews/serviceTopology/src/js/config.js
new file mode 100644
index 0000000..b5c0db0
--- /dev/null
+++ b/gui/ngXosViews/serviceTopology/src/js/config.js
@@ -0,0 +1,10 @@
+(function () {
+  'use strict';
+
+  angular.module('xos.serviceTopology')
+  .constant('serviceTopologyConfig', {
+    widthMargin: 100,
+    heightMargin: 30
+  })
+
+}());
\ No newline at end of file
diff --git a/gui/ngXosViews/serviceTopology/src/js/d3.js b/gui/ngXosViews/serviceTopology/src/js/d3.js
new file mode 100644
index 0000000..d87ecda
--- /dev/null
+++ b/gui/ngXosViews/serviceTopology/src/js/d3.js
@@ -0,0 +1,9 @@
+(function () {
+  'use strict';
+
+  angular.module('xos.serviceTopology')
+    .factory('d3', function($window){
+      return $window.d3;
+    })
+
+}());
\ No newline at end of file
diff --git a/gui/ngXosViews/serviceTopology/src/js/main.js b/gui/ngXosViews/serviceTopology/src/js/main.js
new file mode 100644
index 0000000..1d86d86
--- /dev/null
+++ b/gui/ngXosViews/serviceTopology/src/js/main.js
@@ -0,0 +1,38 @@
+'use strict';
+
+angular.module('xos.serviceTopology', [
+  'ngResource',
+  'ngCookies',
+  'ngLodash',
+  'ui.router',
+  'xos.helpers'
+])
+.config(($stateProvider) => {
+  $stateProvider
+  .state('user-list', {
+    url: '/',
+    template: '<service-canvas></service-canvas>'
+  });
+})
+.config(function($httpProvider){
+  $httpProvider.interceptors.push('NoHyperlinks');
+})
+.directive('usersList', function(){
+  return {
+    restrict: 'E',
+    scope: {},
+    bindToController: true,
+    controllerAs: 'vm',
+    templateUrl: 'templates/users-list.tpl.html',
+    controller: function(Services){
+      // retrieving user list
+      Services.query().$promise
+      .then((res) => {
+        console.log(res);
+      })
+      .catch((e) => {
+        throw new Error(e);
+      });
+    }
+  };
+});
\ No newline at end of file
diff --git a/gui/ngXosViews/serviceTopology/src/js/services.js b/gui/ngXosViews/serviceTopology/src/js/services.js
new file mode 100644
index 0000000..93a1edb
--- /dev/null
+++ b/gui/ngXosViews/serviceTopology/src/js/services.js
@@ -0,0 +1,9 @@
+(function () {
+  'use strict';
+
+  angular.module('xos.serviceTopology')
+  .service('Services', function($resource){
+    return $resource('/xos/services');
+  });
+
+}());
\ No newline at end of file
diff --git a/gui/ngXosViews/serviceTopology/src/js/topologyCanvas.js b/gui/ngXosViews/serviceTopology/src/js/topologyCanvas.js
new file mode 100644
index 0000000..88d1388
--- /dev/null
+++ b/gui/ngXosViews/serviceTopology/src/js/topologyCanvas.js
@@ -0,0 +1,201 @@
+(function () {
+  'use strict';
+
+  angular.module('xos.serviceTopology')
+  .directive('serviceCanvas', function(){
+    return {
+      restrict: 'E',
+      scope: {},
+      bindToController: true,
+      controllerAs: 'vm',
+      templateUrl: 'templates/topology_canvas.tpl.html',
+      controller: function($element, $window, d3, serviceTopologyConfig){
+
+        // count the mas depth of an object
+        const depthOf = (obj) => {
+          var depth = 0;
+          if (obj.children) {
+            obj.children.forEach(function (d) {
+              var tmpDepth = depthOf(d);
+              if (tmpDepth > depth) {
+                depth = tmpDepth
+              }
+            })
+          }
+          return 1 + depth
+        };
+
+        const treeData = [
+          {
+            'name': 'Top Level',
+            'parent': 'null',
+            'children': [
+              {
+                'name': 'Level 2: A',
+                'parent': 'Top Level',
+                'children': [
+                  {
+                    'name': 'Son of A',
+                    'parent': 'Level 2: A'
+                  },
+                  {
+                    'name': 'Daughter of A',
+                    'parent': 'Level 2: A'
+                  }
+                ]
+              },
+              {
+                'name': 'Level 2: B',
+                'parent': 'Top Level'
+              }
+            ]
+          }
+        ];
+
+        const width = $window.innerWidth - serviceTopologyConfig.widthMargin;
+        const height = $window.innerHeight - serviceTopologyConfig.heightMargin;
+
+        const tree = d3.layout.tree()
+          .size([height, width]);
+
+        const diagonal = d3.svg.diagonal()
+          .projection(d => [d.y, d.x]);
+
+        const svg = d3.select($element[0])
+          .append('svg')
+          .style('width', `${$window.innerWidth}px`)
+          .style('height', `${$window.innerHeight}px`)
+          .append('g')
+          .attr("transform", "translate(" + serviceTopologyConfig.widthMargin+ "," + serviceTopologyConfig.heightMargin + ")");;
+
+        const resizeCanvas = () => {
+          var targetSize = svg.node().getBoundingClientRect();
+
+          d3.select(self.frameElement)
+            .attr('width', `${targetSize.width}px`)
+            .attr('height', `${targetSize.height}px`)
+        };
+
+        //d3.select(window)
+        //  .on('load', () => {
+        //    resizeCanvas();
+        //  });
+        //d3.select(window)
+        //  .on('resize', () => {
+        //    resizeCanvas();
+        //    update(root);
+        //  });
+
+        var root = treeData[0];
+        root.x0 = $window.innerHeight / 2;
+        root.y0 = 0;
+
+        var i = 0;
+        var duration = 750;
+
+        update(root);
+
+        function update(source) {
+
+          const maxDepth = depthOf(source);
+
+          // Compute the new tree layout.
+          var nodes = tree.nodes(root).reverse(),
+            links = tree.links(nodes);
+
+          // Normalize for fixed-depth.
+          nodes.forEach(function(d) {
+            console.log(d);
+            // 180 should be based on window.width and max node depth
+
+            d.y = d.depth * (($window.innerWidth - (serviceTopologyConfig.widthMargin * 2)) / maxDepth);
+            console.log(d.x);
+          });
+
+          // Update the nodes…
+          var node = svg.selectAll('g.node')
+            .data(nodes, function(d) { return d.id || (d.id = ++i); });
+
+          // Enter any new nodes at the parent's previous position.
+          var nodeEnter = node.enter().append('g')
+            .attr('class', 'node')
+            .attr('transform', function(d) {
+              // this is the starting position
+              return 'translate(' + source.y0 + ',' + source.x0 + ')';
+            });
+            //.on('click', click);
+
+          nodeEnter.append('circle')
+            .attr('r', 1e-6)
+            .style('fill', function(d) { return d._children ? 'lightsteelblue' : '#fff'; });
+
+          nodeEnter.append('text')
+            .attr('x', function(d) { return d.children || d._children ? -13 : 13; })
+            .attr('dy', '.35em')
+            .attr('text-anchor', function(d) { return d.children || d._children ? 'end' : 'start'; })
+            .text(function(d) { return d.name; })
+            .style('fill-opacity', 1e-6);
+
+          // Transition nodes to their new position.
+          var nodeUpdate = node.transition()
+            .duration(duration)
+            .attr('transform', function(d) {
+              return 'translate(' + d.y + ',' + d.x + ')';
+            });
+
+          nodeUpdate.select('circle')
+            .attr('r', 10)
+            .style('fill', function(d) { return d._children ? 'lightsteelblue' : '#fff'; });
+
+          nodeUpdate.select('text')
+            .style('fill-opacity', 1);
+
+          // Transition exiting nodes to the parent's new position.
+          var nodeExit = node.exit().transition()
+            .duration(duration)
+            .attr('transform', function(d) { return 'translate(' + source.y + ',' + source.x + ')'; })
+            .remove();
+
+          nodeExit.select('circle')
+            .attr('r', 1e-6);
+
+          nodeExit.select('text')
+            .style('fill-opacity', 1e-6);
+
+          // Update the links…
+          var link = svg.selectAll('path.link')
+            .data(links, function(d) { return d.target.id; });
+
+          // Enter any new links at the parent's previous position.
+          link.enter().insert('path', 'g')
+            .attr('class', 'link')
+            .attr('d', function(d) {
+              var o = {x: source.x0, y: source.y0};
+              return diagonal({source: o, target: o});
+            });
+
+          // Transition links to their new position.
+          link.transition()
+            .duration(duration)
+            .attr('d', diagonal);
+
+          // Transition exiting nodes to the parent's new position.
+          link.exit().transition()
+            .duration(duration)
+            .attr('d', function(d) {
+              var o = {x: source.x, y: source.y};
+              return diagonal({source: o, target: o});
+            })
+            .remove();
+
+          // Stash the old positions for transition.
+          nodes.forEach(function(d) {
+            d.x0 = d.x;
+            d.y0 = d.y;
+          });
+        }
+      }
+    }
+  });
+
+}());
\ No newline at end of file
diff --git a/gui/ngXosViews/serviceTopology/src/templates/topology_canvas.tpl.html b/gui/ngXosViews/serviceTopology/src/templates/topology_canvas.tpl.html
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gui/ngXosViews/serviceTopology/src/templates/topology_canvas.tpl.html
diff --git a/gui/ngXosViews/serviceTopology/src/templates/users-list.tpl.html b/gui/ngXosViews/serviceTopology/src/templates/users-list.tpl.html
new file mode 100644
index 0000000..2983ad0
--- /dev/null
+++ b/gui/ngXosViews/serviceTopology/src/templates/users-list.tpl.html
@@ -0,0 +1,14 @@
+<div class="row">
+  <h1>Users List</h1>
+  <p>This is only an example view.</p>
+</div>
+<div class="row">
+  <div class="span4">Email</div>
+  <div class="span4">First Name</div>
+  <div class="span4">Last Name</div>
+</div>  
+<div class="row" ng-repeat="user in vm.users">
+  <div class="span4">{{user.email}}</div>
+  <div class="span4">{{user.firstname}}</div>
+  <div class="span4">{{user.lastname}}</div>
+</div>  
\ No newline at end of file